From: Brendan Hansen Date: Sat, 19 Aug 2023 00:53:09 +0000 (-0500) Subject: added: tagged globals X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=7a54ba426ea9152682ec04540b85db06d7531f91;p=onyx.git added: tagged globals --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index a9afab4d..d93fa1b0 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -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; diff --git a/compiler/include/wasm_emit.h b/compiler/include/wasm_emit.h index 8f79b699..ee5cfcc2 100644 --- a/compiler/include/wasm_emit.h +++ b/compiler/include/wasm_emit.h @@ -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 ) diff --git a/compiler/src/builtins.c b/compiler/src/builtins.c index ef30beec..09d63ad1 100644 --- a/compiler/src/builtins.c +++ b/compiler/src/builtins.c @@ -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"); diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 198b7c6a..bb4450c7 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -3276,6 +3276,10 @@ CheckStatus check_memres(AstMemRes* memres) { } } + bh_arr_each(AstTyped *, ptag, memres->tags) { + CHECK(expression, ptag); + } + return Check_Success; } diff --git a/compiler/src/onyx.c b/compiler/src/onyx.c index dd01aa15..dc583189 100644 --- a/compiler/src/onyx.c +++ b/compiler/src/onyx.c @@ -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--; diff --git a/compiler/src/parser.c b/compiler/src/parser.c index 81622ebc..8ec4eb56 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -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); diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 50a1163c..af8ff885 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -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; } diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index be3fb191..35b3ef24 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -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; diff --git a/compiler/src/wasm_type_table.h b/compiler/src/wasm_type_table.h index b177cb3c..def9c665 100644 --- a/compiler/src/wasm_type_table.h +++ b/compiler/src/wasm_type_table.h @@ -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 index 00000000..0993f507 --- /dev/null +++ b/core/runtime/info/global_tags.onyx @@ -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 index 00000000..c5a3194b --- /dev/null +++ b/tests/tagged_globals @@ -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 index 00000000..9f1d0f35 --- /dev/null +++ b/tests/tagged_globals.onyx @@ -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); + } +} +