added relocatable data segments; better linking support
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 17 Jul 2022 04:13:58 +0000 (23:13 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 17 Jul 2022 04:13:58 +0000 (23:13 -0500)
include/astnodes.h
include/wasm_emit.h
src/builtins.c
src/checker.c
src/onyx.c
src/parser.c
src/wasm_emit.c
src/wasm_intrinsics.h
src/wasm_output.h
src/wasm_type_table.h

index cdcf01ed9921b9f3176119d4beab9786549d1aaf..f3b2ee00daaad9788da508fec3cbe8ddd07bd6d4 100644 (file)
@@ -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;
index c16753089ef15927fabd84e535472c3f14c4737d..3c7e44ed7d954e0dc605a499ff0b4de98561652b 100644 (file)
@@ -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);
index a102fa11a5eada16144cc04b049282ae9ac513cf..b964d20c93a37df231af2edaf203d9c16265ddc3 100644 (file)
@@ -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 };
index 99e7747febdcea49db26eef1d8139435c977c668..6dd82e7a5153acee15fa9efc7f5eb885423176b6 100644 (file)
@@ -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;
index 8488921866883d1c361502f94628c621e7c79046..f394815bb70791d3871c75753d4e81c6832d5aef 100644 (file)
@@ -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);
 
index 4c59577c27d8e9796215f02e38c1749fe6622421..7992ea9d2fc0de2bffb7e9150ad1c66b9d7ebe50 100644 (file)
@@ -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;
 
index 179caf44aa01e402e9b253ec6410094e737e4e71..b8beb9ec134ab1daf761f1e579ed51eba9424154 100644 (file)
@@ -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);
index 9f4ccba40656c94f7bd7228eb6fa845aeadf761d..72b6bf837d18bff155f1abf72a2b04dc0b6930c9 100644 (file)
@@ -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 }));
index adf4e274959af361a87cb2c0718d138a6ba257c4..2398f9fbf229a9bb009251191ccf56793e8d67f9 100644 (file)
@@ -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);
index 6ce7112a5e314410fc8a159d3366a83da459f735..2cb1c67199c08b947f176c2d5403eeb3a5a658fd 100644 (file)
@@ -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