From 4789b5ffee11a0b7c129c2cd0a565ba907df0519 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sat, 16 Jul 2022 23:13:58 -0500 Subject: [PATCH] added relocatable data segments; better linking support --- include/astnodes.h | 11 +- include/wasm_emit.h | 68 +++++++- src/builtins.c | 2 +- src/checker.c | 2 +- src/onyx.c | 4 + src/parser.c | 6 +- src/wasm_emit.c | 367 +++++++++++++++++++++++++++--------------- src/wasm_intrinsics.h | 12 +- src/wasm_output.h | 20 ++- src/wasm_type_table.h | 284 ++++++++++++++++---------------- 10 files changed, 483 insertions(+), 293 deletions(-) diff --git a/include/astnodes.h b/include/astnodes.h index cdcf01ed..f3b2ee00 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -593,7 +593,7 @@ struct AstTyped { AstTyped_base; }; struct AstNamedValue { AstTyped_base; AstTyped* value; }; struct AstUnaryOp { AstTyped_base; UnaryOp operation; AstTyped *expr; }; struct AstNumLit { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; }; -struct AstStrLit { AstTyped_base; u64 addr; u64 length; b32 is_cstr: 1; }; +struct AstStrLit { AstTyped_base; u64 data_id; u64 length; b32 is_cstr: 1; }; struct AstLocal { AstTyped_base; }; struct AstDereference { AstTyped_base; AstTyped *expr; }; struct AstSizeOf { AstTyped_base; AstType *so_ast_type; Type *so_type; u64 size; }; @@ -654,7 +654,7 @@ struct AstFileContents { AstTyped *filename_expr; char *filename; // The parsed file name, with '\' sequences removed and resolved to a particular file if possible. - u32 addr, size; + u32 data_id, size; }; struct AstUnaryFieldAccess { AstTyped_base; @@ -1002,12 +1002,15 @@ struct AstAlias { AstTyped_base; AstTyped* alias; }; struct AstInclude { AstNode_base; AstTyped* name_node; char* name; }; struct AstMemRes { AstTyped_base; - u64 addr; AstTyped *initial_value; struct Entity *type_entity; b32 threadlocal : 1; + + // Set and used in the wasm emission. + u32 data_id; + u32 tls_offset; }; struct AstGlobal { AstTyped_base; @@ -1588,7 +1591,7 @@ extern Type type_auto_return; extern AstBasicType basic_type_auto_return; extern OnyxToken builtin_package_token; -extern AstNumLit builtin_heap_start; +extern AstGlobal builtin_heap_start; extern AstGlobal builtin_stack_top; extern AstGlobal builtin_tls_base; extern AstGlobal builtin_tls_size; diff --git a/include/wasm_emit.h b/include/wasm_emit.h index c1675308..3c7e44ed 100644 --- a/include/wasm_emit.h +++ b/include/wasm_emit.h @@ -577,10 +577,66 @@ typedef struct WasmImport { } WasmImport; typedef struct WasmDatum { - u32 offset, length; + u32 id; + u32 offset_, alignment; + u32 length; ptr data; } WasmDatum; +typedef enum DatumPatchInfoKind { + Datum_Patch_Instruction, + Datum_Patch_Data, + Datum_Patch_Relative, +} DatumPatchInfoKind; + +// +// This represents a pointer that should be filled in +// later when the corresponding data element is placed. +// +// There are three kinds of patches: +// - Instruction +// - Data +// - Relative +// +// In all cases, the `data_id` member is set to the id +// of the WasmDatum entry that will be the base address, +// and then the `offset` member will be added to that. +// +// In instruction patches, the `index` member is set +// to the index of the function where the instruction should +// be patched. The `location` member is set to the instruction +// that needs to have its data changed. +// +// In data patches, the `index` member is set to the id +// of the WasmDatum entry that needs to have a part of it +// updated. The `location` member is the offset into the +// data to update. It is assumed that 4 bytes will be reserved +// to be replaced with the pointer value. +// +// In relative patches, `index` member is set to the id +// of the WasmDatum entry that needs to have a part of it +// updated. The `location` member is the offset into the +// data to update. The difference between `Data` and `Relative` +// is that `Relative` *adds* the base address to the current +// value in the 4 bytes, as opposed to replacing it. As a +// convenience, if the value is 0 (null), it will remain as +// 0. +// +typedef struct DatumPatchInfo { + DatumPatchInfoKind kind; + u32 data_id; + u32 offset; + u32 location; + u32 index; +} DatumPatchInfo; + +// Context used when building a constexpr buffer +typedef struct ConstExprContext { + struct OnyxWasmModule *module; + ptr data; + u32 data_id; +} ConstExprContext; + typedef enum DeferredStmtType { Deferred_Stmt_Node, Deferred_Stmt_Code, @@ -605,7 +661,7 @@ typedef struct AllocatedSpace { } AllocatedSpace; typedef struct StrLitInfo { - u32 addr; + u32 data_id; u32 len; } StrLitInfo; @@ -633,6 +689,7 @@ typedef struct OnyxWasmModule { // NOTE: Mapping from local ast node ptrs to indicies or offsets, depending on the mode bh_imap local_map; + i32 current_func_idx; LocalAllocator* local_alloc; // NOTE: Mapping ptrs to elements @@ -642,6 +699,7 @@ typedef struct OnyxWasmModule { bh_arr(AllocatedSpace) local_allocations; bh_arr(PatchInfo) stack_leave_patches; + bh_arr(DatumPatchInfo) data_patches; bh_arr(ForRemoveInfo) for_remove_info; @@ -676,13 +734,13 @@ typedef struct OnyxWasmModule { u32 next_type_idx; u32 next_func_idx; u32 next_global_idx; - u32 next_datum_offset; u32 next_tls_offset; u32 next_elem_idx; u32 foreign_function_count; i32 *stack_top_ptr; i32 *tls_size_ptr; + i32 *heap_start_ptr; u64 stack_base_idx; CallingConvention curr_cc; i32 null_proc_func_idx; @@ -690,7 +748,11 @@ typedef struct OnyxWasmModule { b32 has_stack_locals : 1; } OnyxWasmModule; +typedef struct OnyxWasmLinkOptions { +} OnyxWasmLinkOptions; + OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc); +void onyx_wasm_module_link(OnyxWasmModule *module, OnyxWasmLinkOptions *options); void onyx_wasm_module_free(OnyxWasmModule* module); void onyx_wasm_module_write_to_buffer(OnyxWasmModule* module, bh_buffer* buffer); void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file); diff --git a/src/builtins.c b/src/builtins.c index a102fa11..b964d20c 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -42,7 +42,7 @@ static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_sta static OnyxToken builtin_stack_top_token = { Token_Type_Symbol, 11, "__stack_top ", { 0 } }; static OnyxToken builtin_tls_base_token = { Token_Type_Symbol, 10, "__tls_base ", { 0 } }; static OnyxToken builtin_tls_size_token = { Token_Type_Symbol, 10, "__tls_size ", { 0 } }; -AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL, 0 }; +AstGlobal builtin_heap_start = { Ast_Kind_Global, Ast_Flag_Const, &builtin_heap_start_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL }; AstGlobal builtin_stack_top = { Ast_Kind_Global, 0, &builtin_stack_top_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL }; AstGlobal builtin_tls_base = { Ast_Kind_Global, 0, &builtin_tls_base_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL }; AstGlobal builtin_tls_size = { Ast_Kind_Global, 0, &builtin_tls_size_token, NULL, NULL, (AstType *) &basic_type_u32, NULL }; diff --git a/src/checker.c b/src/checker.c index 99e7747f..6dd82e7a 100644 --- a/src/checker.c +++ b/src/checker.c @@ -675,7 +675,7 @@ CheckStatus check_call(AstCall** pcall) { memset(filename, 0, sizeof(AstStrLit)); filename->kind = Ast_Kind_StrLit; filename->token = str_token; - filename->addr = 0; + filename->data_id = 0; add_entities_for_node(NULL, (AstNode *) filename, NULL, NULL); callsite->filename = filename; diff --git a/src/onyx.c b/src/onyx.c index 84889218..f394815b 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -298,6 +298,7 @@ static void context_init(CompileOptions* opts) { } add_entities_for_node(NULL, (AstNode *) &builtin_stack_top, context.global_scope, NULL); + add_entities_for_node(NULL, (AstNode *) &builtin_heap_start, context.global_scope, NULL); add_entities_for_node(NULL, (AstNode *) &builtin_tls_base, context.global_scope, NULL); add_entities_for_node(NULL, (AstNode *) &builtin_tls_size, context.global_scope, NULL); @@ -649,6 +650,7 @@ static i32 onyx_compile() { } static CompilerProgress onyx_flush_module() { + onyx_wasm_module_link(context.wasm_module, NULL); // NOTE: Output to file bh_file output_file; @@ -700,6 +702,8 @@ static CompilerProgress onyx_flush_module() { #ifdef ENABLE_RUN_WITH_WASMER static b32 onyx_run() { + onyx_wasm_module_link(context.wasm_module, NULL); + bh_buffer code_buffer; onyx_wasm_module_write_to_buffer(context.wasm_module, &code_buffer); diff --git a/src/parser.c b/src/parser.c index 4c59577c..7992ea9d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -502,7 +502,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { case Token_Type_Literal_String: { AstStrLit* str_node = make_node(AstStrLit, Ast_Kind_StrLit); str_node->token = expect_token(parser, Token_Type_Literal_String); - str_node->addr = 0; + str_node->data_id = 0; str_node->flags |= Ast_Flag_Comptime; ENTITY_SUBMIT(str_node); @@ -599,7 +599,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { AstStrLit* filename = make_node(AstStrLit, Ast_Kind_StrLit); filename->token = str_token; - filename->addr = 0; + filename->data_id = 0; ENTITY_SUBMIT(filename); retval = (AstTyped *) filename; @@ -739,7 +739,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { // Copy pasted from above. AstStrLit* str_node = make_node(AstStrLit, Ast_Kind_StrLit); str_node->token = expect_token(parser, Token_Type_Literal_String); - str_node->addr = 0; + str_node->data_id = 0; str_node->flags |= Ast_Flag_Comptime; str_node->is_cstr = 1; diff --git a/src/wasm_emit.c b/src/wasm_emit.c index 179caf44..b8beb9ec 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -250,12 +250,14 @@ enum StructuredBlockType { local_raw_free(mod->local_alloc, type2); \ } #define SUBMIT_PATCH(patch_arr, offset) bh_arr_push((patch_arr), ((PatchInfo) { bh_arr_length(code) - offset })) +#define NEXT_DATA_ID(mod) ((u32) bh_arr_length((mod)->data) + 1) EMIT_FUNC(function_body, AstFunction* fd); EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers); EMIT_FUNC(statement, AstNode* stmt); EMIT_FUNC(local_allocation, AstTyped* stmt); EMIT_FUNC_NO_ARGS(free_local_allocations); +EMIT_FUNC(data_relocation, u32 data_id); EMIT_FUNC(assignment, AstBinaryOp* assign); EMIT_FUNC(assignment_of_array, AstTyped* left, AstTyped* right); EMIT_FUNC(compound_assignment, AstBinaryOp* assign); @@ -299,8 +301,10 @@ EMIT_FUNC(zero_value_for_type, Type* type, OnyxToken* where); EMIT_FUNC(enter_structured_block, StructuredBlockType sbt); EMIT_FUNC_NO_ARGS(leave_structured_block); -static void emit_raw_data(OnyxWasmModule* mod, ptr data, AstTyped* node); -static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node); +static u32 emit_data_entry(OnyxWasmModule *mod, WasmDatum *datum); + +static void emit_constexpr(ConstExprContext *ctx, AstTyped *node, u32 offset); +static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset); #include "wasm_intrinsics.h" #include "wasm_type_table.h" @@ -509,6 +513,24 @@ EMIT_FUNC_NO_ARGS(free_local_allocations) { } } +EMIT_FUNC(data_relocation, u32 data_id) { + bh_arr(WasmInstruction) code = *pcode; + + u32 instr_idx = bh_arr_length(code); + WID(WI_PTR_CONST, 0); + assert(mod->current_func_idx >= 0); + + DatumPatchInfo patch; + patch.kind = Datum_Patch_Instruction; + patch.index = mod->current_func_idx; + patch.location = instr_idx; + patch.data_id = data_id; + patch.offset = 0; + bh_arr_push(mod->data_patches, patch); + + *pcode = code; +} + EMIT_FUNC(assignment, AstBinaryOp* assign) { bh_arr(WasmInstruction) code = *pcode; @@ -2277,12 +2299,17 @@ EMIT_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) { EMIT_FUNC(memory_reservation_location, AstMemRes* memres) { bh_arr(WasmInstruction) code = *pcode; - WID(WI_PTR_CONST, memres->addr); if (memres->threadlocal) { u64 tls_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_tls_base); + WID(WI_PTR_CONST, memres->tls_offset); WIL(WI_GLOBAL_GET, tls_base_idx); WI(WI_PTR_ADD); + + } else { + // :ProperLinking + assert(memres->data_id != 0); + emit_data_relocation(mod, &code, memres->data_id); } *pcode = code; @@ -2786,10 +2813,13 @@ EMIT_FUNC(expression, AstTyped* expr) { } case Ast_Kind_StrLit: { - WID(WI_PTR_CONST, ((AstStrLit *) expr)->addr); + // :ProperLinking + AstStrLit *strlit = (AstStrLit *) expr; + assert(strlit->data_id > 0); + emit_data_relocation(mod, &code, strlit->data_id); - if (((AstStrLit *) expr)->is_cstr == 0) - WID(WI_I32_CONST, ((AstStrLit *) expr)->length); + if (strlit->is_cstr == 0) + WID(WI_I32_CONST, strlit->length); break; } @@ -2980,10 +3010,11 @@ EMIT_FUNC(expression, AstTyped* expr) { case Ast_Kind_File_Contents: { AstFileContents* fc = (AstFileContents *) expr; - assert(fc->addr > 0); + assert(fc->data_id > 0); assert(fc->size > 0); - WID(WI_PTR_CONST, fc->addr); + // :ProperLinking + emit_data_relocation(mod, &code, fc->data_id); WID(WI_I32_CONST, fc->size); break; } @@ -3398,11 +3429,13 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { bh_arr_new(mod->allocator, wasm_func.code, 4); i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) fd); + mod->current_func_idx = func_idx; if (fd == builtin_initialize_data_segments && context.options->use_post_mvp_features) { emit_initialize_data_segments_body(mod, &wasm_func.code); 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); + mod->current_func_idx = -1; return; } @@ -3410,6 +3443,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { emit_run_init_procedures(mod, &wasm_func.code); 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); + mod->current_func_idx = -1; return; } @@ -3476,6 +3510,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); + mod->current_func_idx = -1; } static void emit_foreign_function(OnyxWasmModule* mod, AstFunction* fd) { @@ -3547,9 +3582,11 @@ static void emit_global(OnyxWasmModule* module, AstGlobal* global) { if (global == &builtin_stack_top) module->stack_top_ptr = &module->globals[global_idx].initial_value[0].data.i1; - if (global == &builtin_tls_size) { + if (global == &builtin_heap_start) + module->heap_start_ptr = &module->globals[global_idx].initial_value[0].data.i1; + + if (global == &builtin_tls_size) module->globals[global_idx].initial_value[0].data.i1 = module->next_tls_offset; - } } static void emit_string_literal(OnyxWasmModule* mod, AstStrLit* strlit) { @@ -3560,54 +3597,57 @@ static void emit_string_literal(OnyxWasmModule* mod, AstStrLit* strlit) { i8* strdata = bh_alloc_array(global_heap_allocator, i8, strlit->token->length + 1); i32 length = string_process_escape_seqs(strdata, strlit->token->text, strlit->token->length); - // Warning for having '%' in a string literal (because that probably is being used for a old print format) - /* - if (charset_contains((const char *) strdata, '%')) { - onyx_report_warning(strlit->token->pos, "Found string literal with '%%'"); - } - */ - i32 index = shgeti(mod->string_literals, (char *) strdata); if (index != -1) { StrLitInfo sti = mod->string_literals[index].value; - strlit->addr = sti.addr; - strlit->length = sti.len + (strlit->is_cstr ? 1 : 0); + strlit->data_id = sti.data_id; + strlit->length = sti.len; bh_free(global_heap_allocator, strdata); return; } - + + // :ProperLinking u32 actual_length = length + (strlit->is_cstr ? 1 : 0); WasmDatum datum = { - .offset = mod->next_datum_offset, + .alignment = 1, .length = actual_length, .data = strdata, }; - strlit->addr = (u32) mod->next_datum_offset, - strlit->length = length; - mod->next_datum_offset += actual_length; + strlit->data_id = emit_data_entry(mod, &datum); + strlit->length = length; - shput(mod->string_literals, (char *) strdata, ((StrLitInfo) { strlit->addr, strlit->length })); + // :ProperLinking + shput(mod->string_literals, (char *) strdata, ((StrLitInfo) { strlit->data_id, strlit->length })); +} - bh_arr_push(mod->data, datum); +static u32 emit_data_entry(OnyxWasmModule *mod, WasmDatum *datum) { + datum->offset_ = 0; + datum->id = NEXT_DATA_ID(mod); + bh_arr_push(mod->data, *datum); + return datum->id; } -static void emit_raw_data(OnyxWasmModule* mod, ptr data, AstTyped* node) { - if (!emit_raw_data_(mod, data, node)) { +static void emit_constexpr(ConstExprContext *ctx, AstTyped *node, u32 offset) { + if (!emit_constexpr_(ctx, node, offset)) { onyx_report_error(node->token->pos, Error_Critical, "Cannot generate constant data for '%s'.", onyx_ast_node_kind_string(node->kind)); } } -static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { +static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset) { +#define CE(type, off) (*((type *) bh_pointer_add(ctx->data, offset + (off)))) + assert(ctx->data_id); + assert(ctx->data); + b32 retval = 1; node = (AstTyped *) strip_aliases((AstNode *) node); if (node_is_type((AstNode *) node)) { Type* constructed_type = type_build_from_ast(context.ast_alloc, (AstType *) node); - ((i32 *) data)[0] = constructed_type->id; + CE(i32, 0) = constructed_type->id; return 1; } @@ -3619,7 +3659,7 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { i32 elem_size = type_size_of(al->type->Array.elem); bh_arr_each(AstTyped *, expr, al->values) { - retval &= emit_raw_data_(mod, bh_pointer_add(data, i * elem_size), *expr); + retval &= emit_constexpr_(ctx, *expr, i * elem_size + offset); i++; } @@ -3641,7 +3681,7 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { fori (i, 0, mem_count) { type_lookup_member_by_idx(sl_type, i, &smem); - retval &= emit_raw_data_(mod, bh_pointer_add(data, smem.offset), sl->args.values[i]); + retval &= emit_constexpr_(ctx, sl->args.values[i], smem.offset + offset); } break; @@ -3650,47 +3690,55 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { case Ast_Kind_StrLit: { AstStrLit* sl = (AstStrLit *) node; - // NOTE: This assumes the address and the length fields have been filled out + // NOTE: This assumes the data_id and the length fields have been filled out // by emit_string_literal. - u32* sdata = (u32 *) data; if (POINTER_SIZE == 4) { - sdata[0] = sl->addr; - sdata[1] = sl->length; + CE(u32, 0) = 0; + CE(u32, 4) = sl->length; } else { - sdata[0] = sl->addr; - sdata[1] = 0; - sdata[2] = sl->length; - sdata[3] = 0; + CE(u64, 0) = 0; + CE(u64, 8) = sl->length; } + + assert(sl->data_id > 0); + + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.index = ctx->data_id; + patch.location = offset; + patch.data_id = sl->data_id; + patch.offset = 0; + bh_arr_push(ctx->module->data_patches, patch); + break; } case Ast_Kind_Enum_Value: { AstEnumValue* ev = (AstEnumValue *) node; - retval &= emit_raw_data_(mod, data, (AstTyped *) ev->value); + retval &= emit_constexpr_(ctx, (AstTyped *) ev->value, offset); break; } case Ast_Kind_Function: { AstFunction* func = (AstFunction *) node; - *((u32 *) data) = get_element_idx(mod, func); + CE(u32, 0) = get_element_idx(ctx->module, func); break; } case Ast_Kind_Size_Of: { AstSizeOf* so = (AstSizeOf *) node; - *((u32 *) data) = so->size; + CE(u32, 0) = so->size; break; } case Ast_Kind_Align_Of: { AstAlignOf* ao = (AstAlignOf *) node; - *((u32 *) data) = ao->alignment; + CE(u32, 0) = ao->alignment; break; } case Ast_Kind_Zero_Value: { - memset(data, 0, type_size_of(node->type)); + memset(bh_pointer_add(ctx->data, offset), 0, type_size_of(node->type)); break; } @@ -3710,31 +3758,31 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { case Basic_Kind_Bool: case Basic_Kind_I8: case Basic_Kind_U8: - *((i8 *) data) = (i8) ((AstNumLit *) node)->value.i; + CE(i8, 0) = (i8) ((AstNumLit *) node)->value.i; return retval; case Basic_Kind_I16: case Basic_Kind_U16: - *((i16 *) data) = (i16) ((AstNumLit *) node)->value.i; + CE(i16, 0) = (i16) ((AstNumLit *) node)->value.i; return retval; case Basic_Kind_I32: case Basic_Kind_U32: case Basic_Kind_Rawptr: - *((i32 *) data) = ((AstNumLit *) node)->value.i; + CE(i32, 0) = ((AstNumLit *) node)->value.i; return retval; case Basic_Kind_I64: case Basic_Kind_U64: - *((i64 *) data) = ((AstNumLit *) node)->value.l; + CE(i64, 0) = ((AstNumLit *) node)->value.l; return retval; case Basic_Kind_F32: - *((f32 *) data) = ((AstNumLit *) node)->value.f; + CE(f32, 0) = ((AstNumLit *) node)->value.f; return retval; case Basic_Kind_F64: - *((f64 *) data) = ((AstNumLit *) node)->value.d; + CE(f64, 0) = ((AstNumLit *) node)->value.d; return retval; default: break; @@ -3749,9 +3797,12 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) { } return retval; + +#undef CE } static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) { + // :ProperLinking Type* effective_type = memres->type; u64 alignment = type_alignment_of(effective_type); @@ -3759,49 +3810,49 @@ static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) { if (type_table_node != NULL && (AstMemRes *) type_table_node == memres) { u64 table_location = build_type_table(mod); - memres->addr = table_location; - + memres->data_id = table_location; return; } if (foreign_blocks_node != NULL && (AstMemRes *) foreign_blocks_node == memres) { u64 foreign_blocks_location = build_foreign_blocks(mod); - memres->addr = foreign_blocks_location; - + memres->data_id = foreign_blocks_location; return; } if (tagged_procedures_node != NULL && (AstMemRes *) tagged_procedures_node == memres) { u64 tagged_procedures_location = build_tagged_procedures(mod); - memres->addr = tagged_procedures_location; - + memres->data_id = tagged_procedures_location; return; } if (memres->threadlocal) { - memres->addr = mod->next_tls_offset; - bh_align(memres->addr, alignment); - mod->next_tls_offset = memres->addr + size; + memres->tls_offset = mod->next_tls_offset; + bh_align(memres->tls_offset, alignment); + mod->next_tls_offset = memres->tls_offset + size; } else { - memres->addr = mod->next_datum_offset; - bh_align(memres->addr, alignment); - mod->next_datum_offset = memres->addr + size; - } - - if (memres->initial_value != NULL) { - assert(!memres->threadlocal); - - u8* data = bh_alloc(global_heap_allocator, size); - emit_raw_data(mod, data, memres->initial_value); + // :ProperLinking + u8* data = NULL; + if (memres->initial_value != NULL) { + assert(!memres->threadlocal); + data = bh_alloc(global_heap_allocator, size); + } WasmDatum datum = { - .offset = memres->addr, + .alignment = alignment, .length = size, .data = data, }; - - bh_arr_push(mod->data, datum); + memres->data_id = emit_data_entry(mod, &datum); + + if (memres->initial_value != NULL) { + ConstExprContext constexpr_ctx; + constexpr_ctx.module = mod; + constexpr_ctx.data = data; + constexpr_ctx.data_id = memres->data_id; + emit_constexpr(&constexpr_ctx, memres->initial_value, 0); + } } } @@ -3829,14 +3880,11 @@ static void emit_file_contents(OnyxWasmModule* mod, AstFileContents* fc) { i32 index = shgeti(mod->loaded_file_info, fc->filename); if (index != -1) { StrLitInfo info = mod->loaded_file_info[index].value; - fc->addr = info.addr; - fc->size = info.len; + fc->data_id = info.data_id; + fc->size = info.len; return; } - u32 offset = mod->next_datum_offset; - bh_align(offset, 16); - if (!bh_file_exists(fc->filename)) { onyx_report_error(fc->token->pos, Error_Critical, "Unable to open file for reading, '%s'.", @@ -3855,23 +3903,18 @@ static void emit_file_contents(OnyxWasmModule* mod, AstFileContents* fc) { actual_data[contents.length] = 0; bh_file_contents_free(&contents); - shput(mod->loaded_file_info, fc->filename, ((StrLitInfo) { - .addr = offset, - .len = length - 1, - })); - - fc->addr = offset; - fc->size = length - 1; - WasmDatum datum = { - .offset = offset, + .alignment = 16, .length = length, .data = actual_data, }; + fc->data_id = emit_data_entry(mod, &datum); + fc->size = length - 1; - bh_arr_push(mod->data, datum); - - mod->next_datum_offset = offset + length; + shput(mod->loaded_file_info, fc->filename, ((StrLitInfo) { + .data_id = fc->data_id, + .len = fc->size, + })); } OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { @@ -3894,8 +3937,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .next_global_idx = 0, .data = NULL, - .next_datum_offset = 32, // Starting offset so null pointers don't immediately - // break constant data. - brendanfh 2020/12/16 + .data_patches = NULL, .next_tls_offset = 0, .tls_size_ptr = NULL, @@ -3909,6 +3951,8 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .stack_leave_patches = NULL, .deferred_stmts = NULL, + .heap_start_ptr = NULL, + .stack_top_ptr = NULL, .stack_base_idx = 0, @@ -3957,54 +4001,14 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { bh_arr_new(global_heap_allocator, module.stack_leave_patches, 4); bh_arr_new(global_heap_allocator, module.foreign_blocks, 4); bh_arr_new(global_heap_allocator, module.procedures_with_tags, 4); - - if (context.options->use_multi_threading) { - WasmImport mem_import = { - .kind = WASM_FOREIGN_MEMORY, - .min = 1024, - .max = 65536, // NOTE: Why not use all 4 Gigs of memory? - .shared = context.options->runtime == Runtime_Js, - - .mod = "onyx", - .name = "memory", - }; - - bh_arr_push(module.imports, mem_import); - } - - WasmExport mem_export = { - .kind = WASM_FOREIGN_MEMORY, - .idx = 0, - }; - - shput(module.exports, "memory", mem_export); - module.export_count++; - - WasmExport func_table_export = { - .kind = WASM_FOREIGN_TABLE, - .idx = 0, - }; - shput(module.exports, "func_type", func_table_export); - module.export_count++; + bh_arr_new(global_heap_allocator, module.data_patches, 4); return module; } void emit_entity(Entity* ent) { OnyxWasmModule* module = context.wasm_module; - - if (module->stack_top_ptr) { - *module->stack_top_ptr = module->next_datum_offset; - - if (*module->stack_top_ptr % 16 != 0) { - *module->stack_top_ptr += 16 - (*module->stack_top_ptr % 16); - } - - builtin_heap_start.value.i = *module->stack_top_ptr + (1 << 20); - if (builtin_heap_start.value.i % 16 != 0) { - builtin_heap_start.value.i += 16 - (builtin_heap_start.value.i % 16); - } - } + module->current_func_idx = -1; switch (ent->type) { case Entity_Type_Foreign_Function_Header: @@ -4094,6 +4098,101 @@ void emit_entity(Entity* ent) { ent->state = Entity_State_Finalized; } +void onyx_wasm_module_link(OnyxWasmModule *module, OnyxWasmLinkOptions *options) { + // If the pointer size is going to change, + // the code will probably need to be altered. + static_assert(POINTER_SIZE == 4); + + if (context.options->use_multi_threading) { + WasmImport mem_import = { + .kind = WASM_FOREIGN_MEMORY, + .min = 1024, + .max = 65536, // NOTE: Why not use all 4 Gigs of memory? + .shared = context.options->runtime == Runtime_Js, + + .mod = "onyx", + .name = "memory", + }; + + bh_arr_push(module->imports, mem_import); + } + + WasmExport mem_export = { + .kind = WASM_FOREIGN_MEMORY, + .idx = 0, + }; + + shput(module->exports, "memory", mem_export); + module->export_count++; + + WasmExport func_table_export = { + .kind = WASM_FOREIGN_TABLE, + .idx = 0, + }; + shput(module->exports, "func_type", func_table_export); + module->export_count++; + + u32 datum_offset = 32; // :LinkOption + bh_arr_each(WasmDatum, datum, module->data) { + assert(datum->id > 0); + + bh_align(datum_offset, datum->alignment); + datum->offset_ = datum_offset; + + // printf("Data ID %d -> %d\n", datum->id, datum->offset); + + datum_offset += datum->length; + } + + bh_arr_each(DatumPatchInfo, patch, module->data_patches) { + assert(patch->data_id > 0); + WasmDatum *datum = &module->data[patch->data_id - 1]; + assert(datum->id == patch->data_id); + + switch (patch->kind) { + case Datum_Patch_Instruction: { + WasmFunc *func = &module->funcs[patch->index - module->foreign_function_count]; + // printf("Patching instruction %d in func[%d] with %d\n", patch->location, patch->index, datum->offset); + + assert(func->code[patch->location].type == WI_PTR_CONST); + func->code[patch->location].data.l = (u64) datum->offset_ + patch->offset; + break; + } + + case Datum_Patch_Data: { + WasmDatum *datum_to_alter = &module->data[patch->index - 1]; + assert(datum_to_alter->id == patch->index); + // printf("Patching data %d in data[%d] with %d + %d\n", patch->location, patch->index, target_datum->offset, patch->offset); + + *((u32 *) bh_pointer_add(datum_to_alter->data, patch->location)) = (u32) datum->offset_ + patch->offset; + break; + } + + case Datum_Patch_Relative: { + WasmDatum *datum_to_alter = &module->data[patch->index - 1]; + assert(datum_to_alter->id == patch->index); + + u32 *addr = (u32 *) bh_pointer_add(datum_to_alter->data, patch->location); + if (*addr != 0) { + // printf("Patching data %d in data[%d] with %d + %d + %d\n", patch->location, patch->index, target_datum->offset, *addr, patch->offset); + *addr += (u32) datum->offset_ + patch->offset; + } + break; + } + + default: assert(0); + } + } + + assert(module->stack_top_ptr && module->heap_start_ptr); + + *module->stack_top_ptr = datum_offset; + bh_align(*module->stack_top_ptr, 16); // :LinkOption + + *module->heap_start_ptr = *module->stack_top_ptr + (1 << 20); // :LinkOption + bh_align(*module->heap_start_ptr, 16); +} + void onyx_wasm_module_free(OnyxWasmModule* module) { if (module->extended_instr_data != NULL) bh_arena_free(module->extended_instr_data); diff --git a/src/wasm_intrinsics.h b/src/wasm_intrinsics.h index 9f4ccba4..72b6bf83 100644 --- a/src/wasm_intrinsics.h +++ b/src/wasm_intrinsics.h @@ -412,13 +412,23 @@ bad_type: } EMIT_FUNC_NO_ARGS(initialize_data_segments_body) { + // :ProperLinking if (!context.options->use_multi_threading || !context.options->use_post_mvp_features) return; bh_arr(WasmInstruction) code = *pcode; + // + // Because this code is generated direction in the function + // it is assumed that EVERY data entry will be entered by + // this point. If data section entries can be entered after + // function body generation starts, this code will have to + // move to a link phase thing. i32 index = 0; bh_arr_each(WasmDatum, datum, mod->data) { - WID(WI_PTR_CONST, datum->offset); + assert(datum->id > 0); + if (datum->data == NULL) { index++; continue; } + + emit_data_relocation(mod, &code, datum->id); WID(WI_PTR_CONST, 0); WID(WI_I32_CONST, datum->length); WID(WI_MEMORY_INIT, ((WasmInstructionData) { index, 0 })); diff --git a/src/wasm_output.h b/src/wasm_output.h index adf4e274..2398f9fb 100644 --- a/src/wasm_output.h +++ b/src/wasm_output.h @@ -167,6 +167,7 @@ static i32 output_tablesection(OnyxWasmModule* module, bh_buffer* buff) { } static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) { + // :ProperLinking if (context.options->use_multi_threading) return 0; i32 prev_len = buff->length; @@ -181,7 +182,7 @@ static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) { // FIXME: This needs to be dynamically chosen depending on the size of // the data section and stack size pre-requeseted. - // :WasmMemory + // :WasmMemory :ProperLinking output_limits(1024, -1, 0, &vec_buff); leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); @@ -638,23 +639,28 @@ static i32 output_datasection(OnyxWasmModule* module, bh_buffer* buff) { bh_buffer_append(&vec_buff, leb, leb_len); bh_arr_each(WasmDatum, datum, module->data) { - assert(datum->data != NULL); - i32 memory_flags = 0x00; + // :ProperLinking if (context.options->use_multi_threading) memory_flags |= 0x01; bh_buffer_write_byte(&vec_buff, memory_flags); + // :ProperLinking if (!context.options->use_multi_threading) { bh_buffer_write_byte(&vec_buff, WI_I32_CONST); - leb = int_to_leb128((i64) datum->offset, &leb_len); + leb = int_to_leb128((i64) datum->offset_, &leb_len); bh_buffer_append(&vec_buff, leb, leb_len); bh_buffer_write_byte(&vec_buff, WI_BLOCK_END); } - leb = uint_to_uleb128((u64) datum->length, &leb_len); - bh_buffer_append(&vec_buff, leb, leb_len); - fori (i, 0, datum->length) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]); + if (datum->data != NULL) { + leb = uint_to_uleb128((u64) datum->length, &leb_len); + bh_buffer_append(&vec_buff, leb, leb_len); + fori (i, 0, datum->length) bh_buffer_write_byte(&vec_buff, ((u8 *) datum->data)[i]); + } else { + leb = uint_to_uleb128(0, &leb_len); + bh_buffer_append(&vec_buff, leb, leb_len); + } } leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); diff --git a/src/wasm_type_table.h b/src/wasm_type_table.h index 6ce7112a..2cb1c671 100644 --- a/src/wasm_type_table.h +++ b/src/wasm_type_table.h @@ -37,6 +37,12 @@ static u64 build_type_table(OnyxWasmModule* module) { bh_buffer table_buffer; bh_buffer_init(&table_buffer, global_heap_allocator, 4096); + u32 type_table_info_data_id = NEXT_DATA_ID(module); + + ConstExprContext constexpr_ctx; + constexpr_ctx.module = module; + constexpr_ctx.data_id = type_table_info_data_id; + // Write a "NULL" at the beginning so nothing will have to point to the first byte of the buffer. bh_buffer_write_u64(&table_buffer, 0); @@ -221,8 +227,8 @@ static u64 build_type_table(OnyxWasmModule* module) { u32 size = type_size_of(sln->value->type); bh_buffer_grow(&table_buffer, table_buffer.length + size); - u8* buffer = table_buffer.data + table_buffer.length; - if (emit_raw_data_(module, buffer, sln->value)) { + constexpr_ctx.data = table_buffer.data; + if (emit_constexpr_(&constexpr_ctx, sln->value, table_buffer.length)) { table_buffer.length += size; break; } @@ -263,9 +269,8 @@ static u64 build_type_table(OnyxWasmModule* module) { bh_buffer_align(&table_buffer, type_alignment_of(value->type)); bh_buffer_grow(&table_buffer, table_buffer.length + size); - u8* buffer = table_buffer.data + table_buffer.length; - - if (!emit_raw_data_(module, buffer, value)) { + constexpr_ctx.data = table_buffer.data; + if (!emit_constexpr_(&constexpr_ctx, value, table_buffer.length)) { // Failed to generate raw data // onyx_report_warning(value->token->pos, "Warning: failed to generate default value for '%s' in '%s'.\n", mem->name, s->name); value_locations[i++] = 0; @@ -304,9 +309,8 @@ static u64 build_type_table(OnyxWasmModule* module) { meta_tag_locations[j] = table_buffer.length; bh_buffer_grow(&table_buffer, table_buffer.length + size); - u8* buffer = table_buffer.data + table_buffer.length; - - assert(emit_raw_data_(module, buffer, value)); + constexpr_ctx.data = table_buffer.data; + assert(emit_constexpr_(&constexpr_ctx, value, table_buffer.length)); table_buffer.length += size; j += 1; @@ -369,9 +373,8 @@ static u64 build_type_table(OnyxWasmModule* module) { struct_tag_locations[i] = table_buffer.length; bh_buffer_grow(&table_buffer, table_buffer.length + size); - u8* buffer = table_buffer.data + table_buffer.length; - - assert(emit_raw_data_(module, buffer, value)); + constexpr_ctx.data = table_buffer.data; + assert(emit_constexpr_(&constexpr_ctx, value, table_buffer.length)); table_buffer.length += size; i += 1; @@ -491,9 +494,9 @@ static u64 build_type_table(OnyxWasmModule* module) { tag_locations[i] = table_buffer.length; bh_buffer_grow(&table_buffer, table_buffer.length + size); - u8* buffer = table_buffer.data + table_buffer.length; - assert(emit_raw_data_(module, buffer, value)); + constexpr_ctx.data = table_buffer.data; + assert(emit_constexpr_(&constexpr_ctx, value, table_buffer.length)); table_buffer.length += size; i += 1; @@ -538,63 +541,62 @@ static u64 build_type_table(OnyxWasmModule* module) { bh_printf("Type table size: %d bytes.\n", table_buffer.length); } - u32 offset = module->next_datum_offset; - bh_align(offset, 8); + WasmDatum type_info_data = { + .alignment = 8, + .length = table_buffer.length, + .data = table_buffer.data, + }; + emit_data_entry(module, &type_info_data); + assert(type_info_data.id == type_table_info_data_id); - u64 type_table_location = offset; + bh_arr_each(u32, patch_loc, base_patch_locations) { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Relative; + patch.data_id = type_info_data.id; + patch.offset = 0; + patch.index = type_info_data.id; + patch.location = *patch_loc; + bh_arr_push(module->data_patches, patch); + } WasmDatum type_table_data = { - .offset = offset, + .alignment = POINTER_SIZE, .length = type_count * POINTER_SIZE, .data = table_info, }; - bh_arr_push(module->data, type_table_data); - - offset += type_table_data.length; + emit_data_entry(module, &type_table_data); fori (i, 0, type_count) { - table_info[i] += offset; - } - - bh_arr_each(u32, patch_loc, base_patch_locations) { - if (POINTER_SIZE == 4) { - u32* loc = bh_pointer_add(table_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } - if (POINTER_SIZE == 8) { - u64* loc = bh_pointer_add(table_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.data_id = type_info_data.id; + patch.offset = table_info[i]; + patch.index = type_table_data.id; + patch.location = i * POINTER_SIZE; + bh_arr_push(module->data_patches, patch); } - WasmDatum type_info_data = { - .offset = offset, - .length = table_buffer.length, - .data = table_buffer.data, - }; - bh_arr_push(module->data, type_info_data); - offset += type_info_data.length; - - u64 global_data_ptr = offset; - Table_Info_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE); - tmp_data[0] = type_table_location; + tmp_data[0] = 0; tmp_data[1] = type_count; WasmDatum type_table_global_data = { - .offset = offset, + .alignment = POINTER_SIZE, .length = 2 * POINTER_SIZE, .data = tmp_data, }; - bh_arr_push(module->data, type_table_global_data); - offset += type_table_global_data.length; - - module->next_datum_offset = offset; + emit_data_entry(module, &type_table_global_data); + + { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.data_id = type_table_data.id; + patch.offset = 0; + patch.index = type_table_global_data.id; + patch.location = 0; + bh_arr_push(module->data_patches, patch); + } - return global_data_ptr; + return type_table_global_data.id; #undef WRITE_SLICE #undef WRITE_PTR @@ -686,63 +688,61 @@ static u64 build_foreign_blocks(OnyxWasmModule* module) { bh_printf("Foreign blocks size: %d bytes.\n", foreign_buffer.length); } - u32 offset = module->next_datum_offset; - bh_align(offset, 8); + WasmDatum foreign_info_data = { + .alignment = 8, + .length = foreign_buffer.length, + .data = foreign_buffer.data, + }; + emit_data_entry(module, &foreign_info_data); - u64 foreign_blocks_location = offset; + bh_arr_each(u32, patch_loc, base_patch_locations) { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Relative; + patch.data_id = foreign_info_data.id; + patch.offset = 0; + patch.index = foreign_info_data.id; + patch.location = *patch_loc; + bh_arr_push(module->data_patches, patch); + } - WasmDatum foreign_blocks_data = { - .offset = offset, + WasmDatum foreign_table_data = { + .alignment = POINTER_SIZE, .length = block_count * POINTER_SIZE, .data = foreign_info, }; - bh_arr_push(module->data, foreign_blocks_data); - - offset += foreign_blocks_data.length; + emit_data_entry(module, &foreign_table_data); fori (i, 0, block_count) { - foreign_info[i] += offset; - } - - bh_arr_each(u32, patch_loc, base_patch_locations) { - if (POINTER_SIZE == 4) { - u32* loc = bh_pointer_add(foreign_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } - if (POINTER_SIZE == 8) { - u64* loc = bh_pointer_add(foreign_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.data_id = foreign_info_data.id; + patch.offset = foreign_info[i]; + patch.index = foreign_table_data.id; + patch.location = i * POINTER_SIZE; + bh_arr_push(module->data_patches, patch); } - WasmDatum foreign_blocks_info_data = { - .offset = offset, - .length = foreign_buffer.length, - .data = foreign_buffer.data, - }; - bh_arr_push(module->data, foreign_blocks_info_data); - offset += foreign_blocks_info_data.length; - - u64 global_data_ptr = offset; - Foreign_Block_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE); - tmp_data[0] = foreign_blocks_location; + tmp_data[0] = 0; tmp_data[1] = block_count; - WasmDatum foreign_blocks_global_data = { - .offset = offset, + WasmDatum foreign_table_global_data = { + .alignment = POINTER_SIZE, .length = 2 * POINTER_SIZE, .data = tmp_data, }; - bh_arr_push(module->data, foreign_blocks_global_data); - offset += foreign_blocks_global_data.length; - - module->next_datum_offset = offset; + emit_data_entry(module, &foreign_table_global_data); + + { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.data_id = foreign_table_data.id; + patch.location = 0; + patch.index = foreign_table_global_data.id; + patch.offset = 0; + bh_arr_push(module->data_patches, patch); + } - return global_data_ptr; + return foreign_table_global_data.id; #undef WRITE_SLICE #undef WRITE_PTR @@ -778,6 +778,12 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { bh_buffer tag_proc_buffer; bh_buffer_init(&tag_proc_buffer, global_heap_allocator, 4096); + u32 proc_info_data_id = NEXT_DATA_ID(module); + + ConstExprContext constexpr_ctx; + constexpr_ctx.module = module; + constexpr_ctx.data_id = proc_info_data_id; + // // This is necessary because 0 is an invalid offset to store in this // buffer, as 0 will map to NULL. This could be a single byte insertion, @@ -806,8 +812,9 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { u32 size = type_size_of(tag->type); bh_buffer_grow(&tag_proc_buffer, tag_proc_buffer.length + size); - u8* buffer = tag_proc_buffer.data + tag_proc_buffer.length; - emit_raw_data(module, buffer, tag); + + constexpr_ctx.data = tag_proc_buffer.data; + emit_constexpr(&constexpr_ctx, tag, tag_proc_buffer.length); tag_proc_buffer.length += size; } @@ -831,63 +838,62 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) { bh_printf("Tagged procedure size: %d bytes.\n", tag_proc_buffer.length); } - u32 offset = module->next_datum_offset; - bh_align(offset, 8); + WasmDatum proc_info_data = { + .alignment = 8, + .length = tag_proc_buffer.length, + .data = tag_proc_buffer.data, + }; + emit_data_entry(module, &proc_info_data); + assert(proc_info_data.id == proc_info_data_id); - u64 tagged_procedures_location = offset; + bh_arr_each(u32, patch_loc, base_patch_locations) { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Relative; + patch.data_id = proc_info_data.id; + patch.location = *patch_loc; + patch.index = proc_info_data.id; + patch.offset = 0; + bh_arr_push(module->data_patches, patch); + } - WasmDatum tagged_procedures_data = { - .offset = offset, + WasmDatum proc_table_data = { + .alignment = POINTER_SIZE, .length = proc_count * POINTER_SIZE, .data = tag_proc_info, }; - bh_arr_push(module->data, tagged_procedures_data); - - offset += tagged_procedures_data.length; + emit_data_entry(module, &proc_table_data); fori (i, 0, proc_count) { - tag_proc_info[i] += offset; - } - - bh_arr_each(u32, patch_loc, base_patch_locations) { - if (POINTER_SIZE == 4) { - u32* loc = bh_pointer_add(tag_proc_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } - if (POINTER_SIZE == 8) { - u64* loc = bh_pointer_add(tag_proc_buffer.data, *patch_loc); - if (*loc == 0) continue; - - *loc += offset; - } + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.data_id = proc_info_data.id; + patch.offset = tag_proc_info[i]; + patch.index = proc_table_data.id; + patch.location = i * POINTER_SIZE; + bh_arr_push(module->data_patches, patch); } - WasmDatum tagged_procedures_info_data = { - .offset = offset, - .length = tag_proc_buffer.length, - .data = tag_proc_buffer.data, - }; - bh_arr_push(module->data, tagged_procedures_info_data); - offset += tagged_procedures_info_data.length; - - u64 global_data_ptr = offset; - Tagged_Procedure_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE); - tmp_data[0] = tagged_procedures_location; + tmp_data[0] = 0; tmp_data[1] = proc_count; - WasmDatum tagged_procedures_global_data = { - .offset = offset, + WasmDatum proc_table_global_data = { + .alignment = POINTER_SIZE, .length = 2 * POINTER_SIZE, .data = tmp_data, }; - bh_arr_push(module->data, tagged_procedures_global_data); - offset += tagged_procedures_global_data.length; - - module->next_datum_offset = offset; + emit_data_entry(module, &proc_table_global_data); + + { + DatumPatchInfo patch; + patch.kind = Datum_Patch_Data; + patch.offset = 0; + patch.data_id = proc_table_data.id; + patch.index = proc_table_global_data.id; + patch.location = 0; + bh_arr_push(module->data_patches, patch); + } - return global_data_ptr; + return proc_table_global_data.id; #undef WRITE_SLICE #undef WRITE_PTR -- 2.25.1