struct Entity *type_entity;
+ bh_arr(AstTyped *) tags;
+
b32 threadlocal : 1;
// Set and used in the wasm emission.
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;
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 )
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;
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;
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");
}
}
+ bh_arr_each(AstTyped *, ptag, memres->tags) {
+ CHECK(expression, ptag);
+ }
+
return Check_Success;
}
}
// 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) {
prepare_builtins();
// HACK
- special_global_entities_remaining = 4;
+ special_global_entities_remaining = 5;
context.options = opts;
context.cycle_detected = 0;
.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,
// 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--;
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);
if ((*memres)->initial_value != NULL) {
SYMRES(expression, &(*memres)->initial_value);
}
+
+ bh_arr_each(AstTyped *, ptag, (*memres)->tags) {
+ SYMRES(expression, ptag);
+ }
+
return Symres_Success;
}
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) {
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
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;
#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;
+}
+
--- /dev/null
+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;
+}
+
--- /dev/null
+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!" }
--- /dev/null
+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);
+ }
+}
+