added: tagged globals
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 19 Aug 2023 00:53:09 +0000 (19:53 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 19 Aug 2023 00:53:09 +0000 (19:53 -0500)
12 files changed:
compiler/include/astnodes.h
compiler/include/wasm_emit.h
compiler/src/builtins.c
compiler/src/checker.c
compiler/src/onyx.c
compiler/src/parser.c
compiler/src/symres.c
compiler/src/wasm_emit.c
compiler/src/wasm_type_table.h
core/runtime/info/global_tags.onyx [new file with mode: 0644]
tests/tagged_globals [new file with mode: 0644]
tests/tagged_globals.onyx [new file with mode: 0644]

index a9afab4d59877703d562dccbc7d929a242e8f279..d93fa1b09a747e9ef17abf569b9341d809079ada 100644 (file)
@@ -1134,6 +1134,8 @@ struct AstMemRes        {
 
     struct Entity *type_entity;
 
+    bh_arr(AstTyped *) tags;
+
     b32 threadlocal : 1;
 
     // Set and used in the wasm emission.
@@ -1931,6 +1933,7 @@ extern AstTyped *type_table_node;
 extern AstTyped *foreign_blocks_node;
 extern AstType  *foreign_block_type;
 extern AstTyped *tagged_procedures_node;
+extern AstTyped *tagged_globals_node;
 extern AstFunction *builtin_initialize_data_segments;
 extern AstFunction *builtin_run_init_procedures;
 extern AstFunction *builtin_closure_block_allocate;
index 8f79b6995b1d0af89e406896d6e5087911766708..ee5cfcc298871000f7c56a495e986641bb27eddb 100644 (file)
@@ -710,6 +710,7 @@ typedef struct OnyxWasmModule {
     u32 next_foreign_block_idx;
 
     bh_arr(AstFunction *) procedures_with_tags;
+    bh_arr(AstMemRes *)   globals_with_tags;
 
     // NOTE: Used internally as a map from strings that represent function types,
     // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
index ef30beec9aaeecbc828e50cd7985daf082c79696..09d63ad119cc8fe2173c436a3cb364da3303bc82 100644 (file)
@@ -70,6 +70,7 @@ AstTyped    *type_table_node = NULL;
 AstTyped    *foreign_blocks_node = NULL;
 AstType     *foreign_block_type = NULL;
 AstTyped    *tagged_procedures_node = NULL;
+AstTyped    *tagged_globals_node = NULL;
 AstFunction *builtin_initialize_data_segments = NULL;
 AstFunction *builtin_run_init_procedures = NULL;
 AstFunction *builtin_closure_block_allocate = NULL;
@@ -402,6 +403,7 @@ void prepare_builtins() {
     foreign_blocks_node = NULL;
     foreign_block_type = NULL;
     tagged_procedures_node = NULL;
+    tagged_globals_node = NULL;
     builtin_initialize_data_segments = NULL;
     builtin_run_init_procedures = NULL;
     init_procedures = NULL;
@@ -572,6 +574,7 @@ void initalize_special_globals() {
         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");
+        tagged_globals_node = (AstTyped *) symbol_raw_resolve(p->scope, "tagged_globals");
 
         if (context.options->stack_trace_enabled) {
             builtin_stack_trace_type = (AstType *) symbol_raw_resolve(p->scope, "Stack_Trace");
index 198b7c6a0907527d0832b8490e63835810727ccc..bb4450c765ed67c17ec0ec4fdffe8f8cb62a9e14 100644 (file)
@@ -3276,6 +3276,10 @@ CheckStatus check_memres(AstMemRes* memres) {
         }
     }
 
+    bh_arr_each(AstTyped *, ptag, memres->tags) {
+        CHECK(expression, ptag);
+    }
+
     return Check_Success;
 }
 
index dd01aa15cdb7a35c2de0cdb31e7a163e5347f16d..dc583189af1cedc596a3761cb99842737fd01157 100644 (file)
@@ -395,10 +395,11 @@ static void introduce_defined_variables() {
 }
 
 // HACK
-static u32 special_global_entities_remaining = 4;
+static u32 special_global_entities_remaining = 5;
 static Entity *runtime_info_types_entity;
 static Entity *runtime_info_foreign_entity;
 static Entity *runtime_info_proc_tags_entity;
+static Entity *runtime_info_global_tags_entity;
 static Entity *runtime_info_stack_trace_entity;
 
 static void context_init(CompileOptions* opts) {
@@ -408,7 +409,7 @@ static void context_init(CompileOptions* opts) {
     prepare_builtins();
 
     // HACK
-    special_global_entities_remaining = 4;
+    special_global_entities_remaining = 5;
 
     context.options = opts;
     context.cycle_detected = 0;
@@ -473,6 +474,12 @@ static void context_init(CompileOptions* opts) {
             .package = NULL,
             .include = create_load(context.ast_alloc, "core/runtime/info/proc_tags"),
         }));
+        runtime_info_global_tags_entity = entity_heap_insert(&context.entities, ((Entity) {
+            .state = Entity_State_Parse,
+            .type = Entity_Type_Load_File,
+            .package = NULL,
+            .include = create_load(context.ast_alloc, "core/runtime/info/global_tags"),
+        }));
         runtime_info_stack_trace_entity = entity_heap_insert(&context.entities, ((Entity) {
             .state = Entity_State_Parse,
             .type = Entity_Type_Load_File,
@@ -726,6 +733,7 @@ static b32 process_entity(Entity* ent) {
                 // GROSS
                 if (ent == runtime_info_types_entity
                     || ent == runtime_info_proc_tags_entity
+                    || ent == runtime_info_global_tags_entity
                     || ent == runtime_info_foreign_entity
                     || ent == runtime_info_stack_trace_entity) {
                     special_global_entities_remaining--;
index 81622ebc283e9eeaffd17c08637e39ec6ed54b27..8ec4eb56501b2d896a6202fd6982a351feb51f52 100644 (file)
@@ -3198,12 +3198,12 @@ 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;
 
+    flush_stored_tags(parser, &memres->tags);
+
     if (parser->curr->type != '=')
         memres->type_node = parse_type(parser);
 
index 50a1163c714a25e907c046c9a74a2655ac2b6023..af8ff885238780edc284e600800286a338f1f037 100644 (file)
@@ -1384,6 +1384,11 @@ static SymresStatus symres_memres(AstMemRes** memres) {
     if ((*memres)->initial_value != NULL) {
         SYMRES(expression, &(*memres)->initial_value);
     }
+
+    bh_arr_each(AstTyped *, ptag, (*memres)->tags) {
+        SYMRES(expression, ptag);
+    }
+
     return Symres_Success;
 }
 
index be3fb191424187754530824baf2b9995ed77189f..35b3ef247277869b3eb1ea9b876bda2ca0c30010 100644 (file)
@@ -4830,6 +4830,12 @@ static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) {
             memres->data_id = tagged_procedures_location;
             return;
         }
+
+        if (tagged_globals_node != NULL && (AstMemRes *) tagged_globals_node == memres) {
+            u64 tagged_globals_location = build_tagged_globals(mod);
+            memres->data_id = tagged_globals_location;
+            return;
+        }
     }
 
     if (foreign_blocks_node != NULL && (AstMemRes *) foreign_blocks_node == memres) {
@@ -5020,6 +5026,7 @@ 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);
+    bh_arr_new(global_heap_allocator, module.globals_with_tags, 4);
     bh_arr_new(global_heap_allocator, module.data_patches, 4);
 
 #ifdef ENABLE_DEBUG_INFO
@@ -5091,6 +5098,13 @@ void emit_entity(Entity* ent) {
             break;
         }
 
+        case Entity_Type_Memory_Reservation_Type: {
+            if (ent->mem_res->tags != NULL) {
+                bh_arr_push(module->globals_with_tags, ent->mem_res);
+            }
+            break;
+        }
+
         case Entity_Type_Memory_Reservation: {
             emit_memory_reservation(module, (AstMemRes *) ent->mem_res);
             break;
index b177cb3c3b6bc0be89bc163d23e0c9a4abe0c9a8..def9c665e0f80e7e358c866a7ffc121f58697fcf 100644 (file)
@@ -1191,3 +1191,157 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) {
 #undef PATCH
 }
 
+
+static u64 build_tagged_globals(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_global_buffer.length))
+#define WRITE_PTR(val) \
+    bh_buffer_align(&tag_global_buffer, POINTER_SIZE); \
+    PATCH; \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&tag_global_buffer, val); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&tag_global_buffer, val); 
+#define WRITE_SLICE(ptr, count) \
+    WRITE_PTR(ptr); \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&tag_global_buffer, count); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&tag_global_buffer, count); 
+
+    #if (POINTER_SIZE == 4)
+        #define Tagged_Global_Type u32
+    #else
+        #define Tagged_Global_Type u64
+    #endif
+    u32 global_count = bh_arr_length(module->globals_with_tags);
+    Tagged_Global_Type* tag_global_info = bh_alloc_array(global_heap_allocator, Tagged_Global_Type, global_count); // HACK
+    memset(tag_global_info, 0, global_count * sizeof(Tagged_Global_Type));
+
+    bh_buffer tag_global_buffer;
+    bh_buffer_init(&tag_global_buffer, global_heap_allocator, 4096);
+
+    u32 global_info_data_id = NEXT_DATA_ID(module);
+
+    ConstExprContext constexpr_ctx;
+    constexpr_ctx.module = module;
+    constexpr_ctx.data_id = global_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,
+    // but 64 bytes keeps better alignment.
+    bh_buffer_write_u64(&tag_global_buffer, 0);
+
+    u32 index = 0;
+    bh_arr_each(AstMemRes *, pmemres, module->globals_with_tags) {
+        AstMemRes *memres = *pmemres;
+
+        u32 tag_count = bh_arr_length(memres->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, memres->tags) {
+            AstTyped *tag = *ptag;
+            bh_buffer_align(&tag_global_buffer, type_alignment_of(tag->type));
+
+            tag_data_offsets[tag_index  ] = tag_global_buffer.length;
+            tag_data_types  [tag_index++] = tag->type->id;
+
+            u32 size = type_size_of(tag->type);
+            bh_buffer_grow(&tag_global_buffer, tag_global_buffer.length + size);
+
+            constexpr_ctx.data = tag_global_buffer.data;
+            emit_constexpr(&constexpr_ctx, tag, tag_global_buffer.length);
+            tag_global_buffer.length += size;
+        }
+
+        bh_buffer_align(&tag_global_buffer, 4);
+        u32 tag_array_base = tag_global_buffer.length;
+        fori (i, 0, tag_count) {
+            PATCH;
+            bh_buffer_write_u32(&tag_global_buffer, tag_data_offsets[i]);
+            bh_buffer_write_u32(&tag_global_buffer, tag_data_types[i]);
+        }
+
+        bh_buffer_align(&tag_global_buffer, 4);
+        tag_global_info[index++] = tag_global_buffer.length;
+
+        assert(memres->entity && memres->entity->package);
+
+        DatumPatchInfo patch;
+        patch.kind = Datum_Patch_Data;
+        patch.index = global_info_data_id;
+        patch.location = tag_global_buffer.length;
+        patch.offset = 0;
+        patch.data_id = 0;
+        patch.node_to_use_if_data_id_is_null = memres;
+        bh_arr_push(module->data_patches, patch);
+
+        bh_buffer_write_u32(&tag_global_buffer, 0);
+        bh_buffer_write_u32(&tag_global_buffer, memres->type->id);
+        WRITE_SLICE(tag_array_base, tag_count);
+        bh_buffer_write_u32(&tag_global_buffer, memres->entity->package->id);
+    }
+
+    if (context.options->verbose_output == 1) {
+        bh_printf("Tagged global size: %d bytes.\n", tag_global_buffer.length);
+    }
+
+    WasmDatum global_info_data = {
+        .alignment = 8,
+        .length = tag_global_buffer.length,
+        .data = tag_global_buffer.data,
+    };
+    emit_data_entry(module, &global_info_data);
+    assert(global_info_data.id == global_info_data_id);
+
+    bh_arr_each(u32, patch_loc, base_patch_locations) {
+        DatumPatchInfo patch;
+        patch.kind = Datum_Patch_Relative;
+        patch.data_id = global_info_data.id;
+        patch.location = *patch_loc;
+        patch.index = global_info_data.id;
+        patch.offset = 0;
+        bh_arr_push(module->data_patches, patch);
+    }
+
+    WasmDatum global_table_data = {
+        .alignment = POINTER_SIZE,
+        .length = global_count * POINTER_SIZE,
+        .data = tag_global_info,
+    };
+    emit_data_entry(module, &global_table_data);
+
+    fori (i, 0, global_count) {
+        DatumPatchInfo patch;
+        patch.kind = Datum_Patch_Data;
+        patch.data_id = global_info_data.id;
+        patch.offset = tag_global_info[i];
+        patch.index = global_table_data.id;
+        patch.location = i * POINTER_SIZE;
+        bh_arr_push(module->data_patches, patch);
+    }
+
+    Tagged_Procedure_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE);
+    tmp_data[0] = 0;
+    tmp_data[1] = global_count;
+    WasmDatum global_table_global_data = {
+        .alignment = POINTER_SIZE,
+        .length = 2 * POINTER_SIZE,
+        .data = tmp_data,
+    };
+    emit_data_entry(module, &global_table_global_data);
+
+    {
+        DatumPatchInfo patch;
+        patch.kind = Datum_Patch_Data;
+        patch.offset = 0;
+        patch.data_id = global_table_data.id;
+        patch.index = global_table_global_data.id;
+        patch.location = 0;
+        bh_arr_push(module->data_patches, patch);
+    }
+
+    return global_table_global_data.id;
+}
+
diff --git a/core/runtime/info/global_tags.onyx b/core/runtime/info/global_tags.onyx
new file mode 100644 (file)
index 0000000..0993f50
--- /dev/null
@@ -0,0 +1,37 @@
+package runtime.info
+
+use core {array, slice}
+
+tagged_globals: [] &Tagged_Global
+
+Tagged_Global :: struct {
+    data: rawptr;
+    type: type_expr;
+    tags: [] any;
+    pack: package_id;
+}
+
+#local GGWT_Result :: struct (T: type_expr) {
+    data: rawptr;
+    type: type_expr;
+    tag: &T;
+    pack: package_id;
+}
+
+get_globals_with_tag :: ($tag_type: type_expr) -> [] GGWT_Result(tag_type) {
+    results := make([..] GGWT_Result(tag_type));
+
+    for glob: tagged_globals {
+        slice.find_opt(glob.tags, [v](v.type == tag_type))->with([tag] {
+            array.push(&results, .{
+                data = glob.data,
+                type = glob.type,
+                tag = cast(&tag_type) tag.data,
+                pack = glob.pack
+            });
+        });
+    }
+
+    return results;
+}
+
diff --git a/tests/tagged_globals b/tests/tagged_globals
new file mode 100644 (file)
index 0000000..c5a3194
--- /dev/null
@@ -0,0 +1,9 @@
+i32
+package_id[7]
+1
+Default value is: 1234
+New value is: 5678
+Test that strings work!
+==============================================
+Something_Interesting { version = 10, about = "This is a cool variable" }
+Something_Interesting { version = 20, about = "This is another cool variable!" }
diff --git a/tests/tagged_globals.onyx b/tests/tagged_globals.onyx
new file mode 100644 (file)
index 0000000..9f1d0f3
--- /dev/null
@@ -0,0 +1,48 @@
+package main
+
+use core {*}
+use runtime.info
+
+@"Test that strings work!"
+x: i32 = 1234;
+
+
+Something_Interesting :: struct {
+    version: u32;
+    about: str;
+}
+
+@Something_Interesting.{ 10, "This is a cool variable" }
+value_1 := "Working!"
+
+@Something_Interesting.{ 20, "This is another cool variable!" }
+value_2 := "Also working!"
+
+
+main :: () {
+    for info.tagged_globals {
+        if it.type != i32 do continue;
+        println(it.type);
+        println(it.pack);
+        println(it.tags.count);
+
+        val_ptr: &i32 = it.data;
+        printf("Default value is: {*}\n", val_ptr);
+
+        *val_ptr = 5678;
+        printf("New value is: {*}\n", val_ptr);
+
+        for t: it.tags {
+            if t.type == str {
+                printf("{*}\n", misc.any_as(t, str));
+            }
+        }
+    }
+
+    println("==============================================");
+
+    for info.get_globals_with_tag(Something_Interesting) {
+        println(*it.tag);
+    }
+}
+