added '#tag' to procedures; use runtime.info.tagged_procedures
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 11 May 2022 00:53:22 +0000 (19:53 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 11 May 2022 00:53:22 +0000 (19:53 -0500)
15 files changed:
core/container/map.onyx
core/runtime/info/proc_tags.onyx [new file with mode: 0644]
core/std.onyx
include/astnodes.h
include/parser.h
include/wasm_emit.h
src/builtins.c
src/checker.c
src/clone.c
src/onyx.c
src/parser.c
src/symres.c
src/wasm_emit.c
src/wasm_type_table.h
tests/interfaces.onyx

index 1ab17a08661d326b5e0b8ff6ea0eb3fc6d4b1448..b8db2fb8d2f03cb0ad9e577eca50968277e7bc10 100644 (file)
@@ -21,9 +21,10 @@ package core.map
     }
 }
 
+#tag conv.Custom_Format.{
+    #solidify format_map {K=Key_Type, V=Value_Type}
+}
 Map :: struct (Key_Type: type_expr, Value_Type: type_expr) where ValidKey(Key_Type) {
-    #struct_tag conv.Custom_Format.{ #solidify format_map {K=Key_Type, V=Value_Type} };
-
     allocator : Allocator;
 
     hashes  : [] i32;
diff --git a/core/runtime/info/proc_tags.onyx b/core/runtime/info/proc_tags.onyx
new file mode 100644 (file)
index 0000000..0c8c433
--- /dev/null
@@ -0,0 +1,12 @@
+
+package runtime.info
+
+tagged_procedures: [] ^Tagged_Procedure
+
+Tagged_Procedure :: struct {
+    // This should be cast to the correct function type.
+    // i.e.  *cast(^(i32, i32) -> i32) ^tagged_procedures[0].func;
+    func: () -> void;
+    type: type_expr;
+    tags: [] any;
+}
index ec79d75bdb12a74436b89555b55162fa80f66187..28a22830d4be9234ac2bde99abc7902a842c8a0a 100644 (file)
@@ -36,8 +36,6 @@ package core
 #load "./runtime/common"
 
 #load "./runtime/info/helper"
-#load "./runtime/info/types"
-#load "./runtime/info/foreign_blocks"
 
 #load "./arg_parse"
 
index 740667e140dbefeb8ecf9595fa34b7f8c94c75f1..16acbc5f4f45ad3977aa46c098eb08229628e1a0 100644 (file)
@@ -1192,6 +1192,8 @@ struct AstFunction {
 
     ConstraintContext constraints;
 
+    bh_arr(AstTyped *) tags;
+
     // Polymorphic procedures use the following fields
     Scope *parent_scope_of_poly_proc;
     bh_arr(AstPolyParam) poly_params;
@@ -1589,6 +1591,7 @@ extern AstType  *builtin_code_type;
 extern AstTyped *type_table_node;
 extern AstTyped *foreign_blocks_node;
 extern AstType  *foreign_block_type;
+extern AstTyped *tagged_procedures_node;
 extern AstFunction *builtin_initialize_data_segments;
 extern AstFunction *builtin_run_init_procedures;
 extern bh_arr(AstFunction *) init_procedures;
@@ -1769,6 +1772,7 @@ static inline void convert_polyproc_to_function(AstFunction *func) {
     func->poly_scope = NULL;
     func->entity = NULL;
     func->type = NULL;
+    func->tags = NULL;
 }
 
 static inline void convert_function_to_polyproc(AstFunction *func) {
index 70a35b96f66a6d3e92b3bf8ff25415757f838f1f..054dd7574962d99a6f228a80777977ab5bbf85ab 100644 (file)
@@ -32,6 +32,8 @@ typedef struct OnyxParser {
 
     bh_arr(AstFlags) scope_flags;
 
+    bh_arr(AstTyped *) stored_tags;
+
     b32 hit_unexpected_token : 1;
 
     b32 parse_calls : 1;
index c9f10ab02ccff120db270dc35b56826c19825f5a..c16753089ef15927fabd84e535472c3f14c4737d 100644 (file)
@@ -648,6 +648,8 @@ typedef struct OnyxWasmModule {
     bh_arr(AstForeignBlock *) foreign_blocks;
     u32 next_foreign_block_idx;
 
+    bh_arr(AstFunction *) procedures_with_tags;
+
     // NOTE: Used internally as a map from strings that represent function types,
     // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
     // to the function type index if it has been created.
index 3655d2d611a8b61720adf2463f40b67de06945b9..9e9b16c5d4c5d27e733f9543fe6d793a12d2a170 100644 (file)
@@ -63,6 +63,7 @@ AstType  *builtin_code_type;
 AstTyped    *type_table_node = NULL;
 AstTyped    *foreign_blocks_node = NULL;
 AstType     *foreign_block_type = NULL;
+AstTyped    *tagged_procedures_node = NULL;
 AstFunction *builtin_initialize_data_segments = NULL;
 AstFunction *builtin_run_init_procedures = NULL;
 bh_arr(AstFunction *) init_procedures = NULL;
@@ -462,6 +463,7 @@ void initialize_builtins(bh_allocator a) {
         type_table_node     = (AstTyped *) symbol_raw_resolve(p->scope, "type_table");
         foreign_blocks_node = (AstTyped *) symbol_raw_resolve(p->scope, "foreign_blocks");
         foreign_block_type  = (AstType *)  symbol_raw_resolve(p->scope, "foreign_block");
+        tagged_procedures_node = (AstTyped *) symbol_raw_resolve(p->scope, "tagged_procedures");
     }
 
     fori (i, 0, Binary_Op_Count) {
index 52b10f94ce06143d38b1999607ee48515449ed30..a9941989a42fc35aa400938514f8e0f93bfa0d5c 100644 (file)
@@ -2100,6 +2100,14 @@ CheckStatus check_function(AstFunction* func) {
     if (func->entity_header && func->entity_header->state < Entity_State_Code_Gen)
         YIELD(func->token->pos, "Waiting for procedure header to pass type-checking");
 
+    bh_arr_each(AstTyped *, pexpr, func->tags) {
+        CHECK(expression, pexpr);
+
+        if (((*pexpr)->flags & Ast_Flag_Comptime) == 0) {
+            ERROR((*pexpr)->token->pos, "#tag expressions should be compile time known.");
+        }
+    }
+
     inside_for_iterator = 0;
     expected_return_type = &func->type->Function.return_type;
     if (func->body) {
index 9c92cfda57aef5071c36d7c6fe4190f1596b221a..b1a2a98d197b035bbe9ff5fa9222fc9bd344e4cb 100644 (file)
@@ -452,7 +452,7 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             captured_entities = NULL;
 
             df->params = NULL;
-            bh_arr_new(global_heap_allocator, df->params, bh_arr_length(sf->params));
+            bh_arr_new(context.ast_alloc, df->params, bh_arr_length(sf->params));
 
             bh_arr_each(AstParam, param, sf->params) {
                 AstParam new_param = { 0 };
@@ -470,13 +470,20 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
             if (sf->constraints.constraints) {
                 memset(&df->constraints, 0, sizeof(ConstraintContext));
-                bh_arr_new(global_heap_allocator, df->constraints.constraints, bh_arr_length(sf->constraints.constraints));
+                bh_arr_new(context.ast_alloc, df->constraints.constraints, bh_arr_length(sf->constraints.constraints));
 
                 bh_arr_each(AstConstraint *, constraint, sf->constraints.constraints) {
                     bh_arr_push(df->constraints.constraints, (AstConstraint *) ast_clone(a, (AstNode *) *constraint));
                 }
             }
 
+            if (sf->tags) {
+                bh_arr_new(context.ast_alloc, df->tags, bh_arr_length(sf->tags));
+                bh_arr_each(AstTyped *, pexpr, sf->tags) {
+                    bh_arr_push(df->tags, (AstTyped *) ast_clone(a, (AstNode *) *pexpr));
+                }    
+            }
+
             break;
         }
 
index 9154d8a32884caec00482df95d06515e2f71310a..69dd81aa47f92a4f40d9f6eea54329e945917f8a 100644 (file)
@@ -270,6 +270,12 @@ static void context_init(CompileOptions* opts) {
         .package = NULL,
         .include = create_load(context.ast_alloc, "core/runtime/info/foreign_blocks"),
     }));
+    entity_heap_insert(&context.entities, ((Entity) {
+        .state = Entity_State_Parse_Builtin,
+        .type = Entity_Type_Load_File,
+        .package = NULL,
+        .include = create_load(context.ast_alloc, "core/runtime/info/proc_tags"),
+    }));
 
     entity_heap_insert(&context.entities, ((Entity) {
         .state = Entity_State_Parse_Builtin,
index defe98024c3a5382f8f2faf6142db661d3b29f81..8c7ad4ed4d1cca4ea49c79e337fa0e65e0e25c6a 100644 (file)
@@ -176,6 +176,36 @@ static b32 next_tokens_are(OnyxParser* parser, i32 n, ...) {
 }
 
 
+static void expect_no_stored_tags_pos(OnyxParser *parser, OnyxFilePos pos) {
+    if (bh_arr_length(parser->stored_tags) > 0) {
+        onyx_report_error(pos, Error_Critical, "#tag is not allowed on this element.");
+        parser->hit_unexpected_token = 1;
+    }
+}
+
+static void expect_no_stored_tags(OnyxParser *parser) {
+    expect_no_stored_tags_pos(parser, parser->curr->pos);
+}
+
+static void flush_stored_tags(OnyxParser *parser, bh_arr(AstTyped *) *out_arr) {
+    if (bh_arr_length(parser->stored_tags) == 0) return;
+
+    bh_arr(AstTyped *) arr = *out_arr;
+
+    if (arr == NULL) {
+        bh_arr_new(parser->allocator, arr, bh_arr_length(parser->stored_tags));
+    }
+
+    bh_arr_each(AstTyped *, pexpr, parser->stored_tags) {
+        bh_arr_push(arr, *pexpr);
+    }
+
+    bh_arr_clear(parser->stored_tags);
+
+    *out_arr = arr;
+}
+
+
 // TODO: Make parsing numeric literals not rely on the C standard libary.
 static AstNumLit* parse_int_literal(OnyxParser* parser) {
     AstNumLit* int_node = make_node(AstNumLit, Ast_Kind_NumLit);
@@ -1921,6 +1951,8 @@ static AstStructType* parse_struct(OnyxParser* parser) {
     s_node = make_node(AstStructType, Ast_Kind_Struct_Type);
     s_node->token = s_token;
 
+    flush_stored_tags(parser, &s_node->meta_tags);
+
     // Parse polymorphic parameters
     if (consume_token_if_next(parser, '(')) {
         bh_arr(AstPolyStructParam) poly_params = NULL;
@@ -1987,8 +2019,6 @@ static AstStructType* parse_struct(OnyxParser* parser) {
         }
     }
 
-    bh_arr(AstTyped *) struct_meta_tags=NULL;
-
     expect_token(parser, '{');
 
     b32 member_is_used = 0;
@@ -1998,15 +2028,6 @@ static AstStructType* parse_struct(OnyxParser* parser) {
     while (!consume_token_if_next(parser, '}')) {
         if (parser->hit_unexpected_token) return s_node;
 
-        if (parse_possible_directive(parser, "struct_tag")) {
-            if (struct_meta_tags == NULL) bh_arr_new(global_heap_allocator, struct_meta_tags, 1);
-            AstTyped* expr = parse_expression(parser, 0);
-            bh_arr_push(struct_meta_tags, expr);
-
-            consume_token_if_next(parser, ';');
-            continue;
-        }
-
         if (parse_possible_directive(parser, "persist")) {
             struct_type_create_scope(parser, s_node);
             
@@ -2095,7 +2116,6 @@ static AstStructType* parse_struct(OnyxParser* parser) {
         expect_token(parser, ';');
     }
 
-    s_node->meta_tags = struct_meta_tags;
     if (s_node->scope) parser->current_scope = parser->current_scope->parent;
 
     bh_arr_free(member_list_temp);
@@ -2360,6 +2380,8 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
     func_def->token = token;
     bh_arr_push(parser->current_function_stack, func_def);
 
+    flush_stored_tags(parser, &func_def->tags);
+
     bh_arr_new(global_heap_allocator, func_def->params, 4);
 
     bh_arr(AstPolyParam) polymorphic_vars = NULL;
@@ -2660,6 +2682,8 @@ static b32 parse_possible_quick_function_definition(OnyxParser* parser, AstTyped
 }
 
 static AstTyped* parse_global_declaration(OnyxParser* parser) {
+    expect_no_stored_tags(parser);
+
     AstGlobal* global_node = make_node(AstGlobal, Ast_Kind_Global);
     global_node->token = expect_token(parser, Token_Type_Keyword_Global);
 
@@ -2671,12 +2695,16 @@ static AstTyped* parse_global_declaration(OnyxParser* parser) {
 }
 
 static AstEnumType* parse_enum_declaration(OnyxParser* parser) {
+    expect_no_stored_tags(parser);
+
     AstEnumType* enum_node = make_node(AstEnumType, Ast_Kind_Enum_Type);
     enum_node->token = expect_token(parser, Token_Type_Keyword_Enum);
 
     bh_arr_new(global_heap_allocator, enum_node->values, 4);
 
     while (parser->curr->type == '#') {
+        if (parser->hit_unexpected_token) return enum_node;
+
         if (parse_possible_directive(parser, "flags")) {
             enum_node->is_flags = 1;
         } else {
@@ -2720,6 +2748,8 @@ static AstEnumType* parse_enum_declaration(OnyxParser* parser) {
 }
 
 static AstIf* parse_static_if_stmt(OnyxParser* parser, b32 parse_block_as_statements) {
+    expect_no_stored_tags(parser);
+
     AstIf* static_if_node = make_node(AstIf, Ast_Kind_Static_If);
     static_if_node->token = expect_token(parser, '#');
     static_if_node->defined_in_scope = parser->current_scope;
@@ -2769,6 +2799,8 @@ static AstIf* parse_static_if_stmt(OnyxParser* parser, b32 parse_block_as_statem
 static AstMemRes* parse_memory_reservation(OnyxParser* parser, OnyxToken* symbol, b32 threadlocal) {
     expect_token(parser, ':');
 
+    expect_no_stored_tags(parser);
+
     AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres);
     memres->threadlocal = threadlocal;
     memres->token = symbol;
@@ -2784,6 +2816,8 @@ static AstMemRes* parse_memory_reservation(OnyxParser* parser, OnyxToken* symbol
 }
 
 static AstMacro* parse_macro(OnyxParser* parser) {
+    expect_no_stored_tags(parser);
+
     AstMacro* macro = make_node(AstMacro, Ast_Kind_Macro);
     macro->token = expect_token(parser, Token_Type_Keyword_Macro);
 
@@ -2913,7 +2947,8 @@ static char* generate_name_within_scope(OnyxParser* parser, OnyxToken* symbol) {
 }
 
 static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol) {
-    expect_token(parser, ':');
+    OnyxToken *after_second_colon = expect_token(parser, ':');
+    if (after_second_colon) after_second_colon += 1;
 
     AstTyped* node = parse_top_level_expression(parser);
     if (parser->hit_unexpected_token || node == NULL)
@@ -2978,6 +3013,7 @@ default_case:
     binding->token = symbol;
     binding->node = (AstNode *) node;
 
+    if (after_second_colon) expect_no_stored_tags_pos(parser, after_second_colon->pos);
     return binding;
 }
 
@@ -3197,6 +3233,11 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 ENTITY_SUBMIT(library);
                 return;
             }
+            else if (parse_possible_directive(parser, "tag")) {
+                AstTyped *expr = parse_expression(parser, 0);
+                bh_arr_push(parser->stored_tags, expr);
+                return;
+            }
             else {
                 OnyxToken* directive_token = expect_token(parser, '#');
                 OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
@@ -3339,6 +3380,7 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
     parser.current_symbol_stack = NULL;
     parser.current_function_stack = NULL;
     parser.scope_flags = NULL;
+    parser.stored_tags = NULL;
     parser.parse_calls = 1;
 
     parser.polymorph_context = (PolymorphicContext) {
@@ -3349,6 +3391,7 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
     bh_arr_new(global_heap_allocator, parser.alternate_entity_placement_stack, 4);
     bh_arr_new(global_heap_allocator, parser.current_symbol_stack, 4);
     bh_arr_new(global_heap_allocator, parser.scope_flags, 4);
+    bh_arr_new(global_heap_allocator, parser.stored_tags, 4);
 
     return parser;
 }
index b5edf7ac08a9b2bb067cf8c5da6c8d29f72cbf74..01a86c16d2f789ad84ff034c1a592cf1088127e1 100644 (file)
@@ -1148,6 +1148,10 @@ SymresStatus symres_function(AstFunction* func) {
             }
         }
 
+        bh_arr_each(AstTyped *, pexpr, func->tags) {
+            SYMRES(expression, pexpr);
+        }
+
         func->flags |= Ast_Flag_Has_Been_Symres;
     }
 
index 9ddd934a1af93b9b849f18cfddc6f7eaa091d3a0..a20c7e7afdcefb42d4c5f5cc8cedfda3c039bae7 100644 (file)
@@ -187,6 +187,24 @@ static u64 local_lookup_idx(LocalAllocator* la, u64 value) {
 }
 
 
+static inline b32 should_emit_function(AstFunction* fd) {
+    // NOTE: Don't output intrinsic functions
+    if (fd->is_intrinsic) return 0;
+
+    // NOTE: Don't output functions that are not used, only if
+    // they are also not exported.
+    if ((fd->flags & Ast_Flag_Function_Used) == 0) {
+        if (fd->is_exported || bh_arr_length(fd->tags) > 0) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+
 typedef enum StructuredBlockType StructuredBlockType;
 enum StructuredBlockType {
     SBT_Basic_Block,       // Cannot be targeted using jump
@@ -3338,23 +3356,6 @@ static i32 get_element_idx(OnyxWasmModule* mod, AstFunction* func) {
     }
 }
 
-static inline b32 should_emit_function(AstFunction* fd) {
-    // NOTE: Don't output intrinsic functions
-    if (fd->is_intrinsic) return 0;
-
-    // NOTE: Don't output functions that are not used, only if
-    // they are also not exported.
-    if ((fd->flags & Ast_Flag_Function_Used) == 0) {
-        if (fd->is_exported) {
-            return 1;
-        } else {
-            return 0;
-        }
-    }
-
-    return 1;
-}
-
 
 static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
     if (!should_emit_function(fd)) return;
@@ -3734,6 +3735,13 @@ static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) {
         return;
     }
 
+    if (tagged_procedures_node != NULL && (AstMemRes *) tagged_procedures_node == memres) {
+        u64 tagged_procedures_location = build_tagged_procedures(mod);
+        memres->addr = tagged_procedures_location;
+
+        return;
+    }
+
     if (memres->threadlocal) {
         memres->addr = mod->next_tls_offset;
         bh_align(memres->addr, alignment);
@@ -3876,6 +3884,8 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
 
         .foreign_blocks = NULL,
         .next_foreign_block_idx = 0,
+
+        .procedures_with_tags = NULL
     };
 
     bh_arena* eid = bh_alloc(global_heap_allocator, sizeof(bh_arena));
@@ -3909,6 +3919,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_arr_new(global_heap_allocator, module.local_allocations, 4);
     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 = {
@@ -3982,6 +3993,10 @@ void emit_entity(Entity* ent) {
             if (ent->function->flags & Ast_Flag_Proc_Is_Null) {
                 if (module->null_proc_func_idx == -1) module->null_proc_func_idx = get_element_idx(module, ent->function);
             }
+
+            if (ent->function->tags != NULL) {
+                bh_arr_push(module->procedures_with_tags, ent->function);
+            }
             break;
 
         case Entity_Type_Global_Header:
index 80ed9df21e3bcdb37aaca21018a9d51ceb0298c6..0b13fe7739c80ae5ab04698938a650cce1d9b3d5 100644 (file)
@@ -8,7 +8,7 @@ typedef struct StructMethodData {
     u32 data_loc;
 } StructMethodData;
 
-u64 build_type_table(OnyxWasmModule* module) {
+static u64 build_type_table(OnyxWasmModule* module) {
 
     bh_arr(u32) base_patch_locations=NULL;
     bh_arr_new(global_heap_allocator, base_patch_locations, 256);
@@ -603,7 +603,7 @@ u64 build_type_table(OnyxWasmModule* module) {
 
 
 
-static b32 build_foreign_blocks(OnyxWasmModule* module) {
+static u64 build_foreign_blocks(OnyxWasmModule* module) {
     bh_arr(u32) base_patch_locations=NULL;
     bh_arr_new(global_heap_allocator, base_patch_locations, 256);
 
@@ -744,5 +744,153 @@ static b32 build_foreign_blocks(OnyxWasmModule* module) {
 
     return global_data_ptr;
 
+#undef WRITE_SLICE
+#undef WRITE_PTR
 #undef PATCH
-}
\ No newline at end of file
+}
+
+
+
+static u64 build_tagged_procedures(OnyxWasmModule *module) {
+    bh_arr(u32) base_patch_locations=NULL;
+    bh_arr_new(global_heap_allocator, base_patch_locations, 256);
+
+#define PATCH (bh_arr_push(base_patch_locations, tag_proc_buffer.length))
+#define WRITE_PTR(val) \
+    bh_buffer_align(&tag_proc_buffer, POINTER_SIZE); \
+    PATCH; \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&tag_proc_buffer, val); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&tag_proc_buffer, val); 
+#define WRITE_SLICE(ptr, count) \
+    WRITE_PTR(ptr); \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&tag_proc_buffer, count); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&tag_proc_buffer, count); 
+
+    #if (POINTER_SIZE == 4)
+        #define Tagged_Procedure_Type u32
+    #else
+        #define Tagged_Procedure_Type u64
+    #endif
+    u32 proc_count = bh_arr_length(module->procedures_with_tags);
+    Tagged_Procedure_Type* tag_proc_info = bh_alloc_array(global_heap_allocator, Tagged_Procedure_Type, proc_count); // HACK
+    memset(tag_proc_info, 0, proc_count * sizeof(Tagged_Procedure_Type));
+
+    bh_buffer tag_proc_buffer;
+    bh_buffer_init(&tag_proc_buffer, global_heap_allocator, 4096);
+
+    // 
+    // 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,
+    // but 64 bytes keeps better alignment.
+    bh_buffer_write_u64(&tag_proc_buffer, 0);
+
+    u32 index = 0;
+    bh_arr_each(AstFunction *, pfunc, module->procedures_with_tags) {
+        AstFunction *func = *pfunc;
+        if (!should_emit_function(func)) {
+            proc_count--;
+            continue;
+        }
+
+        u32 tag_count = bh_arr_length(func->tags);
+        u32 *tag_data_offsets = bh_alloc_array(global_scratch_allocator, u32, tag_count);
+        u32 *tag_data_types   = bh_alloc_array(global_scratch_allocator, u32, tag_count);
+
+        u32 tag_index = 0;
+        bh_arr_each(AstTyped *, ptag, func->tags) {
+            AstTyped *tag = *ptag;
+            bh_buffer_align(&tag_proc_buffer, type_alignment_of(tag->type));
+
+            tag_data_offsets[tag_index  ] = tag_proc_buffer.length;
+            tag_data_types  [tag_index++] = tag->type->id;
+
+            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);
+            tag_proc_buffer.length += size;
+        }
+
+        bh_buffer_align(&tag_proc_buffer, 4);
+        u32 tag_array_base = tag_proc_buffer.length;
+        fori (i, 0, tag_count) {
+            PATCH;
+            bh_buffer_write_u32(&tag_proc_buffer, tag_data_offsets[i]);
+            bh_buffer_write_u32(&tag_proc_buffer, tag_data_types[i]);
+        }
+
+        bh_buffer_align(&tag_proc_buffer, 4);
+        tag_proc_info[index++] = tag_proc_buffer.length;
+
+        bh_buffer_write_u32(&tag_proc_buffer, get_element_idx(module, func));
+        bh_buffer_write_u32(&tag_proc_buffer, func->type->id);
+        WRITE_SLICE(tag_array_base, tag_count);
+    }    
+
+    if (context.options->verbose_output == 1) {
+        bh_printf("Foreign blocks size: %d bytes.\n", tag_proc_buffer.length);
+    }
+
+    u32 offset = module->next_datum_offset;
+    bh_align(offset, 8);
+
+    u64 tagged_procedures_location = offset;
+
+    WasmDatum tagged_procedures_data = {
+        .offset = offset,
+        .length = proc_count * POINTER_SIZE,
+        .data = tag_proc_info,
+    };
+    bh_arr_push(module->data, tagged_procedures_data);
+
+    offset += tagged_procedures_data.length;
+
+    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;
+        }
+    }
+
+    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[1] = proc_count;
+    WasmDatum tagged_procedures_global_data = {
+        .offset = offset,
+        .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;
+
+    return global_data_ptr;
+
+#undef WRITE_SLICE
+#undef WRITE_PTR
+#undef PATCH
+}
+
index 69c1eb1a86d0dffd91c096e7ad713cdad90ef7d2..f65fe987bb65b705fa8ec80f8d779106d8ce32d0 100644 (file)
@@ -53,10 +53,10 @@ BitField :: interface (t: $T) {
     { t ^ t } -> T;
 }
 
+#tag conv.Custom_Format.{ Complex.format }
 Complex :: struct {
     x, y: f32;
 
-    #struct_tag conv.Custom_Format.{ format }
     format :: (output: ^conv.Format_Output, format: ^conv.Format, c: ^Complex) {
         conv.format(output, "{.2} + {.2}i", c.x, c.y);
     }