From e1d6b9f3196693160dce5664e321c028b8a74aa9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 6 Aug 2025 17:21:44 -0700 Subject: [PATCH 001/302] tweaks --- src/raddbg/raddbg_widgets.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 286a38cc..d1da7715 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -2384,17 +2384,24 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // if(do_scope_lines && cursor_scope_node != &txt_scope_node_nil) { - Vec4F32 scope_line_color = highlight_color; - scope_line_color.w *= 0.25f; + F32 scope_line_thickness = params->font_size*0.1f; + scope_line_thickness = Max(scope_line_thickness, 1.f); DR_Bucket *bucket = dr_bucket_make(); DR_BucketScope(bucket) { Vec2F32 text_base_pos = v2f32(text_container_box->rect.x0 + params->line_num_width_px + line_num_padding_px, text_container_box->rect.y0); + F32 ancestor_chain_depth = 0; for(TXT_ScopeNode *scope_n = cursor_scope_node; scope_n != &txt_scope_node_nil; - scope_n = txt_scope_node_from_info_num(params->text_info, scope_n->parent_num)) + scope_n = txt_scope_node_from_info_num(params->text_info, scope_n->parent_num), ancestor_chain_depth += 1) { + Vec4F32 scope_line_color = highlight_color; + F32 scope_line_color_target = highlight_color.w; + scope_line_color_target *= 1 - ancestor_chain_depth / 6.f; + scope_line_color_target = Max(0.2f, scope_line_color_target); + F32 scope_line_color_t = ui_anim(ui_key_from_stringf(text_container_box->key, "###scope_depth_%I64x_%I64x", scope_n->token_idx_range.min, scope_n->token_idx_range.max), scope_line_color_target, .rate = rd_state->menu_animation_rate__slow); + scope_line_color.w = scope_line_color_t*0.5f; Rng1U64 token_idx_range = scope_n->token_idx_range; Rng1U64 off_range = r1u64(params->text_info->tokens.v[token_idx_range.min].range.min, params->text_info->tokens.v[token_idx_range.max].range.min); TxtRng txt_range = txt_rng(txt_pt_from_info_off__linear_scan(params->text_info, off_range.min), txt_pt_from_info_off__linear_scan(params->text_info, off_range.max)); @@ -2422,7 +2429,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe underline_clip.y1 = 10000; DR_ClipScope(underline_clip) { - dr_rect(underline_rect, scope_line_color, params->font_size*0.1f, 1.f, 1.f); + dr_rect(underline_rect, scope_line_color, params->font_size*0.1f, scope_line_thickness, 1.f); } } @@ -2460,7 +2467,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } DR_ClipScope(scope_clip_rect) { - dr_rect(scope_rect, scope_line_color, params->font_size*0.1f, 1.f, 1.f); + dr_rect(scope_rect, scope_line_color, params->font_size*0.1f, scope_line_thickness, 1.f); } } } From 9a1f96bda288b209c7a0b082cad595bacac1457d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 7 Aug 2025 17:35:52 -0700 Subject: [PATCH 002/302] progress on /opt:ref Link the debugger and strip unreferenced sections TODO: Mark referenced undefined symbols for unresolved symbol reporting --- src/linker/lnk.c | 925 ++++++++++++++++------------------ src/linker/lnk.h | 4 +- src/linker/lnk_obj.c | 29 +- src/linker/lnk_obj.h | 14 +- src/linker/lnk_symbol_table.c | 285 ++++++----- src/linker/lnk_symbol_table.h | 20 +- 6 files changed, 621 insertions(+), 656 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 87081b2a..d7117e31 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -964,204 +964,284 @@ lnk_make_linker_obj(Arena *arena, LNK_Config *config) internal void lnk_queue_lib_member_input(Arena *arena, - PathStyle path_style, - LNK_SymbolLib *symbol, + LNK_Config *config, + LNK_Symbol *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { - LNK_Lib *lib = symbol->lib; - U64 input_idx = Compose64Bit(lib->input_idx, symbol->member_offset); + B32 was_live = lnk_mark_symbol_live(symbol); + if (!was_live) { + LNK_SymbolLib *member = &symbol->u.lib; + LNK_Lib *lib = member->lib; + U64 input_idx = Compose64Bit(lib->input_idx, member->member_offset); - // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, symbol->member_offset); - COFF_DataType member_type = coff_data_type_from_data(member_info.data); - - switch (member_type) { - case COFF_DataType_Null: break; - case COFF_DataType_Import: { - LNK_InputImportNode *input = lnk_input_import_list_push(arena, input_import_list); - input->data.coff_import = member_info.data; - input->data.input_idx = input_idx; - } break; - case COFF_DataType_BigObj: - case COFF_DataType_Obj: { - String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); + // parse member + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member->member_offset); + COFF_DataType member_type = coff_data_type_from_data(member_info.data); - // obj path in thin archive has slash appended which screws up - // file lookup on disk; it couble be there to enable paths to symbols - // but we don't use this feature - String8 slash = str8_lit("/"); - if (str8_ends_with(obj_path, slash, 0)) { - obj_path = str8_chop(obj_path, slash.size); - } + switch (member_type) { + case COFF_DataType_Null: break; + case COFF_DataType_Import: { + LNK_InputImportNode *input = lnk_input_import_list_push(arena, input_import_list); + input->data.coff_import = member_info.data; + input->data.input_idx = input_idx; + } break; + case COFF_DataType_BigObj: + case COFF_DataType_Obj: { + String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); - // obj path in thin archive is relative to directory with archive - B32 is_thin = lib->type == COFF_Archive_Thin; - if (is_thin) { - Temp scratch = scratch_begin(&arena, 1); - String8List obj_path_list = {0}; - str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); - str8_list_push(scratch.arena, &obj_path_list, obj_path); - obj_path = str8_path_list_join_by_style(arena, &obj_path_list, path_style); - scratch_end(scratch); - } - - LNK_InputObj *input = lnk_input_obj_list_push(arena, input_obj_list); - input->is_thin = is_thin; - input->dedup_id = push_str8f(arena, "%S/%S", lib->path, obj_path); - input->path = obj_path; - input->data = member_info.data; - input->lib = lib; - input->input_idx = input_idx; - } break; - } -} - -internal -THREAD_POOL_TASK_FUNC(lnk_undef_symbol_finder) -{ - LNK_SymbolFinder *task = raw_task; - LNK_SymbolFinderResult *result = &task->result_arr[task_id]; - Rng1U64 range = task->range_arr[task_id]; - - for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { - LNK_SymbolNode *symbol_n = task->lookup_node_arr.v[symbol_idx]; - LNK_Symbol *symbol = symbol_n->data; - - LNK_Symbol *has_defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol->name); - if (has_defn) { - continue; - } - - LNK_Symbol *member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol) { - lnk_queue_lib_member_input(arena, task->path_style, &member_symbol->u.lib, &result->input_import_list, &result->input_obj_list); - } else { - lnk_symbol_list_push_node(&result->unresolved_symbol_list, symbol_n); - } - } -} - -internal -THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) -{ - LNK_SymbolFinder *task = raw_task; - LNK_SymbolFinderResult *result = &task->result_arr[task_id]; - Rng1U64 range = task->range_arr[task_id]; - - for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { - LNK_SymbolNode *symbol_n = task->lookup_node_arr.v[symbol_idx]; - LNK_Symbol *symbol = symbol_n->data; - - LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol->name); - if (defn) { - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); - COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); - if (defn_interp != COFF_SymbolValueInterp_Weak) { - continue; + // obj path in thin archive has slash appended which screws up + // file lookup on disk; it couble be there to enable paths to symbols + // but we don't use this feature + String8 slash = str8_lit("/"); + if (str8_ends_with(obj_path, slash, 0)) { + obj_path = str8_chop(obj_path, slash.size); } - } - - LNK_Symbol *member_symbol = 0; - { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(parsed_symbol, symbol->u.defined.obj->header.is_big_obj); - switch (weak_ext->characteristics) { - case COFF_WeakExt_NoLibrary: { - // NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member. - } break; - case COFF_WeakExt_AntiDependency: - case COFF_WeakExt_SearchLibrary: { - member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, symbol->name); - } break; - case COFF_WeakExt_SearchAlias: { - member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol == 0) { - if (str8_match_lit(".weak.", symbol->name, StringMatchFlag_RightSideSloppy)) { - // TODO: Clang and MingGW encode extra info in alias - // - // __attribute__((weak,alias("foo"))) void bar(void); - // static void foo() {} - // - // Clang write these COFF symbols in obj for code above: - // - // 30 00000000 0000000001 0 FUNC NULL EXTERNAL foo - // ... - // 33 00000000 UNDEF 1 NULL NULL WEAK_EXTERNAL bar - // Tag Index 35, Characteristics SEARCH_ALIAS - // 35 00000000 0000000001 0 NULL NULL EXTERNAL .weak.bar.default.foo - // - // In this case linker needs to parse .weak.bar.default.foo and search for bar and foo as well. - Assert("TODO: MinGW weak symbol"); - } else { - COFF_ParsedSymbol tag = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, weak_ext->tag_index); - member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, tag.name); - } - } - } break; + + // obj path in thin archive is relative to directory with archive + B32 is_thin = lib->type == COFF_Archive_Thin; + if (is_thin) { + Temp scratch = scratch_begin(&arena, 1); + String8List obj_path_list = {0}; + str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); + str8_list_push(scratch.arena, &obj_path_list, obj_path); + obj_path = str8_path_list_join_by_style(arena, &obj_path_list, config->path_style); + scratch_end(scratch); } - } - - if (member_symbol) { - lnk_queue_lib_member_input(arena, task->path_style, &member_symbol->u.lib, &result->input_import_list, &result->input_obj_list); - } else { - lnk_symbol_list_push_node(&result->unresolved_symbol_list, symbol_n); + + LNK_InputObj *input = lnk_input_obj_list_push(arena, input_obj_list); + input->is_thin = is_thin; + input->dedup_id = push_str8f(arena, "%S/%S", lib->path, obj_path); + input->path = obj_path; + input->data = member_info.data; + input->lib = lib; + input->input_idx = input_idx; + } break; } } } -internal LNK_SymbolFinderResult -lnk_run_symbol_finder(TP_Context *tp, - TP_Arena *arena, - LNK_Config *config, - LNK_SymbolTable *symtab, - LNK_SymbolList lookup_list, - TP_TaskFunc *task_func) +internal void +lnk_find_refs(Arena *arena, + TP_Context *tp, + LNK_SymbolTable *symtab, + LNK_Config *config, + LNK_ObjList objs, + LNK_InputImportList *imports_out, + LNK_InputObjList *objs_out) { ProfBeginFunction(); - Temp scratch = scratch_begin(arena->v, arena->count); - - ProfBegin("Setup Task"); - LNK_SymbolFinder task = {0}; - task.path_style = config->path_style; - task.symtab = symtab; - task.lookup_node_arr = lnk_symbol_node_array_from_list(scratch.arena, lookup_list); - task.result_arr = push_array(scratch.arena, LNK_SymbolFinderResult, tp->worker_count); - task.range_arr = tp_divide_work(scratch.arena, task.lookup_node_arr.count, tp->worker_count); - ProfEnd(); - - ProfBegin("Run Task"); - tp_for_parallel(tp, arena, tp->worker_count, task_func, &task); - ProfEnd(); - - ProfBegin("Concat Results"); - LNK_SymbolFinderResult result = {0}; - for (U64 i = 0; i < tp->worker_count; ++i) { - LNK_SymbolFinderResult *src = &task.result_arr[i]; - lnk_symbol_list_concat_in_place(&result.unresolved_symbol_list, &src->unresolved_symbol_list); - lnk_input_obj_list_concat_in_place(&result.input_obj_list, &src->input_obj_list); - lnk_input_import_list_concat_in_place(&result.input_import_list, &src->input_import_list); + Temp scratch = scratch_begin(&arena,1); + + struct Task { struct Task *next; LNK_Obj *obj; COFF_RelocArray relocs; U32 section_number; }; + struct Task *task_stack = 0; + const U64 RELOCS_PER_TASK = 1024; + + // + // reset live flag on sections + // + for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + for EachIndex(sect_idx, obj_n->data.header.section_count_no_null) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(&obj_n->data, sect_idx+1); + section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; + } } - ProfEnd(); - - // to get deterministic output accross multiple linker runs we have to sort inputs - ProfBegin("Sort Objs [Count %llu]", result.input_obj_list.count); - LNK_InputObj **input_obj_ptr_arr = lnk_array_from_input_obj_list(scratch.arena, result.input_obj_list); - qsort(input_obj_ptr_arr, result.input_obj_list.count, sizeof(input_obj_ptr_arr[0]), lnk_input_obj_compar); - //radsort(input_obj_ptr_arr, result.input_obj_list.count, lnk_input_obj_compar_is_before); - result.input_obj_list = lnk_list_from_input_obj_arr(input_obj_ptr_arr, result.input_obj_list.count); - ProfEnd(); - - ProfBegin("Sort Imports [Count %llu]", result.input_import_list.count); - LNK_InputImportNode **input_imp_ptr_arr = lnk_input_import_arr_from_list(scratch.arena, result.input_import_list); - //radsort(input_imp_ptr_arr, result.input_import_list.count, lnk_input_import_is_before); - qsort(input_imp_ptr_arr, result.input_import_list.count, sizeof(input_imp_ptr_arr[0]), lnk_input_import_node_compar); - result.input_import_list = lnk_list_from_input_import_arr(input_imp_ptr_arr, result.input_import_list.count); - ProfEnd(); - + + // + // define roots + // + { + String8List roots = str8_list_copy(scratch.arena, &config->include_symbol_list); + + // tls + LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); + if (tls_symbol) { + str8_list_pushf(scratch.arena, &roots, MSCRT_TLS_SYMBOL_NAME); + } + + // push tasks for each root symbol + for (String8Node *root_n = roots.first; root_n != 0; root_n = root_n->next) { + LNK_Symbol *root = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, root_n->string); + + struct Task *t = push_array(scratch.arena, struct Task, 1); + t->obj = root->u.defined.obj; + t->relocs.count = 1; + t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); + t->relocs.v[0].isymbol = root->u.defined.symbol_idx; + + SLLStackPush(task_stack, t); + } + + // push task for every non-COMDAT section + for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + LNK_Obj *obj = &obj_n->data; + for EachIndex(sect_idx, obj->header.section_count_no_null) { + U32 section_number = sect_idx+1; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + + // is section eligible for walking? + if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (config->opt_ref == LNK_SwitchState_Yes && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } + + // divide relocs and push task for each reloc block + COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number); + U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); + struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); + for EachIndex(new_task_idx, new_task_count) { + struct Task *t = new_tasks + new_task_idx; + t->obj = obj; + t->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); + t->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); + t->section_number = section_number; + SLLStackPush(task_stack, t); + } + } + } + } + + // + // walk relocations and unset the remove flag on visited sections + // + for (; task_stack; ) { + struct Task *t = task_stack; SLLStackPop(task_stack); + for EachIndex(reloc_idx, t->relocs.count) { + COFF_Reloc *reloc = &t->relocs.v[reloc_idx]; + LNK_SymbolDefined reloc_defn = (LNK_SymbolDefined){ .obj = t->obj, .symbol_idx = reloc->isymbol }; + COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_defn.obj, reloc_defn.symbol_idx); + COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed); + + LNK_SymbolDefined ref_symbol = reloc_defn; + for (;;) { + COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); + COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); + + if (ref_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); + COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + + if (defn_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *member_symbol = 0; + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(ref_parsed, ref_symbol.obj->header.is_big_obj); + switch (weak_ext->characteristics) { + case COFF_WeakExt_NoLibrary: { + // NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member. + } break; + case COFF_WeakExt_AntiDependency: + case COFF_WeakExt_SearchLibrary: { + member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); + } break; + case COFF_WeakExt_SearchAlias: { + member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); + if (member_symbol == 0) { + if (str8_match_lit(".weak.", ref_parsed.name, StringMatchFlag_RightSideSloppy)) { + // TODO: Clang and MingGW encode extra info in alias + // + // __attribute__((weak,alias("foo"))) void bar(void); + // static void foo() {} + // + // Clang write these COFF symbols in obj for code above: + // + // 30 00000000 0000000001 0 FUNC NULL EXTERNAL foo + // ... + // 33 00000000 UNDEF 1 NULL NULL WEAK_EXTERNAL bar + // Tag Index 35, Characteristics SEARCH_ALIAS + // 35 00000000 0000000001 0 NULL NULL EXTERNAL .weak.bar.default.foo + // + // In this case linker needs to parse .weak.bar.default.foo and search for bar and foo as well. + Assert("TODO: MinGW weak symbol"); + } else { + COFF_ParsedSymbol tag = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, weak_ext->tag_index); + member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, tag.name); + } + } + } break; + default: { NotImplemented; } break; + } + + member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); + if (member_symbol) { + lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + MemoryZeroStruct(&ref_symbol); + break; + } else { + ref_symbol = lnk_default_symbol_from_weak(symtab, ref_symbol); + } + } else { + ref_symbol = defn->u.defined; + } + } + else if (ref_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); + COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + if (defn_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); + if (member_symbol) { + lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + } + MemoryZeroStruct(&ref_symbol); + break; + } else { + ref_symbol = defn->u.defined; + } + } else if (ref_interp == COFF_SymbolValueInterp_Regular) { + LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); + if (symlink) { + ref_symbol = symlink->u.defined; + } + break; + } else { + break; + } + } + + // skip unresolved symbol + if (ref_symbol.obj == 0) { continue; } + + COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); + COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); + LNK_Obj *ref_obj = ref_symbol.obj; + + if (ref_interp == COFF_SymbolValueInterp_Regular) { + // make section number list (reloc section + associates) + U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); + section_number_list->data = ref_parsed.section_number; + section_number_list->next = ref_obj->associated_sections[ref_parsed.section_number]; + + // push section headers relocations to the task stack + for (U32Node *section_number_n = section_number_list; section_number_n != 0; section_number_n = section_number_n->next) { + U32 section_number = section_number_n->data; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number); + + // is section eligible for walking? + if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (lnk_is_coff_section_debug(ref_obj, section_number-1)) { continue; } + + // mark section + section_header->flags |= LNK_SECTION_FLAG_IS_LIVE; + + // divide relocs and push task for each reloc block + COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(ref_obj, section_number); + U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); + struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); + for EachIndex(new_task_idx, new_task_count) { + struct Task *n = new_tasks + new_task_idx; + n->obj = ref_obj; + n->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); + n->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); + n->section_number = section_number; + SLLStackPush(task_stack, n); + } + } + } + } + } + scratch_end(scratch); ProfEnd(); - return result; } internal LNK_LinkContext @@ -1178,8 +1258,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) State_PushDllHelperUndefSymbol, State_InputLinkerObjs, State_PushLoadConfigUndefSymbol, - State_LookupUndef, - State_LookupWeak, + State_FindRefs, State_LookupEntryPoint, State_ReportUnresolvedSymbols, }; @@ -1234,13 +1313,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) HashTable *loaded_lib_ht = hash_table_init(scratch.arena, 0x100); HashTable *missing_lib_ht = hash_table_init(scratch.arena, 0x100); HashTable *loaded_obj_ht = hash_table_init(scratch.arena, 0x4000); - LNK_SymbolList lookup_undef_list = {0}; - LNK_SymbolList lookup_weak_list = {0}; - LNK_SymbolList unresolved_undef_list = {0}; - LNK_SymbolList unresolved_weak_list = {0}; U64 entry_point_lookup_attempts = 0; - B32 report_unresolved_symbols = 1; B32 input_linker_objs = 1; + B32 pending_refs = 0; // // Init state machine @@ -1293,11 +1368,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) continue; } - // was import already created? - if (lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, import_header.func_name)) { - continue; - } - // create import stubs (later replaced with acutal imports generated by linker) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(LNK_IMPORT_STUB)); LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(scratch.arena, import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); @@ -1346,7 +1416,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // input obj with includes LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->path = str8_lit("* INCLUDE SYMBOLS *"); - input->dedup_id = push_str8f(scratch.arena, "%S %llu", input->path, input_obj_list.count); + input->dedup_id = push_str8f(scratch.arena, "%S %llu", input->path, obj_list.count); input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); coff_obj_writer_release(&obj_writer); @@ -1439,12 +1509,10 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); // input extern symbols from each obj to the symbol table - LNK_SymbolInputResult input_result = lnk_input_obj_symbols(tp, tp_arena, symtab, obj_node_arr); + lnk_input_obj_symbols(tp, tp_arena, symtab, obj_node_arr); // schedule symbol input - lnk_symbol_list_concat_in_place(&lookup_undef_list, &unresolved_undef_list); - lnk_symbol_list_concat_in_place(&lookup_undef_list, &input_result.undef_symbols); - lnk_symbol_list_concat_in_place(&lookup_weak_list, &input_result.weak_symbols); + pending_refs = 1; // reset input objs MemoryZeroStruct(&input_obj_list); @@ -1538,6 +1606,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) temp_end(temp); ProfEnd(); } + + // schedule symbol input + pending_refs = 1; ProfEnd(); } break; @@ -1591,39 +1662,16 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); } break; - case State_LookupUndef: { - ProfBegin("Lookup Undefined Symbols"); + case State_FindRefs: { + ProfBegin("Find Refs"); - // search archives - LNK_SymbolFinderResult result = lnk_run_symbol_finder(tp, tp_arena, config, symtab, lookup_undef_list, lnk_undef_symbol_finder); // TODO: put these on temp arena - - // new inputs found - input_obj_list = result.input_obj_list; - input_import_list = result.input_import_list; - - // undefined symbols that weren't resolved - lnk_symbol_list_concat_in_place(&unresolved_undef_list, &result.unresolved_symbol_list); - - // reset input - MemoryZeroStruct(&lookup_undef_list); + LNK_InputImportList new_imports = {0}; + LNK_InputObjList new_objs = {0}; + lnk_find_refs(scratch.arena, tp, symtab, config, obj_list, &new_imports, &new_objs); - ProfEnd(); - } break; - case State_LookupWeak: { - ProfBegin("Lookup Weak Symbols"); - - // search archives - LNK_SymbolFinderResult result = lnk_run_symbol_finder(tp, tp_arena, config, symtab, lookup_weak_list, lnk_weak_symbol_finder); // TODO: put these on temp arena - // schedule new inputs - input_obj_list = result.input_obj_list; - input_import_list = result.input_import_list; - - // weak symbols that weren't resolved - lnk_symbol_list_concat_in_place(&unresolved_weak_list, &result.unresolved_symbol_list); - - // reset input - MemoryZeroStruct(&lookup_weak_list); + lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); + lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); ProfEnd(); } break; @@ -1747,15 +1795,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); } break; - case State_ReportUnresolvedSymbols: { - // report unresolved symbols - for (LNK_SymbolNode *node = unresolved_undef_list.first; node != 0; node = node->next) { - lnk_error_obj(LNK_Error_UnresolvedSymbol, node->data->u.undef.obj, "unresolved symbol %S", node->data->name); - } - if (unresolved_undef_list.count) { - goto exit; - } - } break; case State_InputLinkerObjs: { { ProfBegin("Push Linker Symbols"); @@ -1779,34 +1818,34 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (delayed_imports->count) { ProfBegin("Build Delay Import Table"); - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; - B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; + B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; + String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); for (U64 dll_idx = 0; dll_idx < delayed_imports->count; dll_idx += 1) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); - input->path = dll_names[dll_idx]; - input->dedup_id = input->path; + input->input_idx = obj_list.count; + input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); + input->path = dll_names[dll_idx]; + input->dedup_id = input->path; } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(tp_arena->v[0], config->machine); { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Import Descriptor *"); - input->dedup_id = input->path; + input->input_idx = obj_list.count; + input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Delayed Null Import Descriptor *"); + input->dedup_id = input->path; } { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Thunk Data *"); - input->dedup_id = input->path; + input->input_idx = obj_list.count; + input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Delayed Null Thunk Data *"); + input->dedup_id = input->path; } ProfEnd(); @@ -1816,31 +1855,31 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (static_imports->count) { ProfBegin("Build Static Import Table"); - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); for (U64 dll_idx = 0; dll_idx < static_imports->count; dll_idx += 1) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_import_dll_obj_static(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); - input->path = dll_names[dll_idx]; - input->dedup_id = dll_names[dll_idx]; + input->input_idx = obj_list.count; + input->data = pe_make_import_dll_obj_static(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); + input->path = dll_names[dll_idx]; + input->dedup_id = dll_names[dll_idx]; } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Import Descriptor *"); - input->dedup_id = input->path; + input->input_idx = obj_list.count; + input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Null Import Descriptor *"); + input->dedup_id = input->path; } { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Thunk Data *"); - input->dedup_id = input->path; + input->input_idx = obj_list.count; + input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Null Thunk Data *"); + input->dedup_id = input->path; } ProfEnd(); @@ -2016,10 +2055,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputAlternateNames); continue; } - if (input_obj_list.count) { - state_list_push(scratch.arena, state_list, State_InputObjs); - continue; - } { B32 have_pending_lib_inputs = 0; for (U64 i = 0; i < ArrayCount(input_libs); ++i) { @@ -2033,18 +2068,13 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) continue; } } - if (lookup_undef_list.count) { - state_list_push(scratch.arena, state_list, State_LookupUndef); + if (input_obj_list.count) { + state_list_push(scratch.arena, state_list, State_InputObjs); continue; } - if (lookup_weak_list.count) { - state_list_push(scratch.arena, state_list, State_LookupWeak); - continue; - } - if (unresolved_weak_list.count) { - // we can't find strong definitions for unresolved weak symbols - // so now we have to use fallback symbols - MemoryZeroStruct(&unresolved_weak_list); + if (pending_refs) { + pending_refs = 0; + state_list_push(scratch.arena, state_list, State_FindRefs); continue; } if (entry_point_lookup_attempts == 0) { @@ -2057,44 +2087,118 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputLinkerObjs); continue; } - if (unresolved_undef_list.count) { - if (report_unresolved_symbols) { - report_unresolved_symbols = 0; - state_list_push(scratch.arena, state_list, State_ReportUnresolvedSymbols); - continue; - } - } break; } - // pass over symbol table and replace weak symbols without a strong definition with fallback definitions - lnk_finalize_weak_symbols(tp_arena, tp, symtab); - - // log + ProfBegin("Report Unresolved Symbols"); { - if (lnk_get_log_status(LNK_Log_InputObj)) { - U64 total_input_size = 0; - for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; } - lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size); - } - if (lnk_get_log_status(LNK_Log_InputLib)) { - U64 total_input_size = 0; - for (U64 i = 0; i < ArrayCount(lib_index); ++i) { - LNK_LibList list = lib_index[i]; - for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; } + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], tp->worker_count, &chunks_count); + + U64 undefs_count = 0; + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + if (symbol->is_live) { + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + undefs_count += 1; + } + } } - lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); + } + + U64 undefs_cursor = 0; + LNK_Symbol **undefs = push_array(scratch.arena, LNK_Symbol *, undefs_count); + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + if (symbol->is_live) { + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + undefs[undefs_cursor++] = chunk->v[i].symbol; + } + } + } + } + + radsort(undefs, undefs_count, lnk_symbol_defined_ptr_is_before); + + for EachIndex(i, undefs_count) { + LNK_Symbol *s = undefs[i]; + lnk_error_obj(LNK_Error_UnresolvedSymbol, s->u.defined.obj, "unresolved symbol %S", s->name); + } + + if (undefs_count > 0) { + lnk_exit(LNK_Error_UnresolvedSymbol); } } - - exit:; - // TODO: include symbol list + ProfEnd(); + + ProfBegin("Remove Unreachable Sections"); + { + for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { + LNK_Obj *obj = &obj_n->data; + for EachIndex(sect_idx, obj->header.section_count_no_null) { + U32 section_number = sect_idx+1; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + + if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } + + if (config->opt_ref == LNK_SwitchState_Yes) { + // remove unreferenced sections + if (~section_header->flags & LNK_SECTION_FLAG_IS_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { + section_header->flags |= COFF_SectionFlag_LnkRemove; + } + } + + // TODO: Reset reserved flag so it does not get propagated to the image sections. + // We need to mask out reserved flags when gathering section definitions to actually + // prevent propagation. + section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; + + if (section_header->flags & COFF_SectionFlag_LnkRemove) { + for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { + U32 section_number = section_number_n->data; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + section_header->flags |= COFF_SectionFlag_LnkRemove; + } + } + } + } + } + ProfEnd(); + + lnk_replace_weak_symbols_with_default_symbols(tp, symtab); + LNK_LinkContext link_ctx = {0}; link_ctx.symtab = symtab; link_ctx.objs_count = obj_list.count; link_ctx.objs = lnk_array_from_obj_list(tp_arena->v[0], obj_list); MemoryCopyTyped(&link_ctx.lib_index[0], &lib_index[0], ArrayCount(lib_index)); + + // + // log + // + if (lnk_get_log_status(LNK_Log_InputObj)) { + U64 total_input_size = 0; + for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; } + lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size); + } + if (lnk_get_log_status(LNK_Log_InputLib)) { + U64 total_input_size = 0; + for (U64 i = 0; i < ArrayCount(lib_index); ++i) { + LNK_LibList list = lib_index[i]; + for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; } + } + lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); + } + ProfEnd(); scratch_end(scratch); @@ -2150,166 +2254,6 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_Symbol return is_resolved; } -internal void -lnk_gc_comdats(TP_Context *tp, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, LNK_Config *config) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0,0); - - struct Task { struct Task *next; LNK_Obj *obj; COFF_RelocArray relocs; }; - struct Task *task_stack = 0; - const U64 RELOCS_PER_TASK = 1024; - - // - // define roots - // - { - String8List roots = str8_list_copy(scratch.arena, &config->include_symbol_list); - - // tls - LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); - if (tls_symbol) { - str8_list_pushf(scratch.arena, &roots, MSCRT_TLS_SYMBOL_NAME); - } - - // push tasks for each root symbol - for (String8Node *root_n = roots.first; root_n != 0; root_n = root_n->next) { - LNK_Symbol *root = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, root_n->string); - - struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root->u.defined.obj; - t->relocs.count = 1; - t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root->u.defined.symbol_idx; - - SLLStackPush(task_stack, t); - } - - // push task for every non-COMDAT section - for EachIndex(obj_idx, objs_count) { - LNK_Obj *obj = objs[obj_idx]; - for EachIndex(sect_idx, obj->header.section_count_no_null) { - if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } - - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1); - if ((~section_header->flags & COFF_SectionFlag_LnkCOMDAT) && (~section_header->flags & COFF_SectionFlag_LnkRemove)) { - // extract reloc info - COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, sect_idx+1); - - // alloc new tasks - U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); - struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); - - // divide relocs and push tasks - for EachIndex(new_task_idx, new_task_count) { - struct Task *t = new_tasks + new_task_idx; - t->obj = obj; - t->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); - t->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); - SLLStackPush(task_stack, t); - } - } - } - } - } - - // - // begin with COMDAT sections flagged as removed - // - for EachIndex(obj_idx, objs_count) { - LNK_Obj *obj = objs[obj_idx]; - COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj); - for EachIndex(sect_idx, obj->header.section_count_no_null) { - COFF_SectionHeader *section_header = §ion_table[sect_idx]; - if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { - section_header->flags |= COFF_SectionFlag_LnkRemove; - } - } - } - - // - // init per section flag array - // - B8 **was_section_visited = push_array(scratch.arena, B8 *, objs_count); - for EachIndex(obj_idx, objs_count) { was_section_visited[obj_idx] = push_array(scratch.arena, B8, objs[obj_idx]->header.section_count_no_null + 1); } - - // - // walk relocations and unset the remove flag on visited sections - // - for (; task_stack; ) { - struct Task *t = task_stack; SLLStackPop(task_stack); - for EachIndex(reloc_idx, t->relocs.count) { - COFF_Reloc *reloc = &t->relocs.v[reloc_idx]; - LNK_SymbolDefined reloc_symbol = {0}; - B32 is_reloc_symbol_resolved = lnk_resolve_symbol(symtab, (LNK_SymbolDefined){ .obj = t->obj, .symbol_idx = reloc->isymbol }, &reloc_symbol); - if (is_reloc_symbol_resolved) { - // parse and interp reloc symbol - LNK_Obj *reloc_obj = reloc_symbol.obj; - COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_obj, reloc_symbol.symbol_idx); - COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed); - if (reloc_interp == COFF_SymbolValueInterp_Regular) { - // make section number list (reloc section + associates) - U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); - section_number_list->data = reloc_parsed.section_number; - section_number_list->next = reloc_obj->associated_sections[reloc_parsed.section_number]; - - // push section headers relocations to the task stack - for (U32Node *section_number_n = section_number_list; section_number_n != 0; section_number_n = section_number_n->next) { - if (was_section_visited[reloc_symbol.obj->input_idx][section_number_n->data]) { continue; } - was_section_visited[reloc_symbol.obj->input_idx][section_number_n->data] = 1; - - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(reloc_symbol.obj, section_number_n->data); - if (lnk_is_coff_section_debug(reloc_obj, section_number_n->data-1)) { continue; } - - // skip regular sections that were removed - if (~section_header->flags & COFF_SectionFlag_LnkCOMDAT && section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - - // on reachable COMDAT sections, unset remove flag - if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { section_header->flags &= ~COFF_SectionFlag_LnkRemove; } - - // extract reloc info - COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(reloc_symbol.obj, section_number_n->data); - - // alloc new tasks - U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); - struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); - - // divide relocs and push tasks - for EachIndex(new_task_idx, new_task_count) { - struct Task *t = new_tasks + new_task_idx; - t->obj = reloc_obj; - t->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); - t->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); - SLLStackPush(task_stack, t); - } - } - } - } - } - } - - // - // unset flag on debug sections that associate with live sections - // - for EachIndex(obj_idx, objs_count) { - LNK_Obj *obj = objs[obj_idx]; - for EachIndex(sect_idx, obj->header.section_count_no_null) { - U32 section_number = sect_idx+1; - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); - if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { - if (lnk_is_coff_section_debug(obj, section_number_n->data-1)) { - COFF_SectionHeader *associated_section_header = lnk_coff_section_header_from_section_number(obj, section_number_n->data); - associated_section_header->flags &= ~COFF_SectionFlag_LnkRemove; - } - } - } - } - - scratch_end(scratch); - ProfEnd(); -} - internal THREAD_POOL_TASK_FUNC(lnk_gather_section_definitions_task) { @@ -2676,19 +2620,28 @@ lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patch COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class); AssertAlways(fixup_type == COFF_SymbolValueInterp_Regular || fixup_type == COFF_SymbolValueInterp_Abs || - fixup_type == COFF_SymbolValueInterp_Common); + fixup_type == COFF_SymbolValueInterp_Common || + fixup_type == COFF_SymbolValueInterp_Undefined); + + U32 section_number; + U32 value; + if (fixup_type == COFF_SymbolValueInterp_Undefined) { + section_number = lnk_obj_get_removed_section_number(obj); + value = 0; + } else { + section_number = fixup_src.section_number; + value = fixup_src.value; + } if (obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = fixup_dst.raw_symbol; - symbol32->section_number = fixup_src.section_number; - symbol32->value = fixup_src.value; - symbol32->type = fixup_src.type; + symbol32->section_number = section_number; + symbol32->value = value; symbol32->storage_class = COFF_SymStorageClass_Static; } else { COFF_Symbol16 *symbol16 = fixup_dst.raw_symbol; - symbol16->section_number = (U16)fixup_src.section_number; - symbol16->value = fixup_src.value; - symbol16->type = fixup_src.type; + symbol16->section_number = (U16)section_number; + symbol16->value = value; symbol16->storage_class = COFF_SymStorageClass_Static; } @@ -2751,7 +2704,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) String8 symbol_table = str8_substr(obj->data, obj_header.symbol_table_range); String8 string_table = str8_substr(obj->data, obj_header.string_table_range); - for (U64 sect_idx = 0; sect_idx < obj_header.section_count_no_null; sect_idx += 1) { + for EachIndex(sect_idx, obj_header.section_count_no_null) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } @@ -2767,7 +2720,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); // apply relocs - for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; reloc_idx += 1) { + for EachIndex(reloc_idx, reloc_info.count) { COFF_Reloc *reloc = &relocs[reloc_idx]; // error check relocation @@ -2860,7 +2813,7 @@ THREAD_POOL_TASK_FUNC(lnk_count_common_block_contribs_task) LNK_SymbolTable *symtab = task->symtab; for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { - for (U64 i = 0; i < chunk->count; i += 1) { + for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); @@ -2879,7 +2832,7 @@ THREAD_POOL_TASK_FUNC(lnk_fill_out_common_block_contribs_task) U64 cursor = task->u.common_block.offsets[task_id]; for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { - for (U64 i = 0; i < chunk->count; i += 1) { + for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); @@ -3826,25 +3779,13 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config } internal LNK_ImageContext -lnk_build_image(TP_Arena *arena, - TP_Context *tp, - LNK_Config *config, - LNK_SymbolTable *symtab, - U64 objs_count, - LNK_Obj **objs) +lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs) { ProfBegin("Image"); lnk_timer_begin(LNK_Timer_Image); Temp scratch = scratch_begin(arena->v, arena->count); - // - // remove unreachable COMDAT sections - // - if (config->opt_ref == LNK_SwitchState_Yes) { - lnk_gc_comdats(tp, symtab, objs_count, objs, config); - } - // // init section table // diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 3d7ce197..d4ec69d4 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -19,6 +19,8 @@ typedef struct LNK_LinkContext #define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3 #define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3 +#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) + typedef struct LNK_ImageContext { String8 image_data; @@ -212,7 +214,7 @@ internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config); -internal void lnk_queue_lib_member_input(Arena *arena, PathStyle path_style, LNK_SymbolLib *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 38cbce44..8af306fa 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -365,7 +365,6 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); - lnk_symbol_list_push(arena, &task->weak_lists[worker_id], defn); } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); @@ -378,16 +377,9 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) } } break; case COFF_SymbolValueInterp_Undefined: { - LNK_Symbol *s = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name); - if (s == 0) { - if (symbol.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *undef = lnk_make_undefined_symbol(arena, symbol.name, obj); - lnk_symbol_list_push(arena, &task->undef_lists[worker_id], undef); - } else if (symbol.storage_class == COFF_SymStorageClass_Section) { - // lookup is performed during image patching step - } else { - Assert(!"unexpected storage class on undefined symbol"); - } + if (symbol.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); } } break; case COFF_SymbolValueInterp_Debug: { @@ -426,27 +418,16 @@ THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task) obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj); } -internal LNK_SymbolInputResult +internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs) { ProfBeginFunction(); - Temp scratch = scratch_begin(arena->v, arena->count); - LNK_InputCoffSymbolTable task = {0}; - task.symtab = symtab; - task.objs = objs; - task.weak_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count); - task.undef_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count); + LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs }; tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task); tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task); - LNK_SymbolInputResult result = {0}; - SLLConcatInPlaceArray(&result.weak_symbols, task.weak_lists, tp->worker_count); - SLLConcatInPlaceArray(&result.undef_symbols, task.undef_lists, tp->worker_count); - - scratch_end(scratch); ProfEnd(); - return result; } internal COFF_ParsedSymbol diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 78510b80..dcbc9207 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -37,12 +37,6 @@ typedef struct LNK_ObjNodeArray LNK_ObjNode *v; } LNK_ObjNodeArray; -typedef struct LNK_SymbolInputResult -{ - LNK_SymbolList weak_symbols; - LNK_SymbolList undef_symbols; -} LNK_SymbolInputResult; - // --- Directive Parser -------------------------------------------------------- typedef struct LNK_Directive @@ -78,8 +72,6 @@ typedef struct { LNK_SymbolTable *symtab; LNK_ObjNodeArray objs; - LNK_SymbolList *weak_lists; - LNK_SymbolList *undef_lists; } LNK_InputCoffSymbolTable; typedef struct @@ -96,9 +88,9 @@ internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...); // --- Input ------------------------------------------------------------------- -internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list); -internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs); -internal LNK_SymbolInputResult lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs); +internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list); +internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs); +internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs); // --- Metadata ---------------------------------------------------------------- diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 7d5b5dda..268abedb 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -21,15 +21,6 @@ lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_ return symbol; } -internal LNK_Symbol * -lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj) -{ - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->u.undef.obj = obj; - return symbol; -} - internal B32 lnk_symbol_defined_is_before(void *raw_a, void *raw_b) { @@ -37,6 +28,12 @@ lnk_symbol_defined_is_before(void *raw_a, void *raw_b) return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx; } +internal B32 +lnk_symbol_defined_ptr_is_before(void *raw_a, void *raw_b) +{ + return lnk_symbol_defined_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); +} + internal B32 lnk_symbol_lib_is_before(void *raw_a, void *raw_b) { @@ -144,8 +141,36 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); + // undefined vs regular + if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { + can_replace = 1; + } + // undefined vs weak + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak) { + can_replace = 1; + } + // undefined vs undefined + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = lnk_symbol_defined_is_before(src, dst); + } + // undefined vs common + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { + can_replace = 1; + } + // undefined vs abs + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) { + can_replace = 1; + } + // undefined vs debug + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { + can_replace = 1; + } + // regular/weak/common/abs/debug vs undefined + else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = 0; + } // regular vs abs - if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { + else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { lnk_error_multiply_defined_symbol(dst, src); } // abs vs regular @@ -439,6 +464,129 @@ lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie) ins_atomic_ptr_eval_assign(&trie->symbol, 0); } +internal LNK_SymbolHashTrieChunk ** +lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out) +{ + U64 chunks_count = 0; + for EachIndex(i, lists_count) { chunks_count += lists[i].count; } + + LNK_SymbolHashTrieChunk **chunks = push_array(arena, LNK_SymbolHashTrieChunk *, chunks_count); + U64 chunks_cursor = 0; + for EachIndex(i, lists_count) { + for (LNK_SymbolHashTrieChunk *chunk = lists[i].first; chunk != 0; chunk = chunk->next) { + chunks[chunks_cursor++] = chunk; + } + } + + if (count_out) { + *count_out = chunks_count; + } + + return chunks; +} + +internal COFF_ParsedSymbol +lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) +{ + return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); +} + +internal B32 +lnk_mark_symbol_live(LNK_Symbol *symbol) +{ + B32 was_live = ins_atomic_u32_eval_assign(&symbol->is_live, 1); + return was_live; +} + +internal LNK_SymbolDefined +lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) +{ + Temp scratch = scratch_begin(0,0); + + struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dep; }; + struct LookupLocation *lookup_first = 0, *lookup_last = 0; + + COFF_ParsedSymbol head_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); + COFF_SymbolWeakExt *head_weak_ext = coff_parse_weak_tag(head_parsed, symbol.obj->header.is_big_obj); + LNK_SymbolDefined current_symbol = (LNK_SymbolDefined){ .obj = symbol.obj, .symbol_idx = head_weak_ext->tag_index }; + + for (;;) { + // guard against self-referencing weak symbols + struct LookupLocation *was_visited = 0; + for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { + if (MemoryCompare(&l->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = l; break; } + } + if (was_visited) { + Temp temp = temp_begin(scratch.arena); + + String8List ref_list = {0}; + for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { + COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(l->symbol.obj, l->symbol.symbol_idx); + str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x) =>", l->symbol.obj->path, loc_symbol.name, l->symbol.symbol_idx); + } + COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(lookup_first->symbol.obj, lookup_first->symbol.symbol_idx); + str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x)", lookup_first->symbol.obj->path, loc_symbol.name, lookup_first->symbol.symbol_idx); + + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); + String8 loc_string = str8_list_join(temp.arena, &ref_list, &(StringJoin){ .sep = str8_lit("\n") }); + lnk_error_obj(LNK_Error_WeakCycle, symbol.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", parsed_symbol.name, loc_string); + + MemoryZeroStruct(¤t_symbol); + + temp_end(temp); + break; + } + + COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); + COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); + if (current_interp == COFF_SymbolValueInterp_Weak) { + // check for anti dependency + for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { + if (l->is_anti_dep) { + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol.obj, "unresolved symbol %S", head_parsed.name); + break; + } + } + + // does weak symbol have a definition? + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx); + COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); + if (defn_interp != COFF_SymbolValueInterp_Weak) { + current_symbol = defn_symbol->u.defined; + break; + } + + // no definition fallback to default symbol + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); + COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); + COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); + current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; + + // record visited symbol + struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1); + loc->symbol = current_symbol; + loc->is_anti_dep = weak_ext->characteristics == COFF_WeakExt_AntiDependency; + SLLQueuePush(lookup_first, lookup_last, loc); + } else if (current_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn_symbol); + COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + + current_symbol = defn_symbol->u.defined; + + if (defn_interp == COFF_SymbolValueInterp_Undefined) { + break; + } + } else { + break; + } + } + + scratch_end(scratch); + return current_symbol; +} + internal U64 lnk_symbol_hash(String8 string) { @@ -539,10 +687,8 @@ THREAD_POOL_TASK_FUNC(lnk_check_anti_dependecy_task) } internal -THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task) +THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbols_task) { - Temp scratch = scratch_begin(&arena,1); - LNK_FinalizeWeakSymbolsTask *task = raw_task; LNK_SymbolTable *symtab = task->symtab; LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; @@ -552,117 +698,22 @@ THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task) COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dependency; }; - struct LookupLocation *lookup_first = 0, *lookup_last = 0; - - LNK_SymbolDefined current_symbol = symbol->u.defined; - for (;;) { - // guard against self-referencing weak symbols - struct LookupLocation *was_visited = 0; - for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { - if (MemoryCompare(&l->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = l; break; } - } - if (was_visited) { - Temp temp = temp_begin(scratch.arena); - - String8List ref_list = {0}; - for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { - COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(l->symbol.obj, l->symbol.symbol_idx); - str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x) =>", l->symbol.obj->path, loc_symbol.name, l->symbol.symbol_idx); - } - COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(lookup_first->symbol.obj, lookup_first->symbol.symbol_idx); - str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x)", lookup_first->symbol.obj->path, loc_symbol.name, lookup_first->symbol.symbol_idx); - - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); - String8 loc_string = str8_list_join(temp.arena, &ref_list, &(StringJoin){ .sep = str8_lit("\n") }); - lnk_error_obj(LNK_Error_WeakCycle, symbol->u.defined.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", parsed_symbol.name, loc_string); - - MemoryZeroStruct(¤t_symbol); - - temp_end(temp); - break; - } - - COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); - COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); - if (current_interp == COFF_SymbolValueInterp_Weak) { - // record visited symbol - struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1); - loc->symbol = current_symbol; - SLLQueuePush(lookup_first, lookup_last, loc); - - // does weak symbol have a definition? - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx); - COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); - if (defn_interp != COFF_SymbolValueInterp_Weak) { - current_symbol = defn_symbol->u.defined; - break; - } - - // no definition fallback to the tag - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); - COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); - COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); - current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; - } else if (current_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); - if (defn_symbol == 0) { - MemoryZeroStruct(¤t_symbol); - break; - } - current_symbol = defn_symbol->u.defined; - } else { - break; - } - } - - // replace weak symbol with it's tag - symbol->u.defined = current_symbol; + symbol->u.defined = lnk_default_symbol_from_weak(symtab, symbol->u.defined); } } - - scratch_end(scratch); } internal void -lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab) +lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) { ProfBeginFunction(); - Temp scratch = scratch_begin(arena->v, arena->count); + Temp scratch = scratch_begin(0,0); - U64 chunks_count = 0; - for EachIndex(worker_id, tp->worker_count) { chunks_count += symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].count; } - - LNK_SymbolHashTrieChunk **chunks = push_array(scratch.arena, LNK_SymbolHashTrieChunk *, chunks_count); - U64 chunks_cursor = 0; - for EachIndex(worker_id, tp->worker_count) { - for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; chunk != 0; chunk = chunk->next) { - chunks[chunks_cursor++] = chunk; - } - } + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); LNK_FinalizeWeakSymbolsTask task = { .symtab = symtab, .chunks = chunks }; - - { - TP_Temp temp = tp_temp_begin(arena); - task.anti_dependency_symbols = push_array(scratch.arena, LNK_SymbolList, tp->worker_count); - tp_for_parallel(tp, arena, chunks_count, lnk_check_anti_dependecy_task, &task); - - LNK_SymbolList anti_dependency_symbol_list = {0}; - lnk_symbol_concat_in_place_array(&anti_dependency_symbol_list, task.anti_dependency_symbols, tp->worker_count); - LNK_SymbolArray anti_dependency_symbols = lnk_symbol_array_from_list(scratch.arena, anti_dependency_symbol_list); - radsort(anti_dependency_symbols.v, anti_dependency_symbols.count, lnk_symbol_defined_is_before); - - for EachIndex(symbol_idx, anti_dependency_symbols.count) { - LNK_Symbol *s = &anti_dependency_symbols.v[symbol_idx]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, s->u.defined.obj, "unresolved symbol %S", s->name); - } - - tp_temp_end(temp); - } - - tp_for_parallel(tp, 0, chunks_count, lnk_finalize_weak_symbols_task, &task); + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_symbols_with_default_symbols_task, &task); scratch_end(scratch); ProfEnd(); @@ -708,9 +759,3 @@ lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol) return foff; } -internal COFF_ParsedSymbol -lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) -{ - return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); -} - diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index f6fed011..7135331e 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -32,10 +32,10 @@ typedef struct LNK_SymbolUndefined typedef struct LNK_Symbol { String8 name; + B32 is_live; union { LNK_SymbolDefined defined; LNK_SymbolLib lib; - LNK_SymbolUndefined undef; } u; } LNK_Symbol; @@ -112,7 +112,6 @@ typedef struct internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset); -internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj); // --- Symbol Containers ------------------------------------------------------ @@ -126,9 +125,16 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol // --- Symbol Hash Trie -------------------------------------------------------- -internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol); -internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name); -internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie); +internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol); +internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name); +internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie); +internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out); + +// --- Symbol Helpers ---------------------------------------------------------- + +internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); +internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol); +internal LNK_SymbolDefined lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol); // --- Symbol Table ------------------------------------------------------------ @@ -139,7 +145,7 @@ internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Sy internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name); internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...); -internal void lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab); +internal void lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab); // --- Symbol Contrib Helpers -------------------------------------------------- @@ -149,5 +155,3 @@ internal U64 lnk_sect_off_from_symbol(LNK_Symbol *symbol); internal U64 lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol); internal U64 lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol); -internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); - From 4f6f9d61ed6f5e9db440e0839cb13b9947664d8c Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 7 Aug 2025 17:41:45 -0700 Subject: [PATCH 003/302] inline function for replacing weak symbols with default symbol --- src/linker/lnk.c | 29 ++++++++++++++- src/linker/lnk.h | 6 +++ src/linker/lnk_symbol_table.c | 69 ----------------------------------- src/linker/lnk_symbol_table.h | 11 ------ 4 files changed, 33 insertions(+), 82 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index d7117e31..e4553842 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1244,6 +1244,22 @@ lnk_find_refs(Arena *arena, ProfEnd(); } +internal +THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbol_task) +{ + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + symbol->u.defined = lnk_default_symbol_from_weak(symtab, symbol->u.defined); + } + } +} + internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { @@ -2174,8 +2190,18 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } ProfEnd(); - lnk_replace_weak_symbols_with_default_symbols(tp, symtab); + ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); + { + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_symbols_with_default_symbol_task, &task); + } + ProfEnd(); + // + // fill out link context + // LNK_LinkContext link_ctx = {0}; link_ctx.symtab = symtab; link_ctx.objs_count = obj_list.count; @@ -2198,7 +2224,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); } - ProfEnd(); scratch_end(scratch); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index d4ec69d4..d25c18da 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -75,6 +75,12 @@ typedef struct LNK_BaseRelocPageArray // --- Workers Contexts -------------------------------------------------------- +typedef struct +{ + LNK_SymbolTable *symtab; + LNK_SymbolHashTrieChunk **chunks; +} LNK_ReplaceWeakSymbolsWithDefaultSymbolTask; + typedef struct { LNK_SymbolTable *symtab; diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 268abedb..2022aade 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -650,75 +650,6 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f return symbol; } -internal -THREAD_POOL_TASK_FUNC(lnk_check_anti_dependecy_task) -{ - LNK_FinalizeWeakSymbolsTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; - - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - COFF_ParsedSymbol default_symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, weak_ext->tag_index); - COFF_SymbolValueInterpType default_symbol_interp = coff_interp_from_parsed_symbol(default_symbol_parsed); - - COFF_SymbolValueInterpType actual_default_symbol_interp = default_symbol_interp; - if (default_symbol_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *actual_default_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, default_symbol_parsed.name); - if (actual_default_symbol) { - COFF_ParsedSymbol actual_default_symbol_parsed = lnk_parsed_symbol_from_defined(actual_default_symbol); - actual_default_symbol_interp = coff_interp_from_parsed_symbol(actual_default_symbol_parsed); - } - } - - if (actual_default_symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolNode *symbol_n = push_array(arena, LNK_SymbolNode, 1); - symbol_n->data = symbol; - lnk_symbol_list_push_node(&task->anti_dependency_symbols[task_id], symbol_n); - } - } - } - } -} - -internal -THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbols_task) -{ - LNK_FinalizeWeakSymbolsTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; - - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - symbol->u.defined = lnk_default_symbol_from_weak(symtab, symbol->u.defined); - } - } -} - -internal void -lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0,0); - - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); - - LNK_FinalizeWeakSymbolsTask task = { .symtab = symtab, .chunks = chunks }; - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_symbols_with_default_symbols_task, &task); - - scratch_end(scratch); - ProfEnd(); -} - internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 7135331e..772df460 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -99,15 +99,6 @@ typedef struct LNK_SymbolTable LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScope_Count]; } LNK_SymbolTable; -// --- Workers Contensts ------------------------------------------------------- - -typedef struct -{ - LNK_SymbolTable *symtab; - LNK_SymbolHashTrieChunk **chunks; - LNK_SymbolList *anti_dependency_symbols; -} LNK_FinalizeWeakSymbolsTask; - // --- Symbol Make ------------------------------------------------------------- internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); @@ -145,8 +136,6 @@ internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Sy internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name); internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...); -internal void lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab); - // --- Symbol Contrib Helpers -------------------------------------------------- internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol); From 137eb6403a747db77ad003ac8ed7411b00240556 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 7 Aug 2025 22:40:14 -0700 Subject: [PATCH 004/302] fix crash when relocation points to an undefined section symbol --- src/linker/lnk.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e4553842..f5731161 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1101,7 +1101,7 @@ lnk_find_refs(Arena *arena, } // - // walk relocations and unset the remove flag on visited sections + // walk relocations and mark referenced sections as live // for (; task_stack; ) { struct Task *t = task_stack; SLLStackPop(task_stack); @@ -1160,7 +1160,6 @@ lnk_find_refs(Arena *arena, default: { NotImplemented; } break; } - member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); if (member_symbol) { lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); MemoryZeroStruct(&ref_symbol); @@ -1173,18 +1172,23 @@ lnk_find_refs(Arena *arena, } } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); - COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); - if (defn_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); - if (member_symbol) { - lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + MemoryZeroStruct(&ref_symbol); + + if (ref_parsed.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); + COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + if (defn_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); + if (member_symbol) { + lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + } + break; + } else { + ref_symbol = defn->u.defined; } - MemoryZeroStruct(&ref_symbol); - break; } else { - ref_symbol = defn->u.defined; + break; } } else if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); From 9893a8135d01ca92584ea255c56ec1d54c87f700 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 8 Aug 2025 13:35:47 -0700 Subject: [PATCH 005/302] fix crash when linking undefined weak symbol --- src/linker/lnk.c | 4 +- src/linker/lnk_symbol_table.c | 83 +++++++++++++++++------------------ src/linker/lnk_symbol_table.h | 7 +-- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f5731161..1ce0b985 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1165,7 +1165,7 @@ lnk_find_refs(Arena *arena, MemoryZeroStruct(&ref_symbol); break; } else { - ref_symbol = lnk_default_symbol_from_weak(symtab, ref_symbol); + ref_symbol = lnk_resolve_weak_symbol(symtab, ref_symbol); } } else { ref_symbol = defn->u.defined; @@ -1259,7 +1259,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbol_task) COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - symbol->u.defined = lnk_default_symbol_from_weak(symtab, symbol->u.defined); + symbol->u.defined = lnk_resolve_weak_symbol(symtab, symbol->u.defined); } } } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 2022aade..4c0f6a0b 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -491,6 +491,13 @@ lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); } +internal COFF_SymbolValueInterpType +lnk_interp_from_symbol(LNK_Symbol *symbol) +{ + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + return coff_interp_from_parsed_symbol(symbol_parsed); +} + internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol) { @@ -499,41 +506,33 @@ lnk_mark_symbol_live(LNK_Symbol *symbol) } internal LNK_SymbolDefined -lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) +lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) { Temp scratch = scratch_begin(0,0); - struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dep; }; - struct LookupLocation *lookup_first = 0, *lookup_last = 0; - - COFF_ParsedSymbol head_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); - COFF_SymbolWeakExt *head_weak_ext = coff_parse_weak_tag(head_parsed, symbol.obj->header.is_big_obj); - LNK_SymbolDefined current_symbol = (LNK_SymbolDefined){ .obj = symbol.obj, .symbol_idx = head_weak_ext->tag_index }; + struct S { struct S *next; LNK_SymbolDefined symbol; B32 is_anti_dep; }; + struct S *sf = 0, *sl = 0; + LNK_SymbolDefined current_symbol = symbol; for (;;) { // guard against self-referencing weak symbols - struct LookupLocation *was_visited = 0; - for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { - if (MemoryCompare(&l->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = l; break; } + struct S *was_visited = 0; + for (struct S *s = sf; s != 0; s = s->next) { + if (MemoryCompare(&s->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = s; break; } } if (was_visited) { - Temp temp = temp_begin(scratch.arena); - - String8List ref_list = {0}; - for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { - COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(l->symbol.obj, l->symbol.symbol_idx); - str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x) =>", l->symbol.obj->path, loc_symbol.name, l->symbol.symbol_idx); + String8List chain = {0}; + for (struct S *s = sf; s != 0; s = s->next) { + COFF_ParsedSymbol s_parsed = lnk_parsed_symbol_from_coff_symbol_idx(s->symbol.obj, s->symbol.symbol_idx); + str8_list_pushf(scratch.arena, &chain, "\t%S Symbol %S (No. %#x) =>", s->symbol.obj->path, s_parsed.name, s->symbol.symbol_idx); } - COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(lookup_first->symbol.obj, lookup_first->symbol.symbol_idx); - str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x)", lookup_first->symbol.obj->path, loc_symbol.name, lookup_first->symbol.symbol_idx); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); + str8_list_pushf(scratch.arena, &chain, "\t%S Symbol %S (No. %#x)", sf->symbol.obj->path, symbol_parsed.name, sf->symbol.symbol_idx); - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); - String8 loc_string = str8_list_join(temp.arena, &ref_list, &(StringJoin){ .sep = str8_lit("\n") }); - lnk_error_obj(LNK_Error_WeakCycle, symbol.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", parsed_symbol.name, loc_string); + String8 chain_string = str8_list_join(scratch.arena, &chain, &(StringJoin){ .sep = str8_lit("\n") }); + lnk_error_obj(LNK_Error_WeakCycle, symbol.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", symbol_parsed.name, chain_string); MemoryZeroStruct(¤t_symbol); - - temp_end(temp); break; } @@ -541,9 +540,11 @@ lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); if (current_interp == COFF_SymbolValueInterp_Weak) { // check for anti dependency - for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) { - if (l->is_anti_dep) { - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol.obj, "unresolved symbol %S", head_parsed.name); + for (struct S *s = sf; s != 0; s = s->next) { + if (s->is_anti_dep) { + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol.obj, "unresolved symbol %S", parsed_symbol.name); + MemoryZeroStruct(¤t_symbol); break; } } @@ -557,30 +558,28 @@ lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) break; } + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); + + // record visited symbol + struct S *s = push_array(scratch.arena, struct S, 1); + s->symbol = current_symbol; + s->is_anti_dep = weak_ext->characteristics == COFF_WeakExt_AntiDependency; + SLLQueuePush(sf, sl, s); + // no definition fallback to default symbol - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; - - // record visited symbol - struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1); - loc->symbol = current_symbol; - loc->is_anti_dep = weak_ext->characteristics == COFF_WeakExt_AntiDependency; - SLLQueuePush(lookup_first, lookup_last, loc); } else if (current_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn_symbol); - COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); + // unresolved undefined symbol + if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } + + // follow symbol definition current_symbol = defn_symbol->u.defined; - - if (defn_interp == COFF_SymbolValueInterp_Undefined) { - break; - } - } else { - break; - } + } else { break; } } scratch_end(scratch); diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 772df460..813103e9 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -123,9 +123,10 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A // --- Symbol Helpers ---------------------------------------------------------- -internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); -internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol); -internal LNK_SymbolDefined lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol); +internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); +internal COFF_SymbolValueInterpType lnk_interp_from_symbol(LNK_Symbol *symbol); +internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol); +internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol); // --- Symbol Table ------------------------------------------------------------ From 7466da14792e06ef1b8040482323104421f790c0 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 8 Aug 2025 15:53:55 -0700 Subject: [PATCH 006/302] mark referenced symbols as live for unresolved-symbol detection --- src/coff/coff_parse.c | 7 ++++ src/coff/coff_parse.h | 1 + src/linker/lnk.c | 24 +++++++------ src/linker/lnk.h | 6 ++-- src/linker/lnk_obj.c | 14 ++++---- src/torture/torture.c | 83 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 22 deletions(-) diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c index f8b2a3a4..e3bd1dff 100644 --- a/src/coff/coff_parse.c +++ b/src/coff/coff_parse.c @@ -285,6 +285,13 @@ coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol) return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); } +internal B32 +coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol) +{ + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); + return interp == COFF_SymbolValueInterp_Undefined && symbol.storage_class == COFF_SymStorageClass_External; +} + internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out) { diff --git a/src/coff/coff_parse.h b/src/coff/coff_parse.h index 92106867..3125c1f8 100644 --- a/src/coff/coff_parse.h +++ b/src/coff/coff_parse.h @@ -268,6 +268,7 @@ internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16L internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class); internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol); +internal B32 coff_is_undefined_data_symbol(COFF_ParsedSymbol symbol); internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out); internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1ce0b985..54ee97a0 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1101,7 +1101,7 @@ lnk_find_refs(Arena *arena, } // - // walk relocations and mark referenced sections as live + // walk relocations and mark referenced sections with live flag // for (; task_stack; ) { struct Task *t = task_stack; SLLStackPop(task_stack); @@ -1115,12 +1115,10 @@ lnk_find_refs(Arena *arena, for (;;) { COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); - if (ref_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); - if (defn_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *member_symbol = 0; COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(ref_parsed, ref_symbol.obj->header.is_big_obj); @@ -1172,12 +1170,11 @@ lnk_find_refs(Arena *arena, } } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { - MemoryZeroStruct(&ref_symbol); - if (ref_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); + if (defn_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); if (member_symbol) { @@ -1208,6 +1205,13 @@ lnk_find_refs(Arena *arena, COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); LNK_Obj *ref_obj = ref_symbol.obj; + // mark referenced symbol live + if (ref_parsed.storage_class == COFF_SymStorageClass_External || + ref_parsed.storage_class == COFF_SymStorageClass_WeakExternal) { + LNK_Symbol *ref_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + lnk_mark_symbol_live(ref_symbol); + } + if (ref_interp == COFF_SymbolValueInterp_Regular) { // make section number list (reloc section + associates) U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); @@ -2122,9 +2126,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; if (symbol->is_live) { - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + if (coff_is_undefined_data_symbol(symbol_parsed)) { undefs_count += 1; } } @@ -2138,9 +2141,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; if (symbol->is_live) { - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + if (coff_is_undefined_data_symbol(symbol_parsed)) { undefs[undefs_cursor++] = chunk->v[i].symbol; } } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index d25c18da..d2150f06 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -5,6 +5,9 @@ // --- Link -------------------------------------------------------------------- +#define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" +#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) + typedef struct LNK_LinkContext { LNK_SymbolTable *symtab; @@ -15,12 +18,9 @@ typedef struct LNK_LinkContext // -- Image -------------------------------------------------------------------- -#define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" #define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3 #define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3 -#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) - typedef struct LNK_ImageContext { String8 image_data; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 8af306fa..f27d7088 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -345,11 +345,9 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) { LNK_InputCoffSymbolTable *task = raw_task; LNK_Obj *obj = &task->objs.v[task_id].data; - COFF_ParsedSymbol symbol = {0}; for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); switch (interp) { case COFF_SymbolValueInterp_Regular: { @@ -366,17 +364,17 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); } break; - case COFF_SymbolValueInterp_Common: { - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); - } break; - case COFF_SymbolValueInterp_Abs: { + case COFF_SymbolValueInterp_Undefined: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); } } break; - case COFF_SymbolValueInterp_Undefined: { + case COFF_SymbolValueInterp_Common: { + LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + } break; + case COFF_SymbolValueInterp_Abs: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); diff --git a/src/torture/torture.c b/src/torture/torture.c index 0aa3f83d..ebbdb025 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -743,6 +743,87 @@ exit:; return result; } +internal T_Result +t_link_undef(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 undef_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("undef")); + undef_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("undef")); + coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, symbol); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("undef.obj"), undef_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // try linking unresolved symbol and see if linker picks up on that + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj undef.obj"); + if (linker_exit_code != LNK_Error_UnresolvedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_link_unref_undef(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 undef_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("undef")); + undef_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("undef.obj"), undef_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // try linking unreferenced unresolved symbol, this must link + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj undef.obj"); + if (linker_exit_code != 0) { goto exit; } + + result = T_Result_Pass; + exit:; + scratch_end(scratch); + return result; +} + internal T_Result t_weak_vs_weak(void) { @@ -3910,6 +3991,8 @@ entry_point(CmdLine *cmdline) { "merge", t_merge }, { "undef_section", t_undef_section }, { "undef_reloc_section", t_undef_reloc_section }, + { "link_undef", t_link_undef }, + { "link_unref_undef", t_link_unref_undef }, { "weak_vs_weak", t_weak_vs_weak }, { "weak_vs_common", t_weak_vs_common }, { "abs_vs_weak", t_abs_vs_weak }, From 2b02f5cec6173bcfcabe5ae6fd7b0eeaf67bbc03 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 10 Aug 2025 21:35:13 -0700 Subject: [PATCH 007/302] lifetime fixes - fully serialize the lib because we cannot guarantee that its members will have the same lifetime as the serialized lib - put import stub symbols on the symbol table arena --- src/coff/coff_lib_writer.c | 54 ++++++++++++++++++----------------- src/coff/coff_lib_writer.h | 2 +- src/linker/lnk.c | 8 +++--- src/pe/pe_make_export_table.c | 4 +-- src/pe/pe_make_export_table.h | 2 +- src/torture/torture.c | 12 ++++---- 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index ad7fa781..d61f825c 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -165,7 +165,7 @@ coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine } } -internal String8List +internal String8 coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member) { Temp scratch = scratch_begin(&arena, 1); @@ -215,30 +215,30 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta member_offsets[member_idx] = member_data_list.total_size; String8 member_data = member->data; - String8 member_header = coff_make_lib_member_header(arena, name, time_stamp, 0, 0, mode, member_data.size); + String8 member_header = coff_make_lib_member_header(scratch.arena, name, time_stamp, 0, 0, mode, member_data.size); - str8_list_push(arena, &member_data_list, member_header); - str8_list_push(arena, &member_data_list, member_data); + str8_list_push(scratch.arena, &member_data_list, member_header); + str8_list_push(scratch.arena, &member_data_list, member_data); { U64 pad_size = AlignPadPow2(member_data_list.total_size, COFF_Archive_MemberAlign); - U8 *pad = push_array(arena, U8, pad_size); - str8_list_push(arena, &member_data_list, str8(pad, pad_size)); + U8 *pad = push_array(scratch.arena, U8, pad_size); + str8_list_push(scratch.arena, &member_data_list, str8(pad, pad_size)); } } } // long names member if (long_names_list.total_size) { - String8 header = coff_make_lib_member_header(arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size); - String8 data = str8_list_join(arena, &long_names_list, 0); + String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size); + String8 data = str8_list_join(scratch.arena, &long_names_list, 0); U64 member_offset = member_data_list.total_size + data.size + header.size; { U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign); - U8 *pad = push_array(arena, U8, pad_size); - str8_list_push_front(arena, &member_data_list, str8(pad, pad_size)); + U8 *pad = push_array(scratch.arena, U8, pad_size); + str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size)); } - str8_list_push_front(arena, &member_data_list, data); - str8_list_push_front(arena, &member_data_list, header); + str8_list_push_front(scratch.arena, &member_data_list, data); + str8_list_push_front(scratch.arena, &member_data_list, header); } // compute size for symbol string table @@ -310,17 +310,17 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta str8_list_push(scratch.arena, &second_member_data_list, str8_array(member_idx16_arr, symbols_count)); str8_list_push(scratch.arena, &second_member_data_list, str8(name_buffer, name_buffer_size)); - String8 member_data = str8_list_join(arena, &second_member_data_list, 0); - String8 member_header = coff_make_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); + String8 member_data = str8_list_join(scratch.arena, &second_member_data_list, 0); + String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); U64 member_offset = member_data_list.total_size + member_data.size + member_header.size; { U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign); - U8 *pad = push_array(arena, U8, pad_size); - str8_list_push_front(arena, &member_data_list, str8(pad, pad_size)); + U8 *pad = push_array(scratch.arena, U8, pad_size); + str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size)); } - str8_list_push_front(arena, &member_data_list, member_data); - str8_list_push_front(arena, &member_data_list, member_header); + str8_list_push_front(scratch.arena, &member_data_list, member_data); + str8_list_push_front(scratch.arena, &member_data_list, member_header); } // first linker member (obsolete, but kept for compatability reasons) @@ -343,23 +343,25 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta str8_list_push(scratch.arena, &first_member_data_list, str8_array(member_off32_arr, symbols_count)); str8_list_push(scratch.arena, &first_member_data_list, str8(name_buffer, name_buffer_size)); - String8 member_data = str8_list_join(arena, &first_member_data_list, 0); - String8 member_header = coff_make_lib_member_header(arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); + String8 member_data = str8_list_join(scratch.arena, &first_member_data_list, 0); + String8 member_header = coff_make_lib_member_header(scratch.arena, str8_lit("/"), time_stamp, 0, 0, mode, member_data.size); U64 member_offset = sizeof(g_coff_archive_sig) + member_header.size + member_data.size; { U64 pad_size = AlignPadPow2(member_offset, COFF_Archive_MemberAlign); - U8 *pad = push_array(arena, U8, pad_size); - str8_list_push_front(arena, &member_data_list, str8(pad, pad_size)); + U8 *pad = push_array(scratch.arena, U8, pad_size); + str8_list_push_front(scratch.arena, &member_data_list, str8(pad, pad_size)); } - str8_list_push_front(arena, &member_data_list, member_data); - str8_list_push_front(arena, &member_data_list, member_header); + str8_list_push_front(scratch.arena, &member_data_list, member_data); + str8_list_push_front(scratch.arena, &member_data_list, member_header); } // archive signature - str8_list_push_front(arena, &member_data_list, str8_struct(&g_coff_archive_sig)); + str8_list_push_front(scratch.arena, &member_data_list, str8_struct(&g_coff_archive_sig)); + + String8 raw_lib = str8_list_join(arena, &member_data_list, 0); scratch_end(scratch); - return member_data_list; + return raw_lib; } diff --git a/src/coff/coff_lib_writer.h b/src/coff/coff_lib_writer.h index 76b283c0..8a8c2327 100644 --- a/src/coff/coff_lib_writer.h +++ b/src/coff/coff_lib_writer.h @@ -63,7 +63,7 @@ internal COFF_LibWriter * coff_lib_writer_alloc(void); internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr); internal U64 coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_data); internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type); -internal String8List coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member); +internal String8 coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeStamp time_stamp, U16 mode, B32 emit_second_member); #endif // COFF_LIB_WRITER_H diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 54ee97a0..7d60727a 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1394,8 +1394,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // create import stubs (later replaced with acutal imports generated by linker) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(scratch.arena, import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); - LNK_Symbol *imp_symbol = lnk_make_defined_symbol(scratch.arena, push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); + LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); + LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, thunk_symbol); lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, imp_symbol); @@ -4749,8 +4749,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) ProfBegin("Build Import Library"); lnk_timer_begin(LNK_Timer_Lib); String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); - String8List lib_list = pe_make_import_lib(arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, config->export_symbol_list); - lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list); + String8 lib = pe_make_import_lib(arena->v[0], config->machine, config->time_stamp, str8_skip_last_slash(config->image_name), linker_debug_symbols, config->export_symbol_list); + lnk_write_data_to_file_path(config->imp_lib_name, str8_zero(), lib); lnk_timer_end(LNK_Timer_Lib); ProfEnd(); } diff --git a/src/pe/pe_make_export_table.c b/src/pe/pe_make_export_table.c index 761a61ae..6e47b3a0 100644 --- a/src/pe/pe_make_export_table.c +++ b/src/pe/pe_make_export_table.c @@ -324,7 +324,7 @@ pe_make_edata_obj(Arena *arena, return obj; } -internal String8List +internal String8 pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, String8 debug_symbols, PE_ExportParseList export_list) { ProfBeginFunction(); @@ -354,7 +354,7 @@ pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_s } // serialize lib - String8List lib = coff_lib_writer_serialize(arena, lib_writer, COFF_TimeStamp_Max, 0, /* emit second member: */ 1); + String8 lib = coff_lib_writer_serialize(arena, lib_writer, COFF_TimeStamp_Max, 0, /* emit second member: */ 1); coff_lib_writer_release(&lib_writer); ProfEnd(); diff --git a/src/pe/pe_make_export_table.h b/src/pe/pe_make_export_table.h index 3249d815..349007b8 100644 --- a/src/pe/pe_make_export_table.h +++ b/src/pe/pe_make_export_table.h @@ -57,6 +57,6 @@ typedef struct PE_FinalizedExports internal PE_ExportParsePtrArray pe_array_from_export_list(Arena *arena, PE_ExportParseList list); internal PE_ExportParseNode * pe_export_parse_list_push(Arena *arena, PE_ExportParseList *list, PE_ExportParse data); -internal String8List pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, String8 debug_symbols, PE_ExportParseList export_list); +internal String8 pe_make_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, String8 debug_symbols, PE_ExportParseList export_list); #endif // COFF_EXPORT_TABLE_H diff --git a/src/torture/torture.c b/src/torture/torture.c index ebbdb025..b7b960d3 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -2010,9 +2010,9 @@ t_simple_lib_test(void) { COFF_LibWriter *lib_writer = coff_lib_writer_alloc(); coff_lib_writer_push_obj(lib_writer, str8_lit("test.obj"), test_obj); - String8List test_lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 1); + String8 test_lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 1); coff_lib_writer_release(&lib_writer); - if (!t_write_file_list(test_lib_name, test_lib)) { + if (!t_write_file(test_lib_name, test_lib)) { goto exit; } } @@ -3304,9 +3304,9 @@ t_include(void) COFF_LibWriter *lib_writer = coff_lib_writer_alloc(); coff_lib_writer_push_obj(lib_writer, str8_lit("include.obj"), obj); - String8List lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 1); + String8 lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 1); coff_lib_writer_release(&lib_writer); - if (!t_write_file_list(str8_lit("include.lib"), lib)) { goto exit; } + if (!t_write_file(str8_lit("include.lib"), lib)) { goto exit; } } { @@ -3944,7 +3944,7 @@ t_opt_ref_dangling_section(void) coff_obj_writer_release(&obj_writer); } - String8List b_lib; + String8 b_lib; { COFF_LibWriter *lib_writer = coff_lib_writer_alloc(); coff_lib_writer_push_obj(lib_writer, str8_lit("b.obj"), b_obj); @@ -3954,7 +3954,7 @@ t_opt_ref_dangling_section(void) if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } - if (!t_write_file_list(str8_lit("b.lib"), b_lib)) { goto exit; } + if (!t_write_file(str8_lit("b.lib"), b_lib)) { goto exit; } int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj b.lib"); if (linker_exit_code != 0) { goto exit; } From 702fd74b23079b4e9bc6d687a8cc915a0bea5806 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 10 Aug 2025 21:41:39 -0700 Subject: [PATCH 008/302] minor cleanup in obj initer --- src/linker/lnk_obj.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index f27d7088..8fc3ecee 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -58,7 +58,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) String8 raw_coff_string_table = str8_substr(input->data, header.string_table_range); // - // error check: section table / symbol table / string table + // error check section table / symbol table / string table // if (raw_coff_section_table.size != dim_1u64(header.section_table_range)) { lnk_error_input_obj(LNK_Error_IllData, input, "corrupted file, unable to read section header table"); @@ -104,15 +104,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // - // error check symbols + // error check symbol table // { COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(input->data, header.section_table_range).str; - String8 string_table = str8_substr(input->data, header.string_table_range); - String8 symbol_table = str8_substr(input->data, header.symbol_table_range); COFF_ParsedSymbol symbol; for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = coff_parse_symbol(header, string_table, symbol_table, symbol_idx); + symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { if (symbol.section_number == 0 || symbol.section_number > header.section_count_no_null) { @@ -140,11 +138,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) comdats = push_array_no_zero(arena, U32, header.section_count_no_null); MemorySet(comdats, 0xff, header.section_count_no_null * sizeof(comdats[0])); - String8 string_table = str8_substr(input->data, header.string_table_range); - String8 symbol_table = str8_substr(input->data, header.symbol_table_range); COFF_ParsedSymbol symbol; for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = coff_parse_symbol(header, string_table, symbol_table, symbol_idx); + symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { @@ -180,8 +176,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) { Temp scratch = scratch_begin(&arena, 1); - String8 string_table = str8_substr(input->data, header.string_table_range); - String8 symbol_table = str8_substr(input->data, header.symbol_table_range); HashTable *visited_sections = hash_table_init(scratch.arena, 32); for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { for (U32 curr_section = sect_idx;;) { @@ -193,7 +187,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // extract COMDAT info for current section - COFF_ParsedSymbol symbol = coff_parse_symbol(header, string_table, symbol_table, symbol_idx); + COFF_ParsedSymbol symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); COFF_ComdatSelectType select = COFF_ComdatSelect_Null; U32 section_number = 0; coff_parse_secdef(symbol, header.is_big_obj, &select, §ion_number, 0, 0); @@ -205,7 +199,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // was section visited? -- loop found if (hash_table_search_u64(visited_sections, curr_section)) { - COFF_ParsedSymbol symbol = coff_parse_symbol(header, string_table, symbol_table, comdats[sect_idx]); + COFF_ParsedSymbol symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, comdats[sect_idx]); lnk_error_input_obj(LNK_Error_AssociativeLoop, input, "section symbol %S (No. 0x%x) does not terminate on a non-associate COMDAT symbol", symbol.name, comdats[sect_idx]); break; } @@ -230,12 +224,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // U32Node **associated_sections = push_array(arena, U32Node *, header.section_count_no_null + 1); { - String8 string_table = str8_substr(input->data, header.string_table_range); - String8 symbol_table = str8_substr(input->data, header.symbol_table_range); - COFF_ParsedSymbol symbol; for (U32 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = coff_parse_symbol(header, string_table, symbol_table, symbol_idx); + symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); if (interp == COFF_SymbolValueInterp_Regular && symbol.storage_class == COFF_SymStorageClass_Static && symbol.aux_symbol_count > 0) { COFF_ComdatSelectType selection = COFF_ComdatSelect_Null; From 829a35430cbd8f8008077414cabfb8479ebdee3b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 11 Aug 2025 02:49:26 -0700 Subject: [PATCH 009/302] add flag to exclude objs from debug info input --- src/linker/lnk.c | 110 ++++++++++++++++++++++++----------------- src/linker/lnk_input.h | 5 +- src/linker/lnk_obj.c | 17 ++++--- src/linker/lnk_obj.h | 1 + 4 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7d60727a..2d6146a1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1313,10 +1313,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // input :null_obj { - LNK_InputObj *null_obj_input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - null_obj_input->path = str8_lit("* Null Obj *"); - null_obj_input->dedup_id = null_obj_input->path; - null_obj_input->data = lnk_make_null_obj(tp_arena->v[0]); + LNK_InputObj *null_obj_input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + null_obj_input->exclude_from_debug_info = 1; + null_obj_input->path = str8_lit("* Null Obj *"); + null_obj_input->dedup_id = null_obj_input->path; + null_obj_input->data = lnk_make_null_obj(tp_arena->v[0]); } // input command line objs @@ -1438,10 +1439,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } // input obj with includes - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* INCLUDE SYMBOLS *"); - input->dedup_id = push_str8f(scratch.arena, "%S %llu", input->path, obj_list.count); - input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->exclude_from_debug_info = 1; + input->path = str8_lit("* INCLUDE SYMBOLS *"); + input->dedup_id = push_str8f(scratch.arena, "%S %llu", input->path, obj_list.count); + input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); coff_obj_writer_release(&obj_writer); @@ -1651,11 +1653,12 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // flush on last directive or next directive is issued from a different obj if ((*last_alt_name)->next == 0 || (*last_alt_name)->data.obj != (*last_alt_name)->next->data.obj) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK"); - input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S *", input->path); - input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); - input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0; + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK"); + input->exclude_from_debug_info = 1; + input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S *", input->path); + input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); + input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0; // reset obj writer coff_obj_writer_release(&obj_writer); @@ -1822,10 +1825,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) case State_InputLinkerObjs: { { ProfBegin("Push Linker Symbols"); - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Linker Symbols *"); - input->dedup_id = input->path; - input->data = lnk_make_linker_obj(tp_arena->v[0], config); + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = str8_lit("* Linker Symbols *"); + input->exclude_from_debug_info = 1; + input->dedup_id = input->path; + input->data = lnk_make_linker_obj(tp_arena->v[0], config); ProfEnd(); } @@ -1858,18 +1862,20 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(tp_arena->v[0], config->machine); { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Import Descriptor *"); - input->dedup_id = input->path; + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->input_idx = obj_list.count; + input->exclude_from_debug_info = 1; + input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Delayed Null Import Descriptor *"); + input->dedup_id = input->path; } { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Thunk Data *"); - input->dedup_id = input->path; + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->input_idx = obj_list.count; + input->exclude_from_debug_info = 1; + input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Delayed Null Thunk Data *"); + input->dedup_id = input->path; } ProfEnd(); @@ -1892,18 +1898,20 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Import Descriptor *"); - input->dedup_id = input->path; + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->input_idx = obj_list.count; + input->exclude_from_debug_info = 1; + input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Null Import Descriptor *"); + input->dedup_id = input->path; } { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Thunk Data *"); - input->dedup_id = input->path; + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->input_idx = obj_list.count; + input->exclude_from_debug_info = 1; + input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + input->path = str8_lit("* Null Thunk Data *"); + input->dedup_id = input->path; } ProfEnd(); @@ -2045,16 +2053,18 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { ProfBegin("Build * Debug Directories *"); if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Debug Directory PDB *"); - input->dedup_id = input->path; - input->data = pe_make_debug_directory_pdb_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path); + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->exclude_from_debug_info = 1; + input->path = str8_lit("* Debug Directory PDB *"); + input->dedup_id = input->path; + input->data = pe_make_debug_directory_pdb_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path); } if (config->rad_debug == LNK_SwitchState_Yes) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Debug Directory RDI *"); - input->dedup_id = input->path; - input->data = pe_make_debug_directory_rdi_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path); + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->exclude_from_debug_info = 1; + input->path = str8_lit("* Debug Directory RDI *"); + input->dedup_id = input->path; + input->data = pe_make_debug_directory_rdi_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path); } ProfEnd(); } @@ -4762,10 +4772,18 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) ProfBegin("Debug Info"); lnk_timer_begin(LNK_Timer_Debug); + U64 objs_count = 0; + LNK_Obj **objs = push_array(scratch.arena, LNK_Obj *, link_ctx.objs_count); + for EachIndex(obj_idx, link_ctx.objs_count) { + LNK_Obj *obj = link_ctx.objs[obj_idx]; + if (obj->exclude_from_debug_info) { continue; } + objs[objs_count++] = obj; + } + // // CodeView // - LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, link_ctx.objs_count, link_ctx.objs); + LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, objs_count, objs); CV_DebugT *types = lnk_import_types(tp, arena, &input); // diff --git a/src/linker/lnk_input.h b/src/linker/lnk_input.h index f139e39c..63eb305f 100644 --- a/src/linker/lnk_input.h +++ b/src/linker/lnk_input.h @@ -37,8 +37,9 @@ typedef struct LNK_InputImportList typedef struct LNK_InputObj { struct LNK_InputObj *next; - B32 is_thin; - B32 has_disk_read_failed; + B8 is_thin; + B8 exclude_from_debug_info; + B8 has_disk_read_failed; String8 dedup_id; String8 path; String8 data; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 8fc3ecee..667f3e2b 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -283,14 +283,15 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // fill out obj - obj->data = input->data; - obj->path = push_str8_copy(arena, input->path); - obj->lib = input->lib; - obj->input_idx = obj_idx; - obj->header = header; - obj->comdats = comdats; - obj->hotpatch = hotpatch; - obj->associated_sections = associated_sections; + obj->data = input->data; + obj->path = push_str8_copy(arena, input->path); + obj->lib = input->lib; + obj->input_idx = obj_idx; + obj->header = header; + obj->comdats = comdats; + obj->exclude_from_debug_info = input->exclude_from_debug_info; + obj->hotpatch = hotpatch; + obj->associated_sections = associated_sections; ProfEnd(); } diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index dcbc9207..52ac822e 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -14,6 +14,7 @@ typedef struct LNK_Obj COFF_FileHeaderInfo header; U32 *comdats; B8 hotpatch; + B8 exclude_from_debug_info; U32Node **associated_sections; LNK_SymbolHashTrie **symlinks; } LNK_Obj; From 056604fb94285abda85009839514e4e73a81ec02 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 11 Aug 2025 13:46:06 -0700 Subject: [PATCH 010/302] sketch out tline -> vline text wrapping cache types; first pass of async call stack tree builder --- src/ctrl/ctrl_core.c | 184 +++++++++++++++++++++++++++-- src/ctrl/ctrl_core.h | 61 +++++++++- src/dbg_engine/dbg_engine_core.c | 4 +- src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/raddbg.mdesk | 4 +- src/raddbg/raddbg_core.c | 8 +- src/raddbg/raddbg_eval.c | 15 ++- src/raddbg/raddbg_eval.h | 6 + src/raddbg/raddbg_views.c | 19 ++- src/raddbg/raddbg_views.h | 30 +++++ src/raddbg/raddbg_widgets.c | 2 +- 11 files changed, 315 insertions(+), 20 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 26b59be8..a434ceca 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1451,6 +1451,14 @@ ctrl_scope_close(CTRL_Scope *scope) os_condition_variable_broadcast(t->stripe->cv); SLLStackPush(ctrl_tctx->free_call_stack_touch, t); } + for(U64 idx = 0; idx < scope->call_stack_tree_touch_count; idx += 1) + { + ins_atomic_u64_dec_eval(&ctrl_state->call_stack_tree_cache.scope_touch_count); + } + if(scope->call_stack_tree_touch_count != 0) + { + os_condition_variable_broadcast(ctrl_state->call_stack_tree_cache.cv); + } SLLStackPush(ctrl_tctx->free_scope, scope); } @@ -3407,7 +3415,7 @@ ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U //~ rjf: Call Stack Cache Functions internal CTRL_CallStack -ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_Entity *thread, B32 high_priority, U64 endt_us) +ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us) { CTRL_CallStack call_stack = {0}; CTRL_CallStackCache *cache = &ctrl_state->call_stack_cache; @@ -3415,8 +3423,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ ////////////////////////////// //- rjf: unpack thread // - CTRL_Handle handle = thread->handle; - U64 hash = ctrl_hash_from_handle(handle); + U64 hash = ctrl_hash_from_handle(thread_handle); U64 slot_idx = hash%cache->slots_count; U64 stripe_idx = slot_idx%cache->stripes_count; CTRL_CallStackCacheSlot *slot = &cache->slots[slot_idx]; @@ -3439,7 +3446,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ CTRL_CallStackCacheNode *node = 0; for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) { - if(ctrl_handle_match(n->thread, handle)) + if(ctrl_handle_match(n->thread, thread_handle)) { node = n; node_exists = 1; @@ -3478,7 +3485,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ CTRL_CallStackCacheNode *node = 0; for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) { - if(ctrl_handle_match(n->thread, handle)) + if(ctrl_handle_match(n->thread, thread_handle)) { node = n; break; @@ -3488,7 +3495,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ { node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1); DLLPushBack(slot->first, slot->last, node); - node->thread = thread->handle; + node->thread = thread_handle; } if(node->working_count == 0) { @@ -3500,7 +3507,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ //- rjf: request if needed if(node_to_request != 0) { - if(ctrl_u2csb_enqueue_req(thread->handle, endt_us)) + if(ctrl_u2csb_enqueue_req(thread_handle, endt_us)) { async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); } @@ -3514,6 +3521,47 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_ return call_stack; } +//////////////////////////////// +//~ rjf: Call Stack Tree Cache Functions + +internal CTRL_CallStackTree +ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us) +{ + CTRL_CallStackTree result = {&ctrl_call_stack_tree_node_nil}; + { + U64 reg_gen = ctrl_reg_gen(); + U64 mem_gen = ctrl_mem_gen(); + CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; + OS_MutexScopeR(cache->rw_mutex) for(;;) + { + // rjf: unpack cache/time state + B32 is_stale = (cache->reg_gen != reg_gen || cache->mem_gen != mem_gen); + B32 out_of_time = (os_now_microseconds() >= endt_us); + + // rjf: is stale? -> request new calculation + if(is_stale && !ins_atomic_u64_eval_cond_assign(&cache->request_count, 1, 0)) + { + os_rw_mutex_drop_r(cache->rw_mutex); + async_push_work(ctrl_call_stack_tree_build_work); + os_rw_mutex_take_r(cache->rw_mutex); + } + + // rjf: is not stale, or we're out of time? -> grab cached result & touch, exit + if(!is_stale || out_of_time) + { + result = cache->tree; + ins_atomic_u64_inc_eval(&cache->scope_touch_count); + scope->call_stack_tree_touch_count += 1; + break; + } + + // rjf: wait for new results + os_condition_variable_wait_rw_r(cache->cv, cache->rw_mutex, endt_us); + } + } + return result; +} + //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -7261,3 +7309,125 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) scratch_end(scratch); return 0; } + +//////////////////////////////// +//~ rjf: Asynchronous Call Stack Tree Building Functions + +ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) +{ + Temp scratch = scratch_begin(0, 0); + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + + //- rjf: gather list of all thread handles + U64 threads_count = 0; + CTRL_Handle *threads = 0; + CTRL_Handle *threads_processes = 0; + Arch *threads_arches = 0; + OS_MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + { + CTRL_EntityCtx *ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_EntityArray thread_entities = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Thread); + threads_count = thread_entities.count; + threads = push_array(scratch.arena, CTRL_Handle, threads_count); + threads_processes = push_array(scratch.arena, CTRL_Handle, threads_count); + threads_arches = push_array(scratch.arena, Arch, threads_count); + for EachIndex(idx, threads_count) + { + threads[idx] = thread_entities.v[idx]->handle; + threads_processes[idx] = thread_entities.v[idx]->parent->handle; + threads_arches[idx] = thread_entities.v[idx]->arch; + } + } + + //- rjf: gather all callstacks + U64 pre_mem_gen = ctrl_mem_gen(); + U64 pre_reg_gen = ctrl_reg_gen(); + CTRL_CallStack *call_stacks = push_array(scratch.arena, CTRL_CallStack, threads_count); + { + for EachIndex(idx, threads_count) + { + call_stacks[idx] = ctrl_call_stack_from_thread(ctrl_scope, threads[idx], 0, os_now_microseconds()+1000); + } + } + U64 post_mem_gen = ctrl_mem_gen(); + U64 post_reg_gen = ctrl_reg_gen(); + + //- rjf: build call stack tree + Arena *arena = 0; + CTRL_CallStackTree tree = {&ctrl_call_stack_tree_node_nil}; + if(pre_mem_gen == post_mem_gen && + pre_reg_gen == post_reg_gen) + { + arena = arena_alloc(); + tree.root = push_array(arena, CTRL_CallStackTreeNode, 1); + MemoryCopyStruct(tree.root, &ctrl_call_stack_tree_node_nil); + for EachIndex(thread_idx, threads_count) + { + CTRL_Handle thread = threads[thread_idx]; + CTRL_Handle process = threads_processes[thread_idx]; + Arch arch = threads_arches[thread_idx]; + CTRL_CallStack call_stack = call_stacks[thread_idx]; + CTRL_CallStackTreeNode *thread_node = tree.root; + for EachIndex(frame_idx, call_stack.frames_count) + { + U64 vaddr = regs_rip_from_arch_block(arch, call_stack.frames[frame_idx].regs); + U64 depth = call_stack.frames[frame_idx].inline_depth; + CTRL_CallStackTreeNode *next_node = &ctrl_call_stack_tree_node_nil; + for(CTRL_CallStackTreeNode *child = thread_node->first; child != &ctrl_call_stack_tree_node_nil; child = child->next) + { + if(ctrl_handle_match(child->process, process) && child->vaddr == vaddr && child->depth == depth) + { + next_node = child; + break; + } + } + if(next_node == &ctrl_call_stack_tree_node_nil) + { + next_node = push_array(arena, CTRL_CallStackTreeNode, 1); + MemoryCopyStruct(next_node, &ctrl_call_stack_tree_node_nil); + SLLQueuePush_NZ(&ctrl_call_stack_tree_node_nil, thread_node->first, thread_node->last, next_node, next); + next_node->parent = thread_node; + thread_node->child_count += 1; + } + thread_node = next_node; + } + ctrl_handle_list_push(arena, &thread_node->threads, &thread); + for(CTRL_CallStackTreeNode *n = thread_node; n != &ctrl_call_stack_tree_node_nil; n = n->parent) + { + n->all_descendant_threads_count += 1; + } + } + } + + //- rjf: commit to cache + Arena *old_arena = 0; + CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; + if(tree.root != &ctrl_call_stack_tree_node_nil) + { + OS_MutexScopeW(cache->rw_mutex) for(;;) + { + if(cache->scope_touch_count == 0) + { + old_arena = cache->arena; + cache->arena = arena; + cache->tree = tree; + cache->reg_gen = post_reg_gen; + cache->mem_gen = post_mem_gen; + cache->request_count -= 1; + break; + } + os_condition_variable_wait_rw_w(cache->cv, cache->rw_mutex, max_U64); + } + } + os_condition_variable_broadcast(cache->cv); + + //- rjf: release old arena + if(old_arena) + { + arena_release(old_arena); + } + + ctrl_scope_close(ctrl_scope); + scratch_end(scratch); + return 0; +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index d31a5e1b..48701ef7 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -271,6 +271,30 @@ struct CTRL_CallStack U64 concrete_frames_count; }; +//////////////////////////////// +//~ rjf: Call Stack Tree Types + +typedef struct CTRL_CallStackTreeNode CTRL_CallStackTreeNode; +struct CTRL_CallStackTreeNode +{ + CTRL_CallStackTreeNode *first; + CTRL_CallStackTreeNode *last; + CTRL_CallStackTreeNode *next; + CTRL_CallStackTreeNode *parent; + U64 child_count; + CTRL_Handle process; + U64 vaddr; + U64 depth; + CTRL_HandleList threads; + U64 all_descendant_threads_count; +}; + +typedef struct CTRL_CallStackTree CTRL_CallStackTree; +struct CTRL_CallStackTree +{ + CTRL_CallStackTreeNode *root; +}; + //////////////////////////////// //~ rjf: Trap Types @@ -700,6 +724,22 @@ struct CTRL_ModuleImageInfoCache CTRL_ModuleImageInfoCacheStripe *stripes; }; +//////////////////////////////// +//~ rjf: Call Stack Tree Cache Types + +typedef struct CTRL_CallStackTreeCache CTRL_CallStackTreeCache; +struct CTRL_CallStackTreeCache +{ + Arena *arena; + CTRL_CallStackTree tree; + OS_Handle cv; + OS_Handle rw_mutex; + U64 reg_gen; + U64 mem_gen; + U64 scope_touch_count; + U64 request_count; +}; + //////////////////////////////// //~ rjf: Touched Debug Info Directory Cache @@ -746,6 +786,7 @@ struct CTRL_Scope CTRL_Scope *next; CTRL_ScopeCallStackTouch *first_call_stack_touch; CTRL_ScopeCallStackTouch *last_call_stack_touch; + U64 call_stack_tree_touch_count; }; typedef struct CTRL_TCTX CTRL_TCTX; @@ -791,6 +832,7 @@ struct CTRL_State CTRL_ThreadRegCache thread_reg_cache; CTRL_CallStackCache call_stack_cache; CTRL_ModuleImageInfoCache module_image_info_cache; + CTRL_CallStackTreeCache call_stack_tree_cache; // rjf: generations U64 run_gen; @@ -867,6 +909,13 @@ read_only global CTRL_Entity ctrl_entity_nil = &ctrl_entity_nil, &ctrl_entity_nil, }; +read_only global CTRL_CallStackTreeNode ctrl_call_stack_tree_node_nil = +{ + &ctrl_call_stack_tree_node_nil, + &ctrl_call_stack_tree_node_nil, + &ctrl_call_stack_tree_node_nil, + &ctrl_call_stack_tree_node_nil, +}; thread_static CTRL_TCTX *ctrl_tctx = 0; thread_static CTRL_EntityCtxLookupAccel *ctrl_entity_ctx_lookup_accel = 0; @@ -1071,7 +1120,12 @@ internal CTRL_CallStackFrame *ctrl_call_stack_frame_from_unwind_and_inline_depth //////////////////////////////// //~ rjf: Call Stack Cache Functions -internal CTRL_CallStack ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_Entity *thread, B32 high_priority, U64 endt_us); +internal CTRL_CallStack ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); + +//////////////////////////////// +//~ rjf: Call Stack Tree Cache Functions + +internal CTRL_CallStackTree ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us); //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -1155,4 +1209,9 @@ internal void ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread); //- rjf: entry point ASYNC_WORK_DEF(ctrl_call_stack_build_work); +//////////////////////////////// +//~ rjf: Asynchronous Call Stack Tree Building Functions + +ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); + #endif // CTRL_CORE_H diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index ad61e676..980f99ae 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1209,7 +1209,7 @@ d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) else { CTRL_Scope *ctrl_scope = ctrl_scope_open(); - CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, 0); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, 0); if(callstack.concrete_frames_count != 0) { result = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[unwind_count%callstack.concrete_frames_count]->regs); @@ -1889,7 +1889,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P CTRL_Scope *ctrl_scope = ctrl_scope_open(); // rjf: thread => call stack - CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); // rjf: use first unwind frame to generate trap if(callstack.concrete_frames_count > 1) diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 0be16561..59dbf0e3 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -424,7 +424,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[24] = {str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n\n //- rjf: theme settings\n @default(1) @display_name('Use Project Theme') @description(\"Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.\")\n 'use_project_theme': bool,\n}\n")}, {str8_lit_comp("tab"), str8_lit_comp("@row_commands(@file copy_tab_full_path, @file show_file_in_explorer, duplicate_tab, close_tab)\nx:\n{\n @override @display_name('Tab Font Size') @description(\"Controls the tab's font size.\") @no_callee_helper\n 'font_size': @range[6, 72] u64,\n}\n")}, {str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': query,\n}\n")}, -{str8_lit_comp("text"), str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change':bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, +{str8_lit_comp("text"), str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(1) @display_name('Line Wrapping') @description(\"Splits textual lines into multiple visual lines, so that all text is within the visible area.\")\n 'line_wrapping': bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change': bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, {str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n 'arch': code_string,\n 'syntax': code_string,\n 'size': expr_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n\n}\n")}, {str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n}\n")}, {str8_lit_comp("bitmap"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as a bitmap.\")\n 'expression': expr_string,\n @description(\"An expression describing the width of the bitmap, in pixels.\") @order(0) 'w': u64,\n @description(\"An expression describing the height of the bitmap, in pixels.\") @order(1) 'h': u64,\n @display_name(\"Bitmap Format\") @description(\"The pixel format that the bitmap data should be interpreted as being within.\")\n 'fmt': code_string,\n}\n")}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 0e0d27c2..7248a67a 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -481,8 +481,10 @@ RD_VocabTable: 'lang': code_string, @default(1) @description("Controls whether or not line numbers are shown.") 'show_line_numbers':bool, + @no_callee_helper @default(1) @display_name('Line Wrapping') @description("Splits textual lines into multiple visual lines, so that all text is within the visible area.") + 'line_wrapping': bool, @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description("Scrolls to the bottom if the text is changed.") - 'scroll_to_bottom_on_change':bool, + 'scroll_to_bottom_on_change': bool, @no_callee_helper @no_revert @default(0) @display_name('Transient') @description("Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.") 'auto': bool, } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 08186ae4..f15ce2fa 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1817,7 +1817,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) case CTRL_EntityKind_Thread: { CTRL_Scope *ctrl_scope = ctrl_scope_open(); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, 1, rd_state->frame_eval_memread_endt_us); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, 1, rd_state->frame_eval_memread_endt_us); U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count; if(concrete_frame_idx < call_stack.concrete_frames_count) { @@ -6469,7 +6469,7 @@ rd_window_frame(void) Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process); B32 call_stack_high_priority = ctrl_handle_match(ctrl_entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, ctrl_entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, ctrl_entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(call_stack.frames_count != 0) { ui_spacer(ui_em(1.5f, 1.f)); @@ -16231,7 +16231,7 @@ rd_frame(void) { CTRL_Scope *ctrl_scope = ctrl_scope_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); if(frame == 0) { @@ -16250,7 +16250,7 @@ rd_frame(void) { CTRL_Scope *ctrl_scope = ctrl_scope_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *current_frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); CTRL_CallStackFrame *next_frame = current_frame; if(current_frame != 0) switch(kind) diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 20d9e521..7ecf2d77 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -968,7 +968,7 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack) B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); accel->arch = entity->arch; accel->process = ctrl_process_from_entity(entity)->handle; - accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); } scratch_end(scratch); } @@ -1538,6 +1538,19 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities) } } +//////////////////////////////// +//~ rjf: Call Stack Tree Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree) +{ + +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree) +{ + +} + //////////////////////////////// //~ rjf: Debug Info Tables Eval Hooks diff --git a/src/raddbg/raddbg_eval.h b/src/raddbg/raddbg_eval.h index b5980a03..3a04761c 100644 --- a/src/raddbg/raddbg_eval.h +++ b/src/raddbg/raddbg_eval.h @@ -100,6 +100,12 @@ E_TYPE_ACCESS_FUNCTION_DEF(ctrl_entities); E_TYPE_EXPAND_INFO_FUNCTION_DEF(ctrl_entities); E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities); +//////////////////////////////// +//~ rjf: Call Stack Tree Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree); + //////////////////////////////// //~ rjf: Debug Info Tables Eval Hooks diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 1379a785..73b687d9 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -104,6 +104,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla } } + ////////////////////////////// + //- rjf: set up wrap cache + // + if(cv->wrap_arena == 0) + { + cv->wrap_arena = rd_push_view_arena(); + } + if(cv->wrap_total_vline_count == 0) + { + arena_clear(cv->wrap_arena); + cv->wrap_total_vline_count = text_info->lines_count; + cv->wrap_cache_slots_count = text_info->lines_count/64; + cv->wrap_cache_slots = push_array(cv->wrap_arena, RD_CodeViewTLineWrapCacheSlot, cv->wrap_cache_slots_count); + } + ////////////////////////////// //- rjf: determine visible line range / count // @@ -1015,7 +1030,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) info.callstack_thread = entity; U64 frame_num = ev_block_num_from_id(block, key.child_id); B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(1 <= frame_num && frame_num <= call_stack.frames_count) { CTRL_CallStackFrame *f = &call_stack.frames[frame_num-1]; @@ -2924,7 +2939,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) CTRL_Scope *ctrl_scope = ctrl_scope_open(); CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *selected_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); - CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, selected_thread, 1, 0); + CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread(ctrl_scope, selected_thread->handle, 1, 0); CTRL_Entity *eval_process = &ctrl_entity_nil; if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity) { diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index 3b6d5c2a..f13b2ecc 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -14,6 +14,30 @@ enum RD_CodeViewBuildFlag_All = 0xffffffff, }; +typedef struct RD_CodeViewTLineSplitNode RD_CodeViewTLineSplitNode; +struct RD_CodeViewTLineSplitNode +{ + RD_CodeViewTLineSplitNode *next; + U64 off; +}; + +typedef struct RD_CodeViewTLineWrapCacheNode RD_CodeViewTLineWrapCacheNode; +struct RD_CodeViewTLineWrapCacheNode +{ + RD_CodeViewTLineWrapCacheNode *hash_next; + RD_CodeViewTLineWrapCacheNode *hash_prev; + S64 line_num; + RD_CodeViewTLineSplitNode *first_split; + RD_CodeViewTLineSplitNode *last_split; +}; + +typedef struct RD_CodeViewTLineWrapCacheSlot RD_CodeViewTLineWrapCacheSlot; +struct RD_CodeViewTLineWrapCacheSlot +{ + RD_CodeViewTLineWrapCacheNode *first; + RD_CodeViewTLineWrapCacheNode *last; +}; + typedef struct RD_CodeViewState RD_CodeViewState; struct RD_CodeViewState { @@ -32,6 +56,12 @@ struct RD_CodeViewState Arena *find_text_arena; String8 find_text_fwd; String8 find_text_bwd; + + // rjf: line wrapping cache & info + Arena *wrap_arena; + RD_CodeViewTLineWrapCacheSlot *wrap_cache_slots; + U64 wrap_cache_slots_count; + U64 wrap_total_vline_count; }; typedef struct RD_CodeViewBuildResult RD_CodeViewBuildResult; diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index d1da7715..64ea699e 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -552,7 +552,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); Arch arch = entity->arch; B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); B32 did_first_known = 0; for(U64 idx = 0, limit = 10; idx < call_stack.frames_count && idx < limit; From 36dcd65a83897784e4a3823c9fb9eabf06832a7a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 11 Aug 2025 16:08:04 -0700 Subject: [PATCH 011/302] first pass at call stack tree evaluation --- src/ctrl/ctrl_core.c | 27 ++++++++++++++ src/ctrl/ctrl_core.h | 13 +++++++ src/raddbg/raddbg_core.c | 21 +++++++++++ src/raddbg/raddbg_core.h | 3 ++ src/raddbg/raddbg_eval.c | 80 +++++++++++++++++++++++++++++++++++++++- src/raddbg/raddbg_eval.h | 1 + 6 files changed, 143 insertions(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index a434ceca..5fe76704 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -188,6 +188,22 @@ ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src) return dst; } +internal CTRL_HandleArray +ctrl_handle_array_from_list(Arena *arena, CTRL_HandleList *src) +{ + CTRL_HandleArray array = {0}; + array.count = src->count; + array.v = push_array_no_zero(arena, CTRL_Handle, array.count); + { + U64 idx = 0; + for(CTRL_HandleNode *n = src->first; n != 0; n = n->next, idx += 1) + { + array.v[idx] = n->v; + } + } + return array; +} + internal String8 ctrl_string_from_handle(Arena *arena, CTRL_Handle handle) { @@ -1543,6 +1559,9 @@ ctrl_init(void) ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc(); ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); } + ctrl_state->call_stack_tree_cache.tree.root = &ctrl_call_stack_tree_node_nil; + ctrl_state->call_stack_tree_cache.cv = os_condition_variable_alloc(); + ctrl_state->call_stack_tree_cache.rw_mutex = os_rw_mutex_alloc(); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -7358,9 +7377,14 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) if(pre_mem_gen == post_mem_gen && pre_reg_gen == post_reg_gen) { + U64 id_gen = 0; arena = arena_alloc(); tree.root = push_array(arena, CTRL_CallStackTreeNode, 1); MemoryCopyStruct(tree.root, &ctrl_call_stack_tree_node_nil); + tree.root->id = id_gen; + tree.slots_count = Max(1, threads_count); + tree.slots = push_array(arena, CTRL_CallStackTreeNode *, tree.slots_count); + id_gen += 1; for EachIndex(thread_idx, threads_count) { CTRL_Handle thread = threads[thread_idx]; @@ -7385,6 +7409,9 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) { next_node = push_array(arena, CTRL_CallStackTreeNode, 1); MemoryCopyStruct(next_node, &ctrl_call_stack_tree_node_nil); + next_node->id = id_gen; + SLLStackPush_N(tree.slots[next_node->id%tree.slots_count], next_node, hash_next); + id_gen += 1; SLLQueuePush_NZ(&ctrl_call_stack_tree_node_nil, thread_node->first, thread_node->last, next_node, next); next_node->parent = thread_node; thread_node->child_count += 1; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 48701ef7..b5d6e612 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -84,6 +84,13 @@ struct CTRL_HandleList U64 count; }; +typedef struct CTRL_HandleArray CTRL_HandleArray; +struct CTRL_HandleArray +{ + CTRL_Handle *v; + U64 count; +}; + //////////////////////////////// //~ rjf: Generated Code @@ -277,11 +284,13 @@ struct CTRL_CallStack typedef struct CTRL_CallStackTreeNode CTRL_CallStackTreeNode; struct CTRL_CallStackTreeNode { + CTRL_CallStackTreeNode *hash_next; CTRL_CallStackTreeNode *first; CTRL_CallStackTreeNode *last; CTRL_CallStackTreeNode *next; CTRL_CallStackTreeNode *parent; U64 child_count; + U64 id; CTRL_Handle process; U64 vaddr; U64 depth; @@ -293,6 +302,8 @@ typedef struct CTRL_CallStackTree CTRL_CallStackTree; struct CTRL_CallStackTree { CTRL_CallStackTreeNode *root; + U64 slots_count; + CTRL_CallStackTreeNode **slots; }; //////////////////////////////// @@ -911,6 +922,7 @@ read_only global CTRL_Entity ctrl_entity_nil = }; read_only global CTRL_CallStackTreeNode ctrl_call_stack_tree_node_nil = { + 0, &ctrl_call_stack_tree_node_nil, &ctrl_call_stack_tree_node_nil, &ctrl_call_stack_tree_node_nil, @@ -945,6 +957,7 @@ internal CTRL_Handle ctrl_handle_make(CTRL_MachineID machine_id, DMN_Handle dmn_ internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b); internal void ctrl_handle_list_push(Arena *arena, CTRL_HandleList *list, CTRL_Handle *pair); internal CTRL_HandleList ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src); +internal CTRL_HandleArray ctrl_handle_array_from_list(Arena *arena, CTRL_HandleList *src); internal String8 ctrl_string_from_handle(Arena *arena, CTRL_Handle handle); internal CTRL_Handle ctrl_handle_from_string(String8 string); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index f15ce2fa..5ba92c99 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11499,6 +11499,7 @@ rd_frame(void) CTRL_Scope *frame_ctrl_scope_restore = rd_state->frame_ctrl_scope; rd_state->frame_di_scope = di_scope_open(); rd_state->frame_ctrl_scope = ctrl_scope_open(); + rd_state->got_frame_call_stack_tree = 0; ////////////////////////////// //- rjf: calculate avg length in us of last many frames @@ -12296,6 +12297,26 @@ rd_frame(void) e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); } + //- rjf: add macro for call stack tree + { + String8 collection_name = str8_lit("call_stack_tree"); + E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = collection_name, + .flags = E_TypeFlag_StubSingleLineExpansion, + .access = E_TYPE_ACCESS_FUNCTION_NAME(call_stack_tree), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(call_stack_tree), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(call_stack_tree) + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafValue, r1u64(0, 0)); + expr->value.u64 = 1; + expr->type_key = collection_type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaCallStackTree); + e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); + } + //- rjf: add macro / lookup rules for unattached processes { String8 collection_name = str8_lit("unattached_processes"); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index adc9f532..2cdcabc0 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -88,6 +88,7 @@ enum RD_EvalSpaceKind_MetaTheme, RD_EvalSpaceKind_MetaCtrlEntity, RD_EvalSpaceKind_MetaUnattachedProcess, + RD_EvalSpaceKind_MetaCallStackTree, }; //////////////////////////////// @@ -600,6 +601,8 @@ struct RD_State F32 frame_dt; DI_Scope *frame_di_scope; CTRL_Scope *frame_ctrl_scope; + CTRL_CallStackTree frame_call_stack_tree; + B32 got_frame_call_stack_tree; // rjf: dbgi match store DI_MatchStore *match_store; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 7ecf2d77..c1795d34 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1541,14 +1541,90 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities) //////////////////////////////// //~ rjf: Call Stack Tree Type Hooks +E_TYPE_ACCESS_FUNCTION_DEF(call_stack_tree) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_MemberAccess) + { + String8 id_string = expr->first->next->string; + U64 id = u64_from_str8(str8_skip(id_string, 1), 16); + if(id != 0) + { + result.type_key = lhs_irtree->type_key; + result.mode = E_Mode_Value; + result.root = e_irtree_set_space(arena, e_space_make(RD_EvalSpaceKind_MetaCallStackTree), e_irtree_const_u(arena, id)); + } + } + return result; +} + +typedef struct RD_CallStackTreeExpandAccel RD_CallStackTreeExpandAccel; +struct RD_CallStackTreeExpandAccel +{ + CTRL_CallStackTreeNode *node; + CTRL_CallStackTreeNode **children; + CTRL_HandleArray threads; +}; + E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree) { - + if(!rd_state->got_frame_call_stack_tree) + { + rd_state->got_frame_call_stack_tree = 1; + rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_ctrl_scope, 0); + } + RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1); + accel->node = &ctrl_call_stack_tree_node_nil; + U64 id = e_value_eval_from_eval(eval).value.u64; + if(rd_state->frame_call_stack_tree.slots_count != 0) + { + for(CTRL_CallStackTreeNode *n = rd_state->frame_call_stack_tree.slots[id%rd_state->frame_call_stack_tree.slots_count]; + n != 0; + n = n->hash_next) + { + if(n->id == id) + { + accel->node = n; + break; + } + } + } + accel->children = push_array(arena, CTRL_CallStackTreeNode *, accel->node->child_count); + { + U64 idx = 0; + for(CTRL_CallStackTreeNode *n = accel->node->first; + n != &ctrl_call_stack_tree_node_nil; + n = n->next, idx += 1) + { + accel->children[idx] = n; + } + } + accel->threads = ctrl_handle_array_from_list(arena, &accel->node->threads); + E_TypeExpandInfo result = {accel}; + result.expr_count = accel->node->child_count + accel->threads.count; + return result; } E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree) { - + Temp scratch = scratch_begin(&arena, 1); + RD_CallStackTreeExpandAccel *accel = (RD_CallStackTreeExpandAccel *)user_data; + CTRL_CallStackTreeNode *node = accel->node; + U64 needed_row_count = dim_1u64(idx_range); + for EachIndex(idx, needed_row_count) + { + E_Eval eval = e_eval_nil; + if(idx < node->child_count) + { + eval = e_eval_from_stringf("query:call_stack_tree.$%I64x", accel->children[idx]->id); + } + else if(node->child_count <= idx && idx < node->child_count + accel->threads.count) + { + eval = e_eval_from_stringf("query:control.%S", ctrl_string_from_handle(scratch.arena, accel->threads.v[idx - node->child_count])); + } + evals_out[idx] = eval; + } + scratch_end(scratch); } //////////////////////////////// diff --git a/src/raddbg/raddbg_eval.h b/src/raddbg/raddbg_eval.h index 3a04761c..b2269be9 100644 --- a/src/raddbg/raddbg_eval.h +++ b/src/raddbg/raddbg_eval.h @@ -103,6 +103,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities); //////////////////////////////// //~ rjf: Call Stack Tree Type Hooks +E_TYPE_ACCESS_FUNCTION_DEF(call_stack_tree); E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree); E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree); From a8f6142e6351c2cd48b456428e8dc215f61543f6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 11 Aug 2025 16:18:39 -0700 Subject: [PATCH 012/302] eval/ir: do not strip enum types off when doing address operations --- src/eval/eval_ir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index a551bba4..e9efeb63 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -752,9 +752,9 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_Expr *r_expr = expr->first; E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative & ~E_TypeUnwrapFlag_Enums); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - E_TypeKey r_type_direct = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_All); + E_TypeKey r_type_direct = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_All & ~E_TypeUnwrapFlag_Enums); U64 r_type_direct_size = e_type_byte_size_from_key(r_type_direct); // rjf: bad conditions? -> error if applicable, exit @@ -812,7 +812,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); E_TypeKey r_type = r_tree.type_key; - E_TypeKey r_type_unwrapped = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey r_type_unwrapped = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_AllDecorative & (~E_TypeUnwrapFlag_Enums)); E_TypeKind r_type_unwrapped_kind = e_type_kind_from_key(r_type_unwrapped); // rjf: bad conditions? -> error if applicable, exit From b50f3094227219ff9bf26083128d9df413d0e450 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 11 Aug 2025 23:28:03 -0700 Subject: [PATCH 013/302] modified member queue logic to prioritize libs where pull-in reference symbol is declared --- src/linker/lnk.c | 30 ++++++++++++++++++++++-------- src/linker/lnk.h | 2 +- src/linker/lnk_symbol_table.c | 10 +++++----- src/linker/lnk_symbol_table.h | 10 ++++------ 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 2d6146a1..9cc82fb7 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -965,18 +965,32 @@ lnk_make_linker_obj(Arena *arena, LNK_Config *config) internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, - LNK_Symbol *symbol, + LNK_Symbol *pull_in_ref, + LNK_Symbol *member_symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { - B32 was_live = lnk_mark_symbol_live(symbol); + // lookup member in the lib where pull-in reference is declared + LNK_Symbol *best_match = member_symbol; + for (LNK_Symbol *s = member_symbol; s != 0; s = s->u.member.next) { + if (s->u.member.v.lib == pull_in_ref->u.member.v.lib) { + best_match = s; + break; + } + } + + B32 was_live = lnk_mark_symbol_live(best_match); if (!was_live) { - LNK_SymbolLib *member = &symbol->u.lib; - LNK_Lib *lib = member->lib; - U64 input_idx = Compose64Bit(lib->input_idx, member->member_offset); + LNK_Lib *lib = best_match->u.member.v.lib; + U64 member_offset = best_match->u.member.v.member_offset; + + // compose input index so that members are laid out in the image + // in the order of undefined symbols appearing in objs, + // mimicking serial discovery + U64 input_idx = Compose64Bit(pull_in_ref->u.defined.obj->input_idx, pull_in_ref->u.defined.symbol_idx); // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member->member_offset); + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { @@ -1159,7 +1173,7 @@ lnk_find_refs(Arena *arena, } if (member_symbol) { - lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + lnk_queue_lib_member_input(arena, config, defn, member_symbol, imports_out, objs_out); MemoryZeroStruct(&ref_symbol); break; } else { @@ -1178,7 +1192,7 @@ lnk_find_refs(Arena *arena, if (defn_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); if (member_symbol) { - lnk_queue_lib_member_input(arena, config, member_symbol, imports_out, objs_out); + lnk_queue_lib_member_input(arena, config, defn, member_symbol, imports_out, objs_out); } break; } else { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index d2150f06..2aa1dc61 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -220,7 +220,7 @@ internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config); -internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Symbol *member_symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 4c0f6a0b..c04709a9 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -14,10 +14,10 @@ lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 sym internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset) { - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->u.lib.lib = lib; - symbol->u.lib.member_offset = member_offset; + LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); + symbol->name = name; + symbol->u.member.v.lib = lib; + symbol->u.member.v.member_offset = member_offset; return symbol; } @@ -38,7 +38,7 @@ internal B32 lnk_symbol_lib_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - return a->u.lib.lib->input_idx < b->u.lib.lib->input_idx; + return a->u.member.v.lib->input_idx < b->u.member.v.lib->input_idx; } internal void diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 813103e9..2af086fd 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -24,18 +24,16 @@ typedef struct LNK_SymbolLib U64 member_offset; } LNK_SymbolLib; -typedef struct LNK_SymbolUndefined -{ - struct LNK_Obj *obj; -} LNK_SymbolUndefined; - typedef struct LNK_Symbol { String8 name; B32 is_live; union { LNK_SymbolDefined defined; - LNK_SymbolLib lib; + struct { + struct LNK_Symbol *next; + LNK_SymbolLib v; + } member; } u; } LNK_Symbol; From 788df5f556dc950c63599db1fb9416193991e93a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Aug 2025 10:12:05 -0700 Subject: [PATCH 014/302] os: barrier --- src/os/core/linux/os_core_linux.c | 66 ++++++++++++++++++++++++------- src/os/core/linux/os_core_linux.h | 2 + src/os/core/os_core.h | 7 +++- src/os/core/win32/os_core_win32.c | 26 ++++++++++++ src/os/core/win32/os_core_win32.h | 2 + 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index d8ded967..c61fa270 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1091,14 +1091,18 @@ internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { OS_Handle result = {0}; - if (name.size > 0) { + if (name.size > 0) + { // TODO: we need to allocate shared memory to store sem_t // NotImplemented; - } else { + } + else + { sem_t *s = mmap(0, sizeof(*s), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); AssertAlways(s != MAP_FAILED); int err = sem_init(s, 0, initial_count); - if (err == 0) { + if(err == 0) + { result.u64[0] = (U64)s; } } @@ -1127,17 +1131,19 @@ os_semaphore_close(OS_Handle semaphore) internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us) { + // TODO(rjf): we need to use `sem_timedwait` here. AssertAlways(endt_us == max_U64); - for (;;) { + for(;;) + { int err = sem_wait((sem_t*)semaphore.u64[0]); - if (err == 0) { + if(err == 0) + { break; - } else { - if (errno == EAGAIN) { - continue; - } } - InvalidPath; + else if(errno == EAGAIN) + { + continue; + } break; } return 1; @@ -1146,20 +1152,50 @@ os_semaphore_take(OS_Handle semaphore, U64 endt_us) internal void os_semaphore_drop(OS_Handle semaphore) { - for (;;) { + for(;;) + { int err = sem_post((sem_t*)semaphore.u64[0]); - if (err == 0) { + if(err == 0) + { break; - } else { - if (errno == EAGAIN) { + } + else + { + if(errno == EAGAIN) + { continue; } } - InvalidPath; break; } } +//- rjf: barriers + +internal OS_Handle +os_barrier_alloc(U64 count) +{ + OS_LNX_Entity *entity = os_w32_entity_alloc(OS_LNX_EntityKind_Barrier); + pthread_barrier_init(&entity->barrier, count); + OS_Handle result = {IntFromPtr(entity)}; + return result; +} + +internal void +os_barrier_release(OS_Handle barrier) +{ + OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); + pthread_barrier_destroy(&entity->barrier); + os_lnx_entity_release(entity); +} + +internal void +os_barrier_wait(OS_Handle barrier) +{ + OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]); + pthread_barrier_wait(&entity->barrier); +} + //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) diff --git a/src/os/core/linux/os_core_linux.h b/src/os/core/linux/os_core_linux.h index 1770d239..4b345a4b 100644 --- a/src/os/core/linux/os_core_linux.h +++ b/src/os/core/linux/os_core_linux.h @@ -67,6 +67,7 @@ typedef enum OS_LNX_EntityKind OS_LNX_EntityKind_Mutex, OS_LNX_EntityKind_RWMutex, OS_LNX_EntityKind_ConditionVariable, + OS_LNX_EntityKind_Barrier, } OS_LNX_EntityKind; @@ -90,6 +91,7 @@ struct OS_LNX_Entity pthread_cond_t cond_handle; pthread_mutex_t rwlock_mutex_handle; } cv; + pthread_barrier_t barrier; }; }; diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 415bb662..158c5185 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -299,7 +299,12 @@ internal void os_semaphore_release(OS_Handle semaphore); internal OS_Handle os_semaphore_open(String8 name); internal void os_semaphore_close(OS_Handle semaphore); internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us); -internal void os_semaphore_drop(OS_Handle semaphore); +internal void os_semaphore_drop(OS_Handle semaphore); + +//- rjf: barriers +internal OS_Handle os_barrier_alloc(U64 count); +internal void os_barrier_release(OS_Handle barrier); +internal void os_barrier_wait(OS_Handle barrier); //- rjf: scope macros #define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 65d7926d..175ad4f5 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1352,6 +1352,32 @@ os_semaphore_drop(OS_Handle semaphore) ReleaseSemaphore(handle, 1, 0); } +//- rjf: barriers + +internal OS_Handle +os_barrier_alloc(U64 count) +{ + OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Barrier); + InitializeSynchronizationBarrier(&entity->sb, count, -1); + OS_Handle result = {IntFromPtr(entity)}; + return result; +} + +internal void +os_barrier_release(OS_Handle barrier) +{ + OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); + DeleteSynchronizationBarrier(&entity->sb); + os_w32_entity_release(entity); +} + +internal void +os_barrier_wait(OS_Handle barrier) +{ + OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); + EnterSynchronizationBarrier(&entity->sb, 0); +} + //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) diff --git a/src/os/core/win32/os_core_win32.h b/src/os/core/win32/os_core_win32.h index 22a21f80..4938a828 100644 --- a/src/os/core/win32/os_core_win32.h +++ b/src/os/core/win32/os_core_win32.h @@ -46,6 +46,7 @@ typedef enum OS_W32_EntityKind OS_W32_EntityKind_Mutex, OS_W32_EntityKind_RWMutex, OS_W32_EntityKind_ConditionVariable, + OS_W32_EntityKind_Barrier, } OS_W32_EntityKind; @@ -66,6 +67,7 @@ struct OS_W32_Entity CRITICAL_SECTION mutex; SRWLOCK rw_mutex; CONDITION_VARIABLE cv; + SYNCHRONIZATION_BARRIER sb; }; }; From 086d774b8bd7dbb17dcec9b562c4353a459d3ac4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 5 Aug 2025 15:49:51 -0700 Subject: [PATCH 015/302] fix ELF compressed header and skip duplicate sections --- src/dwarf/dwarf_elf.c | 93 +++++++++++++++++++++---------------------- src/elf/elf.h | 3 +- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/dwarf/dwarf_elf.c b/src/dwarf/dwarf_elf.c index 1e4c8bdd..0f1ecdc8 100644 --- a/src/dwarf/dwarf_elf.c +++ b/src/dwarf/dwarf_elf.c @@ -32,7 +32,6 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin) { DW_Input result = {0}; B32 is_section_present[ArrayCount(result.sec)] = {0}; - Temp scratch = scratch_begin(&arena, 1); for(U64 section_idx = 1; section_idx < bin->shdrs.count; section_idx += 1) { ELF_Shdr64 *shdr = &bin->shdrs.v[section_idx]; @@ -49,69 +48,67 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin) is_dwo = (section_kind != DW_Section_Null); } + if(section_kind == DW_Section_Null) { continue; } // skip unknown sections + if(is_section_present[section_kind]) { continue; } // skip duplicate sections + //- rjf: decompress section data if needed String8 section_data__uncompressed = {0}; - if(section_kind != DW_Section_Null) + if(!(shdr->sh_flags & ELF_Shf_Compressed)) { - if(!(shdr->sh_flags & ELF_Shf_Compressed)) + section_data__uncompressed = section_data__maybe_compressed; + } + else + { + // rjf: read compressed-section header + ELF_Chdr64 chdr64 = {0}; + U64 chdr_size = 0; + if(ELF_HdrIs64Bit(bin->hdr.e_ident)) { - section_data__uncompressed = section_data__maybe_compressed; + chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr64); } - else + else if(ELF_HdrIs32Bit(bin->hdr.e_ident)) { - // rjf: read compressed-section header - ELF_Chdr64 chdr64 = {0}; - U64 chdr_size = 0; - if(ELF_HdrIs64Bit(bin->hdr.e_ident)) + ELF_Chdr32 chdr32 = {0}; + chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr32); + if(chdr_size == sizeof(chdr32)) { - chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr64); + chdr64 = elf_chdr64_from_chdr32(chdr32); } - else if(ELF_HdrIs32Bit(bin->hdr.e_ident)) + } + + // rjf: decompress + { + String8 section_data__compressed_contents = str8_skip(section_data__maybe_compressed, chdr_size); + switch(chdr64.ch_type) { - ELF_Chdr32 chdr32 = {0}; - chdr_size = str8_deserial_read_struct(section_data__maybe_compressed, 0, &chdr32); - if(chdr_size == sizeof(chdr32)) + case ELF_CompressType_None: { - chdr64 = elf_chdr64_from_chdr32(chdr32); - } - } - - // rjf: decompress - { - String8 section_data__compressed_contents = str8_skip(section_data__maybe_compressed, chdr_size); - switch(chdr64.ch_type) + section_data__uncompressed = section_data__compressed_contents; + }break; + case ELF_CompressType_ZLib: { - default: - case ELF_CompressType_None: - { - section_data__uncompressed = section_data__compressed_contents; - }break; - case ELF_CompressType_ZLib: - { - U8 *section_data_uncompressed_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align); - U64 section_data_uncompressed_size = 0; - section_data_uncompressed_size = zsinflate(section_data_uncompressed_buffer, chdr64.ch_size, section_data__compressed_contents.str, section_data__compressed_contents.size); - section_data__uncompressed = str8(section_data_uncompressed_buffer, section_data_uncompressed_size); - }break; - case ELF_CompressType_ZStd: - { - NotImplemented; - }break; - } + U8 *section_data_uncompressed_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align); + U64 section_data_uncompressed_size = zsinflate(section_data_uncompressed_buffer, chdr64.ch_size, section_data__compressed_contents.str, section_data__compressed_contents.size); + section_data__uncompressed = str8(section_data_uncompressed_buffer, section_data_uncompressed_size); + }break; + case ELF_CompressType_ZStd: + { + NotImplemented; + }break; + default: + { + NotImplemented; + }break; } } } //- rjf: store - if(section_kind != DW_Section_Null) - { - is_section_present[section_kind] = 1; - DW_Section *d = &result.sec[section_kind]; - d->name = push_str8_copy(arena, section_name); - d->data = section_data__uncompressed; - d->is_dwo = is_dwo; - } + is_section_present[section_kind] = 1; + DW_Section *d = &result.sec[section_kind]; + d->name = push_str8_copy(arena, section_name); + d->data = section_data__uncompressed; + d->is_dwo = is_dwo; } - scratch_end(scratch); return result; } diff --git a/src/elf/elf.h b/src/elf/elf.h index 5e1291a2..15577bbc 100644 --- a/src/elf/elf.h +++ b/src/elf/elf.h @@ -971,7 +971,8 @@ typedef struct ELF_Chdr32 typedef struct ELF_Chdr64 { - U64 ch_type; + U32 ch_type; + U32 ch_reserved; U64 ch_size; U64 ch_addr_align; } ELF_Chdr64; From 1d6eae2b188a31cec8d0f95682cefe2a64c8b6bb Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 12 Aug 2025 19:03:51 -0700 Subject: [PATCH 016/302] minor fixes for gathering library members --- src/linker/lnk.c | 2 +- src/linker/lnk_symbol_table.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 9cc82fb7..a2588938 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -973,7 +973,7 @@ lnk_queue_lib_member_input(Arena *arena, // lookup member in the lib where pull-in reference is declared LNK_Symbol *best_match = member_symbol; for (LNK_Symbol *s = member_symbol; s != 0; s = s->u.member.next) { - if (s->u.member.v.lib == pull_in_ref->u.member.v.lib) { + if (s->u.member.v.lib == pull_in_ref->u.defined.obj->lib) { best_match = s; break; } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index c04709a9..e27d4bf3 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -316,7 +316,6 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) } } break; case LNK_SymbolScope_Lib: { - // link.exe picks symbol from lib that is discovered first can_replace = lnk_symbol_lib_is_before(src, dst); } break; default: { InvalidPath; } @@ -345,7 +344,7 @@ lnk_on_symbol_replace(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) } } - // make sure leader section is not removed from the output + // assert leader section is live #if BUILD_DEBUG { COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); @@ -358,7 +357,9 @@ lnk_on_symbol_replace(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) #endif } break; case LNK_SymbolScope_Lib: { - // nothing to replace + LNK_Symbol *last; + for (last = src; last->u.member.next != 0; last = last->u.member.next); + last->u.member.next = dst; } break; default: { InvalidPath; } } From 6a8277536f254b2dee5f59205e14d51b823f2730 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 13 Aug 2025 13:21:34 -0700 Subject: [PATCH 017/302] fix one-sided bounds check in text containing-scope binary search --- src/text_cache/text_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index c142a844..59fdec01 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -2132,7 +2132,7 @@ txt_scope_node_from_info_off(TXT_TextInfo *info, U64 off) scope_n != &txt_scope_node_nil; scope_n = txt_scope_node_from_info_num(info, scope_n->parent_num)) { - if(off < info->tokens.v[scope_n->token_idx_range.max].range.max) + if(info->tokens.v[scope_n->token_idx_range.min].range.min <= off && off < info->tokens.v[scope_n->token_idx_range.max].range.max) { result = scope_n; break; From 5144ced2828ebc384a69cefbf8b473a177decc85 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 13 Aug 2025 13:46:02 -0700 Subject: [PATCH 018/302] turn off call stack tree macro for now --- src/raddbg/raddbg_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 5ba92c99..6d5f3b6f 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -12298,6 +12298,7 @@ rd_frame(void) } //- rjf: add macro for call stack tree +#if 0 { String8 collection_name = str8_lit("call_stack_tree"); E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set, @@ -12316,6 +12317,7 @@ rd_frame(void) e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); } +#endif //- rjf: add macro / lookup rules for unattached processes { From 7be1faaa9bc994ef2d3f9ef4c21cf967c88e578a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 13 Aug 2025 14:13:10 -0700 Subject: [PATCH 019/302] fix callstack cache lookup early out case --- src/ctrl/ctrl_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5fe76704..e2b494e4 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3490,8 +3490,8 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 hi } } - //- rjf: out of time => exit - if(retry_idx > 0 && os_now_microseconds() >= endt_us) + //- rjf: out of time, or got new result => exit + if((retry_idx > 0 && os_now_microseconds() >= endt_us) || !node_stale) { break; } From 83650a5fe033ec05948c935a6d05d6770dafe40f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Aug 2025 10:56:42 -0700 Subject: [PATCH 020/302] support `unsigned` -> `unsigned int`; support `as`-style casts in expressions; pack `int` alias in pdb-produced rdis --- src/eval/eval_ir.c | 2 +- src/eval/eval_parse.c | 53 +++++++++++++++++++++++++++++++-- src/raddbg/raddbg_main.c | 1 + src/rdi_from_pdb/rdi_from_pdb.c | 1 + 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index e9efeb63..3e34a22a 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -2222,7 +2222,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { E_IRTreeAndType direct_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first); result = direct_irtree; - E_TypeKey direct_type_key = result.type_key; + E_TypeKey direct_type_key = e_type_key_unwrap(result.type_key, E_TypeUnwrapFlag_AllDecorative); E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); if(e_type_kind_is_signed(direct_type_kind)) { diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index bf244b4b..7e87d294 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -859,10 +859,19 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing `)`."); } + // rjf: require type + if(type_parse.expr == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected type in `cast(...)`."); + } + // rjf: fill prefix unary info - prefix_unary_kind = E_ExprKind_Cast; - prefix_unary_precedence = 2; - prefix_unary_cast_expr = type_parse.expr; + else + { + prefix_unary_kind = E_ExprKind_Cast; + prefix_unary_precedence = 2; + prefix_unary_cast_expr = type_parse.expr; + } end_cast_parse:; } @@ -1303,6 +1312,33 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t } } + // rjf: "as" style casts + if(token.kind == E_TokenKind_Identifier && + str8_match(token_string, str8_lit("as"), 0)) + { + it += 1; + + // rjf: parse type expression + E_Parse type_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); + it = type_parse.last_token; + + // rjf: require type + if(type_parse.expr == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected type following `as`."); + } + + // rjf: build cast expr + else + { + E_Expr *rhs = atom; + atom = e_push_expr(arena, E_ExprKind_Cast, token.range); + e_expr_push_child(atom, type_parse.expr); + e_expr_push_child(atom, rhs); + } + } + // rjf: quit if this doesn't look like any patterns of postfix unary we know if(!is_postfix_unary) { @@ -1310,6 +1346,17 @@ e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray t } } + //////////////////////////// + //- rjf: no atom, just single `unsigned` prefix unary? -> unsigned int type expr + // + if(atom == &e_expr_nil && + first_prefix_unary != 0 && + first_prefix_unary->kind == E_ExprKind_Unsigned) + { + atom = e_push_expr(arena, E_ExprKind_LeafIdentifier, first_prefix_unary->cast_type_expr->range); + atom->string = str8_lit("int"); + } + //////////////////////////// //- rjf: upgrade `atom` w/ previously parsed prefix unaries // diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 9795474f..4b7b30ed 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -6,6 +6,7 @@ // //- urgent fixes // [ ] hardware breakpoints regression (global eval in ctrl) +// [ ] native filesystem dialog, resizing raddbg window -> crash! // //- memory view // [ ] have smaller visible range than entire memory diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 09ab8fb2..95b57049 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3781,6 +3781,7 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 }, { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 }, { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 }, + { "int" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, { "int32" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, { "uint32" , RDI_TypeKind_U32 , CV_BasicType_UINT32 }, { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 }, From f754b4c2db0b77ba2291da0ce47f762ccb4cc2ca Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Aug 2025 11:31:50 -0700 Subject: [PATCH 021/302] fix pointer/array comparison paths not being enabled for not-equal; fix value arithmetic paths applying in type comparisons --- src/eval/eval_ir.c | 15 ++++++++++++++- src/os/core/linux/os_core_linux.c | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 3e34a22a..83876875 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1184,6 +1184,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I #define E_ArithPath_PtrAdd 1 #define E_ArithPath_PtrSub 2 #define E_ArithPath_PtrArrayCompare 3 +#define E_ArithPath_TypeCompare 4 B32 ptr_arithmetic_mul_rptr = 0; U32 arith_path = E_ArithPath_Normal; if(kind == E_ExprKind_Add) @@ -1216,7 +1217,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } } } - else if(kind == E_ExprKind_EqEq) + else if(kind == E_ExprKind_EqEq || kind == E_ExprKind_NtEq) { if(l_type_kind == E_TypeKind_Array && (r_type_kind == E_TypeKind_Ptr || r_is_decay)) { @@ -1226,6 +1227,10 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I { arith_path = E_ArithPath_PtrArrayCompare; } + if(l_tree.mode == E_Mode_Null && r_tree.mode == E_Mode_Null) + { + arith_path = E_ArithPath_TypeCompare; + } } // rjf: generate according to arithmetic path @@ -1360,6 +1365,14 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I result.type_key = e_type_key_basic(E_TypeKind_Bool); result.mode = E_Mode_Value; }break; + + //- rjf: type comparison + case E_ArithPath_TypeCompare: + { + result.root = e_irtree_const_u(arena, !!e_type_match(l_type, r_type)); + result.type_key = e_type_key_basic(E_TypeKind_Bool); + result.mode = E_Mode_Value; + }break; } }break; diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index c61fa270..16b1e474 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1175,8 +1175,8 @@ os_semaphore_drop(OS_Handle semaphore) internal OS_Handle os_barrier_alloc(U64 count) { - OS_LNX_Entity *entity = os_w32_entity_alloc(OS_LNX_EntityKind_Barrier); - pthread_barrier_init(&entity->barrier, count); + OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Barrier); + pthread_barrier_init(&entity->barrier, 0, count); OS_Handle result = {IntFromPtr(entity)}; return result; } From f1a1863d5c7082dba6bd167c40da8ac0de6641be Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Aug 2025 12:16:58 -0700 Subject: [PATCH 022/302] set up base-layer tctx info for thread wavefront metadata --- src/base/base_entry_point.c | 6 +-- src/base/base_thread_context.c | 81 ++++++++++++++++++++++--------- src/base/base_thread_context.h | 46 ++++++++++++------ src/os/core/linux/os_core_linux.c | 9 ++-- src/os/core/win32/os_core_win32.c | 9 ++-- 5 files changed, 98 insertions(+), 53 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index feaa45e1..6c9c17f2 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -105,10 +105,10 @@ main_thread_base_entry_point(int arguments_count, char **arguments) internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params) { - TCTX tctx; - tctx_init_and_equip(&tctx); + TCTX *tctx = tctx_alloc(); + tctx_select(tctx); entry_point(params); - tctx_release(); + tctx_release(tctx); } internal U64 diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 43bf16f3..22da9dd6 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -2,44 +2,53 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -// NOTE(allen): Thread Context Functions +//~ rjf: Globals C_LINKAGE thread_static TCTX* tctx_thread_local; #if !BUILD_SUPPLEMENTARY_UNIT C_LINKAGE thread_static TCTX* tctx_thread_local = 0; #endif -internal void -tctx_init_and_equip(TCTX *tctx) +//////////////////////////////// +//~ rjf: Thread Context Functions + +//- rjf: thread-context allocation & selection + +internal TCTX * +tctx_alloc(void) +{ + Arena *arena = arena_alloc(); + TCTX *tctx = push_array(arena, TCTX, 1); + tctx->arenas[0] = arena; + tctx->arenas[1] = arena_alloc(); + return tctx; +} + +internal void +tctx_release(TCTX *tctx) +{ + arena_release(tctx->arenas[1]); + arena_release(tctx->arenas[0]); +} + +internal void +tctx_select(TCTX *tctx) { - MemoryZeroStruct(tctx); - Arena **arena_ptr = tctx->arenas; - for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1) - { - *arena_ptr = arena_alloc(); - } tctx_thread_local = tctx; } -internal void -tctx_release(void) -{ - for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1) - { - arena_release(tctx_thread_local->arenas[i]); - } -} - internal TCTX * -tctx_get_equipped(void) +tctx_selected(void) { return tctx_thread_local; } +//- rjf: scratch arenas + internal Arena * tctx_get_scratch(Arena **conflicts, U64 count) { - TCTX *tctx = tctx_get_equipped(); + TCTX *tctx = tctx_selected(); Arena *result = 0; Arena **arena_ptr = tctx->arenas; for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1) @@ -63,10 +72,32 @@ tctx_get_scratch(Arena **conflicts, U64 count) return result; } +//- rjf: wavefront metadata + +internal void +tctx_set_wavefront_info(U64 wavefront_idx, U64 wavefront_count) +{ + TCTX *tctx = tctx_selected(); + OS_Handle barrier = os_barrier_alloc(wavefront_count); + tctx->wavefront_idx = wavefront_idx; + tctx->wavefront_count = wavefront_count; + tctx->wavefront_barrier_id = barrier.u64[0]; +} + +internal void +tctx_wavefront_barrier_wait(void) +{ + TCTX *tctx = tctx_selected(); + OS_Handle barrier = {tctx->wavefront_barrier_id}; + os_barrier_wait(barrier); +} + +//- rjf: thread names + internal void tctx_set_thread_name(String8 string) { - TCTX *tctx = tctx_get_equipped(); + TCTX *tctx = tctx_selected(); U64 size = ClampTop(string.size, sizeof(tctx->thread_name)); MemoryCopy(tctx->thread_name, string.str, size); tctx->thread_name_size = size; @@ -75,15 +106,17 @@ tctx_set_thread_name(String8 string) internal String8 tctx_get_thread_name(void) { - TCTX *tctx = tctx_get_equipped(); + TCTX *tctx = tctx_selected(); String8 result = str8(tctx->thread_name, tctx->thread_name_size); return result; } +//- rjf: thread source-locations + internal void tctx_write_srcloc(char *file_name, U64 line_number) { - TCTX *tctx = tctx_get_equipped(); + TCTX *tctx = tctx_selected(); tctx->file_name = file_name; tctx->line_number = line_number; } @@ -91,7 +124,7 @@ tctx_write_srcloc(char *file_name, U64 line_number) internal void tctx_read_srcloc(char **file_name, U64 *line_number) { - TCTX *tctx = tctx_get_equipped(); + TCTX *tctx = tctx_selected(); *file_name = tctx->file_name; *line_number = tctx->line_number; } diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 44ff7ab2..15984168 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -5,37 +5,55 @@ #define BASE_THREAD_CONTEXT_H //////////////////////////////// -// NOTE(allen): Thread Context +//~ rjf: Base Per-Thread State Bundle typedef struct TCTX TCTX; struct TCTX { + // rjf: scratch arenas Arena *arenas[2]; + // rjf: thread name U8 thread_name[32]; U64 thread_name_size; + // rjf: wavefront info + U64 wavefront_idx; + U64 wavefront_count; + U64 wavefront_barrier_id; + + // rjf: source location info char *file_name; U64 line_number; }; //////////////////////////////// -// NOTE(allen): Thread Context Functions +//~ rjf: Thread Context Functions -internal void tctx_init_and_equip(TCTX *tctx); -internal void tctx_release(void); -internal TCTX* tctx_get_equipped(void); - -internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); - -internal void tctx_set_thread_name(String8 name); -internal String8 tctx_get_thread_name(void); - -internal void tctx_write_srcloc(char *file_name, U64 line_number); -internal void tctx_read_srcloc(char **file_name, U64 *line_number); -#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) +//- rjf: thread-context allocation & selection +internal TCTX *tctx_alloc(void); +internal void tctx_release(TCTX *tctx); +internal void tctx_select(TCTX *tctx); +internal TCTX *tctx_selected(void); +//- rjf: scratch arenas +internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); #define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count))) #define scratch_end(scratch) temp_end(scratch) +//- rjf: wavefront metadata +internal void tctx_set_wavefront_info(U64 wavefront_idx, U64 wavefront_count); +internal void tctx_wavefront_barrier_wait(void); +#define wavefront_thread(idx, count) tctx_set_wavefront_info((idx), (count)) +#define wavefront_barrier() tctx_wavefront_barrier_wait() + +//- rjf: thread names +internal void tctx_set_thread_name(String8 name); +internal String8 tctx_get_thread_name(void); + +//- rjf: thread source-locations +internal void tctx_write_srcloc(char *file_name, U64 line_number); +internal void tctx_read_srcloc(char **file_name, U64 *line_number); +#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) + #endif // BASE_THREAD_CONTEXT_H diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 16b1e474..a0b8c36d 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -123,10 +123,7 @@ os_lnx_thread_entry_point(void *ptr) OS_LNX_Entity *entity = (OS_LNX_Entity *)ptr; OS_ThreadFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; - TCTX tctx_; - tctx_init_and_equip(&tctx_); - func(thread_ptr); - tctx_release(); + supplement_thread_base_entry_point(func, thread_ptr); return 0; } @@ -1302,8 +1299,8 @@ main(int argc, char **argv) } //- rjf: set up thread context - local_persist TCTX tctx; - tctx_init_and_equip(&tctx); + TCTX *tctx = tctx_alloc(); + tctx_select(tctx); //- rjf: set up dynamically allocated state os_lnx_state.arena = arena_alloc(); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 175ad4f5..d4c55dcf 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -145,10 +145,7 @@ os_w32_thread_entry_point(void *ptr) OS_W32_Entity *entity = (OS_W32_Entity *)ptr; OS_ThreadFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; - TCTX tctx_; - tctx_init_and_equip(&tctx_); - func(thread_ptr); - tctx_release(); + supplement_thread_base_entry_point(func, thread_ptr); return 0; } @@ -1776,8 +1773,8 @@ w32_entry_point_caller(int argc, WCHAR **wargv) } //- rjf: set up thread context - local_persist TCTX tctx; - tctx_init_and_equip(&tctx); + TCTX *tctx = tctx_alloc(); + tctx_select(tctx); //- rjf: set up dynamically-alloc'd state Arena *arena = arena_alloc(); From e566b2ed30de42f1e8f38ec3b9980cdb42671bc9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Aug 2025 16:50:28 -0700 Subject: [PATCH 023/302] checkpoint on wavefront-style pdb -> rdi converter --- project.4coder | 4 +- src/base/base_core.h | 1 + src/base/base_thread_context.c | 28 +- src/base/base_thread_context.h | 23 +- src/radbin/radbin_main.c | 2 + src/raddbg/raddbg_main.c | 12 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 609 ++++++++++++++++++++++++++++++ src/rdi_from_pdb/rdi_from_pdb_2.h | 60 +++ 8 files changed, 717 insertions(+), 22 deletions(-) create mode 100644 src/rdi_from_pdb/rdi_from_pdb_2.c create mode 100644 src/rdi_from_pdb/rdi_from_pdb_2.h diff --git a/project.4coder b/project.4coder index 6fc96e05..bd53fe4b 100644 --- a/project.4coder +++ b/project.4coder @@ -46,8 +46,8 @@ load_paths = commands = { //- rjf: [raddbg] - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/base/base_core.h b/src/base/base_core.h index 319837ba..c10021c7 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -136,6 +136,7 @@ #define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1) #define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1)) #define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1)) +#define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1) //////////////////////////////// //~ rjf: Memory Operation Macros diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 22da9dd6..bc5f359d 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -21,6 +21,7 @@ tctx_alloc(void) TCTX *tctx = push_array(arena, TCTX, 1); tctx->arenas[0] = arena; tctx->arenas[1] = arena_alloc(); + tctx->lane_count = 1; return tctx; } @@ -72,26 +73,37 @@ tctx_get_scratch(Arena **conflicts, U64 count) return result; } -//- rjf: wavefront metadata +//- rjf: lane metadata internal void -tctx_set_wavefront_info(U64 wavefront_idx, U64 wavefront_count) +tctx_set_lane_info(U64 lane_idx, U64 lane_count) { TCTX *tctx = tctx_selected(); - OS_Handle barrier = os_barrier_alloc(wavefront_count); - tctx->wavefront_idx = wavefront_idx; - tctx->wavefront_count = wavefront_count; - tctx->wavefront_barrier_id = barrier.u64[0]; + OS_Handle barrier = os_barrier_alloc(lane_count); + tctx->lane_idx = lane_idx; + tctx->lane_count = lane_count; + tctx->lane_barrier_id = barrier.u64[0]; } internal void -tctx_wavefront_barrier_wait(void) +tctx_lane_barrier_wait(void) { TCTX *tctx = tctx_selected(); - OS_Handle barrier = {tctx->wavefront_barrier_id}; + OS_Handle barrier = {tctx->lane_barrier_id}; os_barrier_wait(barrier); } +internal Rng1U64 +tctx_lane_idx_range_from_count(U64 count) +{ + U64 idxes_per_lane = count/lane_count(); + U64 lane_base_idx = lane_idx()*idxes_per_lane; + U64 lane_opl_idx = lane_base_idx + idxes_per_lane; + U64 lane_opl_idx__clamped = Min(lane_opl_idx, count); + Rng1U64 result = r1u64(lane_base_idx, lane_opl_idx__clamped); + return result; +} + //- rjf: thread names internal void diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 15984168..c7411644 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -17,10 +17,10 @@ struct TCTX U8 thread_name[32]; U64 thread_name_size; - // rjf: wavefront info - U64 wavefront_idx; - U64 wavefront_count; - U64 wavefront_barrier_id; + // rjf: lane info + U64 lane_idx; + U64 lane_count; + U64 lane_barrier_id; // rjf: source location info char *file_name; @@ -41,11 +41,16 @@ internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); #define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count))) #define scratch_end(scratch) temp_end(scratch) -//- rjf: wavefront metadata -internal void tctx_set_wavefront_info(U64 wavefront_idx, U64 wavefront_count); -internal void tctx_wavefront_barrier_wait(void); -#define wavefront_thread(idx, count) tctx_set_wavefront_info((idx), (count)) -#define wavefront_barrier() tctx_wavefront_barrier_wait() +//- rjf: lane metadata +internal void tctx_set_lane_info(U64 lane_idx, U64 lane_count); +internal void tctx_lane_barrier_wait(void); +internal Rng1U64 tctx_lane_idx_range_from_count(U64 count); +#define lane_idx() (tctx_selected()->lane_idx) +#define lane_count() (tctx_selected()->lane_count) +#define lane_from_task_idx(idx) ((idx)%lane_count()) +#define lane_thread(idx, count) tctx_set_lane_info((idx), (count)) +#define lane_sync() tctx_lane_barrier_wait() +#define lane_range(count) tctx_lane_idx_range_from_count(count) //- rjf: thread names internal void tctx_set_thread_name(String8 name); diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index f0f6f8b4..4053d23c 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -32,6 +32,7 @@ #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" #include "rdi_from_pdb/rdi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb_2.h" #include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h" #include "rdi_from_dwarf/rdi_from_dwarf.h" #include "radbin/radbin.h" @@ -58,6 +59,7 @@ #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" #include "rdi_from_pdb/rdi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb_2.c" #include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c" #include "rdi_from_dwarf/rdi_from_dwarf.c" #include "radbin/radbin.c" diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 4b7b30ed..b6654ed1 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -197,6 +197,10 @@ #define BUILD_TITLE "The RAD Debugger" #define OS_FEATURE_GRAPHICAL 1 +#define DMN_INIT_MANUAL 1 +#define CTRL_INIT_MANUAL 1 +#define OS_GFX_INIT_MANUAL 1 +#define FP_INIT_MANUAL 1 #define R_INIT_MANUAL 1 #define TEX_INIT_MANUAL 1 #define GEO_INIT_MANUAL 1 @@ -439,9 +443,6 @@ entry_point(CmdLine *cmd_line) jit_attach = (jit_addr != 0); } - //- rjf: set up layers - ctrl_set_wakeup_hook(wakeup_hook_ctrl); - //- rjf: dispatch to top-level codepath based on execution mode switch(exec_mode) { @@ -487,12 +488,17 @@ entry_point(CmdLine *cmd_line) //- rjf: manual layer initialization { + dmn_init(); + ctrl_init(); + os_gfx_init(); + fp_init(); r_init(cmd_line); tex_init(); geo_init(); fnt_init(); d_init(); rd_init(cmd_line); + ctrl_set_wakeup_hook(wakeup_hook_ctrl); } //- rjf: set up shared resources for ipc to this instance; launch IPC signaler thread diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c new file mode 100644 index 00000000..98f748b4 --- /dev/null +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -0,0 +1,609 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal void +p2r2_convert_thread_entry_point(void *p) +{ + P2R2_ConvertThreadParams *params = (P2R2_ConvertThreadParams *)p; + Arena *arena = params->arena; + lane_thread(params->lane_idx, params->lane_count); + + ////////////////////////////////////////////////////////////// + //- rjf: do top-level MSF/PDB extraction + // + if(lane_idx() == 0) ProfScope("do top-level MSF/PDB extraction") + { + ProfScope("parse MSF") + { + p2r2_shared = push_array(arena, P2R2_Shared, 1); + p2r2_shared->msf = msf_parsed_from_data(arena, params->input_pdb_data); + } + ProfScope("parse PDB info") + { + String8 info_data = msf_data_from_stream(p2r2_shared->msf, PDB_FixedStream_Info); + p2r2_shared->pdb_info = pdb_info_from_data(arena, info_data); + if(p2r2_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) + { + log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); + } + } + ProfScope("parse named streams table") + { + p2r2_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r2_shared->pdb_info); + } + } + lane_sync(); + MSF_Parsed *msf = p2r2_shared->msf; + PDB_Info *pdb_info = p2r2_shared->pdb_info; + PDB_NamedStreamTable *named_streams = p2r2_shared->named_streams; + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB strtbl & top-level streams + // + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") + { + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; + String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); + p2r2_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); + p2r2_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r2_shared->strtbl->strblock_min, p2r2_shared->strtbl->strblock_max)); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") + { + String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); + p2r2_shared->dbi = pdb_dbi_from_data(arena, dbi_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") + { + String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); + p2r2_shared->tpi = pdb_tpi_from_data(arena, tpi_data); + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") + { + String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); + p2r2_shared->ipi = pdb_tpi_from_data(arena, ipi_data); + } + } + lane_sync(); + PDB_Strtbl *strtbl = p2r2_shared->strtbl; + String8 raw_strtbl = p2r2_shared->raw_strtbl; + PDB_DbiParsed *dbi = p2r2_shared->dbi; + PDB_TpiParsed *tpi = p2r2_shared->tpi; + PDB_TpiParsed *ipi = p2r2_shared->ipi; + + ////////////////////////////////////////////////////////////// + //- rjf: unpack DBI + // + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") + { + MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; + String8 section_data = msf_data_from_stream(msf, section_stream); + p2r2_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") + { + String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); + p2r2_shared->gsi = pdb_gsi_from_data(arena, gsi_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") + { + String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); + String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); + p2r2_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + } + } + lane_sync(); + COFF_SectionHeaderArray coff_sections = p2r2_shared->coff_sections; + PDB_GsiParsed *gsi = p2r2_shared->gsi; + PDB_GsiParsed *psi_gsi_part = p2r2_shared->psi_gsi_part; + + ////////////////////////////////////////////////////////////// + //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units + // + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") + { + p2r2_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") + { + String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + p2r2_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") + { + String8 leaf_data = pdb_leaf_data_from_tpi(tpi); + p2r2_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") + { + String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + p2r2_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); + } + if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") + { + String8 leaf_data = pdb_leaf_data_from_tpi(ipi); + p2r2_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); + } + if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse global symbol stream") + { + String8 sym_data = msf_data_from_stream(msf, dbi->sym_sn); + p2r2_shared->sym = cv_sym_from_data(arena, sym_data, 4); + } + if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation units") + { + String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); + p2r2_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); + } + if(lane_idx() == lane_from_task_idx(7)) ProfScope("parse compilation unit contributions") + { + String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); + p2r2_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); + } + } + lane_sync(); + U64 exe_hash = p2r2_shared->exe_hash; + PDB_TpiHashParsed *tpi_hash = p2r2_shared->tpi_hash; + CV_LeafParsed *tpi_leaf = p2r2_shared->tpi_leaf; + PDB_TpiHashParsed *ipi_hash = p2r2_shared->ipi_hash; + CV_LeafParsed *ipi_leaf = p2r2_shared->ipi_leaf; + CV_SymParsed *sym = p2r2_shared->sym; + PDB_CompUnitArray *comp_units = p2r2_shared->comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions = p2r2_shared->comp_unit_contributions; + + ////////////////////////////////////////////////////////////// + //- rjf: bucket compilation unit contributions + // + if(lane_idx() == 0) ProfScope("bucket compilation unit contributions") + { + p2r2_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); + for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) + { + PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[idx]; + if(contribution->mod < comp_units->count) + { + RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; + rdim_rng1u64_chunk_list_push(arena, &p2r2_shared->unit_ranges[contribution->mod], 256, r); + } + } + } + lane_sync(); + RDIM_Rng1U64ChunkList *unit_ranges = p2r2_shared->unit_ranges; + + ////////////////////////////////////////////////////////////// + //- rjf: parse syms & line info for each compilation unit + // + ProfScope("parse syms & line info for each compilation unit") + { + //- rjf: setup outputs + if(lane_idx() == 0) + { + p2r2_shared->sym_for_unit = push_array(arena, CV_SymParsed *, comp_units->count); + p2r2_shared->c13_for_unit = push_array(arena, CV_C13Parsed *, comp_units->count); + } + lane_sync(); + + //- rjf: wide fill + { + Rng1U64 range = lane_range(comp_units->count); + for EachInRange(idx, range) + { + PDB_CompUnit *unit = comp_units->units[idx]; + String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); + String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); + p2r2_shared->sym_for_unit[idx] = cv_sym_from_data(arena, unit_sym_data, 4); + p2r2_shared->c13_for_unit[idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + } + } + } + lane_sync(); + CV_SymParsed **sym_for_unit = p2r2_shared->sym_for_unit; + CV_C13Parsed **c13_for_unit = p2r2_shared->c13_for_unit; + + ////////////////////////////////////////////////////////////// + //- rjf: calculate EXE's max voff + // + if(lane_idx() == 0) + { + COFF_SectionHeader *coff_sec_ptr = coff_sections.v; + COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_sections.count; + for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) + { + U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; + p2r2_shared->exe_voff_max = Max(p2r2_shared->exe_voff_max, sec_voff_max); + } + } + lane_sync(); + U64 exe_voff_max = p2r2_shared->exe_voff_max; + + ////////////////////////////////////////////////////////////// + //- rjf: determine architecture + // + if(lane_idx() == 0) + { + // + // TODO(rjf): in some cases, the first compilation unit has a zero + // architecture, as it's sometimes used as a "nil" unit. this causes bugs + // in later stages of conversion - particularly, this was detected via + // busted location info. so i've converted this to a scan-until-we-find-an- + // architecture. however, this may still be fundamentally insufficient, + // because Nick has informed me that x86 units can be linked with x64 + // units, meaning the appropriate architecture at any point in time is not + // a top-level concept, and is rather dependent on to which compilation + // unit particular symbols belong. so in the future, to support that (odd) + // case, we'll need to not only have this be a top-level "contextual" piece + // of info, but to use the appropriate compilation unit's architecture when + // possible. assuming, of course, that we care about supporting that case. + // + for(U64 comp_unit_idx = 0; comp_unit_idx < comp_units->count; comp_unit_idx += 1) + { + p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(sym_for_unit[comp_unit_idx]->info.arch); + if(p2r2_shared->arch != RDI_Arch_NULL) + { + break; + } + } + } + lane_sync(); + RDI_Arch arch = RDI_Arch_NULL; + U64 arch_addr_size = rdi_addr_size_from_arch(arch); + + ////////////////////////////////////////////////////////////// + //- rjf: produce top-level-info + // + RDIM_TopLevelInfo top_level_info = {0}; + { + top_level_info.arch = arch; + top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + if(params->deterministic) + { + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: build binary sections list + // + RDIM_BinarySectionList binary_sections = {0}; + ProfScope("build binary section list") + { + COFF_SectionHeader *coff_ptr = coff_sections.v; + COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; + for(;coff_ptr < coff_opl; coff_ptr += 1) + { + char *name_first = (char *)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + sec->name = str8_cstring_capped(name_first, name_opl); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->voff_first = coff_ptr->voff; + sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; + sec->foff_first = coff_ptr->foff; + sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: gather all source file paths; build nodes + // + ProfScope("gather all source file paths; build nodes") + { + //- rjf: prep outputs + if(lane_idx() == 0) + { + p2r2_shared->unit_src_file_paths = push_array(arena, String8Array, comp_units->count); + } + lane_sync(); + + //- rjf: do wide gather +#if 0 + { + Rng1U64 range = lane_range(comp_units->count); + for EachInRange(idx, range) + { + PDB_CompUnit *unit = comp_units->units[idx]; + CV_SymParsed *unit_sym = sym_for_unit[idx]; + CV_C13Parsed *unit_c13 = c13_for_unit[idx]; + CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; + String8List src_file_paths = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: build local hash table to dedup files within this unit + U64 hit_path_slots_count = 4096; + String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); + + //- rjf: produce obj name/path + String8 obj_name = unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: find all files in this unit's (non-inline) line info + ProfScope("find all files in this unit's (non-inline) line info") + for(CV_C13SubSectionNode *node = unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) + { + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) + { + // rjf: file name -> sanitized file path + String8 file_path = lines_n->v.file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_sanitized, 0)) + { + hit_path_node = n; + break; + } + } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_sanitized; + str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); + } + } + } + } + + //- rjf: find all files in unit's inline line info + ProfScope("find all files in unit's inline line info") + { + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > pdb_unit_sym->data.size || sym_off_first > pdb_unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = pdb_unit_sym->data.str + sym_off_first; + void *sym_data_opl = pdb_unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%pdb_unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = pdb_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = pdb_unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + U64 line_count = 0; + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> gather new file name + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(pdb_unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); + } + + // rjf: file name -> normalized file path + String8 file_path = seq_file_name; + String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + if(file_path_normalized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); + file_path_normalized_parts = obj_folder_path_parts; + file_path_normalized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); + } + + // rjf: normalized file path -> source file node + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_normalized, 0)) + { + hit_path_node = n; + break; + } + } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_normalized; + str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); + } + line_count = 0; + } + + // rjf: count lines + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + } + + scratch_end(scratch); + } + p2r2_shared->unit_src_file_paths[idx] = str8_array_from_list(arena, &src_file_paths); + } + } +#endif + +#if 0 // TODO(rjf): OLD + U64 tasks_count = comp_unit_count; + P2R_GatherUnitSrcFilesIn *tasks_inputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesIn, tasks_count); + P2R_GatherUnitSrcFilesOut *tasks_outputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesOut, tasks_count); + ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); + for EachIndex(idx, tasks_count) + { + tasks_inputs[idx].pdb_strtbl = strtbl; + tasks_inputs[idx].coff_sections = coff_sections; + tasks_inputs[idx].comp_unit = comp_units->units[idx]; + tasks_inputs[idx].comp_unit_syms = sym_for_unit[idx]; + tasks_inputs[idx].comp_unit_c13s = c13_for_unit[idx]; + tasks[idx] = async_task_launch(scratch.arena, p2r_gather_unit_src_file_work, .input = &tasks_inputs[idx]); + } + U64 total_path_count = 0; + for EachIndex(idx, tasks_count) + { + tasks_outputs[idx] = *async_task_join_struct(tasks[idx], P2R_GatherUnitSrcFilesOut); + total_path_count += tasks_outputs[idx].src_file_paths.count; + } + src_file_map.slots_count = total_path_count + total_path_count/2 + 1; + src_file_map.slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map.slots_count); +#endif + + //- rjf: build src file map +#if 0 + for EachIndex(idx, tasks_count) + { + for EachIndex(path_idx, tasks_outputs[idx].src_file_paths.count) + { + String8 file_path_sanitized = tasks_outputs[idx].src_file_paths.v[path_idx]; + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); + SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &all_src_files__sequenceless, total_path_count); + src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + } + } + } +#endif + } + RDIM_SrcFileChunkList all_src_files__sequenceless = {0}; + P2R_SrcFileMap src_file_map = {0}; + +} diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h new file mode 100644 index 00000000..cd18b84f --- /dev/null +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -0,0 +1,60 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RDI_FROM_PDB_2_H +#define RDI_FROM_PDB_2_H + +typedef struct P2R2_ConvertThreadParams P2R2_ConvertThreadParams; +struct P2R2_ConvertThreadParams +{ + Arena *arena; + U64 lane_idx; + U64 lane_count; + String8 input_exe_name; + String8 input_exe_data; + String8 input_pdb_name; + String8 input_pdb_data; + B32 deterministic; +}; + +typedef struct P2R2_Shared P2R2_Shared; +struct P2R2_Shared +{ + MSF_Parsed *msf; + PDB_Info *pdb_info; + PDB_NamedStreamTable *named_streams; + + PDB_Strtbl *strtbl; + String8 raw_strtbl; + PDB_DbiParsed *dbi; + PDB_TpiParsed *tpi; + PDB_TpiParsed *ipi; + + COFF_SectionHeaderArray coff_sections; + PDB_GsiParsed *gsi; + PDB_GsiParsed *psi_gsi_part; + + U64 exe_hash; + PDB_TpiHashParsed *tpi_hash; + CV_LeafParsed *tpi_leaf; + PDB_TpiHashParsed *ipi_hash; + CV_LeafParsed *ipi_leaf; + CV_SymParsed *sym; + PDB_CompUnitArray *comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions; + RDIM_Rng1U64ChunkList *unit_ranges; + + CV_SymParsed **sym_for_unit; + CV_C13Parsed **c13_for_unit; + + U64 exe_voff_max; + RDI_Arch arch; + + String8Array *unit_src_file_paths; +}; + +global P2R2_Shared *p2r2_shared = 0; + +internal void p2r2_convert_thread_entry_point(void *p); + +#endif // RDI_FROM_PDB_2_H From a48651471dff4268b44dedcd6c570ff70f46237d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Aug 2025 16:54:06 -0700 Subject: [PATCH 024/302] share-read in header analysis in radbin --- src/radbin/radbin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 63bb4d84..137004ac 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -34,7 +34,7 @@ rb_entry_point(CmdLine *cmdline) RB_FileFormatFlags file_format_flags = 0; ProfScope("do thin analysis of file") { - OS_Handle file = os_file_open(OS_AccessFlag_Read, n->string); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, n->string); FileProperties props = os_properties_from_file(file); //- rjf: PDB magic -> PDB input From c33dd2869aa179802771cfa7c5d849900ee8688d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 10:46:43 -0700 Subject: [PATCH 025/302] define synchronization primitive interface in base layer, implement using os layer; convert all usage -> base layer; use base sync primitives in lane tctx info --- src/async/async.c | 26 +- src/async/async.h | 14 +- src/base/base_arena.h | 10 +- src/base/base_command_line.c | 2 +- src/base/base_core.c | 113 +- src/base/base_core.h | 102 +- src/base/base_inc.c | 1 + src/base/base_inc.h | 1 + src/base/base_math.c | 3 +- src/base/base_math.h | 1388 ++++++++++++------------- src/base/base_strings.c | 245 +++-- src/base/base_strings.h | 11 +- src/base/base_sync.c | 46 + src/base/base_sync.h | 86 ++ src/base/base_thread_context.c | 14 +- src/base/base_thread_context.h | 25 +- src/ctrl/ctrl_core.c | 90 +- src/ctrl/ctrl_core.h | 34 +- src/dasm_cache/dasm_cache.c | 16 +- src/dasm_cache/dasm_cache.h | 8 +- src/dbgi/dbgi.c | 88 +- src/dbgi/dbgi.h | 34 +- src/demon/linux/demon_core_linux.c | 6 +- src/demon/win32/demon_core_win32.c | 6 +- src/demon/win32/demon_core_win32.h | 2 +- src/eval/eval_types.c | 4 +- src/file_stream/file_stream.c | 22 +- src/file_stream/file_stream.h | 8 +- src/geo_cache/geo_cache.c | 16 +- src/geo_cache/geo_cache.h | 8 +- src/hash_store/hash_store.c | 12 +- src/hash_store/hash_store.h | 4 +- src/mutable_text/mutable_text.c | 14 +- src/mutable_text/mutable_text.h | 6 +- src/os/core/linux/os_core_linux.c | 14 +- src/os/core/linux/os_core_linux_old.c | 4 +- src/os/core/os_core.h | 52 +- src/os/core/win32/os_core_win32.c | 66 +- src/pe/pe.c | 46 +- src/ptr_graph_cache/ptr_graph_cache.c | 16 +- src/ptr_graph_cache/ptr_graph_cache.h | 8 +- src/raddbg/raddbg_core.c | 2 +- src/raddbg/raddbg_main.c | 22 +- src/render/d3d11/render_d3d11.c | 2 +- src/render/d3d11/render_d3d11.h | 2 +- src/text_cache/text_cache.c | 16 +- src/text_cache/text_cache.h | 8 +- src/texture_cache/texture_cache.c | 16 +- src/texture_cache/texture_cache.h | 8 +- 49 files changed, 1454 insertions(+), 1293 deletions(-) create mode 100644 src/base/base_sync.c create mode 100644 src/base/base_sync.h diff --git a/src/async/async.c b/src/async/async.c index 85ff743b..953f34a5 100644 --- a/src/async/async.c +++ b/src/async/async.c @@ -18,11 +18,11 @@ async_init(CmdLine *cmdline) ASYNC_Ring *ring = &async_shared->rings[p]; ring->ring_size = MB(8); ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size); - ring->ring_mutex = os_mutex_alloc(); - ring->ring_cv = os_condition_variable_alloc(); + ring->ring_mutex = mutex_alloc(); + ring->ring_cv = cond_var_alloc(); } - async_shared->ring_mutex = os_mutex_alloc(); - async_shared->ring_cv = os_condition_variable_alloc(); + async_shared->ring_mutex = mutex_alloc(); + async_shared->ring_cv = cond_var_alloc(); String8 work_thread_count_string = cmd_line_string(cmdline, str8_lit("work_threads_count")); if(work_thread_count_string.size == 0 || !try_u64_from_str8_c_rules(work_thread_count_string, &async_shared->work_threads_count)) { @@ -81,7 +81,7 @@ async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params if(available_size >= sizeof(work)) { queued_in_ring_buffer = 1; - if(!os_handle_match(params->semaphore, os_handle_zero())) + if(!MemoryIsZeroStruct(¶ms->semaphore)) { os_semaphore_take(params->semaphore, max_U64); } @@ -92,14 +92,14 @@ async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params { break; } - os_condition_variable_wait(ring->ring_cv, ring->ring_mutex, params->endt_us); + cond_var_wait(ring->ring_cv, ring->ring_mutex, params->endt_us); } // rjf: broadcast ring buffer cv if we wrote successfully if(queued_in_ring_buffer) { - os_condition_variable_broadcast(ring->ring_cv); - os_condition_variable_broadcast(async_shared->ring_cv); + cond_var_broadcast(ring->ring_cv); + cond_var_broadcast(async_shared->ring_cv); } // rjf: if we did not queue successfully, and we have determined that @@ -148,7 +148,7 @@ internal void * async_task_join(ASYNC_Task *task) { void *result = 0; - if(task != 0 && !os_handle_match(task->semaphore, os_handle_zero())) + if(task != 0 && !MemoryIsZeroStruct(&task->semaphore)) { os_semaphore_take(task->semaphore, max_U64); os_semaphore_release(task->semaphore); @@ -193,11 +193,11 @@ async_pop_work(void) } if(!done) { - os_condition_variable_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64); + cond_var_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64); } } - os_condition_variable_broadcast(async_shared->ring_cv); - os_condition_variable_broadcast(async_shared->rings[taken_priority].ring_cv); + cond_var_broadcast(async_shared->ring_cv); + cond_var_broadcast(async_shared->rings[taken_priority].ring_cv); return work; } @@ -216,7 +216,7 @@ async_execute_work(ASYNC_Work work) } //- rjf: release semaphore - if(!os_handle_match(work.semaphore, os_handle_zero())) + if(!MemoryIsZeroStruct(&work.semaphore)) { os_semaphore_drop(work.semaphore); } diff --git a/src/async/async.h b/src/async/async.h index a25492cb..b7fcc6b6 100644 --- a/src/async/async.h +++ b/src/async/async.h @@ -27,7 +27,7 @@ struct ASYNC_WorkParams { void *input; void **output; - OS_Handle semaphore; + Semaphore semaphore; U64 *completion_counter; U64 *working_counter; U64 endt_us; @@ -40,7 +40,7 @@ struct ASYNC_Work ASYNC_WorkFunctionType *work_function; void *input; void **output; - OS_Handle semaphore; + Semaphore semaphore; U64 *completion_counter; U64 *working_counter; }; @@ -51,7 +51,7 @@ struct ASYNC_Work typedef struct ASYNC_Task ASYNC_Task; struct ASYNC_Task { - OS_Handle semaphore; + Semaphore semaphore; void *output; }; @@ -89,8 +89,8 @@ struct ASYNC_Ring U8 *ring_base; U64 ring_write_pos; U64 ring_read_pos; - OS_Handle ring_mutex; - OS_Handle ring_cv; + Mutex ring_mutex; + CondVar ring_cv; }; typedef struct ASYNC_Shared ASYNC_Shared; @@ -100,8 +100,8 @@ struct ASYNC_Shared // rjf: user -> work thread ring buffers ASYNC_Ring rings[ASYNC_Priority_COUNT]; - OS_Handle ring_mutex; - OS_Handle ring_cv; + Mutex ring_mutex; + CondVar ring_cv; // rjf: work threads OS_Handle *work_threads; diff --git a/src/base/base_arena.h b/src/base/base_arena.h index 47c5238d..a98066ed 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -5,13 +5,10 @@ #define BASE_ARENA_H //////////////////////////////// -//~ rjf: Constants +//~ rjf: Arena Types #define ARENA_HEADER_SIZE 128 -//////////////////////////////// -//~ rjf: Types - typedef U64 ArenaFlags; enum { @@ -59,15 +56,12 @@ struct Temp }; //////////////////////////////// -//~ rjf: Global Defaults +//~ rjf: Arena Functions global U64 arena_default_reserve_size = MB(64); global U64 arena_default_commit_size = KB(64); global ArenaFlags arena_default_flags = 0; -//////////////////////////////// -//~ rjf: Arena Functions - //- rjf: arena creation/destruction internal Arena *arena_alloc_(ArenaParams *params); #define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, .allocation_site_file = __FILE__, .allocation_site_line = __LINE__, __VA_ARGS__}) diff --git a/src/base/base_command_line.c b/src/base/base_command_line.c index 7792afde..1150bcc4 100644 --- a/src/base/base_command_line.c +++ b/src/base/base_command_line.c @@ -104,7 +104,7 @@ cmd_line_from_string_list(Arena *arena, String8List command_line) { option_name = str8_skip(option_name, 1); } - else if(operating_system_from_context() == OperatingSystem_Windows && + else if(OperatingSystem_CURRENT == OperatingSystem_Windows && str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0)) { option_name = str8_skip(option_name, 1); diff --git a/src/base/base_core.c b/src/base/base_core.c index e982b684..9121d923 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -246,7 +246,8 @@ sign_from_side_F32(Side side){ //~ rjf: Memory Functions internal B32 -memory_is_zero(void *ptr, U64 size){ +memory_is_zero(void *ptr, U64 size) +{ B32 result = 1; // break down size @@ -257,8 +258,10 @@ memory_is_zero(void *ptr, U64 size){ U64 *p64 = (U64*)ptr; if(result) { - for (U64 i = 0; i < count8; i += 1, p64 += 1){ - if (*p64 != 0){ + for(U64 i = 0; i < count8; i += 1, p64 += 1) + { + if(*p64 != 0) + { result = 0; goto done; } @@ -269,8 +272,10 @@ memory_is_zero(void *ptr, U64 size){ if(result) { U8 *p8 = (U8*)p64; - for (U64 i = 0; i < extra; i += 1, p8 += 1){ - if (*p8 != 0){ + for(U64 i = 0; i < extra; i += 1, p8 += 1) + { + if(*p8 != 0) + { result = 0; goto done; } @@ -278,7 +283,7 @@ memory_is_zero(void *ptr, U64 size){ } done:; - return(result); + return result; } //////////////////////////////// @@ -409,47 +414,6 @@ max_instruction_size_from_arch(Arch arch) return 64; } -internal OperatingSystem -operating_system_from_context(void){ - OperatingSystem os = OperatingSystem_Null; -#if OS_WINDOWS - os = OperatingSystem_Windows; -#elif OS_LINUX - os = OperatingSystem_Linux; -#elif OS_MAC - os = OperatingSystem_Mac; -#endif - return os; -} - -internal Arch -arch_from_context(void){ - Arch arch = Arch_Null; -#if ARCH_X64 - arch = Arch_x64; -#elif ARCH_X86 - arch = Arch_x86; -#elif ARCH_ARM64 - arch = Arch_arm64; -#elif ARCH_ARM32 - arch = Arch_arm32; -#endif - return arch; -} - -internal Compiler -compiler_from_context(void){ - Compiler compiler = Compiler_Null; -#if COMPILER_MSVC - compiler = Compiler_msvc; -#elif COMPILER_GCC - compiler = Compiler_gcc; -#elif COMPILER_CLANG - compiler = Compiler_clang; -#endif - return compiler; -} - //////////////////////////////// //~ rjf: Time Functions @@ -659,3 +623,58 @@ index_of_zero_u64(U64 *ptr, U64 count) } return max_U64; } + +//////////////////////////////// +//~ rjf: Third Party Includes + +#define STB_SPRINTF_DECORATE(name) raddbg_##name +#include "third_party/stb/stb_sprintf.h" + +#if !BUILD_SUPPLEMENTARY_UNIT +# define STB_SPRINTF_IMPLEMENTATION +# define STB_SPRINTF_STATIC +# include "third_party/stb/stb_sprintf.h" +#endif + +//////////////////////////////// +//~ rjf: String <-> Integer Tables + +read_only global U8 integer_symbols[16] = +{ + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', +}; + +// NOTE(rjf): Includes reverses for uppercase and lowercase hex. +read_only global U8 integer_symbol_reverse[128] = +{ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +read_only global U8 base64[64] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '_', '$', +}; + +read_only global U8 base64_reverse[128] = +{ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, + 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, + 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, +}; diff --git a/src/base/base_core.h b/src/base/base_core.h index c10021c7..42e7a918 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -160,6 +160,8 @@ #define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a))) #define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a)) +#define MemoryIsZeroStruct(ptr) memory_is_zero((ptr), sizeof(*(ptr))) + #define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) ) #define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) ) @@ -420,6 +422,37 @@ union U512 U256 u256[2]; }; +//////////////////////////////// +//~ rjf: Basic Type Structures + +typedef struct U16Array U16Array; +struct U16Array +{ + U64 count; + U16 *v; +}; + +typedef struct U32Array U32Array; +struct U32Array +{ + U64 count; + U32 *v; +}; + +typedef struct U64Array U64Array; +struct U64Array +{ + U64 count; + U64 *v; +}; + +typedef struct U128Array U128Array; +struct U128Array +{ + U64 count; + U128 *v; +}; + //////////////////////////////// //~ rjf: Basic Types & Spaces @@ -486,6 +519,15 @@ typedef enum OperatingSystem OperatingSystem_Linux, OperatingSystem_Mac, OperatingSystem_COUNT, +#if OS_WINDOWS + OperatingSystem_CURRENT = OperatingSystem_Windows, +#elif OS_LINUX + OperatingSystem_CURRENT = OperatingSystem_Linux, +#elif OS_MAC + OperatingSystem_CURRENT = OperatingSystem_Mac, +#else + OperatingSystem_CURRENT = OperatingSystem_Null, +#endif } OperatingSystem; @@ -508,6 +550,17 @@ typedef enum Arch Arch_arm64, Arch_arm32, Arch_COUNT, +#if ARCH_X64 + Arch_CURRENT = Arch_x64, +#elif ARCH_X86 + Arch_CURRENT = Arch_x86, +#elif ARCH_ARM64 + Arch_CURRENT = Arch_arm64, +#elif ARCH_ARM32 + Arch_CURRENT = Arch_arm32, +#else + Arch_CURRENT = Arch_Null, +#endif } Arch; @@ -518,6 +571,15 @@ typedef enum Compiler Compiler_gcc, Compiler_clang, Compiler_COUNT, +#if COMPILER_MSVC + Compiler_CURRENT = Compiler_msvc, +#elif COMPILER_GCC + Compiler_CURRENT = Compiler_gcc, +#elif COMPILER_CLANG + Compiler_CURRENT = Compiler_clang, +#else + Compiler_CURRENT = Compiler_Null, +#endif } Compiler; @@ -539,7 +601,7 @@ struct TxtRng }; //////////////////////////////// -//~ Globally Unique Ids +//~ rjf: Globally Unique Ids typedef union Guid Guid; union Guid @@ -556,35 +618,7 @@ union Guid StaticAssert(sizeof(Guid) == 16, g_guid_size_check); //////////////////////////////// -//~ Arrays - -typedef struct U16Array U16Array; -struct U16Array -{ - U64 count; - U16 *v; -}; -typedef struct U32Array U32Array; -struct U32Array -{ - U64 count; - U32 *v; -}; -typedef struct U64Array U64Array; -struct U64Array -{ - U64 count; - U64 *v; -}; -typedef struct U128Array U128Array; -struct U128Array -{ - U64 count; - U128 *v; -}; - -//////////////////////////////// -//~ NOTE(allen): Constants +//~ rjf: Basic Constants global U32 sign32 = 0x80000000; global U32 exponent32 = 0x7F800000; @@ -745,7 +779,7 @@ global const U64 bit63 = (1ull<<62); global const U64 bit64 = (1ull<<63); //////////////////////////////// -//~ allen: Time +//~ rjf: Time Types typedef enum WeekDay { @@ -803,7 +837,7 @@ struct DateTime typedef U64 DenseTime; //////////////////////////////// -//~ allen: Files +//~ rjf: File Types typedef U32 FilePropertyFlags; enum @@ -897,10 +931,6 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt); internal U64 bit_size_from_arch(Arch arch); internal U64 max_instruction_size_from_arch(Arch arch); -internal OperatingSystem operating_system_from_context(void); -internal Arch arch_from_context(void); -internal Compiler compiler_from_context(void); - //////////////////////////////// //~ rjf: Time Functions diff --git a/src/base/base_inc.c b/src/base/base_inc.c index 45e1fe84..dc6cad3c 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -12,6 +12,7 @@ #include "base_arena.c" #include "base_math.c" #include "base_strings.c" +#include "base_sync.c" #include "base_thread_context.c" #include "base_command_line.c" #include "base_markup.c" diff --git a/src/base/base_inc.h b/src/base/base_inc.h index e6adf0d3..72d22362 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -14,6 +14,7 @@ #include "base_arena.h" #include "base_math.h" #include "base_strings.h" +#include "base_sync.h" #include "base_thread_context.h" #include "base_command_line.h" #include "base_markup.h" diff --git a/src/base/base_math.c b/src/base/base_math.c index a5d00232..b21a0a9e 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Scalar Ops +//~ rjf: Scalar Math Ops internal F32 mix_1f32(F32 a, F32 b, F32 t) @@ -809,4 +809,3 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list) } return arr; } - diff --git a/src/base/base_math.h b/src/base/base_math.h index dbabea0b..e9022690 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -1,694 +1,694 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_MATH_H -#define BASE_MATH_H - -//////////////////////////////// -//~ rjf: Vector Types - -//- rjf: 2-vectors - -typedef union Vec2F32 Vec2F32; -union Vec2F32 -{ - struct - { - F32 x; - F32 y; - }; - F32 v[2]; -}; - -typedef union Vec2S64 Vec2S64; -union Vec2S64 -{ - struct - { - S64 x; - S64 y; - }; - S64 v[2]; -}; - -typedef union Vec2S32 Vec2S32; -union Vec2S32 -{ - struct - { - S32 x; - S32 y; - }; - S32 v[2]; -}; - -typedef union Vec2S16 Vec2S16; -union Vec2S16 -{ - struct - { - S16 x; - S16 y; - }; - S16 v[2]; -}; - -//- rjf: 3-vectors - -typedef union Vec3F32 Vec3F32; -union Vec3F32 -{ - struct - { - F32 x; - F32 y; - F32 z; - }; - struct - { - Vec2F32 xy; - F32 _z0; - }; - struct - { - F32 _x0; - Vec2F32 yz; - }; - F32 v[3]; -}; - -typedef union Vec3S32 Vec3S32; -union Vec3S32 -{ - struct - { - S32 x; - S32 y; - S32 z; - }; - struct - { - Vec2S32 xy; - S32 _z0; - }; - struct - { - S32 _x0; - Vec2S32 yz; - }; - S32 v[3]; -}; - -//- rjf: 4-vectors - -typedef union Vec4F32 Vec4F32; -union Vec4F32 -{ - struct - { - F32 x; - F32 y; - F32 z; - F32 w; - }; - struct - { - Vec2F32 xy; - Vec2F32 zw; - }; - struct - { - Vec3F32 xyz; - F32 _z0; - }; - struct - { - F32 _x0; - Vec3F32 yzw; - }; - F32 v[4]; -}; - -typedef union Vec4S32 Vec4S32; -union Vec4S32 -{ - struct - { - S32 x; - S32 y; - S32 z; - S32 w; - }; - struct - { - Vec2S32 xy; - Vec2S32 zw; - }; - struct - { - Vec3S32 xyz; - S32 _z0; - }; - struct - { - S32 _x0; - Vec3S32 yzw; - }; - S32 v[4]; -}; - -//////////////////////////////// -//~ rjf: Matrix Types - -typedef struct Mat3x3F32 Mat3x3F32; -struct Mat3x3F32 -{ - F32 v[3][3]; -}; - -typedef struct Mat4x4F32 Mat4x4F32; -struct Mat4x4F32 -{ - F32 v[4][4]; -}; - -//////////////////////////////// -//~ rjf: Range Types - -//- rjf: 1-range - -typedef union Rng1U32 Rng1U32; -union Rng1U32 -{ - struct - { - U32 min; - U32 max; - }; - U32 v[2]; -}; - -typedef union Rng1S32 Rng1S32; -union Rng1S32 -{ - struct - { - S32 min; - S32 max; - }; - S32 v[2]; -}; - -typedef union Rng1U64 Rng1U64; -union Rng1U64 -{ - struct - { - U64 min; - U64 max; - }; - U64 v[2]; -}; - -typedef union Rng1S64 Rng1S64; -union Rng1S64 -{ - struct - { - S64 min; - S64 max; - }; - S64 v[2]; -}; - -typedef union Rng1F32 Rng1F32; -union Rng1F32 -{ - struct - { - F32 min; - F32 max; - }; - F32 v[2]; -}; - -//- rjf: 2-range (rectangles) - -typedef union Rng2S16 Rng2S16; -union Rng2S16 -{ - struct - { - Vec2S16 min; - Vec2S16 max; - }; - struct - { - Vec2S16 p0; - Vec2S16 p1; - }; - struct - { - S16 x0; - S16 y0; - S16 x1; - S16 y1; - }; - Vec2S16 v[2]; -}; - -typedef union Rng2S32 Rng2S32; -union Rng2S32 -{ - struct - { - Vec2S32 min; - Vec2S32 max; - }; - struct - { - Vec2S32 p0; - Vec2S32 p1; - }; - struct - { - S32 x0; - S32 y0; - S32 x1; - S32 y1; - }; - Vec2S32 v[2]; -}; - -typedef union Rng2F32 Rng2F32; -union Rng2F32 -{ - struct - { - Vec2F32 min; - Vec2F32 max; - }; - struct - { - Vec2F32 p0; - Vec2F32 p1; - }; - struct - { - F32 x0; - F32 y0; - F32 x1; - F32 y1; - }; - Vec2F32 v[2]; -}; - -typedef union Rng2S64 Rng2S64; -union Rng2S64 -{ - struct - { - Vec2S64 min; - Vec2S64 max; - }; - struct - { - Vec2S64 p0; - Vec2S64 p1; - }; - struct - { - S64 x0; - S64 y0; - S64 x1; - S64 y1; - }; - Vec2S64 v[2]; -}; - -//////////////////////////////// -//~ rjf: List Types - -typedef struct Rng1U64Node Rng1U64Node; -struct Rng1U64Node -{ - Rng1U64Node *next; - Rng1U64 v; -}; - -typedef struct Rng1U64List Rng1U64List; -struct Rng1U64List -{ - U64 count; - Rng1U64Node *first; - Rng1U64Node *last; -}; - -typedef struct Rng1U64Array Rng1U64Array; -struct Rng1U64Array -{ - Rng1U64 *v; - U64 count; -}; - -typedef struct Rng1S64Node Rng1S64Node; -struct Rng1S64Node -{ - Rng1S64Node *next; - Rng1S64 v; -}; - -typedef struct Rng1S64List Rng1S64List; -struct Rng1S64List -{ - Rng1S64Node *first; - Rng1S64Node *last; - U64 count; -}; - -typedef struct Rng1S64Array Rng1S64Array; -struct Rng1S64Array -{ - Rng1S64 *v; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Scalar Ops - -#define abs_s64(v) (S64)llabs(v) - -#define sqrt_f32(v) sqrtf(v) -#define cbrt_f32(v) cbrtf(v) -#define mod_f32(a, b) fmodf((a), (b)) -#define pow_f32(b, e) powf((b), (e)) -#define ceil_f32(v) ceilf(v) -#define floor_f32(v) floorf(v) -#define round_f32(v) roundf(v) -#define abs_f32(v) fabsf(v) -#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f)) -#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f)) -#define degrees_from_turns_f32(v) ((v)*360.f) -#define turns_from_degrees_f32(v) ((v)/360.f) -#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v))) -#define radians_from_degrees_f32(v) (radians_from_turns_f32(turns_from_degrees_f32(v))) -#define sin_f32(v) sinf(radians_from_turns_f32(v)) -#define cos_f32(v) cosf(radians_from_turns_f32(v)) -#define tan_f32(v) tanf(radians_from_turns_f32(v)) - -#define sqrt_f64(v) sqrt(v) -#define cbrt_f64(v) cbrt(v) -#define mod_f64(a, b) fmod((a), (b)) -#define pow_f64(b, e) pow((b), (e)) -#define ceil_f64(v) ceil(v) -#define floor_f64(v) floor(v) -#define round_f64(v) round(v) -#define abs_f64(v) fabs(v) -#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897)) -#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897)) -#define degrees_from_turns_f64(v) ((v)*360.0) -#define turns_from_degrees_f64(v) ((v)/360.0) -#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v))) -#define radians_from_degrees_f64(v) (radians_from_turns_f64(turns_from_degrees_f64(v))) -#define sin_f64(v) sin(radians_from_turns_f64(v)) -#define cos_f64(v) cos(radians_from_turns_f64(v)) -#define tan_f64(v) tan(radians_from_turns_f64(v)) - -internal F32 mix_1f32(F32 a, F32 b, F32 t); -internal F64 mix_1f64(F64 a, F64 b, F64 t); - -//////////////////////////////// -//~ rjf: Vector Ops - -#define v2f32(x, y) vec_2f32((x), (y)) -internal Vec2F32 vec_2f32(F32 x, F32 y); -internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b); -internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b); -internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b); -internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b); -internal Vec2F32 scale_2f32(Vec2F32 v, F32 s); -internal F32 dot_2f32(Vec2F32 a, Vec2F32 b); -internal F32 length_squared_2f32(Vec2F32 v); -internal F32 length_2f32(Vec2F32 v); -internal Vec2F32 normalize_2f32(Vec2F32 v); -internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t); - -#define v2s64(x, y) vec_2s64((x), (y)) -internal Vec2S64 vec_2s64(S64 x, S64 y); -internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b); -internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b); -internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b); -internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b); -internal Vec2S64 scale_2s64(Vec2S64 v, S64 s); -internal S64 dot_2s64(Vec2S64 a, Vec2S64 b); -internal S64 length_squared_2s64(Vec2S64 v); -internal S64 length_2s64(Vec2S64 v); -internal Vec2S64 normalize_2s64(Vec2S64 v); -internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t); - -#define v2s32(x, y) vec_2s32((x), (y)) -internal Vec2S32 vec_2s32(S32 x, S32 y); -internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b); -internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b); -internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b); -internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b); -internal Vec2S32 scale_2s32(Vec2S32 v, S32 s); -internal S32 dot_2s32(Vec2S32 a, Vec2S32 b); -internal S32 length_squared_2s32(Vec2S32 v); -internal S32 length_2s32(Vec2S32 v); -internal Vec2S32 normalize_2s32(Vec2S32 v); -internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t); - -#define v2s16(x, y) vec_2s16((x), (y)) -internal Vec2S16 vec_2s16(S16 x, S16 y); -internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b); -internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b); -internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b); -internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b); -internal Vec2S16 scale_2s16(Vec2S16 v, S16 s); -internal S16 dot_2s16(Vec2S16 a, Vec2S16 b); -internal S16 length_squared_2s16(Vec2S16 v); -internal S16 length_2s16(Vec2S16 v); -internal Vec2S16 normalize_2s16(Vec2S16 v); -internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t); - -#define v3f32(x, y, z) vec_3f32((x), (y), (z)) -internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z); -internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b); -internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b); -internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b); -internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b); -internal Vec3F32 scale_3f32(Vec3F32 v, F32 s); -internal F32 dot_3f32(Vec3F32 a, Vec3F32 b); -internal F32 length_squared_3f32(Vec3F32 v); -internal F32 length_3f32(Vec3F32 v); -internal Vec3F32 normalize_3f32(Vec3F32 v); -internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t); -internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b); -internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m); - -#define v3s32(x, y, z) vec_3s32((x), (y), (z)) -internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z); -internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b); -internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b); -internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b); -internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b); -internal Vec3S32 scale_3s32(Vec3S32 v, S32 s); -internal S32 dot_3s32(Vec3S32 a, Vec3S32 b); -internal S32 length_squared_3s32(Vec3S32 v); -internal S32 length_3s32(Vec3S32 v); -internal Vec3S32 normalize_3s32(Vec3S32 v); -internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t); -internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b); - -#define v4f32(x, y, z, w) vec_4f32((x), (y), (z), (w)) -internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w); -internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b); -internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b); -internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b); -internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b); -internal Vec4F32 scale_4f32(Vec4F32 v, F32 s); -internal F32 dot_4f32(Vec4F32 a, Vec4F32 b); -internal F32 length_squared_4f32(Vec4F32 v); -internal F32 length_4f32(Vec4F32 v); -internal Vec4F32 normalize_4f32(Vec4F32 v); -internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t); - -#define v4s32(x, y, z, w) vec_4s32((x), (y), (z), (w)) -internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w); -internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b); -internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b); -internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b); -internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b); -internal Vec4S32 scale_4s32(Vec4S32 v, S32 s); -internal S32 dot_4s32(Vec4S32 a, Vec4S32 b); -internal S32 length_squared_4s32(Vec4S32 v); -internal S32 length_4s32(Vec4S32 v); -internal Vec4S32 normalize_4s32(Vec4S32 v); -internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t); - -//////////////////////////////// -//~ rjf: Matrix Ops - -internal Mat3x3F32 mat_3x3f32(F32 diagonal); -internal Mat3x3F32 make_translate_3x3f32(Vec2F32 delta); -internal Mat3x3F32 make_scale_3x3f32(Vec2F32 scale); -internal Mat3x3F32 mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b); - -internal Mat4x4F32 mat_4x4f32(F32 diagonal); -internal Mat4x4F32 make_translate_4x4f32(Vec3F32 delta); -internal Mat4x4F32 make_scale_4x4f32(Vec3F32 scale); -internal Mat4x4F32 make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z); -internal Mat4x4F32 make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z); -internal Mat4x4F32 make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up); -internal Mat4x4F32 make_rotate_4x4f32(Vec3F32 axis, F32 turns); -internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b); -internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale); -internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m); -internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat); -internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat); - -//////////////////////////////// -//~ rjf: Range Ops - -#define r1u32(min, max) rng_1u32((min), (max)) -internal Rng1U32 rng_1u32(U32 min, U32 max); -internal Rng1U32 shift_1u32(Rng1U32 r, U32 x); -internal Rng1U32 pad_1u32(Rng1U32 r, U32 x); -internal U32 center_1u32(Rng1U32 r); -internal B32 contains_1u32(Rng1U32 r, U32 x); -internal U32 dim_1u32(Rng1U32 r); -internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b); -internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b); -internal U32 clamp_1u32(Rng1U32 r, U32 v); - -#define r1s32(min, max) rng_1s32((min), (max)) -internal Rng1S32 rng_1s32(S32 min, S32 max); -internal Rng1S32 shift_1s32(Rng1S32 r, S32 x); -internal Rng1S32 pad_1s32(Rng1S32 r, S32 x); -internal S32 center_1s32(Rng1S32 r); -internal B32 contains_1s32(Rng1S32 r, S32 x); -internal S32 dim_1s32(Rng1S32 r); -internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b); -internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b); -internal S32 clamp_1s32(Rng1S32 r, S32 v); - -#define r1u64(min, max) rng_1u64((min), (max)) -internal Rng1U64 rng_1u64(U64 min, U64 max); -internal Rng1U64 shift_1u64(Rng1U64 r, U64 x); -internal Rng1U64 pad_1u64(Rng1U64 r, U64 x); -internal U64 center_1u64(Rng1U64 r); -internal B32 contains_1u64(Rng1U64 r, U64 x); -internal U64 dim_1u64(Rng1U64 r); -internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b); -internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b); -internal U64 clamp_1u64(Rng1U64 r, U64 v); - -#define r1s64(min, max) rng_1s64((min), (max)) -internal Rng1S64 rng_1s64(S64 min, S64 max); -internal Rng1S64 shift_1s64(Rng1S64 r, S64 x); -internal Rng1S64 pad_1s64(Rng1S64 r, S64 x); -internal S64 center_1s64(Rng1S64 r); -internal B32 contains_1s64(Rng1S64 r, S64 x); -internal S64 dim_1s64(Rng1S64 r); -internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b); -internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b); -internal S64 clamp_1s64(Rng1S64 r, S64 v); - -#define r1f32(min, max) rng_1f32((min), (max)) -internal Rng1F32 rng_1f32(F32 min, F32 max); -internal Rng1F32 shift_1f32(Rng1F32 r, F32 x); -internal Rng1F32 pad_1f32(Rng1F32 r, F32 x); -internal F32 center_1f32(Rng1F32 r); -internal B32 contains_1f32(Rng1F32 r, F32 x); -internal F32 dim_1f32(Rng1F32 r); -internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b); -internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b); -internal F32 clamp_1f32(Rng1F32 r, F32 v); - -#define r2s16(min, max) rng_2s16((min), (max)) -#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w))) -internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max); -internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x); -internal Rng2S16 pad_2s16(Rng2S16 r, S16 x); -internal Vec2S16 center_2s16(Rng2S16 r); -internal B32 contains_2s16(Rng2S16 r, Vec2S16 x); -internal Vec2S16 dim_2s16(Rng2S16 r); -internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b); -internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b); -internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v); - -#define r2s32(min, max) rng_2s32((min), (max)) -#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w))) -internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max); -internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x); -internal Rng2S32 pad_2s32(Rng2S32 r, S32 x); -internal Vec2S32 center_2s32(Rng2S32 r); -internal B32 contains_2s32(Rng2S32 r, Vec2S32 x); -internal Vec2S32 dim_2s32(Rng2S32 r); -internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b); -internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b); -internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v); - -#define r2s64(min, max) rng_2s64((min), (max)) -#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w))) -internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max); -internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x); -internal Rng2S64 pad_2s64(Rng2S64 r, S64 x); -internal Vec2S64 center_2s64(Rng2S64 r); -internal B32 contains_2s64(Rng2S64 r, Vec2S64 x); -internal Vec2S64 dim_2s64(Rng2S64 r); -internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b); -internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b); -internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v); - -#define r2f32(min, max) rng_2f32((min), (max)) -#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w))) -internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max); -internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x); -internal Rng2F32 pad_2f32(Rng2F32 r, F32 x); -internal Vec2F32 center_2f32(Rng2F32 r); -internal B32 contains_2f32(Rng2F32 r, Vec2F32 x); -internal Vec2F32 dim_2f32(Rng2F32 r); -internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b); -internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b); -internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v); - -//////////////////////////////// -//~ rjf: Color Operations - -//- rjf: hsv <-> rgb -internal Vec3F32 hsv_from_rgb(Vec3F32 rgb); -internal Vec3F32 rgb_from_hsv(Vec3F32 hsv); -internal Vec4F32 hsva_from_rgba(Vec4F32 rgba); -internal Vec4F32 rgba_from_hsva(Vec4F32 hsva); - -//- rjf: srgb <-> linear -internal Vec3F32 linear_from_srgb(Vec3F32 srgb); -internal Vec3F32 srgb_from_linear(Vec3F32 linear); -internal Vec4F32 linear_from_srgba(Vec4F32 srgba); -internal Vec4F32 srgba_from_linear(Vec4F32 linear); - -//- rjf: oklab <-> linear -internal Vec3F32 oklab_from_linear(Vec3F32 linear); -internal Vec3F32 linear_from_oklab(Vec3F32 oklab); -internal Vec4F32 oklab_from_lineara(Vec4F32 lineara); -internal Vec4F32 lineara_from_oklab(Vec4F32 oklab); - -//- rjf: rgba <-> u32 -internal U32 u32_from_rgba(Vec4F32 rgba); -internal Vec4F32 rgba_from_u32(U32 hex); -#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f } - -//////////////////////////////// -//~ rjf: List Type Functions - -internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); -internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); -internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); -internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); - -internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); -internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); - -#endif // BASE_MATH_H +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_MATH_H +#define BASE_MATH_H + +//////////////////////////////// +//~ rjf: Vector Types + +//- rjf: 2-vectors + +typedef union Vec2F32 Vec2F32; +union Vec2F32 +{ + struct + { + F32 x; + F32 y; + }; + F32 v[2]; +}; + +typedef union Vec2S64 Vec2S64; +union Vec2S64 +{ + struct + { + S64 x; + S64 y; + }; + S64 v[2]; +}; + +typedef union Vec2S32 Vec2S32; +union Vec2S32 +{ + struct + { + S32 x; + S32 y; + }; + S32 v[2]; +}; + +typedef union Vec2S16 Vec2S16; +union Vec2S16 +{ + struct + { + S16 x; + S16 y; + }; + S16 v[2]; +}; + +//- rjf: 3-vectors + +typedef union Vec3F32 Vec3F32; +union Vec3F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + }; + struct + { + Vec2F32 xy; + F32 _z0; + }; + struct + { + F32 _x0; + Vec2F32 yz; + }; + F32 v[3]; +}; + +typedef union Vec3S32 Vec3S32; +union Vec3S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + }; + struct + { + Vec2S32 xy; + S32 _z0; + }; + struct + { + S32 _x0; + Vec2S32 yz; + }; + S32 v[3]; +}; + +//- rjf: 4-vectors + +typedef union Vec4F32 Vec4F32; +union Vec4F32 +{ + struct + { + F32 x; + F32 y; + F32 z; + F32 w; + }; + struct + { + Vec2F32 xy; + Vec2F32 zw; + }; + struct + { + Vec3F32 xyz; + F32 _z0; + }; + struct + { + F32 _x0; + Vec3F32 yzw; + }; + F32 v[4]; +}; + +typedef union Vec4S32 Vec4S32; +union Vec4S32 +{ + struct + { + S32 x; + S32 y; + S32 z; + S32 w; + }; + struct + { + Vec2S32 xy; + Vec2S32 zw; + }; + struct + { + Vec3S32 xyz; + S32 _z0; + }; + struct + { + S32 _x0; + Vec3S32 yzw; + }; + S32 v[4]; +}; + +//////////////////////////////// +//~ rjf: Matrix Types + +typedef struct Mat3x3F32 Mat3x3F32; +struct Mat3x3F32 +{ + F32 v[3][3]; +}; + +typedef struct Mat4x4F32 Mat4x4F32; +struct Mat4x4F32 +{ + F32 v[4][4]; +}; + +//////////////////////////////// +//~ rjf: Range Types + +//- rjf: 1-range + +typedef union Rng1U32 Rng1U32; +union Rng1U32 +{ + struct + { + U32 min; + U32 max; + }; + U32 v[2]; +}; + +typedef union Rng1S32 Rng1S32; +union Rng1S32 +{ + struct + { + S32 min; + S32 max; + }; + S32 v[2]; +}; + +typedef union Rng1U64 Rng1U64; +union Rng1U64 +{ + struct + { + U64 min; + U64 max; + }; + U64 v[2]; +}; + +typedef union Rng1S64 Rng1S64; +union Rng1S64 +{ + struct + { + S64 min; + S64 max; + }; + S64 v[2]; +}; + +typedef union Rng1F32 Rng1F32; +union Rng1F32 +{ + struct + { + F32 min; + F32 max; + }; + F32 v[2]; +}; + +//- rjf: 2-range (rectangles) + +typedef union Rng2S16 Rng2S16; +union Rng2S16 +{ + struct + { + Vec2S16 min; + Vec2S16 max; + }; + struct + { + Vec2S16 p0; + Vec2S16 p1; + }; + struct + { + S16 x0; + S16 y0; + S16 x1; + S16 y1; + }; + Vec2S16 v[2]; +}; + +typedef union Rng2S32 Rng2S32; +union Rng2S32 +{ + struct + { + Vec2S32 min; + Vec2S32 max; + }; + struct + { + Vec2S32 p0; + Vec2S32 p1; + }; + struct + { + S32 x0; + S32 y0; + S32 x1; + S32 y1; + }; + Vec2S32 v[2]; +}; + +typedef union Rng2F32 Rng2F32; +union Rng2F32 +{ + struct + { + Vec2F32 min; + Vec2F32 max; + }; + struct + { + Vec2F32 p0; + Vec2F32 p1; + }; + struct + { + F32 x0; + F32 y0; + F32 x1; + F32 y1; + }; + Vec2F32 v[2]; +}; + +typedef union Rng2S64 Rng2S64; +union Rng2S64 +{ + struct + { + Vec2S64 min; + Vec2S64 max; + }; + struct + { + Vec2S64 p0; + Vec2S64 p1; + }; + struct + { + S64 x0; + S64 y0; + S64 x1; + S64 y1; + }; + Vec2S64 v[2]; +}; + +//////////////////////////////// +//~ rjf: Range List Types + +typedef struct Rng1U64Node Rng1U64Node; +struct Rng1U64Node +{ + Rng1U64Node *next; + Rng1U64 v; +}; + +typedef struct Rng1U64List Rng1U64List; +struct Rng1U64List +{ + U64 count; + Rng1U64Node *first; + Rng1U64Node *last; +}; + +typedef struct Rng1U64Array Rng1U64Array; +struct Rng1U64Array +{ + Rng1U64 *v; + U64 count; +}; + +typedef struct Rng1S64Node Rng1S64Node; +struct Rng1S64Node +{ + Rng1S64Node *next; + Rng1S64 v; +}; + +typedef struct Rng1S64List Rng1S64List; +struct Rng1S64List +{ + Rng1S64Node *first; + Rng1S64Node *last; + U64 count; +}; + +typedef struct Rng1S64Array Rng1S64Array; +struct Rng1S64Array +{ + Rng1S64 *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Scalar Math Ops + +#define abs_s64(v) (S64)llabs(v) + +#define sqrt_f32(v) sqrtf(v) +#define cbrt_f32(v) cbrtf(v) +#define mod_f32(a, b) fmodf((a), (b)) +#define pow_f32(b, e) powf((b), (e)) +#define ceil_f32(v) ceilf(v) +#define floor_f32(v) floorf(v) +#define round_f32(v) roundf(v) +#define abs_f32(v) fabsf(v) +#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f)) +#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f)) +#define degrees_from_turns_f32(v) ((v)*360.f) +#define turns_from_degrees_f32(v) ((v)/360.f) +#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v))) +#define radians_from_degrees_f32(v) (radians_from_turns_f32(turns_from_degrees_f32(v))) +#define sin_f32(v) sinf(radians_from_turns_f32(v)) +#define cos_f32(v) cosf(radians_from_turns_f32(v)) +#define tan_f32(v) tanf(radians_from_turns_f32(v)) + +#define sqrt_f64(v) sqrt(v) +#define cbrt_f64(v) cbrt(v) +#define mod_f64(a, b) fmod((a), (b)) +#define pow_f64(b, e) pow((b), (e)) +#define ceil_f64(v) ceil(v) +#define floor_f64(v) floor(v) +#define round_f64(v) round(v) +#define abs_f64(v) fabs(v) +#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897)) +#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897)) +#define degrees_from_turns_f64(v) ((v)*360.0) +#define turns_from_degrees_f64(v) ((v)/360.0) +#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v))) +#define radians_from_degrees_f64(v) (radians_from_turns_f64(turns_from_degrees_f64(v))) +#define sin_f64(v) sin(radians_from_turns_f64(v)) +#define cos_f64(v) cos(radians_from_turns_f64(v)) +#define tan_f64(v) tan(radians_from_turns_f64(v)) + +internal F32 mix_1f32(F32 a, F32 b, F32 t); +internal F64 mix_1f64(F64 a, F64 b, F64 t); + +//////////////////////////////// +//~ rjf: Vector Ops + +#define v2f32(x, y) vec_2f32((x), (y)) +internal Vec2F32 vec_2f32(F32 x, F32 y); +internal Vec2F32 add_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 sub_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 mul_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 div_2f32(Vec2F32 a, Vec2F32 b); +internal Vec2F32 scale_2f32(Vec2F32 v, F32 s); +internal F32 dot_2f32(Vec2F32 a, Vec2F32 b); +internal F32 length_squared_2f32(Vec2F32 v); +internal F32 length_2f32(Vec2F32 v); +internal Vec2F32 normalize_2f32(Vec2F32 v); +internal Vec2F32 mix_2f32(Vec2F32 a, Vec2F32 b, F32 t); + +#define v2s64(x, y) vec_2s64((x), (y)) +internal Vec2S64 vec_2s64(S64 x, S64 y); +internal Vec2S64 add_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 sub_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 mul_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 div_2s64(Vec2S64 a, Vec2S64 b); +internal Vec2S64 scale_2s64(Vec2S64 v, S64 s); +internal S64 dot_2s64(Vec2S64 a, Vec2S64 b); +internal S64 length_squared_2s64(Vec2S64 v); +internal S64 length_2s64(Vec2S64 v); +internal Vec2S64 normalize_2s64(Vec2S64 v); +internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t); + +#define v2s32(x, y) vec_2s32((x), (y)) +internal Vec2S32 vec_2s32(S32 x, S32 y); +internal Vec2S32 add_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 sub_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 mul_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 div_2s32(Vec2S32 a, Vec2S32 b); +internal Vec2S32 scale_2s32(Vec2S32 v, S32 s); +internal S32 dot_2s32(Vec2S32 a, Vec2S32 b); +internal S32 length_squared_2s32(Vec2S32 v); +internal S32 length_2s32(Vec2S32 v); +internal Vec2S32 normalize_2s32(Vec2S32 v); +internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t); + +#define v2s16(x, y) vec_2s16((x), (y)) +internal Vec2S16 vec_2s16(S16 x, S16 y); +internal Vec2S16 add_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 sub_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 mul_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 div_2s16(Vec2S16 a, Vec2S16 b); +internal Vec2S16 scale_2s16(Vec2S16 v, S16 s); +internal S16 dot_2s16(Vec2S16 a, Vec2S16 b); +internal S16 length_squared_2s16(Vec2S16 v); +internal S16 length_2s16(Vec2S16 v); +internal Vec2S16 normalize_2s16(Vec2S16 v); +internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t); + +#define v3f32(x, y, z) vec_3f32((x), (y), (z)) +internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z); +internal Vec3F32 add_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 sub_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 mul_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 div_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 scale_3f32(Vec3F32 v, F32 s); +internal F32 dot_3f32(Vec3F32 a, Vec3F32 b); +internal F32 length_squared_3f32(Vec3F32 v); +internal F32 length_3f32(Vec3F32 v); +internal Vec3F32 normalize_3f32(Vec3F32 v); +internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t); +internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b); +internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m); + +#define v3s32(x, y, z) vec_3s32((x), (y), (z)) +internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z); +internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 sub_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 mul_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 div_3s32(Vec3S32 a, Vec3S32 b); +internal Vec3S32 scale_3s32(Vec3S32 v, S32 s); +internal S32 dot_3s32(Vec3S32 a, Vec3S32 b); +internal S32 length_squared_3s32(Vec3S32 v); +internal S32 length_3s32(Vec3S32 v); +internal Vec3S32 normalize_3s32(Vec3S32 v); +internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t); +internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b); + +#define v4f32(x, y, z, w) vec_4f32((x), (y), (z), (w)) +internal Vec4F32 vec_4f32(F32 x, F32 y, F32 z, F32 w); +internal Vec4F32 add_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 sub_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 mul_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 div_4f32(Vec4F32 a, Vec4F32 b); +internal Vec4F32 scale_4f32(Vec4F32 v, F32 s); +internal F32 dot_4f32(Vec4F32 a, Vec4F32 b); +internal F32 length_squared_4f32(Vec4F32 v); +internal F32 length_4f32(Vec4F32 v); +internal Vec4F32 normalize_4f32(Vec4F32 v); +internal Vec4F32 mix_4f32(Vec4F32 a, Vec4F32 b, F32 t); + +#define v4s32(x, y, z, w) vec_4s32((x), (y), (z), (w)) +internal Vec4S32 vec_4s32(S32 x, S32 y, S32 z, S32 w); +internal Vec4S32 add_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 sub_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 mul_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 div_4s32(Vec4S32 a, Vec4S32 b); +internal Vec4S32 scale_4s32(Vec4S32 v, S32 s); +internal S32 dot_4s32(Vec4S32 a, Vec4S32 b); +internal S32 length_squared_4s32(Vec4S32 v); +internal S32 length_4s32(Vec4S32 v); +internal Vec4S32 normalize_4s32(Vec4S32 v); +internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t); + +//////////////////////////////// +//~ rjf: Matrix Ops + +internal Mat3x3F32 mat_3x3f32(F32 diagonal); +internal Mat3x3F32 make_translate_3x3f32(Vec2F32 delta); +internal Mat3x3F32 make_scale_3x3f32(Vec2F32 scale); +internal Mat3x3F32 mul_3x3f32(Mat3x3F32 a, Mat3x3F32 b); + +internal Mat4x4F32 mat_4x4f32(F32 diagonal); +internal Mat4x4F32 make_translate_4x4f32(Vec3F32 delta); +internal Mat4x4F32 make_scale_4x4f32(Vec3F32 scale); +internal Mat4x4F32 make_perspective_4x4f32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z); +internal Mat4x4F32 make_orthographic_4x4f32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z); +internal Mat4x4F32 make_look_at_4x4f32(Vec3F32 eye, Vec3F32 center, Vec3F32 up); +internal Mat4x4F32 make_rotate_4x4f32(Vec3F32 axis, F32 turns); +internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b); +internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale); +internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m); +internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat); +internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat); + +//////////////////////////////// +//~ rjf: Range Ops + +#define r1u32(min, max) rng_1u32((min), (max)) +internal Rng1U32 rng_1u32(U32 min, U32 max); +internal Rng1U32 shift_1u32(Rng1U32 r, U32 x); +internal Rng1U32 pad_1u32(Rng1U32 r, U32 x); +internal U32 center_1u32(Rng1U32 r); +internal B32 contains_1u32(Rng1U32 r, U32 x); +internal U32 dim_1u32(Rng1U32 r); +internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b); +internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b); +internal U32 clamp_1u32(Rng1U32 r, U32 v); + +#define r1s32(min, max) rng_1s32((min), (max)) +internal Rng1S32 rng_1s32(S32 min, S32 max); +internal Rng1S32 shift_1s32(Rng1S32 r, S32 x); +internal Rng1S32 pad_1s32(Rng1S32 r, S32 x); +internal S32 center_1s32(Rng1S32 r); +internal B32 contains_1s32(Rng1S32 r, S32 x); +internal S32 dim_1s32(Rng1S32 r); +internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b); +internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b); +internal S32 clamp_1s32(Rng1S32 r, S32 v); + +#define r1u64(min, max) rng_1u64((min), (max)) +internal Rng1U64 rng_1u64(U64 min, U64 max); +internal Rng1U64 shift_1u64(Rng1U64 r, U64 x); +internal Rng1U64 pad_1u64(Rng1U64 r, U64 x); +internal U64 center_1u64(Rng1U64 r); +internal B32 contains_1u64(Rng1U64 r, U64 x); +internal U64 dim_1u64(Rng1U64 r); +internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b); +internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b); +internal U64 clamp_1u64(Rng1U64 r, U64 v); + +#define r1s64(min, max) rng_1s64((min), (max)) +internal Rng1S64 rng_1s64(S64 min, S64 max); +internal Rng1S64 shift_1s64(Rng1S64 r, S64 x); +internal Rng1S64 pad_1s64(Rng1S64 r, S64 x); +internal S64 center_1s64(Rng1S64 r); +internal B32 contains_1s64(Rng1S64 r, S64 x); +internal S64 dim_1s64(Rng1S64 r); +internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b); +internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b); +internal S64 clamp_1s64(Rng1S64 r, S64 v); + +#define r1f32(min, max) rng_1f32((min), (max)) +internal Rng1F32 rng_1f32(F32 min, F32 max); +internal Rng1F32 shift_1f32(Rng1F32 r, F32 x); +internal Rng1F32 pad_1f32(Rng1F32 r, F32 x); +internal F32 center_1f32(Rng1F32 r); +internal B32 contains_1f32(Rng1F32 r, F32 x); +internal F32 dim_1f32(Rng1F32 r); +internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b); +internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b); +internal F32 clamp_1f32(Rng1F32 r, F32 v); + +#define r2s16(min, max) rng_2s16((min), (max)) +#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w))) +internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max); +internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x); +internal Rng2S16 pad_2s16(Rng2S16 r, S16 x); +internal Vec2S16 center_2s16(Rng2S16 r); +internal B32 contains_2s16(Rng2S16 r, Vec2S16 x); +internal Vec2S16 dim_2s16(Rng2S16 r); +internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b); +internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b); +internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v); + +#define r2s32(min, max) rng_2s32((min), (max)) +#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w))) +internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max); +internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x); +internal Rng2S32 pad_2s32(Rng2S32 r, S32 x); +internal Vec2S32 center_2s32(Rng2S32 r); +internal B32 contains_2s32(Rng2S32 r, Vec2S32 x); +internal Vec2S32 dim_2s32(Rng2S32 r); +internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b); +internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b); +internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v); + +#define r2s64(min, max) rng_2s64((min), (max)) +#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w))) +internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max); +internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x); +internal Rng2S64 pad_2s64(Rng2S64 r, S64 x); +internal Vec2S64 center_2s64(Rng2S64 r); +internal B32 contains_2s64(Rng2S64 r, Vec2S64 x); +internal Vec2S64 dim_2s64(Rng2S64 r); +internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b); +internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b); +internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v); + +#define r2f32(min, max) rng_2f32((min), (max)) +#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w))) +internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max); +internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x); +internal Rng2F32 pad_2f32(Rng2F32 r, F32 x); +internal Vec2F32 center_2f32(Rng2F32 r); +internal B32 contains_2f32(Rng2F32 r, Vec2F32 x); +internal Vec2F32 dim_2f32(Rng2F32 r); +internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b); +internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b); +internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v); + +//////////////////////////////// +//~ rjf: Color Operations + +//- rjf: hsv <-> rgb +internal Vec3F32 hsv_from_rgb(Vec3F32 rgb); +internal Vec3F32 rgb_from_hsv(Vec3F32 hsv); +internal Vec4F32 hsva_from_rgba(Vec4F32 rgba); +internal Vec4F32 rgba_from_hsva(Vec4F32 hsva); + +//- rjf: srgb <-> linear +internal Vec3F32 linear_from_srgb(Vec3F32 srgb); +internal Vec3F32 srgb_from_linear(Vec3F32 linear); +internal Vec4F32 linear_from_srgba(Vec4F32 srgba); +internal Vec4F32 srgba_from_linear(Vec4F32 linear); + +//- rjf: oklab <-> linear +internal Vec3F32 oklab_from_linear(Vec3F32 linear); +internal Vec3F32 linear_from_oklab(Vec3F32 oklab); +internal Vec4F32 oklab_from_lineara(Vec4F32 lineara); +internal Vec4F32 lineara_from_oklab(Vec4F32 oklab); + +//- rjf: rgba <-> u32 +internal U32 u32_from_rgba(Vec4F32 rgba); +internal Vec4F32 rgba_from_u32(U32 hex); +#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f } + +//////////////////////////////// +//~ rjf: List Type Functions + +internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); +internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); +internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); +internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); + +internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); +internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); + +#endif //BASE_MATH_H diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 84f19d77..62191bcf 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -1,215 +1,196 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -//////////////////////////////// -//~ rjf: Third Party Includes - -#if !BUILD_SUPPLEMENTARY_UNIT -# define STB_SPRINTF_IMPLEMENTATION -# define STB_SPRINTF_STATIC -# include "third_party/stb/stb_sprintf.h" -#endif - -//////////////////////////////// -//~ NOTE(allen): String <-> Integer Tables - -read_only global U8 integer_symbols[16] = { - '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', -}; - -// NOTE(allen): Includes reverses for uppercase and lowercase hex. -read_only global U8 integer_symbol_reverse[128] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -}; - -read_only global U8 base64[64] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '_', '$', -}; - -read_only global U8 base64_reverse[128] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, - 0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32, - 0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E, - 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, - 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF, -}; - //////////////////////////////// //~ rjf: Character Classification & Conversion Functions internal B32 -char_is_space(U8 c){ - return(c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); +char_is_space(U8 c) +{ + return (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'); } internal B32 -char_is_upper(U8 c){ - return('A' <= c && c <= 'Z'); +char_is_upper(U8 c) +{ + return ('A' <= c && c <= 'Z'); } internal B32 -char_is_lower(U8 c){ - return('a' <= c && c <= 'z'); +char_is_lower(U8 c) +{ + return ('a' <= c && c <= 'z'); } internal B32 -char_is_alpha(U8 c){ - return(char_is_upper(c) || char_is_lower(c)); +char_is_alpha(U8 c) +{ + return (char_is_upper(c) || char_is_lower(c)); } internal B32 -char_is_slash(U8 c){ - return(c == '/' || c == '\\'); +char_is_slash(U8 c) +{ + return (c == '/' || c == '\\'); } internal B32 -char_is_digit(U8 c, U32 base){ +char_is_digit(U8 c, U32 base) +{ B32 result = 0; - if (0 < base && base <= 16){ + if(0 < base && base <= 16) + { U8 val = integer_symbol_reverse[c]; - if (val < base){ + if(val < base) + { result = 1; } } - return(result); + return result; } internal U8 -char_to_lower(U8 c){ - if (char_is_upper(c)){ +char_to_lower(U8 c) +{ + if(char_is_upper(c)) + { c += ('a' - 'A'); } - return(c); + return c; } internal U8 -char_to_upper(U8 c){ - if (char_is_lower(c)){ +char_to_upper(U8 c) +{ + if(char_is_lower(c)) + { c += ('A' - 'a'); } - return(c); + return c; } internal U8 -char_to_correct_slash(U8 c){ - if(char_is_slash(c)){ +char_to_correct_slash(U8 c) +{ + if(char_is_slash(c)) + { c = '/'; } - return(c); + return c; } //////////////////////////////// //~ rjf: C-String Measurement internal U64 -cstring8_length(U8 *c){ +cstring8_length(U8 *c) +{ U8 *p = c; for (;*p != 0; p += 1); - return(p - c); + return (p - c); } internal U64 -cstring16_length(U16 *c){ +cstring16_length(U16 *c) +{ U16 *p = c; for (;*p != 0; p += 1); - return(p - c); + return (p - c); } internal U64 -cstring32_length(U32 *c){ +cstring32_length(U32 *c) +{ U32 *p = c; for (;*p != 0; p += 1); - return(p - c); + return (p - c); } //////////////////////////////// //~ rjf: String Constructors internal String8 -str8(U8 *str, U64 size){ +str8(U8 *str, U64 size) +{ String8 result = {str, size}; - return(result); + return result; } internal String8 -str8_range(U8 *first, U8 *one_past_last){ +str8_range(U8 *first, U8 *one_past_last) +{ String8 result = {first, (U64)(one_past_last - first)}; - return(result); + return result; } internal String8 -str8_zero(void){ +str8_zero(void) +{ String8 result = {0}; - return(result); + return result; } internal String16 -str16(U16 *str, U64 size){ +str16(U16 *str, U64 size) +{ String16 result = {str, size}; - return(result); + return result; } internal String16 -str16_range(U16 *first, U16 *one_past_last){ +str16_range(U16 *first, U16 *one_past_last) +{ String16 result = {first, (U64)(one_past_last - first)}; - return(result); + return result; } internal String16 -str16_zero(void){ +str16_zero(void) +{ String16 result = {0}; - return(result); + return result; } internal String32 -str32(U32 *str, U64 size){ +str32(U32 *str, U64 size) +{ String32 result = {str, size}; - return(result); + return result; } internal String32 -str32_range(U32 *first, U32 *one_past_last){ +str32_range(U32 *first, U32 *one_past_last) +{ String32 result = {first, (U64)(one_past_last - first)}; - return(result); + return result; } internal String32 -str32_zero(void){ +str32_zero(void) +{ String32 result = {0}; - return(result); + return result; } internal String8 -str8_cstring(char *c){ +str8_cstring(char *c) +{ String8 result = {(U8*)c, cstring8_length((U8*)c)}; - return(result); + return result; } internal String16 -str16_cstring(U16 *c){ +str16_cstring(U16 *c) +{ String16 result = {(U16*)c, cstring16_length((U16*)c)}; - return(result); + return result; } internal String32 -str32_cstring(U32 *c){ +str32_cstring(U32 *c) +{ String32 result = {(U32*)c, cstring32_length((U32*)c)}; - return(result); + return result; } internal String8 @@ -242,7 +223,6 @@ str8_cstring_capped_reverse(void *raw_start, void *raw_cap) for(; ptr > start; ) { ptr -= 1; - if (*ptr == '\0') { break; @@ -331,35 +311,43 @@ str8_match(String8 a, String8 b, StringMatchFlags flags) } internal U64 -str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags){ +str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags) +{ U8 *p = string.str + start_pos; U64 stop_offset = Max(string.size + 1, needle.size) - needle.size; U8 *stop_p = string.str + stop_offset; - if (needle.size > 0){ + if(needle.size > 0) + { U8 *string_opl = string.str + string.size; String8 needle_tail = str8_skip(needle, 1); StringMatchFlags adjusted_flags = flags | StringMatchFlag_RightSideSloppy; U8 needle_first_char_adjusted = needle.str[0]; - if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + if(adjusted_flags & StringMatchFlag_CaseInsensitive) + { needle_first_char_adjusted = char_to_upper(needle_first_char_adjusted); } - for (;p < stop_p; p += 1){ + for(;p < stop_p; p += 1) + { U8 haystack_char_adjusted = *p; - if(adjusted_flags & StringMatchFlag_CaseInsensitive){ + if(adjusted_flags & StringMatchFlag_CaseInsensitive) + { haystack_char_adjusted = char_to_upper(haystack_char_adjusted); } - if (haystack_char_adjusted == needle_first_char_adjusted){ - if (str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags)){ + if(haystack_char_adjusted == needle_first_char_adjusted) + { + if(str8_match(str8_range(p + 1, string_opl), needle_tail, adjusted_flags)) + { break; } } } } U64 result = string.size; - if (p < stop_p){ + if(p < stop_p) + { result = (U64)(p - string.str); } - return(result); + return result; } internal U64 @@ -578,7 +566,7 @@ str8_is_integer(String8 string, U32 radix){ } } } - return(result); + return result; } internal U64 @@ -1046,7 +1034,7 @@ str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ String8 string = push_str8fv(arena, fmt, args); String8Node *result = str8_list_push(arena, list, string); va_end(args); - return(result); + return result; } internal String8Node* @@ -1056,7 +1044,7 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ String8 string = push_str8fv(arena, fmt, args); String8Node *result = str8_list_push_front(arena, list, string); va_end(args); - return(result); + return result; } internal String8List @@ -1069,7 +1057,7 @@ str8_list_copy(Arena *arena, String8List *list){ String8 new_string = push_str8_copy(arena, node->string); str8_list_push_node_set_string(&result, new_node, new_string); } - return(result); + return result; } internal String8List @@ -1155,7 +1143,7 @@ str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ *ptr = 0; - return(result); + return result; } internal void @@ -1568,7 +1556,7 @@ path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) src_n != 0 && bp_n != 0; src_n = src_n->next, bp_n = bp_n->next) { - if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context()))) + if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(OperatingSystem_CURRENT))) { num_backtracks -= 1; } @@ -1602,7 +1590,7 @@ path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) bp_n != 0; bp_n = bp_n->next) { - if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context())))) + if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(OperatingSystem_CURRENT)))) { unique_from_src = 1; } @@ -1833,7 +1821,7 @@ utf8_decode(U8 *str, U64 max){ } } } - return(result); + return result; } internal UnicodeDecode @@ -1845,7 +1833,7 @@ utf16_decode(U16 *str, U64 max){ result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000); result.inc = 2; } - return(result); + return result; } internal U32 @@ -2045,7 +2033,7 @@ string_from_dimension(Dimension dimension){ if ((U32)dimension < 4){ result = strings[dimension]; } - return(result); + return result; } internal String8 @@ -2058,7 +2046,7 @@ string_from_side(Side side){ if ((U32)side < 2){ result = strings[side]; } - return(result); + return result; } internal String8 @@ -2085,7 +2073,7 @@ string_from_arch(Arch arch){ if (arch < Arch_COUNT){ result = strings[arch]; } - return(result); + return result; } //////////////////////////////// @@ -2106,7 +2094,7 @@ string_from_week_day(WeekDay week_day){ if ((U32)week_day < WeekDay_COUNT){ result = strings[week_day]; } - return(result); + return result; } internal String8 @@ -2129,7 +2117,7 @@ string_from_month(Month month){ if ((U32)month < Month_COUNT){ result = strings[month]; } - return(result); + return result; } internal String8 @@ -2146,7 +2134,7 @@ push_date_time_string(Arena *arena, DateTime *date_time){ String8 result = push_str8f(arena, "%d %s %d, %02d:%02d:%02d %s", date_time->day, mon_str, date_time->year, adjusted_hour, date_time->min, date_time->sec, ampm); - return(result); + return result; } internal String8 @@ -2155,7 +2143,7 @@ push_file_name_date_time_string(Arena *arena, DateTime *date_time){ String8 result = push_str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", date_time->year, mon_str, date_time->day, date_time->hour, date_time->min, date_time->sec); - return(result); + return result; } internal String8 @@ -2176,7 +2164,7 @@ string_from_elapsed_time(Arena *arena, DateTime dt){ StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }; String8 result = str8_list_join(arena, &list, &join); scratch_end(scratch); - return(result); + return result; } //////////////////////////////// @@ -2819,6 +2807,7 @@ str8_is_before_case_sensitive(const void *a, const void *b) return cmp < 0; } +//////////////////////////////// //~ rjf: Basic String Hashes #if !defined(XXH_IMPLEMENTATION) diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 1c3a5d63..3ab73314 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -4,12 +4,6 @@ #ifndef BASE_STRINGS_H #define BASE_STRINGS_H -//////////////////////////////// -//~ rjf: Third Party Includes - -#define STB_SPRINTF_DECORATE(name) raddbg_##name -#include "third_party/stb/stb_sprintf.h" - //////////////////////////////// //~ rjf: String Types @@ -211,8 +205,6 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string); internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); -internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags); -#define str8_ends_with_lit(string, end_lit, flags) str8_ends_with((string), str8_lit(end_lit), (flags)) //////////////////////////////// //~ rjf: String Slicing @@ -245,7 +237,6 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn //- rjf: string -> integer internal S64 sign_from_str8(String8 string, String8 *string_tail); internal B32 str8_is_integer(String8 string, U32 radix); - internal U64 u64_from_str8(String8 string, U32 radix); internal S64 s64_from_str8(String8 string, U32 radix); internal U32 u32_from_str8(String8 string, U32 radix); @@ -474,4 +465,4 @@ internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, Stri internal U64 u64_hash_from_seed_str8(U64 seed, String8 string); internal U64 u64_hash_from_str8(String8 string); -#endif // BASE_STRINGS_H +#endif //BASE_STRINGS_H diff --git a/src/base/base_sync.c b/src/base/base_sync.c new file mode 100644 index 00000000..daa5f462 --- /dev/null +++ b/src/base/base_sync.c @@ -0,0 +1,46 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Synchronization Primitive Functions + +//- rjf: recursive mutexes + +internal Mutex mutex_alloc(void) {return os_mutex_alloc();} +internal void mutex_release(Mutex mutex) {os_mutex_release(mutex);} +internal void mutex_take(Mutex mutex) {os_mutex_take(mutex);} +internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);} + +//- rjf: reader/writer mutexes + +internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();} +internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);} +internal void rw_mutex_take_r(RWMutex mutex) {os_rw_mutex_take_r(mutex);} +internal void rw_mutex_drop_r(RWMutex mutex) {os_rw_mutex_drop_r(mutex);} +internal void rw_mutex_take_w(RWMutex mutex) {os_rw_mutex_take_w(mutex);} +internal void rw_mutex_drop_w(RWMutex mutex) {os_rw_mutex_drop_w(mutex);} + +//- rjf: condition variables + +internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();} +internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);} +internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);} +internal B32 cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us) {return os_cond_var_wait_rw_r(cv, mutex_rw, endt_us);} +internal B32 cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us) {return os_cond_var_wait_rw_w(cv, mutex_rw, endt_us);} +internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);} +internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);} + +//- rjf: cross-process semaphores + +internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name) {return os_semaphore_alloc(initial_count, max_count, name);} +internal void semaphore_release(Semaphore semaphore) {os_semaphore_release(semaphore);} +internal Semaphore semaphore_open(String8 name) {return os_semaphore_open(name);} +internal void semaphore_close(Semaphore semaphore) {os_semaphore_close(semaphore);} +internal B32 semaphore_take(Semaphore semaphore, U64 endt_us) {return os_semaphore_take(semaphore, endt_us);} +internal void semaphore_drop(Semaphore semaphore) {os_semaphore_drop(semaphore);} + +//- rjf: barriers + +internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);} +internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);} +internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);} diff --git a/src/base/base_sync.h b/src/base/base_sync.h new file mode 100644 index 00000000..c3251037 --- /dev/null +++ b/src/base/base_sync.h @@ -0,0 +1,86 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_SYNC_H +#define BASE_SYNC_H + +//////////////////////////////// +//~ rjf: Synchronization Primitive Types + +typedef struct Mutex Mutex; +struct Mutex +{ + U64 u64[1]; +}; + +typedef struct RWMutex RWMutex; +struct RWMutex +{ + U64 u64[1]; +}; + +typedef struct CondVar CondVar; +struct CondVar +{ + U64 u64[1]; +}; + +typedef struct Semaphore Semaphore; +struct Semaphore +{ + U64 u64[1]; +}; + +typedef struct Barrier Barrier; +struct Barrier +{ + U64 u64[1]; +}; + +//////////////////////////////// +//~ rjf: Synchronization Primitive Functions + +//- rjf: recursive mutexes +internal Mutex mutex_alloc(void); +internal void mutex_release(Mutex mutex); +internal void mutex_take(Mutex mutex); +internal void mutex_drop(Mutex mutex); + +//- rjf: reader/writer mutexes +internal RWMutex rw_mutex_alloc(void); +internal void rw_mutex_release(RWMutex mutex); +internal void rw_mutex_take_r(RWMutex mutex); +internal void rw_mutex_drop_r(RWMutex mutex); +internal void rw_mutex_take_w(RWMutex mutex); +internal void rw_mutex_drop_w(RWMutex mutex); + +//- rjf: condition variables +internal CondVar cond_var_alloc(void); +internal void cond_var_release(CondVar cv); +// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout +internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us); +internal B32 cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal B32 cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal void cond_var_signal(CondVar cv); +internal void cond_var_broadcast(CondVar cv); + +//- rjf: cross-process semaphores +internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name); +internal void semaphore_release(Semaphore semaphore); +internal Semaphore semaphore_open(String8 name); +internal void semaphore_close(Semaphore semaphore); +internal B32 semaphore_take(Semaphore semaphore, U64 endt_us); +internal void semaphore_drop(Semaphore semaphore); + +//- rjf: barriers +internal Barrier barrier_alloc(U64 count); +internal void barrier_release(Barrier barrier); +internal void barrier_wait(Barrier barrier); + +//- rjf: scope macros +#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex)) +#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex)) +#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex)) +#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex))) + +#endif // BASE_SYNC_H diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index bc5f359d..1226b994 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -21,7 +21,7 @@ tctx_alloc(void) TCTX *tctx = push_array(arena, TCTX, 1); tctx->arenas[0] = arena; tctx->arenas[1] = arena_alloc(); - tctx->lane_count = 1; + tctx->lane_ctx.lane_count = 1; return tctx; } @@ -76,27 +76,23 @@ tctx_get_scratch(Arena **conflicts, U64 count) //- rjf: lane metadata internal void -tctx_set_lane_info(U64 lane_idx, U64 lane_count) +tctx_set_lane_ctx(LaneCtx lane_ctx) { TCTX *tctx = tctx_selected(); - OS_Handle barrier = os_barrier_alloc(lane_count); - tctx->lane_idx = lane_idx; - tctx->lane_count = lane_count; - tctx->lane_barrier_id = barrier.u64[0]; + tctx->lane_ctx = lane_ctx; } internal void tctx_lane_barrier_wait(void) { TCTX *tctx = tctx_selected(); - OS_Handle barrier = {tctx->lane_barrier_id}; - os_barrier_wait(barrier); + os_barrier_wait(tctx->lane_ctx.barrier); } internal Rng1U64 tctx_lane_idx_range_from_count(U64 count) { - U64 idxes_per_lane = count/lane_count(); + U64 idxes_per_lane = (count + lane_count()-1) / lane_count(); U64 lane_base_idx = lane_idx()*idxes_per_lane; U64 lane_opl_idx = lane_base_idx + idxes_per_lane; U64 lane_opl_idx__clamped = Min(lane_opl_idx, count); diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index c7411644..519f85fb 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -4,6 +4,17 @@ #ifndef BASE_THREAD_CONTEXT_H #define BASE_THREAD_CONTEXT_H +//////////////////////////////// +//~ rjf: Lane Group Context + +typedef struct LaneCtx LaneCtx; +struct LaneCtx +{ + U64 lane_idx; + U64 lane_count; + Barrier barrier; +}; + //////////////////////////////// //~ rjf: Base Per-Thread State Bundle @@ -17,10 +28,8 @@ struct TCTX U8 thread_name[32]; U64 thread_name_size; - // rjf: lane info - U64 lane_idx; - U64 lane_count; - U64 lane_barrier_id; + // rjf: lane context + LaneCtx lane_ctx; // rjf: source location info char *file_name; @@ -42,13 +51,13 @@ internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); #define scratch_end(scratch) temp_end(scratch) //- rjf: lane metadata -internal void tctx_set_lane_info(U64 lane_idx, U64 lane_count); +internal void tctx_set_lane_ctx(LaneCtx lane_ctx); internal void tctx_lane_barrier_wait(void); internal Rng1U64 tctx_lane_idx_range_from_count(U64 count); -#define lane_idx() (tctx_selected()->lane_idx) -#define lane_count() (tctx_selected()->lane_count) +#define lane_idx() (tctx_selected()->lane_ctx.lane_idx) +#define lane_count() (tctx_selected()->lane_ctx.lane_count) #define lane_from_task_idx(idx) ((idx)%lane_count()) -#define lane_thread(idx, count) tctx_set_lane_info((idx), (count)) +#define lane_ctx(ctx) tctx_set_lane_ctx((ctx)) #define lane_sync() tctx_lane_barrier_wait() #define lane_range(count) tctx_lane_idx_range_from_count(count) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index e2b494e4..07f828fb 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -875,7 +875,7 @@ ctrl_entity_ctx_rw_store_alloc(void) store->ctx.hash_slots_count = 1024; store->ctx.hash_slots = push_array(arena, CTRL_EntityHashSlot, store->ctx.hash_slots_count); CTRL_Entity *root = store->ctx.root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, Arch_Null, ctrl_handle_zero(), 0); - CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, arch_from_context(), ctrl_handle_make(CTRL_MachineID_Local, dmn_handle_zero()), 0); + CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, Arch_CURRENT, ctrl_handle_make(CTRL_MachineID_Local, dmn_handle_zero()), 0); Temp scratch = scratch_begin(0, 0); String8 local_machine_name = push_str8f(scratch.arena, "This PC (%S)", os_get_system_info()->machine_name); ctrl_entity_equip_string(store, local_machine, local_machine_name); @@ -1464,7 +1464,7 @@ ctrl_scope_close(CTRL_Scope *scope) { next = t->next; ins_atomic_u64_dec_eval(&t->node->scope_touch_count); - os_condition_variable_broadcast(t->stripe->cv); + cond_var_broadcast(t->stripe->cv); SLLStackPush(ctrl_tctx->free_call_stack_touch, t); } for(U64 idx = 0; idx < scope->call_stack_tree_touch_count; idx += 1) @@ -1473,7 +1473,7 @@ ctrl_scope_close(CTRL_Scope *scope) } if(scope->call_stack_tree_touch_count != 0) { - os_condition_variable_broadcast(ctrl_state->call_stack_tree_cache.cv); + cond_var_broadcast(ctrl_state->call_stack_tree_cache.cv); } SLLStackPush(ctrl_tctx->free_scope, scope); } @@ -1528,8 +1528,8 @@ ctrl_init(void) ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) { - ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); + ctrl_state->process_memory_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); + ctrl_state->process_memory_cache.stripes[idx].cv = cond_var_alloc(); } ctrl_state->thread_reg_cache.slots_count = 1024; ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); @@ -1538,7 +1538,7 @@ ctrl_init(void) for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) { ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); - ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); } ctrl_state->call_stack_cache.slots_count = 1024; ctrl_state->call_stack_cache.slots = push_array(arena, CTRL_CallStackCacheSlot, ctrl_state->call_stack_cache.slots_count); @@ -1547,8 +1547,8 @@ ctrl_init(void) for(U64 idx = 0; idx < ctrl_state->call_stack_cache.stripes_count; idx += 1) { ctrl_state->call_stack_cache.stripes[idx].arena = arena_alloc(); - ctrl_state->call_stack_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ctrl_state->call_stack_cache.stripes[idx].cv = os_condition_variable_alloc(); + ctrl_state->call_stack_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); + ctrl_state->call_stack_cache.stripes[idx].cv = cond_var_alloc(); } ctrl_state->module_image_info_cache.slots_count = 1024; ctrl_state->module_image_info_cache.slots = push_array(arena, CTRL_ModuleImageInfoCacheSlot, ctrl_state->module_image_info_cache.slots_count); @@ -1557,20 +1557,20 @@ ctrl_init(void) for(U64 idx = 0; idx < ctrl_state->module_image_info_cache.stripes_count; idx += 1) { ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc(); - ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); } ctrl_state->call_stack_tree_cache.tree.root = &ctrl_call_stack_tree_node_nil; - ctrl_state->call_stack_tree_cache.cv = os_condition_variable_alloc(); - ctrl_state->call_stack_tree_cache.rw_mutex = os_rw_mutex_alloc(); + ctrl_state->call_stack_tree_cache.cv = cond_var_alloc(); + ctrl_state->call_stack_tree_cache.rw_mutex = rw_mutex_alloc(); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); - ctrl_state->u2c_ring_mutex = os_mutex_alloc(); - ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); + ctrl_state->u2c_ring_mutex = mutex_alloc(); + ctrl_state->u2c_ring_cv = cond_var_alloc(); ctrl_state->c2u_ring_size = KB(64); ctrl_state->c2u_ring_max_string_size = ctrl_state->c2u_ring_size/2; ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); - ctrl_state->c2u_ring_mutex = os_mutex_alloc(); - ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); + ctrl_state->c2u_ring_mutex = mutex_alloc(); + ctrl_state->c2u_ring_cv = cond_var_alloc(); { Temp scratch = scratch_begin(0, 0); String8 user_program_data_path = os_get_process_info()->user_program_data_path; @@ -1580,7 +1580,7 @@ ctrl_init(void) os_write_data_to_file_path(ctrl_state->ctrl_thread_log_path, str8_zero()); scratch_end(scratch); } - ctrl_state->ctrl_thread_entity_ctx_rw_mutex = os_rw_mutex_alloc(); + ctrl_state->ctrl_thread_entity_ctx_rw_mutex = rw_mutex_alloc(); ctrl_state->ctrl_thread_entity_store = ctrl_entity_ctx_rw_store_alloc(); ctrl_state->ctrl_thread_eval_cache = e_cache_alloc(); ctrl_state->ctrl_thread_msg_process_arena = arena_alloc(); @@ -1596,12 +1596,12 @@ ctrl_init(void) } ctrl_state->u2ms_ring_size = KB(64); ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); - ctrl_state->u2ms_ring_mutex = os_mutex_alloc(); - ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); + ctrl_state->u2ms_ring_mutex = mutex_alloc(); + ctrl_state->u2ms_ring_cv = cond_var_alloc(); ctrl_state->u2csb_ring_size = KB(64); ctrl_state->u2csb_ring_base = push_array(arena, U8, ctrl_state->u2csb_ring_size); - ctrl_state->u2csb_ring_mutex = os_mutex_alloc(); - ctrl_state->u2csb_ring_cv = os_condition_variable_alloc(); + ctrl_state->u2csb_ring_mutex = mutex_alloc(); + ctrl_state->u2csb_ring_cv = cond_var_alloc(); ctrl_state->ctrl_thread_log = log_alloc(); ctrl_state->ctrl_thread = os_thread_launch(ctrl_thread__entry_point, 0, 0); } @@ -1726,7 +1726,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 } else { - os_condition_variable_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); + cond_var_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); } } key_is_stale = id_stale; @@ -3482,7 +3482,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 hi } else if(node_working) { - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + cond_var_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); } else { @@ -3560,9 +3560,9 @@ ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us) // rjf: is stale? -> request new calculation if(is_stale && !ins_atomic_u64_eval_cond_assign(&cache->request_count, 1, 0)) { - os_rw_mutex_drop_r(cache->rw_mutex); + rw_mutex_drop_r(cache->rw_mutex); async_push_work(ctrl_call_stack_tree_build_work); - os_rw_mutex_take_r(cache->rw_mutex); + rw_mutex_take_r(cache->rw_mutex); } // rjf: is not stale, or we're out of time? -> grab cached result & touch, exit @@ -3575,7 +3575,7 @@ ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us) } // rjf: wait for new results - os_condition_variable_wait_rw_r(cache->cv, cache->rw_mutex, endt_us); + cond_var_wait_rw_r(cache->cv, cache->rw_mutex, endt_us); } } return result; @@ -3657,11 +3657,11 @@ ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us) { break; } - os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, endt_us); + cond_var_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(ctrl_state->u2c_ring_cv); + cond_var_broadcast(ctrl_state->u2c_ring_cv); } scratch_end(scratch); return good; @@ -3684,9 +3684,9 @@ ctrl_u2c_pop_msgs(Arena *arena) ctrl_state->u2c_ring_read_pos += ring_read(ctrl_state->u2c_ring_base, ctrl_state->u2c_ring_size, ctrl_state->u2c_ring_read_pos, msgs_srlzed_baked.str, size_to_decode); break; } - os_condition_variable_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64); + cond_var_wait(ctrl_state->u2c_ring_cv, ctrl_state->u2c_ring_mutex, max_U64); } - os_condition_variable_broadcast(ctrl_state->u2c_ring_cv); + cond_var_broadcast(ctrl_state->u2c_ring_cv); CTRL_MsgList msgs = ctrl_msg_list_from_serialized_string(arena, msgs_srlzed_baked); scratch_end(scratch); return msgs; @@ -3718,9 +3718,9 @@ ctrl_c2u_push_events(CTRL_EventList *events) ctrl_state->c2u_ring_write_pos += ring_write(ctrl_state->c2u_ring_base, ctrl_state->c2u_ring_size, ctrl_state->c2u_ring_write_pos, event_srlzed.str, event_srlzed.size); break; } - os_condition_variable_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100); + cond_var_wait(ctrl_state->c2u_ring_cv, ctrl_state->c2u_ring_mutex, os_now_microseconds()+100); } - os_condition_variable_broadcast(ctrl_state->c2u_ring_cv); + cond_var_broadcast(ctrl_state->c2u_ring_cv); if(ctrl_state->wakeup_hook != 0) { ctrl_state->wakeup_hook(); @@ -3755,7 +3755,7 @@ ctrl_c2u_pop_events(Arena *arena) break; } } - os_condition_variable_broadcast(ctrl_state->c2u_ring_cv); + cond_var_broadcast(ctrl_state->c2u_ring_cv); scratch_end(scratch); ProfEnd(); return events; @@ -6880,9 +6880,9 @@ ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 break; } if(os_now_microseconds() >= endt_us) {break;} - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); + cond_var_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); + cond_var_broadcast(ctrl_state->u2ms_ring_cv); return good; } @@ -6900,9 +6900,9 @@ ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_va ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); break; } - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); + cond_var_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); + cond_var_broadcast(ctrl_state->u2ms_ring_cv); } //- rjf: entry point @@ -7068,7 +7068,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) } //- rjf: broadcast changes - os_condition_variable_broadcast(process_stripe->cv); + cond_var_broadcast(process_stripe->cv); if(!u128_match(u128_zero(), hash)) { if(ctrl_state->wakeup_hook != 0) @@ -7104,11 +7104,11 @@ ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us) { break; } - os_condition_variable_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, endt_us); + cond_var_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(ctrl_state->u2csb_ring_cv); + cond_var_broadcast(ctrl_state->u2csb_ring_cv); } return good; } @@ -7124,9 +7124,9 @@ ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread) ctrl_state->u2csb_ring_read_pos += ring_read_struct(ctrl_state->u2csb_ring_base, ctrl_state->u2csb_ring_size, ctrl_state->u2csb_ring_read_pos, out_thread); break; } - os_condition_variable_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, max_U64); + cond_var_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, max_U64); } - os_condition_variable_broadcast(ctrl_state->u2csb_ring_cv); + cond_var_broadcast(ctrl_state->u2csb_ring_cv); } //- rjf: entry point @@ -7296,7 +7296,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) // rjf: found, not committed? -> wait & retry if(found && !committed) { - os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+10); + cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+10); } } } @@ -7318,7 +7318,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) } //- rjf: broadcast update - os_condition_variable_broadcast(stripe->cv); + cond_var_broadcast(stripe->cv); if(ctrl_state->wakeup_hook != 0) { ctrl_state->wakeup_hook(); @@ -7443,10 +7443,10 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) cache->request_count -= 1; break; } - os_condition_variable_wait_rw_w(cache->cv, cache->rw_mutex, max_U64); + cond_var_wait_rw_w(cache->cv, cache->rw_mutex, max_U64); } } - os_condition_variable_broadcast(cache->cv); + cond_var_broadcast(cache->cv); //- rjf: release old arena if(old_arena) diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b5d6e612..c9a996d7 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -585,8 +585,8 @@ struct CTRL_ProcessMemoryCacheSlot typedef struct CTRL_ProcessMemoryCacheStripe CTRL_ProcessMemoryCacheStripe; struct CTRL_ProcessMemoryCacheStripe { - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; typedef struct CTRL_ProcessMemoryCache CTRL_ProcessMemoryCache; @@ -634,7 +634,7 @@ typedef struct CTRL_ThreadRegCacheStripe CTRL_ThreadRegCacheStripe; struct CTRL_ThreadRegCacheStripe { Arena *arena; - OS_Handle rw_mutex; + RWMutex rw_mutex; }; typedef struct CTRL_ThreadRegCache CTRL_ThreadRegCache; @@ -680,8 +680,8 @@ typedef struct CTRL_CallStackCacheStripe CTRL_CallStackCacheStripe; struct CTRL_CallStackCacheStripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; typedef struct CTRL_CallStackCache CTRL_CallStackCache; @@ -723,7 +723,7 @@ typedef struct CTRL_ModuleImageInfoCacheStripe CTRL_ModuleImageInfoCacheStripe; struct CTRL_ModuleImageInfoCacheStripe { Arena *arena; - OS_Handle rw_mutex; + RWMutex rw_mutex; }; typedef struct CTRL_ModuleImageInfoCache CTRL_ModuleImageInfoCache; @@ -743,8 +743,8 @@ struct CTRL_CallStackTreeCache { Arena *arena; CTRL_CallStackTree tree; - OS_Handle cv; - OS_Handle rw_mutex; + CondVar cv; + RWMutex rw_mutex; U64 reg_gen; U64 mem_gen; U64 scope_touch_count; @@ -855,8 +855,8 @@ struct CTRL_State U8 *u2c_ring_base; U64 u2c_ring_write_pos; U64 u2c_ring_read_pos; - OS_Handle u2c_ring_mutex; - OS_Handle u2c_ring_cv; + Mutex u2c_ring_mutex; + CondVar u2c_ring_cv; // rjf: ctrl -> user event ring buffer U64 c2u_ring_size; @@ -864,15 +864,15 @@ struct CTRL_State U8 *c2u_ring_base; U64 c2u_ring_write_pos; U64 c2u_ring_read_pos; - OS_Handle c2u_ring_mutex; - OS_Handle c2u_ring_cv; + Mutex c2u_ring_mutex; + CondVar c2u_ring_cv; // rjf: ctrl thread state U64 ctrl_thread_run_state; String8 ctrl_thread_log_path; OS_Handle ctrl_thread; Log *ctrl_thread_log; - OS_Handle ctrl_thread_entity_ctx_rw_mutex; + RWMutex ctrl_thread_entity_ctx_rw_mutex; CTRL_EntityCtxRWStore *ctrl_thread_entity_store; E_Cache *ctrl_thread_eval_cache; Arena *ctrl_thread_msg_process_arena; @@ -896,16 +896,16 @@ struct CTRL_State U8 *u2ms_ring_base; U64 u2ms_ring_write_pos; U64 u2ms_ring_read_pos; - OS_Handle u2ms_ring_mutex; - OS_Handle u2ms_ring_cv; + Mutex u2ms_ring_mutex; + CondVar u2ms_ring_cv; // rjf: user -> call stack builder ring buffer U64 u2csb_ring_size; U8 *u2csb_ring_base; U64 u2csb_ring_write_pos; U64 u2csb_ring_read_pos; - OS_Handle u2csb_ring_mutex; - OS_Handle u2csb_ring_cv; + Mutex u2csb_ring_mutex; + CondVar u2csb_ring_cv; }; //////////////////////////////// diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 39cb7711..1fb6dcc5 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -270,13 +270,13 @@ dasm_init(void) for(U64 idx = 0; idx < dasm_shared->stripes_count; idx += 1) { dasm_shared->stripes[idx].arena = arena_alloc(); - dasm_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dasm_shared->stripes[idx].cv = os_condition_variable_alloc(); + dasm_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + dasm_shared->stripes[idx].cv = cond_var_alloc(); } dasm_shared->u2p_ring_size = KB(64); dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size); - dasm_shared->u2p_ring_cv = os_condition_variable_alloc(); - dasm_shared->u2p_ring_mutex = os_mutex_alloc(); + dasm_shared->u2p_ring_cv = cond_var_alloc(); + dasm_shared->u2p_ring_mutex = mutex_alloc(); dasm_shared->evictor_detector_thread = os_thread_launch(dasm_evictor_detector_thread__entry_point, 0, 0); } @@ -473,11 +473,11 @@ dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us) { break; } - os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, endt_us); + cond_var_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(dasm_shared->u2p_ring_cv); + cond_var_broadcast(dasm_shared->u2p_ring_cv); } return good; } @@ -503,9 +503,9 @@ dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Param dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp); break; } - os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64); + cond_var_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64); } - os_condition_variable_broadcast(dasm_shared->u2p_ring_cv); + cond_var_broadcast(dasm_shared->u2p_ring_cv); } ASYNC_WORK_DEF(dasm_parse_work) diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 521e359a..5423ddb2 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -207,8 +207,8 @@ typedef struct DASM_Stripe DASM_Stripe; struct DASM_Stripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; DASM_Node *free_node; }; @@ -259,8 +259,8 @@ struct DASM_Shared U8 *u2p_ring_base; U64 u2p_ring_write_pos; U64 u2p_ring_read_pos; - OS_Handle u2p_ring_cv; - OS_Handle u2p_ring_mutex; + CondVar u2p_ring_cv; + Mutex u2p_ring_mutex; // rjf: evictor/detector thread OS_Handle evictor_detector_thread; diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 4fd6798d..75609497 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -209,8 +209,8 @@ di_init(void) for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) { di_shared->stripes[idx].arena = arena_alloc(); - di_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - di_shared->stripes[idx].cv = os_condition_variable_alloc(); + di_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + di_shared->stripes[idx].cv = cond_var_alloc(); } di_shared->search_slots_count = 512; di_shared->search_slots = push_array(arena, DI_SearchSlot, di_shared->search_slots_count); @@ -219,23 +219,23 @@ di_init(void) for(U64 idx = 0; idx < di_shared->search_stripes_count; idx += 1) { di_shared->search_stripes[idx].arena = arena_alloc(); - di_shared->search_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - di_shared->search_stripes[idx].cv = os_condition_variable_alloc(); + di_shared->search_stripes[idx].rw_mutex = rw_mutex_alloc(); + di_shared->search_stripes[idx].cv = cond_var_alloc(); } - di_shared->u2p_ring_mutex = os_mutex_alloc(); - di_shared->u2p_ring_cv = os_condition_variable_alloc(); + di_shared->u2p_ring_mutex = mutex_alloc(); + di_shared->u2p_ring_cv = cond_var_alloc(); di_shared->u2p_ring_size = KB(64); di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); - di_shared->p2u_ring_mutex = os_mutex_alloc(); - di_shared->p2u_ring_cv = os_condition_variable_alloc(); + di_shared->p2u_ring_mutex = mutex_alloc(); + di_shared->p2u_ring_cv = cond_var_alloc(); di_shared->p2u_ring_size = KB(64); di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); di_shared->search_threads_count = 1; di_shared->search_threads = push_array(arena, DI_SearchThread, di_shared->search_threads_count); for EachIndex(idx, di_shared->search_threads_count) { - di_shared->search_threads[idx].ring_mutex = os_mutex_alloc(); - di_shared->search_threads[idx].ring_cv = os_condition_variable_alloc(); + di_shared->search_threads[idx].ring_mutex = mutex_alloc(); + di_shared->search_threads[idx].ring_cv = cond_var_alloc(); di_shared->search_threads[idx].ring_size = KB(64); di_shared->search_threads[idx].ring_base = push_array_no_zero(arena, U8, di_shared->search_threads[idx].ring_size); di_shared->search_threads[idx].thread = os_thread_launch(di_search_thread__entry_point, (void *)idx, 0); @@ -279,12 +279,12 @@ di_scope_close(DI_Scope *scope) if(t->node != 0) { ins_atomic_u64_dec_eval(&t->node->touch_count); - os_condition_variable_broadcast(t->stripe->cv); + cond_var_broadcast(t->stripe->cv); } if(t->search_node != 0) { ins_atomic_u64_dec_eval(&t->search_node->scope_refcount); - os_condition_variable_broadcast(t->search_stripe->cv); + cond_var_broadcast(t->search_stripe->cv); } SLLStackPush(di_tctx->free_touch, t); } @@ -343,7 +343,7 @@ di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key) { ProfBeginFunction(); DI_Node *node = 0; - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + StringMatchFlags match_flags = path_match_flags_from_os(OperatingSystem_CURRENT); U64 most_recent_timestamp = max_U64; for(DI_Node *n = slot->first; n != 0; n = n->next) { @@ -505,7 +505,7 @@ di_open(DI_Key *key) { di_u2p_enqueue_key(key, max_U64); ins_atomic_u64_eval_assign(&node->is_working, 1); - DeferLoop(os_rw_mutex_drop_w(stripe->rw_mutex), os_rw_mutex_take_w(stripe->rw_mutex)) + DeferLoop(rw_mutex_drop_w(stripe->rw_mutex), rw_mutex_take_w(stripe->rw_mutex)) { async_push_work(di_parse_work); } @@ -566,7 +566,7 @@ di_close(DI_Key *key) } //- rjf: wait for touch count / working marker to go to 0 - os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64); + cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64); } } } @@ -625,7 +625,7 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us) ProfScope("ask for parse") { ins_atomic_u64_eval_assign(&node->is_working, 1); - DeferLoop(os_rw_mutex_drop_r(stripe->rw_mutex), os_rw_mutex_take_r(stripe->rw_mutex)) + DeferLoop(rw_mutex_drop_r(stripe->rw_mutex), rw_mutex_take_r(stripe->rw_mutex)) { async_push_work(di_parse_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); } @@ -640,7 +640,7 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us) //- rjf: wait on this stripe { - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + cond_var_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); } } scratch_end(scratch); @@ -740,7 +740,7 @@ di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams } // rjf: no results, but have time to wait -> wait - os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, endt_us); + cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, endt_us); } } return items; @@ -770,11 +770,11 @@ di_u2p_enqueue_key(DI_Key *key, U64 endt_us) { break; } - os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); + cond_var_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); } if(sent) { - os_condition_variable_broadcast(di_shared->u2p_ring_cv); + cond_var_broadcast(di_shared->u2p_ring_cv); } return sent; } @@ -793,9 +793,9 @@ di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_key->path.str, out_key->path.size); break; } - os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); + cond_var_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); } - os_condition_variable_broadcast(di_shared->u2p_ring_cv); + cond_var_broadcast(di_shared->u2p_ring_cv); } internal void @@ -813,9 +813,9 @@ di_p2u_push_event(DI_Event *event) di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); break; } - os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); + cond_var_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); } - os_condition_variable_broadcast(di_shared->p2u_ring_cv); + cond_var_broadcast(di_shared->p2u_ring_cv); } internal DI_EventList @@ -839,9 +839,9 @@ di_p2u_pop_events(Arena *arena, U64 endt_us) { break; } - os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); + cond_var_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); } - os_condition_variable_broadcast(di_shared->p2u_ring_cv); + cond_var_broadcast(di_shared->p2u_ring_cv); return events; } @@ -1136,7 +1136,7 @@ ASYNC_WORK_DEF(di_parse_work) os_file_close(file); } } - os_condition_variable_broadcast(stripe->cv); + cond_var_broadcast(stripe->cv); scratch_end(scratch); ProfEnd(); @@ -1167,11 +1167,11 @@ di_u2s_enqueue_req(U128 key, U64 endt_us) { break; } - os_condition_variable_wait(thread->ring_cv, thread->ring_mutex, endt_us); + cond_var_wait(thread->ring_cv, thread->ring_mutex, endt_us); } if(result) { - os_condition_variable_broadcast(thread->ring_cv); + cond_var_broadcast(thread->ring_cv); } return result; } @@ -1189,9 +1189,9 @@ di_u2s_dequeue_req(U64 thread_idx) thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &key); break; } - os_condition_variable_wait(thread->ring_cv, thread->ring_mutex, max_U64); + cond_var_wait(thread->ring_cv, thread->ring_mutex, max_U64); } - os_condition_variable_broadcast(thread->ring_cv); + cond_var_broadcast(thread->ring_cv); return key; } @@ -1541,7 +1541,7 @@ di_search_thread__entry_point(void *p) } if(found && !done) { - os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+1000); + cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+1000); } } } @@ -1610,17 +1610,17 @@ di_match_store_alloc(void) store->gen_arenas[idx] = arena_alloc(); } store->params_arena = arena_alloc(); - store->params_rw_mutex = os_rw_mutex_alloc(); + store->params_rw_mutex = rw_mutex_alloc(); store->match_name_slots_count = 4096; store->match_name_slots = push_array(arena, DI_MatchNameSlot, store->match_name_slots_count); - store->match_rw_mutex = os_rw_mutex_alloc(); - store->match_cv = os_condition_variable_alloc(); - store->u2m_ring_cv = os_condition_variable_alloc(); - store->u2m_ring_mutex = os_mutex_alloc(); + store->match_rw_mutex = rw_mutex_alloc(); + store->match_cv = cond_var_alloc(); + store->u2m_ring_cv = cond_var_alloc(); + store->u2m_ring_mutex = mutex_alloc(); store->u2m_ring_size = KB(2); store->u2m_ring_base = push_array_no_zero(arena, U8, store->u2m_ring_size); - store->m2u_ring_cv = os_condition_variable_alloc(); - store->m2u_ring_mutex = os_mutex_alloc(); + store->m2u_ring_cv = cond_var_alloc(); + store->m2u_ring_mutex = mutex_alloc(); store->m2u_ring_size = KB(2); store->m2u_ring_base = push_array_no_zero(arena, U8, store->m2u_ring_size); return store; @@ -1756,11 +1756,11 @@ di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us) { break; } - os_condition_variable_wait(store->u2m_ring_cv, store->u2m_ring_mutex, endt_us); + cond_var_wait(store->u2m_ring_cv, store->u2m_ring_mutex, endt_us); } if(sent) { - os_condition_variable_broadcast(store->u2m_ring_cv); + cond_var_broadcast(store->u2m_ring_cv); async_push_work(di_match_work, .input = store, .priority = ASYNC_Priority_Low, .completion_counter = &node->cmp_count); node->req_params_hash = store->params_hash; node->req_count += 1; @@ -1780,7 +1780,7 @@ di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us) { break; } - os_condition_variable_wait_rw_r(store->match_cv, store->match_rw_mutex, endt_us); + cond_var_wait_rw_r(store->match_cv, store->match_rw_mutex, endt_us); } } @@ -1817,9 +1817,9 @@ ASYNC_WORK_DEF(di_match_work) store->u2m_ring_read_pos += ring_read(store->u2m_ring_base, store->u2m_ring_size, store->u2m_ring_read_pos, name.str, name.size); break; } - os_condition_variable_wait(store->u2m_ring_cv, store->u2m_ring_mutex, max_U64); + cond_var_wait(store->u2m_ring_cv, store->u2m_ring_mutex, max_U64); } - os_condition_variable_broadcast(store->u2m_ring_cv); + cond_var_broadcast(store->u2m_ring_cv); //- rjf: read parameters U64 params_hash = 0; diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 20699773..48545d26 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -121,8 +121,8 @@ struct DI_Stripe Arena *arena; DI_Node *free_node; DI_StringChunkNode *free_string_chunks[8]; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// @@ -206,8 +206,8 @@ struct DI_SearchStripe { Arena *arena; DI_SearchNode *free_node; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// @@ -249,8 +249,8 @@ typedef struct DI_SearchThread DI_SearchThread; struct DI_SearchThread { OS_Handle thread; - OS_Handle ring_mutex; - OS_Handle ring_cv; + Mutex ring_mutex; + CondVar ring_cv; U64 ring_size; U8 *ring_base; U64 ring_write_pos; @@ -315,7 +315,7 @@ struct DI_MatchStore // rjf: parameters Arena *params_arena; - OS_Handle params_rw_mutex; + RWMutex params_rw_mutex; U64 params_hash; DI_KeyArray params_keys; @@ -327,20 +327,20 @@ struct DI_MatchStore DI_MatchNameNode *first_lru_match_name; DI_MatchNameNode *last_lru_match_name; U64 active_match_name_nodes_count; - OS_Handle match_rw_mutex; - OS_Handle match_cv; + RWMutex match_rw_mutex; + CondVar match_cv; // rjf: user -> match work ring buffer - OS_Handle u2m_ring_cv; - OS_Handle u2m_ring_mutex; + CondVar u2m_ring_cv; + Mutex u2m_ring_mutex; U64 u2m_ring_size; U8 *u2m_ring_base; U64 u2m_ring_write_pos; U64 u2m_ring_read_pos; // rjf: match -> user work ring buffer - OS_Handle m2u_ring_cv; - OS_Handle m2u_ring_mutex; + CondVar m2u_ring_cv; + Mutex m2u_ring_mutex; U64 m2u_ring_size; U8 *m2u_ring_base; U64 m2u_ring_write_pos; @@ -368,16 +368,16 @@ struct DI_Shared DI_SearchStripe *search_stripes; // rjf: user -> parse ring - OS_Handle u2p_ring_mutex; - OS_Handle u2p_ring_cv; + Mutex u2p_ring_mutex; + CondVar u2p_ring_cv; U64 u2p_ring_size; U8 *u2p_ring_base; U64 u2p_ring_write_pos; U64 u2p_ring_read_pos; // rjf: parse -> user event ring - OS_Handle p2u_ring_mutex; - OS_Handle p2u_ring_cv; + Mutex p2u_ring_mutex; + CondVar p2u_ring_cv; U64 p2u_ring_size; U8 *p2u_ring_base; U64 p2u_ring_write_pos; diff --git a/src/demon/linux/demon_core_linux.c b/src/demon/linux/demon_core_linux.c index 206bb56b..4fed12a3 100644 --- a/src/demon/linux/demon_core_linux.c +++ b/src/demon/linux/demon_core_linux.c @@ -905,7 +905,7 @@ dmn_init(void) dmn_lnx_state->entities_arena = arena_alloc(.reserve_size = GB(32), .commit_size = KB(64), .flags = ArenaFlag_NoChain); dmn_lnx_state->entities_base = push_array(dmn_lnx_state->entities_arena, DMN_LNX_Entity, 0); dmn_lnx_entity_alloc(&dmn_lnx_nil_entity, DMN_LNX_EntityKind_Root); - dmn_lnx_state->access_mutex = os_mutex_alloc(); + dmn_lnx_state->access_mutex = mutex_alloc(); } //////////////////////////////// @@ -1649,7 +1649,7 @@ dmn_access_open(void) } else { - os_mutex_take(dmn_lnx_state->access_mutex); + mutex_take(dmn_lnx_state->access_mutex); result = !dmn_lnx_state->access_run_state; } return result; @@ -1660,7 +1660,7 @@ dmn_access_close(void) { if(!dmn_lnx_ctrl_thread) { - os_mutex_drop(dmn_lnx_state->access_mutex); + mutex_drop(dmn_lnx_state->access_mutex); } } diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index 5c23ba35..a4ee8974 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -1142,7 +1142,7 @@ dmn_init(void) Arena *arena = arena_alloc(); dmn_w32_shared = push_array(arena, DMN_W32_Shared, 1); dmn_w32_shared->arena = arena; - dmn_w32_shared->access_mutex = os_mutex_alloc(); + dmn_w32_shared->access_mutex = mutex_alloc(); dmn_w32_shared->detach_arena = arena_alloc(); dmn_w32_shared->entities_arena = arena_alloc(.reserve_size = GB(8), .commit_size = KB(64)); dmn_w32_shared->entities_base = dmn_w32_entity_alloc(&dmn_w32_entity_nil, DMN_W32_EntityKind_Root, 0); @@ -2977,7 +2977,7 @@ dmn_access_open(void) } else { - os_mutex_take(dmn_w32_shared->access_mutex); + mutex_take(dmn_w32_shared->access_mutex); result = !dmn_w32_shared->access_run_state; } return result; @@ -2988,7 +2988,7 @@ dmn_access_close(void) { if(!dmn_w32_ctrl_thread) { - os_mutex_drop(dmn_w32_shared->access_mutex); + mutex_drop(dmn_w32_shared->access_mutex); } } diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h index b06f1d85..01aa3523 100644 --- a/src/demon/win32/demon_core_win32.h +++ b/src/demon/win32/demon_core_win32.h @@ -197,7 +197,7 @@ struct DMN_W32_Shared String8List env_strings; // rjf: access locking mechanism - OS_Handle access_mutex; + Mutex access_mutex; B32 access_run_state; // rjf: detaching info diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 6d7a8e48..7d208b95 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -514,7 +514,7 @@ e_type_key_cons_base(Type *type) if(type->flags & TypeFlag_IsPlainText){ flags |= E_TypeFlag_IsPlainText; } if(type->flags & TypeFlag_IsCodeText) { flags |= E_TypeFlag_IsCodeText; } if(type->flags & TypeFlag_IsPathText) { flags |= E_TypeFlag_IsPathText; } - result = e_type_key_cons_ptr(arch_from_context(), direct_type, 1, flags); + result = e_type_key_cons_ptr(Arch_CURRENT, direct_type, 1, flags); }break; case TypeKind_Array: { @@ -531,7 +531,7 @@ e_type_key_cons_base(Type *type) e_member_list_push_new(scratch.arena, &members, .name = type->members[idx].name, .off = type->members[idx].value, .type_key = member_type_key); } E_MemberArray members_array = e_member_array_from_list(scratch.arena, &members); - result = e_type_key_cons(.arch = arch_from_context(), + result = e_type_key_cons(.arch = Arch_CURRENT, .kind = E_TypeKind_Struct, .name = type->name, .members = members_array.v, diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 959ce166..0fec0e2c 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -49,13 +49,13 @@ fs_init(void) for(U64 idx = 0; idx < fs_shared->stripes_count; idx += 1) { fs_shared->stripes[idx].arena = arena_alloc(); - fs_shared->stripes[idx].cv = os_condition_variable_alloc(); - fs_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + fs_shared->stripes[idx].cv = cond_var_alloc(); + fs_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); } fs_shared->u2s_ring_size = KB(64); fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size); - fs_shared->u2s_ring_cv = os_condition_variable_alloc(); - fs_shared->u2s_ring_mutex = os_mutex_alloc(); + fs_shared->u2s_ring_cv = cond_var_alloc(); + fs_shared->u2s_ring_mutex = mutex_alloc(); fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0); } @@ -177,7 +177,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) fs_u2s_enqueue_req(key, range, path, endt_us)) { ins_atomic_u64_inc_eval(&range_node->working_count); - DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex)) + DeferLoop(rw_mutex_drop_w(path_stripe->rw_mutex), rw_mutex_take_w(path_stripe->rw_mutex)) { async_push_work(fs_stream_work, .working_counter = &range_node->working_count); } @@ -187,7 +187,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) B32 have_results = !u128_match(hs_hash_from_key(key, 0), u128_zero()); if(!have_results && os_now_microseconds() < endt_us) { - os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us); + cond_var_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us); } else { @@ -267,11 +267,11 @@ fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us) fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size); break; } - os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us); + cond_var_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us); } if(result) { - os_condition_variable_broadcast(fs_shared->u2s_ring_cv); + cond_var_broadcast(fs_shared->u2s_ring_cv); } return result; } @@ -292,9 +292,9 @@ fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *p fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size); break; } - os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64); + cond_var_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64); } - os_condition_variable_broadcast(fs_shared->u2s_ring_cv); + cond_var_broadcast(fs_shared->u2s_ring_cv); } ASYNC_WORK_DEF(fs_stream_work) @@ -379,7 +379,7 @@ ASYNC_WORK_DEF(fs_stream_work) node->props = post_props; } } - os_condition_variable_broadcast(path_stripe->cv); + cond_var_broadcast(path_stripe->cv); ProfEnd(); scratch_end(scratch); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index e4c06ba6..b3b4aac2 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -50,8 +50,8 @@ typedef struct FS_Stripe FS_Stripe; struct FS_Stripe { Arena *arena; - OS_Handle cv; - OS_Handle rw_mutex; + CondVar cv; + RWMutex rw_mutex; }; //////////////////////////////// @@ -74,8 +74,8 @@ struct FS_Shared U8 *u2s_ring_base; U64 u2s_ring_write_pos; U64 u2s_ring_read_pos; - OS_Handle u2s_ring_cv; - OS_Handle u2s_ring_mutex; + CondVar u2s_ring_cv; + Mutex u2s_ring_mutex; // rjf: change detector threads OS_Handle detector_thread; diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 298888b7..4aced2ba 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -21,13 +21,13 @@ geo_init(void) for(U64 idx = 0; idx < geo_shared->stripes_count; idx += 1) { geo_shared->stripes[idx].arena = arena_alloc(); - geo_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - geo_shared->stripes[idx].cv = os_condition_variable_alloc(); + geo_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + geo_shared->stripes[idx].cv = cond_var_alloc(); } geo_shared->u2x_ring_size = KB(64); geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); - geo_shared->u2x_ring_cv = os_condition_variable_alloc(); - geo_shared->u2x_ring_mutex = os_mutex_alloc(); + geo_shared->u2x_ring_cv = cond_var_alloc(); + geo_shared->u2x_ring_mutex = mutex_alloc(); geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0); } @@ -217,11 +217,11 @@ geo_u2x_enqueue_req(U128 hash, U64 endt_us) { break; } - os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us); + cond_var_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(geo_shared->u2x_ring_cv); + cond_var_broadcast(geo_shared->u2x_ring_cv); } return good; } @@ -237,9 +237,9 @@ geo_u2x_dequeue_req(U128 *hash_out) geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out); break; } - os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64); + cond_var_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64); } - os_condition_variable_broadcast(geo_shared->u2x_ring_cv); + cond_var_broadcast(geo_shared->u2x_ring_cv); } ASYNC_WORK_DEF(geo_xfer_work) diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index 7ba1cc99..1d3f0bf3 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -32,8 +32,8 @@ typedef struct GEO_Stripe GEO_Stripe; struct GEO_Stripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// @@ -84,8 +84,8 @@ struct GEO_Shared U8 *u2x_ring_base; U64 u2x_ring_write_pos; U64 u2x_ring_read_pos; - OS_Handle u2x_ring_cv; - OS_Handle u2x_ring_mutex; + CondVar u2x_ring_cv; + Mutex u2x_ring_mutex; // rjf: evictor thread OS_Handle evictor_thread; diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 16b64186..e3d934e5 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -76,8 +76,8 @@ hs_init(void) { HS_Stripe *stripe = &hs_shared->stripes[idx]; stripe->arena = arena_alloc(); - stripe->rw_mutex = os_rw_mutex_alloc(); - stripe->cv = os_condition_variable_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); } hs_shared->key_slots_count = 4096; hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_get_system_info()->logical_processor_count); @@ -88,8 +88,8 @@ hs_init(void) { HS_Stripe *stripe = &hs_shared->key_stripes[idx]; stripe->arena = arena_alloc(); - stripe->rw_mutex = os_rw_mutex_alloc(); - stripe->cv = os_condition_variable_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); } hs_shared->root_slots_count = 4096; hs_shared->root_stripes_count = Min(hs_shared->root_slots_count, os_get_system_info()->logical_processor_count); @@ -100,8 +100,8 @@ hs_init(void) { HS_Stripe *stripe = &hs_shared->root_stripes[idx]; stripe->arena = arena_alloc(); - stripe->rw_mutex = os_rw_mutex_alloc(); - stripe->cv = os_condition_variable_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); } hs_shared->evictor_thread = os_thread_launch(hs_evictor_thread__entry_point, 0, 0); } diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index f193b3b1..6bde1a44 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -145,8 +145,8 @@ typedef struct HS_Stripe HS_Stripe; struct HS_Stripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index f53585c7..e052d5d5 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -20,7 +20,7 @@ mtx_init(void) for(U64 idx = 0; idx < mtx_shared->stripes_count; idx += 1) { mtx_shared->stripes[idx].arena = arena_alloc(); - mtx_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + mtx_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); } mtx_shared->mut_threads_count = Min(os_get_system_info()->logical_processor_count, 4); mtx_shared->mut_threads = push_array(arena, MTX_MutThread, mtx_shared->mut_threads_count); @@ -28,8 +28,8 @@ mtx_init(void) { mtx_shared->mut_threads[idx].ring_size = KB(64); mtx_shared->mut_threads[idx].ring_base = push_array_no_zero(arena, U8, mtx_shared->mut_threads[idx].ring_size); - mtx_shared->mut_threads[idx].cv = os_condition_variable_alloc(); - mtx_shared->mut_threads[idx].mutex = os_mutex_alloc(); + mtx_shared->mut_threads[idx].cv = cond_var_alloc(); + mtx_shared->mut_threads[idx].mutex = mutex_alloc(); mtx_shared->mut_threads[idx].thread = os_thread_launch(mtx_mut_thread__entry_point, &mtx_shared->mut_threads[idx], 0); } } @@ -65,9 +65,9 @@ mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) thread->ring_write_pos += ring_write(thread->ring_base, thread->ring_size, thread->ring_write_pos, op.replace.str, op.replace.size); break; } - os_condition_variable_wait(thread->cv, thread->mutex, max_U64); + cond_var_wait(thread->cv, thread->mutex, max_U64); } - os_condition_variable_broadcast(thread->cv); + cond_var_broadcast(thread->cv); } internal void @@ -85,9 +85,9 @@ mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_ thread->ring_read_pos += ring_read(thread->ring_base, thread->ring_size, thread->ring_read_pos, op_out->replace.str, op_out->replace.size); break; } - os_condition_variable_wait(thread->cv, thread->mutex, max_U64); + cond_var_wait(thread->cv, thread->mutex, max_U64); } - os_condition_variable_broadcast(thread->cv); + cond_var_broadcast(thread->cv); } internal void diff --git a/src/mutable_text/mutable_text.h b/src/mutable_text/mutable_text.h index bb6826ac..2f985e85 100644 --- a/src/mutable_text/mutable_text.h +++ b/src/mutable_text/mutable_text.h @@ -27,7 +27,7 @@ struct MTX_Stripe { Arena *arena; MTX_Node *free_node; - OS_Handle rw_mutex; + RWMutex rw_mutex; }; //////////////////////////////// @@ -47,8 +47,8 @@ struct MTX_MutThread U8 *ring_base; U64 ring_read_pos; U64 ring_write_pos; - OS_Handle cv; - OS_Handle mutex; + CondVar cv; + Mutex mutex; OS_Handle thread; }; diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index a0b8c36d..94210eab 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -945,7 +945,7 @@ os_rw_mutex_drop_w(OS_Handle rw_mutex) //- rjf: condition variables internal OS_Handle -os_condition_variable_alloc(void) +os_cond_var_alloc(void) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_ConditionVariable); int init_result = pthread_cond_init(&entity->cv.cond_handle, 0); @@ -970,7 +970,7 @@ os_condition_variable_alloc(void) } internal void -os_condition_variable_release(OS_Handle cv) +os_cond_var_release(OS_Handle cv) { if(os_handle_match(cv, os_handle_zero())) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)cv.u64[0]; @@ -980,7 +980,7 @@ os_condition_variable_release(OS_Handle cv) } internal B32 -os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) +os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) { if(os_handle_match(cv, os_handle_zero())) { return 0; } if(os_handle_match(mutex, os_handle_zero())) { return 0; } @@ -995,7 +995,7 @@ os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) } internal B32 -os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +os_cond_var_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack // this together, but this would probably just be a lot better if we just @@ -1031,7 +1031,7 @@ os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) } internal B32 -os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +os_cond_var_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack // this together, but this would probably just be a lot better if we just @@ -1067,7 +1067,7 @@ os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) } internal void -os_condition_variable_signal(OS_Handle cv) +os_cond_var_signal(OS_Handle cv) { if(os_handle_match(cv, os_handle_zero())) { return; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; @@ -1075,7 +1075,7 @@ os_condition_variable_signal(OS_Handle cv) } internal void -os_condition_variable_broadcast(OS_Handle cv) +os_cond_var_broadcast(OS_Handle cv) { if(os_handle_match(cv, os_handle_zero())) { return; } OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; diff --git a/src/os/core/linux/os_core_linux_old.c b/src/os/core/linux/os_core_linux_old.c index 91a457b0..3e3ae763 100644 --- a/src/os/core/linux/os_core_linux_old.c +++ b/src/os/core/linux/os_core_linux_old.c @@ -1501,7 +1501,7 @@ os_rw_mutex_drop_w_(OS_Handle mutex) //- rjf: condition variables internal OS_Handle -os_condition_variable_alloc(void){ +os_cond_var_alloc(void){ // entity LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_ConditionVariable); @@ -1521,7 +1521,7 @@ os_condition_variable_alloc(void){ } internal void -os_condition_variable_release(OS_Handle cv){ +os_cond_var_release(OS_Handle cv){ LNX_Entity *entity = (LNX_Entity*)PtrFromInt(cv.id); pthread_cond_destroy(&entity->cond); lnx_free_entity(entity); diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 158c5185..7737602c 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -270,41 +270,41 @@ internal void os_thread_detach(OS_Handle handle); //~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) //- rjf: recursive mutexes -internal OS_Handle os_mutex_alloc(void); -internal void os_mutex_release(OS_Handle mutex); -internal void os_mutex_take(OS_Handle mutex); -internal void os_mutex_drop(OS_Handle mutex); +internal Mutex os_mutex_alloc(void); +internal void os_mutex_release(Mutex mutex); +internal void os_mutex_take(Mutex mutex); +internal void os_mutex_drop(Mutex mutex); //- rjf: reader/writer mutexes -internal OS_Handle os_rw_mutex_alloc(void); -internal void os_rw_mutex_release(OS_Handle rw_mutex); -internal void os_rw_mutex_take_r(OS_Handle mutex); -internal void os_rw_mutex_drop_r(OS_Handle mutex); -internal void os_rw_mutex_take_w(OS_Handle mutex); -internal void os_rw_mutex_drop_w(OS_Handle mutex); +internal RWMutex os_rw_mutex_alloc(void); +internal void os_rw_mutex_release(RWMutex mutex); +internal void os_rw_mutex_take_r(RWMutex mutex); +internal void os_rw_mutex_drop_r(RWMutex mutex); +internal void os_rw_mutex_take_w(RWMutex mutex); +internal void os_rw_mutex_drop_w(RWMutex mutex); //- rjf: condition variables -internal OS_Handle os_condition_variable_alloc(void); -internal void os_condition_variable_release(OS_Handle cv); +internal CondVar os_cond_var_alloc(void); +internal void os_cond_var_release(CondVar cv); // returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout -internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us); -internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); -internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); -internal void os_condition_variable_signal(OS_Handle cv); -internal void os_condition_variable_broadcast(OS_Handle cv); +internal B32 os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us); +internal B32 os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal B32 os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal void os_cond_var_signal(CondVar cv); +internal void os_cond_var_broadcast(CondVar cv); //- rjf: cross-process semaphores -internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name); -internal void os_semaphore_release(OS_Handle semaphore); -internal OS_Handle os_semaphore_open(String8 name); -internal void os_semaphore_close(OS_Handle semaphore); -internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us); -internal void os_semaphore_drop(OS_Handle semaphore); +internal Semaphore os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name); +internal void os_semaphore_release(Semaphore semaphore); +internal Semaphore os_semaphore_open(String8 name); +internal void os_semaphore_close(Semaphore semaphore); +internal B32 os_semaphore_take(Semaphore semaphore, U64 endt_us); +internal void os_semaphore_drop(Semaphore semaphore); //- rjf: barriers -internal OS_Handle os_barrier_alloc(U64 count); -internal void os_barrier_release(OS_Handle barrier); -internal void os_barrier_wait(OS_Handle barrier); +internal Barrier os_barrier_alloc(U64 count); +internal void os_barrier_release(Barrier barrier); +internal void os_barrier_wait(Barrier barrier); //- rjf: scope macros #define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index d4c55dcf..676a4ccd 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1143,31 +1143,31 @@ os_thread_detach(OS_Handle thread) //- rjf: mutexes -internal OS_Handle +internal Mutex os_mutex_alloc(void) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Mutex); InitializeCriticalSection(&entity->mutex); - OS_Handle result = {IntFromPtr(entity)}; + Mutex result = {IntFromPtr(entity)}; return result; } internal void -os_mutex_release(OS_Handle mutex) +os_mutex_release(Mutex mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); os_w32_entity_release(entity); } internal void -os_mutex_take(OS_Handle mutex) +os_mutex_take(Mutex mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); EnterCriticalSection(&entity->mutex); } internal void -os_mutex_drop(OS_Handle mutex) +os_mutex_drop(Mutex mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); LeaveCriticalSection(&entity->mutex); @@ -1175,45 +1175,45 @@ os_mutex_drop(OS_Handle mutex) //- rjf: reader/writer mutexes -internal OS_Handle +internal RWMutex os_rw_mutex_alloc(void) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_RWMutex); InitializeSRWLock(&entity->rw_mutex); - OS_Handle result = {IntFromPtr(entity)}; + RWMutex result = {IntFromPtr(entity)}; return result; } internal void -os_rw_mutex_release(OS_Handle rw_mutex) +os_rw_mutex_release(RWMutex rw_mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); os_w32_entity_release(entity); } internal void -os_rw_mutex_take_r(OS_Handle rw_mutex) +os_rw_mutex_take_r(RWMutex rw_mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); AcquireSRWLockShared(&entity->rw_mutex); } internal void -os_rw_mutex_drop_r(OS_Handle rw_mutex) +os_rw_mutex_drop_r(RWMutex rw_mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); ReleaseSRWLockShared(&entity->rw_mutex); } internal void -os_rw_mutex_take_w(OS_Handle rw_mutex) +os_rw_mutex_take_w(RWMutex rw_mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); AcquireSRWLockExclusive(&entity->rw_mutex); } internal void -os_rw_mutex_drop_w(OS_Handle rw_mutex) +os_rw_mutex_drop_w(RWMutex rw_mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); ReleaseSRWLockExclusive(&entity->rw_mutex); @@ -1221,24 +1221,24 @@ os_rw_mutex_drop_w(OS_Handle rw_mutex) //- rjf: condition variables -internal OS_Handle -os_condition_variable_alloc(void) +internal CondVar +os_cond_var_alloc(void) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_ConditionVariable); InitializeConditionVariable(&entity->cv); - OS_Handle result = {IntFromPtr(entity)}; + CondVar result = {IntFromPtr(entity)}; return result; } internal void -os_condition_variable_release(OS_Handle cv) +os_cond_var_release(CondVar cv) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); os_w32_entity_release(entity); } internal B32 -os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) +os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) { U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); BOOL result = 0; @@ -1252,7 +1252,7 @@ os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) } internal B32 -os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us) { U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); BOOL result = 0; @@ -1267,7 +1267,7 @@ os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) } internal B32 -os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us) { U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); BOOL result = 0; @@ -1281,14 +1281,14 @@ os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) } internal void -os_condition_variable_signal(OS_Handle cv) +os_cond_var_signal(CondVar cv) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); WakeConditionVariable(&entity->cv); } internal void -os_condition_variable_broadcast(OS_Handle cv) +os_cond_var_broadcast(CondVar cv) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); WakeAllConditionVariable(&entity->cv); @@ -1296,44 +1296,44 @@ os_condition_variable_broadcast(OS_Handle cv) //- rjf: cross-process semaphores -internal OS_Handle +internal Semaphore os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { Temp scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); HANDLE handle = CreateSemaphoreW(0, initial_count, max_count, (WCHAR *)name16.str); - OS_Handle result = {(U64)handle}; + Semaphore result = {(U64)handle}; scratch_end(scratch); return result; } internal void -os_semaphore_release(OS_Handle semaphore) +os_semaphore_release(Semaphore semaphore) { HANDLE handle = (HANDLE)semaphore.u64[0]; CloseHandle(handle); } -internal OS_Handle +internal Semaphore os_semaphore_open(String8 name) { Temp scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS , 0, (WCHAR *)name16.str); - OS_Handle result = {(U64)handle}; + Semaphore result = {(U64)handle}; scratch_end(scratch); return result; } internal void -os_semaphore_close(OS_Handle semaphore) +os_semaphore_close(Semaphore semaphore) { HANDLE handle = (HANDLE)semaphore.u64[0]; CloseHandle(handle); } internal B32 -os_semaphore_take(OS_Handle semaphore, U64 endt_us) +os_semaphore_take(Semaphore semaphore, U64 endt_us) { U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); HANDLE handle = (HANDLE)semaphore.u64[0]; @@ -1343,7 +1343,7 @@ os_semaphore_take(OS_Handle semaphore, U64 endt_us) } internal void -os_semaphore_drop(OS_Handle semaphore) +os_semaphore_drop(Semaphore semaphore) { HANDLE handle = (HANDLE)semaphore.u64[0]; ReleaseSemaphore(handle, 1, 0); @@ -1351,17 +1351,17 @@ os_semaphore_drop(OS_Handle semaphore) //- rjf: barriers -internal OS_Handle +internal Barrier os_barrier_alloc(U64 count) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Barrier); InitializeSynchronizationBarrier(&entity->sb, count, -1); - OS_Handle result = {IntFromPtr(entity)}; + Barrier result = {IntFromPtr(entity)}; return result; } internal void -os_barrier_release(OS_Handle barrier) +os_barrier_release(Barrier barrier) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); DeleteSynchronizationBarrier(&entity->sb); @@ -1369,7 +1369,7 @@ os_barrier_release(OS_Handle barrier) } internal void -os_barrier_wait(OS_Handle barrier) +os_barrier_wait(Barrier barrier) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]); EnterSynchronizationBarrier(&entity->sb, 0); diff --git a/src/pe/pe.c b/src/pe/pe.c index 93da7636..19714fc0 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -566,7 +566,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) Assert(!"unable to read data directory"); } } - + // export virtual directory ranges data_dir_vranges = push_array(arena, Rng1U64, data_dir_count); for(U32 dir_idx = 0; dir_idx < data_dir_count; dir_idx += 1) @@ -582,7 +582,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) Assert(!"unable to read data directory"); } } - + // export directory range data_dir_range = rng_1u64(optional_range.min + reported_data_dir_offset, optional_range.min + reported_data_dir_offset + data_dir_count * sizeof(PE_DataDirectory)); } @@ -1009,18 +1009,18 @@ pe_parsed_imports_from_data(Arena *arena, { PE_ParsedImport *imports = 0; U64 import_count = 0; - + U64 name_table_foff = coff_foff_from_voff(sections, section_count, name_table_voff); String8 entries = str8_substr(raw_data, rng_1u64(name_table_foff, raw_data.size)); if (is_pe32) { import_count = index_of_zero_u32((U32 *)entries.str, entries.size/sizeof(U32)); if (import_count == max_U64) { import_count = 0; } imports = push_array(arena, PE_ParsedImport, import_count); - + for (U64 imp_idx = 0; imp_idx < import_count; imp_idx += 1) { U32 raw_entry = 0; str8_deserial_read_struct(entries, imp_idx*sizeof(raw_entry), &raw_entry); - + B32 is_ordinal = ExtractBit(raw_entry, 31); if (is_ordinal) { // fill out ordinal import @@ -1048,11 +1048,11 @@ pe_parsed_imports_from_data(Arena *arena, import_count = index_of_zero_u64((U64 *)entries.str, entries.size/sizeof(U64)); if (import_count == max_U64) { import_count = 0; } imports = push_array(arena, PE_ParsedImport, import_count); - + for (U64 imp_idx = 0; imp_idx < import_count; imp_idx += 1) { U64 raw_entry = 0; str8_deserial_read_struct(entries, imp_idx*sizeof(raw_entry), &raw_entry); - + B32 is_ordinal = ExtractBit(raw_entry, 63); if (is_ordinal) { // fill out ordinal import @@ -1215,7 +1215,7 @@ pe_delay_imports_from_data(Arena *arena, raw_dll->name_table_voff, &import_count); - + // parse bound table Rng1U64 bound_table_range = {0}; if (raw_dll->bound_table_voff) { @@ -1224,7 +1224,7 @@ pe_delay_imports_from_data(Arena *arena, } U64 bound_table_count; U64 *bound_table = pe_array_from_null_term_addr(arena, is_pe32, raw_data, bound_table_range, &bound_table_count); - + // parse unload table Rng1U64 unload_table_range = {0}; if (raw_dll->unload_table_voff) { @@ -1233,7 +1233,7 @@ pe_delay_imports_from_data(Arena *arena, } U64 unload_table_count; U64 *unload_table = pe_array_from_null_term_addr(arena, is_pe32, raw_data, unload_table_range, &unload_table_count); - + // fill out DLL PE_ParsedDelayDLLImport *dll = dlls+dll_idx; dll->attributes = raw_dll->attributes; @@ -1782,12 +1782,12 @@ pe_has_plus_header(COFF_MachineType machine) { B32 has_plus_header = 0; switch (machine) { - case COFF_MachineType_X86: { - has_plus_header = 0; - } break; - case COFF_MachineType_X64: { - has_plus_header = 1; - } break; + case COFF_MachineType_X86: { + has_plus_header = 0; + } break; + case COFF_MachineType_X64: { + has_plus_header = 1; + } break; } return has_plus_header; } @@ -1806,13 +1806,13 @@ pe_pdata_sort(COFF_MachineType machine, String8 raw_pdata) { ProfBeginFunction(); switch (machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X86: - case COFF_MachineType_X64: { - U64 count = raw_pdata.size / sizeof(PE_IntelPdata); - radsort((PE_IntelPdata *)raw_pdata.str, count, pe_pdata_is_before_x86_64); - } break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: + case COFF_MachineType_X64: { + U64 count = raw_pdata.size / sizeof(PE_IntelPdata); + radsort((PE_IntelPdata *)raw_pdata.str, count, pe_pdata_is_before_x86_64); + } break; + default: { NotImplemented; } break; } ProfEnd(); } diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 943f563c..7d52ab78 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -17,13 +17,13 @@ ptg_init(void) for(U64 idx = 0; idx < ptg_shared->stripes_count; idx += 1) { ptg_shared->stripes[idx].arena = arena_alloc(); - ptg_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ptg_shared->stripes[idx].cv = os_condition_variable_alloc(); + ptg_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + ptg_shared->stripes[idx].cv = cond_var_alloc(); } ptg_shared->u2b_ring_size = KB(64); ptg_shared->u2b_ring_base = push_array_no_zero(arena, U8, ptg_shared->u2b_ring_size); - ptg_shared->u2b_ring_cv = os_condition_variable_alloc(); - ptg_shared->u2b_ring_mutex = os_mutex_alloc(); + ptg_shared->u2b_ring_cv = cond_var_alloc(); + ptg_shared->u2b_ring_mutex = mutex_alloc(); ptg_shared->builder_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4); ptg_shared->builder_threads = push_array(arena, OS_Handle, ptg_shared->builder_thread_count); for(U64 idx = 0; idx < ptg_shared->builder_thread_count; idx += 1) @@ -136,11 +136,11 @@ ptg_u2b_enqueue_req(PTG_Key *key, U64 endt_us) { break; } - os_condition_variable_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, endt_us); + cond_var_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(ptg_shared->u2b_ring_cv); + cond_var_broadcast(ptg_shared->u2b_ring_cv); } return good; } @@ -156,9 +156,9 @@ ptg_u2b_dequeue_req(PTG_Key *key_out) ptg_shared->u2b_ring_read_pos += ring_read_struct(ptg_shared->u2b_ring_base, ptg_shared->u2b_ring_size, ptg_shared->u2b_ring_read_pos, key_out); break; } - os_condition_variable_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, max_U64); + cond_var_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, max_U64); } - os_condition_variable_broadcast(ptg_shared->u2b_ring_cv); + cond_var_broadcast(ptg_shared->u2b_ring_cv); } internal void diff --git a/src/ptr_graph_cache/ptr_graph_cache.h b/src/ptr_graph_cache/ptr_graph_cache.h index 96193eae..37e18ce9 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.h +++ b/src/ptr_graph_cache/ptr_graph_cache.h @@ -121,8 +121,8 @@ typedef struct PTG_GraphStripe PTG_GraphStripe; struct PTG_GraphStripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; PTG_GraphNode *free_node; }; @@ -176,8 +176,8 @@ struct PTG_Shared U8 *u2b_ring_base; U64 u2b_ring_write_pos; U64 u2b_ring_read_pos; - OS_Handle u2b_ring_cv; - OS_Handle u2b_ring_mutex; + CondVar u2b_ring_cv; + Mutex u2b_ring_mutex; // rjf: builder threads U64 builder_thread_count; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 6d5f3b6f..21bec84a 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -5679,7 +5679,7 @@ rd_arch_from_eval(E_Eval eval) Arch arch = process->arch; if(arch == Arch_Null) { - arch = arch_from_context(); + arch = Arch_CURRENT; } // rjf: try arch arguments diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index b6654ed1..7618b82c 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -335,17 +335,17 @@ struct IPCInfo //- rjf: IPC resources #define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4) StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement); -global OS_Handle ipc_sender2main_signal_semaphore = {0}; -global OS_Handle ipc_sender2main_lock_semaphore = {0}; +global Semaphore ipc_sender2main_signal_semaphore = {0}; +global Semaphore ipc_sender2main_lock_semaphore = {0}; global U8 *ipc_sender2main_shared_memory_base = 0; -global OS_Handle ipc_main2sender_signal_semaphore = {0}; -global OS_Handle ipc_main2sender_lock_semaphore = {0}; +global Semaphore ipc_main2sender_signal_semaphore = {0}; +global Semaphore ipc_main2sender_lock_semaphore = {0}; global U8 *ipc_main2sender_shared_memory_base = 0; global U8 ipc_s2m_ring_buffer[MB(4)] = {0}; global U64 ipc_s2m_ring_write_pos = 0; global U64 ipc_s2m_ring_read_pos = 0; -global OS_Handle ipc_s2m_ring_mutex = {0}; -global OS_Handle ipc_s2m_ring_cv = {0}; +global Mutex ipc_s2m_ring_mutex = {0}; +global CondVar ipc_s2m_ring_cv = {0}; //////////////////////////////// //~ rjf: IPC Signaler Thread @@ -373,9 +373,9 @@ ipc_signaler_thread__entry_point(void *p) ipc_s2m_ring_write_pos += ring_write(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_write_pos, msg.str, msg.size); break; } - os_condition_variable_wait(ipc_s2m_ring_cv, ipc_s2m_ring_mutex, max_U64); + cond_var_wait(ipc_s2m_ring_cv, ipc_s2m_ring_mutex, max_U64); } - os_condition_variable_broadcast(ipc_s2m_ring_cv); + cond_var_broadcast(ipc_s2m_ring_cv); os_send_wakeup_event(); ipc_info->msg_size = 0; os_semaphore_drop(ipc_sender2main_lock_semaphore); @@ -525,8 +525,8 @@ entry_point(CmdLine *cmd_line) ipc_main2sender_lock_semaphore = os_semaphore_alloc(1, 1, ipc_main2sender_lock_semaphore_name); // rjf: set up ipc-receiver -> main thread ring buffer; launch signaler thread - ipc_s2m_ring_mutex = os_mutex_alloc(); - ipc_s2m_ring_cv = os_condition_variable_alloc(); + ipc_s2m_ring_mutex = mutex_alloc(); + ipc_s2m_ring_cv = cond_var_alloc(); IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base; if(ipc_sender2main_shared_memory_base != 0) { @@ -562,7 +562,7 @@ entry_point(CmdLine *cmd_line) } if(consumed) { - os_condition_variable_broadcast(ipc_s2m_ring_cv); + cond_var_broadcast(ipc_s2m_ring_cv); } if(msg.size != 0) { diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c index 4a4e979c..ac9e8a54 100644 --- a/src/render/d3d11/render_d3d11.c +++ b/src/render/d3d11/render_d3d11.c @@ -159,7 +159,7 @@ r_init(CmdLine *cmdln) Arena *arena = arena_alloc(); r_d3d11_state = push_array(arena, R_D3D11_State, 1); r_d3d11_state->arena = arena; - r_d3d11_state->device_rw_mutex = os_rw_mutex_alloc(); + r_d3d11_state->device_rw_mutex = rw_mutex_alloc(); //- rjf: create base device ProfBegin("create base device"); diff --git a/src/render/d3d11/render_d3d11.h b/src/render/d3d11/render_d3d11.h index 5ad8934b..549c63c8 100644 --- a/src/render/d3d11/render_d3d11.h +++ b/src/render/d3d11/render_d3d11.h @@ -135,7 +135,7 @@ struct R_D3D11_State R_D3D11_Buffer *first_free_buffer; R_D3D11_Tex2D *first_to_free_tex2d; R_D3D11_Buffer *first_to_free_buffer; - OS_Handle device_rw_mutex; + RWMutex device_rw_mutex; // rjf: base d3d11 objects ID3D11Device *base_device; diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 59fdec01..15c2f21e 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1607,13 +1607,13 @@ txt_init(void) for(U64 idx = 0; idx < txt_shared->stripes_count; idx += 1) { txt_shared->stripes[idx].arena = arena_alloc(); - txt_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - txt_shared->stripes[idx].cv = os_condition_variable_alloc(); + txt_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + txt_shared->stripes[idx].cv = cond_var_alloc(); } txt_shared->u2p_ring_size = KB(64); txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); - txt_shared->u2p_ring_cv = os_condition_variable_alloc(); - txt_shared->u2p_ring_mutex = os_mutex_alloc(); + txt_shared->u2p_ring_cv = cond_var_alloc(); + txt_shared->u2p_ring_mutex = mutex_alloc(); txt_shared->evictor_thread = os_thread_launch(txt_evictor_thread__entry_point, 0, 0); } @@ -2172,11 +2172,11 @@ txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us) { break; } - os_condition_variable_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, endt_us); + cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(txt_shared->u2p_ring_cv); + cond_var_broadcast(txt_shared->u2p_ring_cv); } return good; } @@ -2193,9 +2193,9 @@ txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out) txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, lang_out); break; } - os_condition_variable_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, max_U64); + cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, max_U64); } - os_condition_variable_broadcast(txt_shared->u2p_ring_cv); + cond_var_broadcast(txt_shared->u2p_ring_cv); } ASYNC_WORK_DEF(txt_parse_work) diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index f7f062f8..db86ee70 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -192,8 +192,8 @@ typedef struct TXT_Stripe TXT_Stripe; struct TXT_Stripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// @@ -248,8 +248,8 @@ struct TXT_Shared U8 *u2p_ring_base; U64 u2p_ring_write_pos; U64 u2p_ring_read_pos; - OS_Handle u2p_ring_cv; - OS_Handle u2p_ring_mutex; + CondVar u2p_ring_cv; + Mutex u2p_ring_mutex; // rjf: evictor thread OS_Handle evictor_thread; diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 245b69f6..71976f5b 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -34,13 +34,13 @@ tex_init(void) for(U64 idx = 0; idx < tex_shared->stripes_count; idx += 1) { tex_shared->stripes[idx].arena = arena_alloc(); - tex_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); - tex_shared->stripes[idx].cv = os_condition_variable_alloc(); + tex_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); + tex_shared->stripes[idx].cv = cond_var_alloc(); } tex_shared->u2x_ring_size = KB(64); tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); - tex_shared->u2x_ring_cv = os_condition_variable_alloc(); - tex_shared->u2x_ring_mutex = os_mutex_alloc(); + tex_shared->u2x_ring_cv = cond_var_alloc(); + tex_shared->u2x_ring_mutex = mutex_alloc(); tex_shared->evictor_thread = os_thread_launch(tex_evictor_thread__entry_point, 0, 0); } @@ -237,11 +237,11 @@ tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) { break; } - os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us); + cond_var_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us); } if(good) { - os_condition_variable_broadcast(tex_shared->u2x_ring_cv); + cond_var_broadcast(tex_shared->u2x_ring_cv); } return good; } @@ -258,9 +258,9 @@ tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out); break; } - os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64); + cond_var_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64); } - os_condition_variable_broadcast(tex_shared->u2x_ring_cv); + cond_var_broadcast(tex_shared->u2x_ring_cv); } ASYNC_WORK_DEF(tex_xfer_work) diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 70b53a85..7d547a59 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -43,8 +43,8 @@ typedef struct TEX_Stripe TEX_Stripe; struct TEX_Stripe { Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; + RWMutex rw_mutex; + CondVar cv; }; //////////////////////////////// @@ -96,8 +96,8 @@ struct TEX_Shared U8 *u2x_ring_base; U64 u2x_ring_write_pos; U64 u2x_ring_read_pos; - OS_Handle u2x_ring_cv; - OS_Handle u2x_ring_mutex; + CondVar u2x_ring_cv; + Mutex u2x_ring_mutex; // rjf: evictor thread OS_Handle evictor_thread; From d0ece7bc5767e9938305925f8c9ce75515dea7be Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 11:26:05 -0700 Subject: [PATCH 026/302] hook up p2r2 to radbin --- project.4coder | 2 +- src/radbin/radbin.c | 18 +++++++++++++- src/raddbg/raddbg_main.c | 2 ++ src/rdi_from_pdb/rdi_from_pdb_2.c | 39 +++++++++++++++++++++++++++++-- src/rdi_from_pdb/rdi_from_pdb_2.h | 4 ++-- 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/project.4coder b/project.4coder index bd53fe4b..23c42411 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 137004ac..7b7f885d 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -672,7 +672,23 @@ rb_entry_point(CmdLine *cmdline) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - ProfScope("convert") bake_params = p2r_convert(arena, async_root, &convert_params); + if(cmd_line_has_flag(cmdline, str8_lit("p2r2"))) + { + ProfScope("convert (2)") + { + U64 thread_count = os_get_system_info()->logical_processor_count; + Arena **thread_arenas = push_array(arena, Arena *, thread_count); + for EachIndex(idx, thread_count) + { + thread_arenas[idx] = arena_alloc(); + } + bake_params = p2r2_convert(thread_arenas, thread_count, &convert_params); + } + } + else + { + ProfScope("convert") bake_params = p2r_convert(arena, async_root, &convert_params); + } // rjf: no output path? -> pick one based on PDB if(output_path.size == 0) switch(output_kind) diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 7618b82c..fcbcda8d 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -239,6 +239,7 @@ #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" #include "rdi_from_pdb/rdi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb_2.h" #include "rdi_from_dwarf/rdi_from_dwarf.h" #include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h" #include "radbin/radbin.h" @@ -289,6 +290,7 @@ #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" #include "rdi_from_pdb/rdi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb_2.c" #include "rdi_from_dwarf/rdi_from_dwarf.c" #include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c" #include "radbin/radbin.c" diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 98f748b4..66a9b045 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -6,7 +6,8 @@ p2r2_convert_thread_entry_point(void *p) { P2R2_ConvertThreadParams *params = (P2R2_ConvertThreadParams *)p; Arena *arena = params->arena; - lane_thread(params->lane_idx, params->lane_count); + lane_ctx(params->lane_ctx); + ThreadNameF("p2r2_convert_thread_%I64u", lane_idx()); ////////////////////////////////////////////////////////////// //- rjf: do top-level MSF/PDB extraction @@ -605,5 +606,39 @@ p2r2_convert_thread_entry_point(void *p) } RDIM_SrcFileChunkList all_src_files__sequenceless = {0}; P2R_SrcFileMap src_file_map = {0}; - +} + +internal RDIM_BakeParams +p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in) +{ + RDIM_BakeParams result = {0}; + Temp scratch = scratch_begin(thread_arenas, thread_count); + Barrier barrier = barrier_alloc(thread_count); + { + P2R2_ConvertThreadParams *thread_params = push_array(scratch.arena, P2R2_ConvertThreadParams, thread_count); + OS_Handle *threads = push_array(scratch.arena, OS_Handle, thread_count); + for EachIndex(idx, thread_count) + { + thread_params[idx].arena = thread_arenas[idx]; + thread_params[idx].lane_ctx.lane_idx = idx; + thread_params[idx].lane_ctx.lane_count = thread_count; + thread_params[idx].lane_ctx.barrier = barrier; + thread_params[idx].input_exe_name = in->input_exe_name; + thread_params[idx].input_exe_data = in->input_exe_data; + thread_params[idx].input_pdb_name = in->input_pdb_name; + thread_params[idx].input_pdb_data = in->input_pdb_data; + thread_params[idx].deterministic = in->deterministic; + } + for EachIndex(idx, thread_count) + { + threads[idx] = os_thread_launch(p2r2_convert_thread_entry_point, &thread_params[idx], 0); + } + for EachIndex(idx, thread_count) + { + os_thread_join(threads[idx], max_U64); + } + } + barrier_release(barrier); + scratch_end(scratch); + return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index cd18b84f..79387ff2 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -8,8 +8,7 @@ typedef struct P2R2_ConvertThreadParams P2R2_ConvertThreadParams; struct P2R2_ConvertThreadParams { Arena *arena; - U64 lane_idx; - U64 lane_count; + LaneCtx lane_ctx; String8 input_exe_name; String8 input_exe_data; String8 input_pdb_name; @@ -56,5 +55,6 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; internal void p2r2_convert_thread_entry_point(void *p); +internal RDIM_BakeParams p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in); #endif // RDI_FROM_PDB_2_H From d52b6d7bcaeebe1e33b9b1da2cdaa4e74a53d04d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 11:36:33 -0700 Subject: [PATCH 027/302] go wide on msf stream extraction --- src/msf/msf_parse.c | 2 ++ src/rdi_from_pdb/rdi_from_pdb_2.c | 35 +++++++++++++++++++++++++------ src/rdi_from_pdb/rdi_from_pdb_2.h | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/msf/msf_parse.c b/src/msf/msf_parse.c index 6fcd65fe..02912ab7 100644 --- a/src/msf/msf_parse.c +++ b/src/msf/msf_parse.c @@ -230,6 +230,7 @@ msf_raw_stream_table_from_data(Arena *arena, String8 msf_data) internal String8 msf_data_from_stream_number(Arena *arena, String8 msf_data, MSF_RawStreamTable *st, MSF_StreamNumber sn) { + ProfBeginFunction(); String8 result = {0}; if(sn < st->stream_count) { @@ -268,6 +269,7 @@ msf_data_from_stream_number(Arena *arena, String8 msf_data, MSF_RawStreamTable * result = str8(stream_buf, copy_size); } + ProfEnd(); return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 66a9b045..9071fc53 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -9,16 +9,40 @@ p2r2_convert_thread_entry_point(void *p) lane_ctx(params->lane_ctx); ThreadNameF("p2r2_convert_thread_%I64u", lane_idx()); + ////////////////////////////////////////////////////////////// + //- rjf: do base MSF parse + // + { + // rjf: setup output buckets + if(lane_idx() == 0) + { + p2r2_shared = push_array(arena, P2R2_Shared, 1); + p2r2_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); + p2r2_shared->msf = push_array(arena, MSF_Parsed, 1); + p2r2_shared->msf->page_size = p2r2_shared->msf_raw_stream_table->page_size; + p2r2_shared->msf->page_count = p2r2_shared->msf_raw_stream_table->total_page_count; + p2r2_shared->msf->stream_count = p2r2_shared->msf_raw_stream_table->stream_count; + p2r2_shared->msf->streams = push_array(arena, String8, p2r2_shared->msf->stream_count); + } + lane_sync(); + + // rjf: do wide fill + { + Rng1U64 range = lane_range(p2r2_shared->msf->stream_count); + for EachInRange(idx, range) + { + p2r2_shared->msf->streams[idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, idx); + } + } + } + lane_sync(); + MSF_Parsed *msf = p2r2_shared->msf; + ////////////////////////////////////////////////////////////// //- rjf: do top-level MSF/PDB extraction // if(lane_idx() == 0) ProfScope("do top-level MSF/PDB extraction") { - ProfScope("parse MSF") - { - p2r2_shared = push_array(arena, P2R2_Shared, 1); - p2r2_shared->msf = msf_parsed_from_data(arena, params->input_pdb_data); - } ProfScope("parse PDB info") { String8 info_data = msf_data_from_stream(p2r2_shared->msf, PDB_FixedStream_Info); @@ -34,7 +58,6 @@ p2r2_convert_thread_entry_point(void *p) } } lane_sync(); - MSF_Parsed *msf = p2r2_shared->msf; PDB_Info *pdb_info = p2r2_shared->pdb_info; PDB_NamedStreamTable *named_streams = p2r2_shared->named_streams; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 79387ff2..f5c79085 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -19,6 +19,7 @@ struct P2R2_ConvertThreadParams typedef struct P2R2_Shared P2R2_Shared; struct P2R2_Shared { + MSF_RawStreamTable *msf_raw_stream_table; MSF_Parsed *msf; PDB_Info *pdb_info; PDB_NamedStreamTable *named_streams; From 34cb8ded2cad6b04c0d934635e9a03748cc30dd1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 12:01:55 -0700 Subject: [PATCH 028/302] better uniform lane range distribution when count / lanes is not cleanly divisible; plug in source file path gathering --- src/base/base_thread_context.c | 11 +++++++---- src/rdi_from_pdb/rdi_from_pdb_2.c | 22 ++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 1226b994..f0a06d07 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -92,11 +92,14 @@ tctx_lane_barrier_wait(void) internal Rng1U64 tctx_lane_idx_range_from_count(U64 count) { - U64 idxes_per_lane = (count + lane_count()-1) / lane_count(); - U64 lane_base_idx = lane_idx()*idxes_per_lane; - U64 lane_opl_idx = lane_base_idx + idxes_per_lane; + U64 main_idxes_per_lane = count/lane_count(); + U64 leftover_idxes_count = count - main_idxes_per_lane*lane_count(); + U64 leftover_idxes_before_this_lane_count = Min(lane_idx(), leftover_idxes_count); + U64 lane_base_idx = lane_idx()*main_idxes_per_lane + leftover_idxes_before_this_lane_count; + U64 lane_base_idx__clamped = Min(lane_base_idx, count); + U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((lane_idx() < leftover_idxes_count) ? 1 : 0); U64 lane_opl_idx__clamped = Min(lane_opl_idx, count); - Rng1U64 result = r1u64(lane_base_idx, lane_opl_idx__clamped); + Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped); return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 9071fc53..3be70c8b 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -45,7 +45,7 @@ p2r2_convert_thread_entry_point(void *p) { ProfScope("parse PDB info") { - String8 info_data = msf_data_from_stream(p2r2_shared->msf, PDB_FixedStream_Info); + String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); p2r2_shared->pdb_info = pdb_info_from_data(arena, info_data); if(p2r2_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { @@ -325,7 +325,6 @@ p2r2_convert_thread_entry_point(void *p) lane_sync(); //- rjf: do wide gather -#if 0 { Rng1U64 range = lane_range(comp_units->count); for EachInRange(idx, range) @@ -417,7 +416,7 @@ p2r2_convert_thread_entry_point(void *p) U64 sym_off_opl = rec_range->off + rec_range->hdr.size; //- rjf: skip invalid ranges - if(sym_off_opl > pdb_unit_sym->data.size || sym_off_first > pdb_unit_sym->data.size || sym_off_first > sym_off_opl) + if(sym_off_opl > unit_sym->data.size || sym_off_first > unit_sym->data.size || sym_off_first > sym_off_opl) { continue; } @@ -425,8 +424,8 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: unpack symbol info CV_SymKind kind = rec_range->hdr.kind; U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = pdb_unit_sym->data.str + sym_off_first; - void *sym_data_opl = pdb_unit_sym->data.str + sym_off_opl; + void *sym_header_struct_base = unit_sym->data.str + sym_off_first; + void *sym_data_opl = unit_sym->data.str + sym_off_opl; //- rjf: skip bad sizes if(sym_off_first + sym_header_struct_size > sym_off_opl) @@ -444,7 +443,7 @@ p2r2_convert_thread_entry_point(void *p) case CV_SymKind_GPROC32: { CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; if(section != 0) { base_voff = section->voff + proc32->off; @@ -462,8 +461,8 @@ p2r2_convert_thread_entry_point(void *p) CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; { U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%pdb_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = pdb_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + U64 slot_idx = hash%unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) { if(n->v.inlinee == sym->inlinee) { @@ -477,7 +476,7 @@ p2r2_convert_thread_entry_point(void *p) if(inlinee_lines_parsed != 0) { // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = pdb_unit_c13->file_chksms_sub_section; + CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; // rjf: gathered lines U32 last_file_off = max_U32; @@ -505,9 +504,9 @@ p2r2_convert_thread_entry_point(void *p) String8 seq_file_name = {0}; if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { - CV_C13Checksum *checksum = (CV_C13Checksum*)(pdb_unit_c13->data.str + file_chksms->off + last_file_off); + CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); } // rjf: file name -> normalized file path @@ -572,7 +571,6 @@ p2r2_convert_thread_entry_point(void *p) p2r2_shared->unit_src_file_paths[idx] = str8_array_from_list(arena, &src_file_paths); } } -#endif #if 0 // TODO(rjf): OLD U64 tasks_count = comp_unit_count; From 55f21018df612759de64c26d31e853d58e4ec519 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 14:19:48 -0700 Subject: [PATCH 029/302] unit conversion, line info conversion --- src/rdi_from_pdb/rdi_from_pdb.c | 2 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 470 ++++++++++++++++++++++++++---- src/rdi_from_pdb/rdi_from_pdb_2.h | 12 + 3 files changed, 430 insertions(+), 54 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 95b57049..0b29493b 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3196,7 +3196,7 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) //- rjf: parse PDB strtbl // PDB_Strtbl *strtbl = 0; - String8 raw_strtbl = str8_zero(); + String8 raw_strtbl = {0}; if(named_streams != 0) ProfScope("parse PDB strtbl") { MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 3be70c8b..215d15b2 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -41,7 +41,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: do top-level MSF/PDB extraction // - if(lane_idx() == 0) ProfScope("do top-level MSF/PDB extraction") + ProfScope("do top-level MSF/PDB extraction") if(lane_idx() == 0) { ProfScope("parse PDB info") { @@ -64,6 +64,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: parse PDB strtbl & top-level streams // + ProfScope("parse PDB strtbl & top-level streams") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") { @@ -98,6 +99,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: unpack DBI // + ProfScope("unpack DBI") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") { @@ -125,6 +127,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units // + ProfScope("hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") { @@ -181,7 +184,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: bucket compilation unit contributions // - if(lane_idx() == 0) ProfScope("bucket compilation unit contributions") + ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) { p2r2_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) @@ -318,13 +321,15 @@ p2r2_convert_thread_entry_point(void *p) ProfScope("gather all source file paths; build nodes") { //- rjf: prep outputs - if(lane_idx() == 0) + ProfScope("prep outputs") if(lane_idx() == 0) { p2r2_shared->unit_src_file_paths = push_array(arena, String8Array, comp_units->count); + p2r2_shared->unit_src_file_paths_hashes = push_array(arena, U64Array, comp_units->count); } lane_sync(); //- rjf: do wide gather + ProfScope("do wide gather") { Rng1U64 range = lane_range(comp_units->count); for EachInRange(idx, range) @@ -565,68 +570,427 @@ p2r2_convert_thread_entry_point(void *p) } } } - scratch_end(scratch); } p2r2_shared->unit_src_file_paths[idx] = str8_array_from_list(arena, &src_file_paths); - } - } - -#if 0 // TODO(rjf): OLD - U64 tasks_count = comp_unit_count; - P2R_GatherUnitSrcFilesIn *tasks_inputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesIn, tasks_count); - P2R_GatherUnitSrcFilesOut *tasks_outputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesOut, tasks_count); - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); - for EachIndex(idx, tasks_count) - { - tasks_inputs[idx].pdb_strtbl = strtbl; - tasks_inputs[idx].coff_sections = coff_sections; - tasks_inputs[idx].comp_unit = comp_units->units[idx]; - tasks_inputs[idx].comp_unit_syms = sym_for_unit[idx]; - tasks_inputs[idx].comp_unit_c13s = c13_for_unit[idx]; - tasks[idx] = async_task_launch(scratch.arena, p2r_gather_unit_src_file_work, .input = &tasks_inputs[idx]); - } - U64 total_path_count = 0; - for EachIndex(idx, tasks_count) - { - tasks_outputs[idx] = *async_task_join_struct(tasks[idx], P2R_GatherUnitSrcFilesOut); - total_path_count += tasks_outputs[idx].src_file_paths.count; - } - src_file_map.slots_count = total_path_count + total_path_count/2 + 1; - src_file_map.slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map.slots_count); -#endif - - //- rjf: build src file map -#if 0 - for EachIndex(idx, tasks_count) - { - for EachIndex(path_idx, tasks_outputs[idx].src_file_paths.count) - { - String8 file_path_sanitized = tasks_outputs[idx].src_file_paths.v[path_idx]; - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + ProfScope("hash all paths") { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) + p2r2_shared->unit_src_file_paths_hashes[idx].count = p2r2_shared->unit_src_file_paths[idx].count; + p2r2_shared->unit_src_file_paths_hashes[idx].v = push_array(arena, U64, p2r2_shared->unit_src_file_paths[idx].count); + for EachIndex(path_idx, p2r2_shared->unit_src_file_paths_hashes[idx].count) { - src_file_node = n; - break; + p2r2_shared->unit_src_file_paths_hashes[idx].v[path_idx] = rdi_hash(p2r2_shared->unit_src_file_paths[idx].v[path_idx].str, p2r2_shared->unit_src_file_paths[idx].v[path_idx].size); } } - if(src_file_node == 0) + } + } + lane_sync(); + + //- rjf: set up table + ProfScope("set up table") if(lane_idx() == 0) + { + p2r2_shared->total_path_count = 0; + for EachIndex(idx, comp_units->count) + { + p2r2_shared->total_path_count += p2r2_shared->unit_src_file_paths[idx].count; + } + p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; + p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); + } + lane_sync(); + + //- rjf: fill table + ProfScope("fill table") if(lane_idx() == 0) + { + for EachIndex(idx, comp_units->count) + { + for EachIndex(path_idx, p2r2_shared->unit_src_file_paths[idx].count) { - src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); - SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &all_src_files__sequenceless, total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + String8 file_path_sanitized = p2r2_shared->unit_src_file_paths[idx].v[path_idx]; + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(arena, P2R_SrcFileNode, 1); + SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); + src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + } } } } -#endif } - RDIM_SrcFileChunkList all_src_files__sequenceless = {0}; - P2R_SrcFileMap src_file_map = {0}; + lane_sync(); + RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; + P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; + + ////////////////////////////////////////////////////////////// + //- rjf: convert unit info + // + ProfScope("convert unit info") + { + //- rjf: set up outputs + ProfScope("set up outputs") if(lane_idx() == 0) + { + for EachIndex(idx, comp_units->count) + { + rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); + } + p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); + p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); + } + lane_sync(); + RDIM_Unit *units = p2r2_shared->all_units.first->v; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + U64 units_count = p2r2_shared->all_units.first->count; + Assert(units_count == comp_units->count); + + //- rjf: wide conversion of units + ProfScope("wide conversion of units") + { + Rng1U64 range = lane_range(units_count); + for EachInRange(idx, range) + { + Temp scratch = scratch_begin(&arena, 1); + PDB_CompUnit *src_unit = comp_units->units[idx]; + CV_SymParsed *src_unit_sym = sym_for_unit[idx]; + CV_C13Parsed *src_unit_c13 = c13_for_unit[idx]; + RDIM_Unit *dst_unit = &units[idx]; + RDIM_LineTableChunkList *dst_line_tables = &p2r2_shared->units_line_tables[idx]; + RDIM_LineTable **dst_unit_first_inline_site_line_table = &p2r2_shared->units_first_inline_site_line_tables[idx]; + + //- rjf: produce unit name + String8 unit_name = src_unit->obj_name; + if(unit_name.size != 0) + { + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) + { + unit_name = unit_name_past_last_slash; + } + } + + //- rjf: produce obj name/path + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: build this unit's line table, fill out primary line info (inline info added after) + RDIM_LineTable *line_table = 0; + ProfScope("build unit line table") + for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) + { + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) + { + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> sanitized file path + String8 file_path = lines->file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + if(lines->line_count != 0) + { + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + } + + // rjf: push sequence into both line table & source file's line map + if(src_file_node != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); + } + } + } + } + + //- rjf: build line tables for all inline sites + ProfScope("build line tables for all inline sites") + { + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first + src_unit_sym->sym_ranges.count; + + //- rjf: parse inlinee line tables + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; + void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + typedef struct LineChunk LineChunk; + struct LineChunk + { + LineChunk *next; + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + }; + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && total_line_chunk_line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> push line chunks gathered for this file + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // rjf: file name -> sanitized file path + String8 file_path = seq_file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + + // rjf: gather all lines + RDI_U64 *voffs = 0; + RDI_U32 *line_nums = 0; + RDI_U64 line_count = 0; + if(src_file_node != 0) + { + voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + line_count = total_line_chunk_line_count; + U64 dst_idx = 0; + for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) + { + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); + MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); + dst_idx += chunk->count; + } + } + + // rjf: push + if(line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(dst_unit_first_inline_site_line_table[0] == 0) + { + dst_unit_first_inline_site_line_table[0] = line_table; + } + } + rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + } + + // rjf: clear line chunks for subsequent sequences + first_line_chunk = last_line_chunk = 0; + total_line_chunk_line_count = 0; + } + + // rjf: new line -> emit to chunk + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 8; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + } + scratch_end(scratch); + } + } + } + lane_sync(); + RDIM_UnitChunkList *units = &p2r2_shared->all_units; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; + + ////////////////////////////////////////////////////////////// + //- rjf: join all line tables + // + ProfScope("join all line tables") if(lane_idx() == 0) + { + for EachIndex(idx, units->total_count) + { + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->units_line_tables[idx]); + } + } + lane_sync(); + RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; } internal RDIM_BakeParams diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index f5c79085..bfc738e3 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -21,6 +21,7 @@ struct P2R2_Shared { MSF_RawStreamTable *msf_raw_stream_table; MSF_Parsed *msf; + PDB_Info *pdb_info; PDB_NamedStreamTable *named_streams; @@ -51,6 +52,17 @@ struct P2R2_Shared RDI_Arch arch; String8Array *unit_src_file_paths; + U64Array *unit_src_file_paths_hashes; + U64 total_path_count; + + RDIM_SrcFileChunkList all_src_files__sequenceless; + P2R_SrcFileMap src_file_map; + + RDIM_UnitChunkList all_units; + RDIM_LineTableChunkList *units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables; + + RDIM_LineTableChunkList all_line_tables; }; global P2R2_Shared *p2r2_shared = 0; From 0fa45fe71b6d6da3614fc6fd561ed2dd899b1a04 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 15:24:25 -0700 Subject: [PATCH 030/302] p2r2: reslice per-lane work; bucket subsets of units by record count, rather than assigning units to lanes --- src/base/base_profile.h | 2 +- src/base/base_thread_context.c | 3 + src/rdi_from_pdb/rdi_from_pdb_2.c | 608 +++++++++++++++++------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 25 +- 4 files changed, 372 insertions(+), 266 deletions(-) diff --git a/src/base/base_profile.h b/src/base/base_profile.h index 3a97d4f3..b750427c 100644 --- a/src/base/base_profile.h +++ b/src/base/base_profile.h @@ -43,7 +43,7 @@ # define ProfEndLockWait(...) tmEndWaitForLock(0) # define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) # define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) -# define ProfColor(color) tmZoneColorSticky(color) +# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f) # define ProfBeginV(...) \ if (TM_API_PTR) { \ static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index f0a06d07..8d0e23c1 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -85,8 +85,11 @@ tctx_set_lane_ctx(LaneCtx lane_ctx) internal void tctx_lane_barrier_wait(void) { + ProfBeginFunction(); + ProfColor(0xff0000ff); TCTX *tctx = tctx_selected(); os_barrier_wait(tctx->lane_ctx.barrier); + ProfEnd(); } internal Rng1U64 diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 215d15b2..fa8a5068 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -1,6 +1,41 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal RDIM_BakeParams +p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in) +{ + RDIM_BakeParams result = {0}; + Temp scratch = scratch_begin(thread_arenas, thread_count); + Barrier barrier = barrier_alloc(thread_count); + { + P2R2_ConvertThreadParams *thread_params = push_array(scratch.arena, P2R2_ConvertThreadParams, thread_count); + OS_Handle *threads = push_array(scratch.arena, OS_Handle, thread_count); + for EachIndex(idx, thread_count) + { + thread_params[idx].arena = thread_arenas[idx]; + thread_params[idx].lane_ctx.lane_idx = idx; + thread_params[idx].lane_ctx.lane_count = thread_count; + thread_params[idx].lane_ctx.barrier = barrier; + thread_params[idx].input_exe_name = in->input_exe_name; + thread_params[idx].input_exe_data = in->input_exe_data; + thread_params[idx].input_pdb_name = in->input_pdb_name; + thread_params[idx].input_pdb_data = in->input_pdb_data; + thread_params[idx].deterministic = in->deterministic; + } + for EachIndex(idx, thread_count) + { + threads[idx] = os_thread_launch(p2r2_convert_thread_entry_point, &thread_params[idx], 0); + } + for EachIndex(idx, thread_count) + { + os_thread_join(threads[idx], max_U64); + } + } + barrier_release(barrier); + scratch_end(scratch); + return result; +} + internal void p2r2_convert_thread_entry_point(void *p) { @@ -279,84 +314,276 @@ p2r2_convert_thread_entry_point(void *p) U64 arch_addr_size = rdi_addr_size_from_arch(arch); ////////////////////////////////////////////////////////////// - //- rjf: produce top-level-info + //- rjf: organize subsets of unit symbol streams by lane // - RDIM_TopLevelInfo top_level_info = {0}; + ProfScope("organize subsets of unit symbol streams by lane") { - top_level_info.arch = arch; - top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); - top_level_info.exe_hash = exe_hash; - top_level_info.voff_max = exe_voff_max; - if(params->deterministic) + //- rjf: set up + ProfScope("set up") if(lane_idx() == 0) { - top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + p2r2_shared->lane_sym_blocks = push_array(arena, P2R2_UnitSymBlockList, lane_count()); + p2r2_shared->total_sym_record_count = 0; + for EachIndex(unit_idx, comp_units->count) + { + p2r2_shared->total_sym_record_count += sym_for_unit[unit_idx]->sym_ranges.count; + } + } + lane_sync(); + + //- rjf: gather + ProfScope("gather") + { + Rng1U64 lane_sym_range = lane_range(p2r2_shared->total_sym_record_count); + { + U64 scan_sym_idx = 0; + for EachIndex(idx, comp_units->count) + { + Rng1U64 unit_sym_range = r1u64(scan_sym_idx, scan_sym_idx + sym_for_unit[idx]->sym_ranges.count); + Rng1U64 sym_range_in_unit = intersect_1u64(unit_sym_range, lane_sym_range); + if(sym_range_in_unit.max > sym_range_in_unit.min) + { + P2R2_UnitSymBlock *block = push_array(arena, P2R2_UnitSymBlock, 1); + SLLQueuePush(p2r2_shared->lane_sym_blocks[lane_idx()].first, p2r2_shared->lane_sym_blocks[lane_idx()].last, block); + block->unit_idx = idx; + block->unit_rec_range = r1u64(sym_range_in_unit.min - scan_sym_idx, sym_range_in_unit.max - scan_sym_idx); + } + scan_sym_idx += sym_for_unit[idx]->sym_ranges.count; + } + } } } + lane_sync(); + P2R2_UnitSymBlockList *lane_sym_blocks = p2r2_shared->lane_sym_blocks; ////////////////////////////////////////////////////////////// - //- rjf: build binary sections list + //- rjf: gather all file paths // - RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") - { - COFF_SectionHeader *coff_ptr = coff_sections.v; - COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; - for(;coff_ptr < coff_opl; coff_ptr += 1) - { - char *name_first = (char *)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); - sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - sec->voff_first = coff_ptr->voff; - sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; - sec->foff_first = coff_ptr->foff; - sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: gather all source file paths; build nodes - // - ProfScope("gather all source file paths; build nodes") + ProfScope("gather all file paths") { //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r2_shared->unit_src_file_paths = push_array(arena, String8Array, comp_units->count); - p2r2_shared->unit_src_file_paths_hashes = push_array(arena, U64Array, comp_units->count); + p2r2_shared->lane_file_paths = push_array(arena, String8Array, lane_count()); + p2r2_shared->lane_file_paths_hashes = push_array(arena, U64Array, lane_count()); } lane_sync(); //- rjf: do wide gather ProfScope("do wide gather") { - Rng1U64 range = lane_range(comp_units->count); - for EachInRange(idx, range) + Temp scratch = scratch_begin(&arena, 1); + String8List src_file_paths = {0}; + + //- rjf: build local hash table to dedup files within this lane + U64 hit_path_slots_count = 4096; + String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); + + //- rjf: iterate lane blocks & gather inline site file names + ProfScope("gather inline site file names from this lane's symbols") + for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + lane_block != 0; + lane_block = lane_block->next) { - PDB_CompUnit *unit = comp_units->units[idx]; - CV_SymParsed *unit_sym = sym_for_unit[idx]; - CV_C13Parsed *unit_c13 = c13_for_unit[idx]; - CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; - String8List src_file_paths = {0}; + //- rjf: unpack unit + PDB_CompUnit *unit = comp_units->units[lane_block->unit_idx]; + CV_SymParsed *unit_sym = sym_for_unit[lane_block->unit_idx]; + CV_C13Parsed *unit_c13 = c13_for_unit[lane_block->unit_idx]; + CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.min; + CV_RecRange *rec_ranges_opl = unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.max; + + //- rjf: produce obj name/path + String8 obj_name = unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { - Temp scratch = scratch_begin(&arena, 1); + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: find all inline site symbols & gather filenames + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - //- rjf: build local hash table to dedup files within this unit - U64 hit_path_slots_count = 4096; - String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); + //- rjf: skip invalid ranges + if(sym_off_opl > unit_sym->data.size || sym_off_first > unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } - //- rjf: produce obj name/path + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = unit_sym->data.str + sym_off_first; + void *sym_data_opl = unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + U64 line_count = 0; + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> gather new file name + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // rjf: file name -> normalized file path + String8 file_path = seq_file_name; + String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + if(file_path_normalized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); + file_path_normalized_parts = obj_folder_path_parts; + file_path_normalized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); + } + + // rjf: normalized file path -> source file node + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_normalized, 0)) + { + hit_path_node = n; + break; + } + } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_normalized; + str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); + } + line_count = 0; + } + + // rjf: count lines + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + } + + //- rjf: do per-unit wide gather from unit line tables + ProfScope("do per-unit wide gather from unit line tables") + { + // rjf: iterate all units for this lane + Rng1U64 range = lane_range(comp_units->count); + for EachInRange(idx, range) + { + PDB_CompUnit *unit = comp_units->units[idx]; + CV_SymParsed *unit_sym = sym_for_unit[idx]; + CV_C13Parsed *unit_c13 = c13_for_unit[idx]; + CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; + + // rjf: produce obj name/path String8 obj_name = unit->obj_name; if(str8_match(obj_name, str8_lit("* Linker *"), 0) || str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { MemoryZeroStruct(&obj_name); } - String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - //- rjf: find all files in this unit's (non-inline) line info + // rjf: find all files in this unit's (non-inline) line info ProfScope("find all files in this unit's (non-inline) line info") for(CV_C13SubSectionNode *node = unit_c13->first_sub_section; node != 0; @@ -407,192 +634,43 @@ p2r2_convert_thread_entry_point(void *p) } } } - - //- rjf: find all files in unit's inline line info - ProfScope("find all files in unit's inline line info") - { - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > unit_sym->data.size || sym_off_first > unit_sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = unit_sym->data.str + sym_off_first; - void *sym_data_opl = unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - U64 line_count = 0; - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> gather new file name - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // rjf: file name -> normalized file path - String8 file_path = seq_file_name; - String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); - String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); - if(file_path_normalized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); - file_path_normalized_parts = obj_folder_path_parts; - file_path_normalized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); - file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); - } - - // rjf: normalized file path -> source file node - U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); - U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_normalized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_normalized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); - } - line_count = 0; - } - - // rjf: count lines - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - scratch_end(scratch); - } - p2r2_shared->unit_src_file_paths[idx] = str8_array_from_list(arena, &src_file_paths); - ProfScope("hash all paths") - { - p2r2_shared->unit_src_file_paths_hashes[idx].count = p2r2_shared->unit_src_file_paths[idx].count; - p2r2_shared->unit_src_file_paths_hashes[idx].v = push_array(arena, U64, p2r2_shared->unit_src_file_paths[idx].count); - for EachIndex(path_idx, p2r2_shared->unit_src_file_paths_hashes[idx].count) - { - p2r2_shared->unit_src_file_paths_hashes[idx].v[path_idx] = rdi_hash(p2r2_shared->unit_src_file_paths[idx].v[path_idx].str, p2r2_shared->unit_src_file_paths[idx].v[path_idx].size); - } } } + + //- rjf: merge into array for this lane + p2r2_shared->lane_file_paths[lane_idx()] = str8_array_from_list(arena, &src_file_paths); + + //- rjf: hash this lane's file paths + { + String8Array lane_paths = p2r2_shared->lane_file_paths[lane_idx()]; + U64Array lane_paths_hashes = {0}; + lane_paths_hashes.count = lane_paths.count; + lane_paths_hashes.v = push_array(arena, U64, lane_paths_hashes.count); + for EachIndex(idx, lane_paths.count) + { + lane_paths_hashes.v[idx] = rdi_hash(lane_paths.v[idx].str, lane_paths.v[idx].size); + } + p2r2_shared->lane_file_paths_hashes[lane_idx()] = lane_paths_hashes; + } + + scratch_end(scratch); } - lane_sync(); - + } + lane_sync(); + String8Array *lane_file_paths = p2r2_shared->lane_file_paths; + U64Array *lane_file_paths_hashes = p2r2_shared->lane_file_paths_hashes; + + ////////////////////////////// + //- rjf: build unified collection & map for source files + // + { //- rjf: set up table ProfScope("set up table") if(lane_idx() == 0) { p2r2_shared->total_path_count = 0; - for EachIndex(idx, comp_units->count) + for EachIndex(idx, lane_count()) { - p2r2_shared->total_path_count += p2r2_shared->unit_src_file_paths[idx].count; + p2r2_shared->total_path_count += p2r2_shared->lane_file_paths[idx].count; } p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); @@ -602,12 +680,12 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: fill table ProfScope("fill table") if(lane_idx() == 0) { - for EachIndex(idx, comp_units->count) + for EachIndex(idx, lane_count()) { - for EachIndex(path_idx, p2r2_shared->unit_src_file_paths[idx].count) + for EachIndex(path_idx, p2r2_shared->lane_file_paths[idx].count) { - String8 file_path_sanitized = p2r2_shared->unit_src_file_paths[idx].v[path_idx]; - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + String8 file_path_sanitized = p2r2_shared->lane_file_paths[idx].v[path_idx]; + U64 file_path_sanitized_hash = p2r2_shared->lane_file_paths_hashes[idx].v[path_idx]; U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; P2R_SrcFileNode *src_file_node = 0; for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) @@ -991,39 +1069,45 @@ p2r2_convert_thread_entry_point(void *p) } lane_sync(); RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; -} - -internal RDIM_BakeParams -p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in) -{ - RDIM_BakeParams result = {0}; - Temp scratch = scratch_begin(thread_arenas, thread_count); - Barrier barrier = barrier_alloc(thread_count); + + //- + //- + //-- + + ////////////////////////////////////////////////////////////// + //- rjf: produce top-level-info + // + RDIM_TopLevelInfo top_level_info = {0}; { - P2R2_ConvertThreadParams *thread_params = push_array(scratch.arena, P2R2_ConvertThreadParams, thread_count); - OS_Handle *threads = push_array(scratch.arena, OS_Handle, thread_count); - for EachIndex(idx, thread_count) + top_level_info.arch = arch; + top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + if(params->deterministic) { - thread_params[idx].arena = thread_arenas[idx]; - thread_params[idx].lane_ctx.lane_idx = idx; - thread_params[idx].lane_ctx.lane_count = thread_count; - thread_params[idx].lane_ctx.barrier = barrier; - thread_params[idx].input_exe_name = in->input_exe_name; - thread_params[idx].input_exe_data = in->input_exe_data; - thread_params[idx].input_pdb_name = in->input_pdb_name; - thread_params[idx].input_pdb_data = in->input_pdb_data; - thread_params[idx].deterministic = in->deterministic; - } - for EachIndex(idx, thread_count) - { - threads[idx] = os_thread_launch(p2r2_convert_thread_entry_point, &thread_params[idx], 0); - } - for EachIndex(idx, thread_count) - { - os_thread_join(threads[idx], max_U64); + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: build binary sections list + // + RDIM_BinarySectionList binary_sections = {0}; + ProfScope("build binary section list") + { + COFF_SectionHeader *coff_ptr = coff_sections.v; + COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; + for(;coff_ptr < coff_opl; coff_ptr += 1) + { + char *name_first = (char *)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + sec->name = str8_cstring_capped(name_first, name_opl); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->voff_first = coff_ptr->voff; + sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; + sec->foff_first = coff_ptr->foff; + sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; } } - barrier_release(barrier); - scratch_end(scratch); - return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index bfc738e3..0b98c2e3 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -16,6 +16,21 @@ struct P2R2_ConvertThreadParams B32 deterministic; }; +typedef struct P2R2_UnitSymBlock P2R2_UnitSymBlock; +struct P2R2_UnitSymBlock +{ + P2R2_UnitSymBlock *next; + U64 unit_idx; + Rng1U64 unit_rec_range; +}; + +typedef struct P2R2_UnitSymBlockList P2R2_UnitSymBlockList; +struct P2R2_UnitSymBlockList +{ + P2R2_UnitSymBlock *first; + P2R2_UnitSymBlock *last; +}; + typedef struct P2R2_Shared P2R2_Shared; struct P2R2_Shared { @@ -51,8 +66,12 @@ struct P2R2_Shared U64 exe_voff_max; RDI_Arch arch; - String8Array *unit_src_file_paths; - U64Array *unit_src_file_paths_hashes; + U64 total_sym_record_count; + P2R2_UnitSymBlockList *lane_sym_blocks; + + String8Array *lane_file_paths; + U64Array *lane_file_paths_hashes; + U64 total_path_count; RDIM_SrcFileChunkList all_src_files__sequenceless; @@ -67,7 +86,7 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; -internal void p2r2_convert_thread_entry_point(void *p); internal RDIM_BakeParams p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in); +internal void p2r2_convert_thread_entry_point(void *p); #endif // RDI_FROM_PDB_2_H From 83d4afabd5b8d792f78c890599ea1a4e87f0ecd2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 16:28:22 -0700 Subject: [PATCH 031/302] p2r2: types building --- src/rdi_from_pdb/rdi_from_pdb_2.c | 1220 ++++++++++++++++++++++++++--- src/rdi_from_pdb/rdi_from_pdb_2.h | 12 +- 2 files changed, 1139 insertions(+), 93 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index fa8a5068..89e1d325 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -723,117 +723,133 @@ p2r2_convert_thread_entry_point(void *p) { rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); } - p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); + p2r2_shared->lanes_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); } lane_sync(); RDIM_Unit *units = p2r2_shared->all_units.first->v; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; U64 units_count = p2r2_shared->all_units.first->count; + RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; Assert(units_count == comp_units->count); - //- rjf: wide conversion of units - ProfScope("wide conversion of units") + //- rjf: do per-lane work { - Rng1U64 range = lane_range(units_count); - for EachInRange(idx, range) + RDIM_LineTableChunkList *dst_line_tables = &lanes_line_tables[lane_idx()]; + + //- rjf: per-unit line table conversion + ProfScope("per-unit line table conversion") { - Temp scratch = scratch_begin(&arena, 1); - PDB_CompUnit *src_unit = comp_units->units[idx]; - CV_SymParsed *src_unit_sym = sym_for_unit[idx]; - CV_C13Parsed *src_unit_c13 = c13_for_unit[idx]; - RDIM_Unit *dst_unit = &units[idx]; - RDIM_LineTableChunkList *dst_line_tables = &p2r2_shared->units_line_tables[idx]; - RDIM_LineTable **dst_unit_first_inline_site_line_table = &p2r2_shared->units_first_inline_site_line_tables[idx]; - - //- rjf: produce unit name - String8 unit_name = src_unit->obj_name; - if(unit_name.size != 0) + Rng1U64 range = lane_range(units_count); + for EachInRange(idx, range) { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) + Temp scratch = scratch_begin(&arena, 1); + PDB_CompUnit *src_unit = comp_units->units[idx]; + CV_SymParsed *src_unit_sym = sym_for_unit[idx]; + CV_C13Parsed *src_unit_c13 = c13_for_unit[idx]; + RDIM_Unit *dst_unit = &units[idx]; + + // rjf: produce obj name/path + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { - unit_name = unit_name_past_last_slash; + MemoryZeroStruct(&obj_name); } - } - - //- rjf: produce obj name/path - String8 obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: build this unit's line table, fill out primary line info (inline info added after) - RDIM_LineTable *line_table = 0; - ProfScope("build unit line table") - for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + // rjf: build this unit's line table, fill out primary line info (inline info added after) + RDIM_LineTable *line_table = 0; + ProfScope("build unit line table") + for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; + node != 0; + node = node->next) { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) + if(node->kind == CV_C13SubSectionKind_Lines) { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> sanitized file path + String8 file_path = lines->file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) - { - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) { - src_file_node = n; - break; + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + if(lines->line_count != 0) + { + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } } } - } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) - { - if(line_table == 0) + + // rjf: push sequence into both line table & source file's line map + if(src_file_node != 0) { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } } } + scratch_end(scratch); } - - //- rjf: build line tables for all inline sites - ProfScope("build line tables for all inline sites") + } + + //- rjf: build per-inline-site line tables + ProfScope("build per-inline-site line tables") + { + U64 last_unit_num_started_by_this_lane = 0; + for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + lane_block != 0; + lane_block = lane_block->next) { - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first + src_unit_sym->sym_ranges.count; - - //- rjf: parse inlinee line tables + Temp scratch = scratch_begin(&arena, 1); + if(lane_block->unit_rec_range.min == 0) + { + last_unit_num_started_by_this_lane = lane_block->unit_idx+1; + } + else if(last_unit_num_started_by_this_lane-1 != lane_block->unit_idx) + { + last_unit_num_started_by_this_lane = 0; + } + PDB_CompUnit *src_unit = comp_units->units[lane_block->unit_idx]; + CV_SymParsed *src_unit_sym = sym_for_unit[lane_block->unit_idx]; + CV_C13Parsed *src_unit_c13 = c13_for_unit[lane_block->unit_idx]; + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.min; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.max; U64 base_voff = 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; @@ -1005,9 +1021,12 @@ p2r2_convert_thread_entry_point(void *p) if(line_table == 0) { line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(dst_unit_first_inline_site_line_table[0] == 0) + if(last_unit_num_started_by_this_lane != 0) { - dst_unit_first_inline_site_line_table[0] = line_table; + if(p2r2_shared->units_first_inline_site_line_tables[last_unit_num_started_by_this_lane-1] == 0) + { + p2r2_shared->units_first_inline_site_line_tables[last_unit_num_started_by_this_lane-1] = line_table; + } } } rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); @@ -1047,14 +1066,14 @@ p2r2_convert_thread_entry_point(void *p) }break; } } + scratch_end(scratch); } - scratch_end(scratch); } } } lane_sync(); - RDIM_UnitChunkList *units = &p2r2_shared->all_units; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + RDIM_UnitChunkList *all_units = &p2r2_shared->all_units; + RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// @@ -1062,14 +1081,1030 @@ p2r2_convert_thread_entry_point(void *p) // ProfScope("join all line tables") if(lane_idx() == 0) { - for EachIndex(idx, units->total_count) + for EachIndex(idx, lane_count()) { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->units_line_tables[idx]); + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_line_tables[idx]); } } lane_sync(); RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; + ////////////////////////////////////////////////////////////// + //- rjf: types pass 1: produce type forward resolution map + // + // this map is used to resolve usage of "incomplete structs" in codeview's + // type info. this often happens when e.g. "struct Foo" is used to refer to + // a later-defined "Foo", which actually contains members and so on. we want + // to hook types up to their actual destination complete types wherever + // possible, and so this map can be used to do that in subsequent stages. + // + ProfScope("types pass 1: produce type forward resolution map") + { + //- rjf: allocate forward resolution map + if(lane_idx() == 0) + { + p2r2_shared->itype_first = tpi_leaf->itype_first; + p2r2_shared->itype_opl = tpi_leaf->itype_opl; + p2r2_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r2_shared->itype_opl); + } + lane_sync(); + + //- rjf: do wide fill + { + Rng1U64 range = lane_range(p2r2_shared->itype_opl); + for EachInRange(idx, range) + { + CV_TypeId itype = (CV_TypeId)idx; + if(itype < p2r2_shared->itype_first) { continue; } + + //- rjf: determine if this itype resolves to another + CV_TypeId itype_fwd = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // rjf: unpack leaf header + CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // rjf: unpack leaf header + CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // rjf: unpack leaf + CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8 *)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves tos + if(lf_union->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && + ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // rjf: unpack leaf + CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; + U8 *name_ptr = (U8 *)(lf_enum + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_enum->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && + ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + } + } + + //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map + if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) + { + p2r2_shared->itype_fwd_map[itype] = itype_fwd; + } + } + } + } + lane_sync(); + CV_TypeId *itype_fwd_map = p2r2_shared->itype_fwd_map; + CV_TypeId itype_first = p2r2_shared->itype_first; + CV_TypeId itype_opl = p2r2_shared->itype_opl; + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 2: produce per-itype itype chain + // + // this pass is to ensure that subsequent passes always produce types for + // dependent itypes first - guaranteeing rdi's "only reference backward" + // rule (which eliminates cycles). each itype slot gets a list of itypes, + // starting with the deepest dependency - when types are produced per-itype, + // this chain is walked, so that deeper dependencies are built first, and + // as such, always show up *earlier* in the actually built types. + // + ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") + { + //- rjf: allocate itype chain table + if(lane_idx() == 0) + { + p2r2_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r2_shared->itype_opl); + } + lane_sync(); + + //- rjf: do wide fill + { + Rng1U64 range = lane_range(p2r2_shared->itype_opl); + for EachInRange(idx, range) + { + CV_TypeId itype = (CV_TypeId)idx; + if(itype < p2r2_shared->itype_first) { continue; } + + //- rjf: push initial itype - should be final-visited-itype for this itype + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + //- rjf: skip basic types for dependency walk + if(itype < tpi_leaf->itype_first) + { + continue; + } + + //- rjf: walk dependent types, push to chain + Temp scratch = scratch_begin(&arena, 1); + P2R_TypeIdChain start_walk_task = {0, itype}; + P2R_TypeIdChain *first_walk_task = &start_walk_task; + P2R_TypeIdChain *last_walk_task = &start_walk_task; + for(P2R_TypeIdChain *walk_task = first_walk_task; + walk_task != 0; + walk_task = walk_task->next) + { + CV_TypeId walk_itype = itype_fwd_map[walk_task->itype] ? itype_fwd_map[walk_task->itype] : walk_task->itype; + if(walk_itype < tpi_leaf->itype_first) + { + continue; + } + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[walk_itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + + // rjf: push return itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk return itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ARRAY + case CV_LeafKind_ARRAY: + { + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + } + } + } + scratch_end(scratch); + } + } + } + lane_sync(); + P2R_TypeIdChain **itype_chains = p2r2_shared->itype_chains; + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 3: construct all types from TPI + // + // this doesn't gather struct/class/union/enum members, which is done by + // subsequent passes, to build RDI "UDT" information, which is distinct + // from regular type info. + // + ProfScope("types pass 3: construct all root/stub types from TPI") if(lane_idx() == 0) + { +#define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + RDIM_Type **itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); + RDIM_Type **basic_type_ptrs = push_array(arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); + RDIM_TypeChunkList all_types = {0}; + + //////////////////////////// + //- rjf: build basic types + // + { + for(RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; + type_kind <= RDI_TypeKind_LastBuiltIn; + type_kind += 1) + { + RDIM_Type *type = rdim_type_chunk_list_push(arena, &all_types, 512); + type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); + type->kind = type_kind; + type->byte_size = rdi_size_from_basic_type_kind(type_kind); + basic_type_ptrs[type_kind - RDI_TypeKind_FirstBuiltIn] = type; + } + } + + //////////////////////////// + //- rjf: build basic type aliases + // + { + RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, arch); + RDI_TypeKind short_type = rdim_short_type_kind_from_data_model(data_model); + RDI_TypeKind ushort_type = rdim_unsigned_short_type_kind_from_data_model(data_model); + RDI_TypeKind long_type = rdim_long_type_kind_from_data_model(data_model); + RDI_TypeKind ulong_type = rdim_unsigned_long_type_kind_from_data_model(data_model); + RDI_TypeKind long_long_type = rdim_long_long_type_kind_from_data_model(data_model); + RDI_TypeKind ulong_long_type = rdim_unsigned_long_long_type_kind_from_data_model(data_model); + RDI_TypeKind ptr_type = rdim_pointer_size_t_type_kind_from_data_model(data_model); + struct + { + char * name; + RDI_TypeKind kind_rdi; + CV_LeafKind kind_cv; + } + table[] = + { + { "signed char" , RDI_TypeKind_Char8 , CV_BasicType_CHAR }, + { "short" , short_type , CV_BasicType_SHORT }, + { "long" , long_type , CV_BasicType_LONG }, + { "long long" , long_long_type , CV_BasicType_QUAD }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_OCT }, // Clang type + { "unsigned char" , RDI_TypeKind_UChar8 , CV_BasicType_UCHAR }, + { "unsigned short" , ushort_type , CV_BasicType_USHORT }, + { "unsigned long" , ulong_type , CV_BasicType_ULONG }, + { "unsigned long long" , ulong_long_type , CV_BasicType_UQUAD }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UOCT }, // Clang type + { "bool" , RDI_TypeKind_S8 , CV_BasicType_BOOL8 }, + { "__bool16" , RDI_TypeKind_S16 , CV_BasicType_BOOL16 }, // not real C type + { "__bool32" , RDI_TypeKind_S32 , CV_BasicType_BOOL32 }, // not real C type + { "float" , RDI_TypeKind_F32 , CV_BasicType_FLOAT32 }, + { "double" , RDI_TypeKind_F64 , CV_BasicType_FLOAT64 }, + { "long double" , RDI_TypeKind_F80 , CV_BasicType_FLOAT80 }, + { "__float128" , RDI_TypeKind_F128 , CV_BasicType_FLOAT128 }, // Clang type + { "__float48" , RDI_TypeKind_F48 , CV_BasicType_FLOAT48 }, // not real C type + { "__float32pp" , RDI_TypeKind_F32PP , CV_BasicType_FLOAT32PP }, // not real C type + { "__float16" , RDI_TypeKind_F16 , CV_BasicType_FLOAT16 }, + { "_Complex float" , RDI_TypeKind_ComplexF32 , CV_BasicType_COMPLEX32 }, + { "_Complex double" , RDI_TypeKind_ComplexF64 , CV_BasicType_COMPLEX64 }, + { "_Complex long double" , RDI_TypeKind_ComplexF80 , CV_BasicType_COMPLEX80 }, + { "_Complex __float128" , RDI_TypeKind_ComplexF128, CV_BasicType_COMPLEX128 }, + { "__int8" , RDI_TypeKind_S8 , CV_BasicType_INT8 }, + { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 }, + { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 }, + { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 }, + { "int" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, + { "int32" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, + { "uint32" , RDI_TypeKind_U32 , CV_BasicType_UINT32 }, + { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 }, + { "__uint64" , RDI_TypeKind_U64 , CV_BasicType_UINT64 }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_INT128 }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UINT128 }, + { "char" , RDI_TypeKind_Char8 , CV_BasicType_RCHAR }, // always ASCII + { "wchar_t" , RDI_TypeKind_UChar16 , CV_BasicType_WCHAR }, // on windows always UTF-16 + { "char8_t" , RDI_TypeKind_Char8 , CV_BasicType_CHAR8 }, // always UTF-8 + { "char16_t" , RDI_TypeKind_Char16 , CV_BasicType_CHAR16 }, // always UTF-16 + { "char32_t" , RDI_TypeKind_Char32 , CV_BasicType_CHAR32 }, // always UTF-32 + { "__pointer" , ptr_type , CV_BasicType_PTR } + }; + for EachElement(idx, table) + { + RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + builtin_alias->kind = RDI_TypeKind_Alias; + builtin_alias->name = str8_cstring(table[idx].name); + builtin_alias->direct_type = p2r_builtin_type_ptr_from_kind(table[idx].kind_rdi); + builtin_alias->byte_size = rdi_size_from_basic_type_kind(table[idx].kind_rdi); + itype_type_ptrs[table[idx].kind_cv] = builtin_alias; + } + itype_type_ptrs[CV_BasicType_HRESULT] = basic_type_ptrs[RDI_TypeKind_HResult - RDI_TypeKind_FirstBuiltIn]; + itype_type_ptrs[CV_BasicType_VOID] = basic_type_ptrs[RDI_TypeKind_Void - RDI_TypeKind_FirstBuiltIn]; + } + + //////////////////////////// + //- rjf: build types from TPI + // + for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) + { + for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; + itype_chain != 0; + itype_chain = itype_chain->next) + { + CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; + B32 itype_is_basic = (itype < tpi->itype_first); + + ////////////////////////// + //- rjf: skip forward-reference itypes - all future resolutions will + // reference whatever this itype resolves to, and so there is no point + // in filling out this slot + // + if(itype_fwd_map[root_itype] != 0) + { + continue; + } + + ////////////////////////// + //- rjf: skip already produced dependencies + // + if(itype_type_ptrs[itype] != 0) + { + continue; + } + + ////////////////////////// + //- rjf: build basic type + // + if(itype_is_basic) + { + RDIM_Type *dst_type = 0; + + // rjf: unpack itype + CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); + CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); + + // rjf: get basic type slot, fill if unfilled + RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; + if(basic_type == 0) + { + RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); + U32 byte_size = rdi_size_from_basic_type_kind(type_kind); + basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(byte_size == 0xffffffff) + { + byte_size = arch_addr_size; + } + basic_type->kind = type_kind; + basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); + basic_type->byte_size = byte_size; + } + + // rjf: nonzero ptr kind -> form ptr type to basic tpye + if(cv_basic_ptr_kind != 0) + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Ptr; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = basic_type; + } + + // rjf: fill this itype's slot with the finished type + itype_type_ptrs[itype] = dst_type; + } + + ////////////////////////// + //- rjf: build non-basic type + // + if(!itype_is_basic && itype >= itype_first) + { + RDIM_Type *dst_type = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: + { + // rjf: unpack leaf + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: cv -> rdi flags + RDI_TypeModifierFlags flags = 0; + if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} + if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} + + // rjf: fill type + if(flags == 0) + { + dst_type = p2r_type_ptr_from_itype(lf->itype); + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = flags; + dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); + dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: + { + // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead + + // rjf: unpack leaf + CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); + + // rjf: cv -> rdi modifier flags + RDI_TypeModifierFlags modifier_flags = 0; + if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} + if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} + if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} + + // rjf: cv info -> rdi pointer type kind + RDI_TypeKind type_kind = RDI_TypeKind_Ptr; + { + if(lf->attribs & CV_PointerAttrib_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(lf->attribs & CV_PointerAttrib_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + if(ptr_mode == CV_PointerMode_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(ptr_mode == CV_PointerMode_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + } + + // rjf: fill type + if(modifier_flags != 0) + { + RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = modifier_flags; + dst_type->direct_type = pointer_type; + dst_type->byte_size = arch_addr_size; + pointer_type->kind = type_kind; + pointer_type->byte_size = arch_addr_size; + pointer_type->direct_type = direct_type; + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = type_kind; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = direct_type; + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + // TODO(rjf): handle call_kind & attribs + + // rjf: unpack leaf + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type's basics + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Function; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count; + dst_type->param_types = params; + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + // TODO(rjf): handle call_kind & attribs + // TODO(rjf): preserve "this_adjust" + + // rjf: unpack leaf + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + U64 num_this_extras = 1; + if(lf->this_itype == 0) + { + num_this_extras = 0; + } + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + if(lf->this_itype != 0) + { + params[0] = p2r_type_ptr_from_itype(lf->this_itype); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count+num_this_extras; + dst_type->param_types = params; + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + // rjf: unpack leaf + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Bitfield; + dst_type->off = lf->pos; + dst_type->count = lf->len; + dst_type->byte_size = direct_type?direct_type->byte_size:0; + dst_type->direct_type = direct_type; + }break; + + //- rjf: ARRAY + case CV_LeafKind_ARRAY: + { + // rjf: unpack leaf + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 full_size = cv_u64_from_numeric(&array_count); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Array; + dst_type->direct_type = direct_type; + dst_type->byte_size = full_size; + dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; + }break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteUnion; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Union; + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); + U8 *name_ptr = (U8 *)(lf + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteEnum; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Enum; + dst_type->direct_type = direct_type; + dst_type->byte_size = direct_type ? direct_type->byte_size : 0; + dst_type->name = name; + } + }break; + } + } + + //- rjf: store finalized type to this itype's slot + itype_type_ptrs[itype] = dst_type; + } + } + } + p2r2_shared->itype_type_ptrs = itype_type_ptrs; + p2r2_shared->basic_type_ptrs = basic_type_ptrs; + p2r2_shared->all_types = all_types; +#undef p2r_type_ptr_from_itype +#undef p2r_builtin_type_ptr_from_kind + } + lane_sync(); + RDIM_Type **itype_type_ptrs = p2r2_shared->itype_type_ptrs; + RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; + RDIM_TypeChunkList all_types = p2r2_shared->all_types; + + //- //- //-- @@ -1110,4 +2145,5 @@ p2r2_convert_thread_entry_point(void *p) sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; } } + } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 0b98c2e3..28bba102 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -78,10 +78,20 @@ struct P2R2_Shared P2R_SrcFileMap src_file_map; RDIM_UnitChunkList all_units; - RDIM_LineTableChunkList *units_line_tables; RDIM_LineTable **units_first_inline_site_line_tables; + RDIM_LineTableChunkList *lanes_line_tables; RDIM_LineTableChunkList all_line_tables; + + CV_TypeId *itype_fwd_map; + CV_TypeId itype_first; + CV_TypeId itype_opl; + + P2R_TypeIdChain **itype_chains; + + RDIM_Type **itype_type_ptrs; + RDIM_Type **basic_type_ptrs; + RDIM_TypeChunkList all_types; }; global P2R2_Shared *p2r2_shared = 0; From cff69f287a5a99239193e24efc6b9723550c4c94 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 18 Aug 2025 16:58:05 -0700 Subject: [PATCH 032/302] p2r2 more progress; src file line sequence equipping, sketch out symbol conversion - we unfortunately cannot currently easily subdivide units! we need to pull out the few 'record-range' concepts and make them flat first, e.g. proc base address for inline sites, frameproc info, etc. --- project.4coder | 2 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 698 +++++++++++++++++++++++++++++- src/rdi_from_pdb/rdi_from_pdb_2.h | 17 + 3 files changed, 715 insertions(+), 2 deletions(-) diff --git a/project.4coder b/project.4coder index 23c42411..f878de39 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 89e1d325..e0e90df5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -660,7 +660,7 @@ p2r2_convert_thread_entry_point(void *p) String8Array *lane_file_paths = p2r2_shared->lane_file_paths; U64Array *lane_file_paths_hashes = p2r2_shared->lane_file_paths_hashes; - ////////////////////////////// + ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files // { @@ -1089,6 +1089,26 @@ p2r2_convert_thread_entry_point(void *p) lane_sync(); RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; + ////////////////////////////////////////////////////////////// + //- rjf: equip source files with line sequences + // + ProfScope("equip source files with line sequences") if(lane_idx() == 0) + { + for(RDIM_LineTableChunkNode *line_table_chunk_n = all_line_tables.first; + line_table_chunk_n != 0; + line_table_chunk_n = line_table_chunk_n->next) + { + for EachIndex(chunk_line_table_idx, line_table_chunk_n->count) + { + RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; + for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) + { + rdim_src_file_push_line_sequence(arena, &all_src_files__sequenceless, s->v.src_file, &s->v); + } + } + } + } + ////////////////////////////////////////////////////////////// //- rjf: types pass 1: produce type forward resolution map // @@ -2104,6 +2124,682 @@ p2r2_convert_thread_entry_point(void *p) RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; RDIM_TypeChunkList all_types = p2r2_shared->all_types; + ////////////////////////////////////////////////////////////// + //- rjf: types pass 4: build UDTs + // + ProfScope("types pass 4: build UDTs") + { +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + + //- rjf: set up + if(lane_idx() == 0) + { + p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); + } + lane_sync(); + + //- rjf: do wide fill + { + U64 udts_chunk_cap = 1024; + RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; + Rng1U64 range = lane_range(itype_opl); + for EachInRange(idx, range) + { + //- rjf: skip basics + CV_TypeId itype = (CV_TypeId)idx; + if(itype < itype_first) { continue; } + + //- rjf: grab type for this itype - skip if empty + RDIM_Type *dst_type = itype_type_ptrs[itype]; + if(dst_type == 0) { continue; } + + //- rjf: unpack itype leaf range - skip if out-of-range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->off+2+header_struct_size > tpi_leaf->data.size || + range->hdr.size < 2) + { + continue; + } + + //- rjf: build UDT + CV_TypeId field_itype = 0; + switch(kind) + { + default:{}break; + + //////////////////////// + //- rjf: structs/unions/classes -> equip members + // + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_UNION: + { + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + equip_members: + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_list_opl; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: MEMBER + case CV_LeafKind_MEMBER: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + U8 *name_ptr = offset_ptr + offset.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_DataField; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: STMEMBER + case CV_LeafKind_STMEMBER: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticData; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: METHOD + case CV_LeafKind_METHOD: + { + // rjf: unpack leaf + CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + //- rjf: method list itype -> range + CV_RecRange *method_list_range = &tpi_leaf->leaf_ranges.ranges[lf->list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad method lists + if(method_list_range->off+method_list_range->hdr.size > tpi_leaf->data.size || + method_list_range->hdr.size < 2 || + method_list_range->hdr.kind != CV_LeafKind_METHODLIST) + { + break; + } + + //- rjf: loop through all methods & emit members + U8 *method_list_first = tpi_leaf->data.str + method_list_range->off + 2; + U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; + for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; + method_read_ptr < method_list_opl; + method_read_ptr = next_method_read_ptr) + { + CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); + RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); + next_method_read_ptr = (U8 *)(method+1); + + // TODO(allen): PROBLEM + // We only get offsets for virtual functions (the "vbaseoff") from + // "Intro" and "PureIntro". In C++ inheritance, when we have a chain + // of inheritance (let's just talk single inheritance for now) the + // first class in the chain that introduces a new virtual function + // has this "Intro" method. If a later class in the chain redefines + // the virtual function it only has a "Virtual" method which does + // not update the offset. There is a "Virtual" and "PureVirtual" + // variant of "Virtual". The "Pure" in either case means there + // is no concrete procedure. When there is no "Pure" the method + // should have a corresponding procedure symbol id. + // + // The issue is we will want to mark all of our virtual methods as + // virtual and give them an offset, but that means we have to do + // some extra figuring to propogate offsets from "Intro" methods + // to "Virtual" methods in inheritance trees. That is - IF we want + // to start preserving the offsets of virtuals. There is room in + // the method struct to make this work, but for now I've just + // decided to drop this information. It is not urgently useful to + // us and greatly complicates matters. + + // rjf: read vbaseoff + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + if(next_method_read_ptr+4 <= method_list_opl) + { + vbaseoff = *(U32 *)next_method_read_ptr; + } + next_method_read_ptr += 4; + } + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + } + + }break; + + //- rjf: ONEMETHOD + case CV_LeafKind_ONEMETHOD: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); + U8 *vbaseoff_ptr = (U8 *)(lf+1); + U8 *vbaseoff_opl_ptr = vbaseoff_ptr; + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + vbaseoff = *(U32 *)(vbaseoff_ptr); + vbaseoff_opl_ptr += sizeof(U32); + } + U8 *name_ptr = vbaseoff_opl_ptr; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + }break; + + //- rjf: NESTTYPE + case CV_LeafKind_NESTTYPE: + { + // rjf: unpack leaf + CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: NESTTYPEEX + case CV_LeafKind_NESTTYPEEX: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: BCLASS + case CV_LeafKind_BCLASS: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = offset_ptr+offset.encoded_size; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Base; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: VBCLASS/IVBCLASS + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + { + // TODO(rjf): log on bad offsets + // TODO(rjf): handle attribs + // TODO(rjf): offsets? + + // rjf: unpack leaf + CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; + U8 *num1_ptr = (U8 *)(lf+1); + CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); + U8 *num2_ptr = num1_ptr + num1.encoded_size; + CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualBase; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: VFUNCTAB + case CV_LeafKind_VFUNCTAB: + { + CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // NOTE(rjf): currently no-op this case + (void)lf; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + + //////////////////////// + //- rjf: enums -> equip enumerates + // + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_enum_vals; + equip_enum_vals:; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: ENUMERATE + case CV_LeafKind_ENUMERATE: + { + // TODO(rjf): attribs + + // rjf: unpack leaf + CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; + U8 *val_ptr = (U8 *)(lf+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); + enum_val->name = name; + enum_val->val = val64; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + } + } + } +#undef p2r_type_ptr_from_itype + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: produce symbols from all streams + // + ProfScope("produce symbols from all streams") + { + //- rjf: set up + if(lane_idx() == 0) + { + p2r2_shared->lanes_procedures = push_array(arena, RDIM_SymbolChunkList, lane_count()); + p2r2_shared->lanes_global_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); + p2r2_shared->lanes_thread_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); + p2r2_shared->lanes_constants = push_array(arena, RDIM_SymbolChunkList, lane_count()); + p2r2_shared->lanes_scopes = push_array(arena, RDIM_ScopeChunkList, lane_count()); + p2r2_shared->lanes_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, lane_count()); + p2r2_shared->lanes_typedefs = push_array(arena, RDIM_TypeChunkList, lane_count()); + } + lane_sync(); + + //- rjf: wide fill + for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + lane_block != 0; + lane_block = lane_block->next) + { + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: join all lane symbols + // + { + // TODO(rjf) + } //- //- diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 28bba102..051a8ac1 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -92,6 +92,23 @@ struct P2R2_Shared RDIM_Type **itype_type_ptrs; RDIM_Type **basic_type_ptrs; RDIM_TypeChunkList all_types; + + RDIM_UDTChunkList *lanes_udts; + + RDIM_SymbolChunkList *lanes_procedures; + RDIM_SymbolChunkList *lanes_global_variables; + RDIM_SymbolChunkList *lanes_thread_variables; + RDIM_SymbolChunkList *lanes_constants; + RDIM_ScopeChunkList *lanes_scopes; + RDIM_InlineSiteChunkList *lanes_inline_sites; + RDIM_TypeChunkList *lanes_typedefs; + + RDIM_SymbolChunkList all_procedures; + RDIM_SymbolChunkList all_global_variables; + RDIM_SymbolChunkList all_thread_variables; + RDIM_SymbolChunkList all_constants; + RDIM_ScopeChunkList all_scopes; + RDIM_InlineSiteChunkList all_inline_sites; }; global P2R2_Shared *p2r2_shared = 0; From c53b8d43d04235d322a87ee7edf82d74b01ce343 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 15 Aug 2025 12:54:19 -0700 Subject: [PATCH 033/302] assign symbol indices before serializing symbols so forward-references are possible --- src/coff/coff_obj_writer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 33da32fb..3770fb12 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -51,13 +51,21 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) // String8List symbol_table = {0}; { + { + U64 symbol_idx = 0; + for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) { + COFF_ObjSymbol *s = &symbol_n->v; + + // assign symbol index + s->idx = symbol_idx++; + symbol_idx += s->aux_symbols.node_count; + } + } + U64 symbol_idx = 0; for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) { COFF_ObjSymbol *s = &symbol_n->v; - // assign symbol index - s->idx = symbol_idx++; - COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1); str8_list_push(scratch.arena, &symbol_table, str8_struct(d)); From e27831902ec4a5ac1d49ebcb7430ea5784bd94b8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 15 Aug 2025 12:54:47 -0700 Subject: [PATCH 034/302] note --- src/coff/coff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coff/coff.h b/src/coff/coff.h index 68038f0c..0cd16897 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -297,7 +297,7 @@ enum COFF_WeakExt_NoLibrary = 1, COFF_WeakExt_SearchLibrary = 2, COFF_WeakExt_SearchAlias = 3, - COFF_WeakExt_AntiDependency = 4, // default symbol must not reference a weak symbol + COFF_WeakExt_AntiDependency = 4, // search libraries only if the default symbol is weak, even if the weak symbol points to itself }; // storage class: External From 81c68cfdd344c2e09da7fcfe076db3ecb31a46d1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 15 Aug 2025 12:56:04 -0700 Subject: [PATCH 035/302] register common and absolute symbols in library's symbol table --- src/coff/coff_lib_writer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index d61f825c..25670f2c 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -116,7 +116,7 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d } COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular) { + if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) { if (symbol.storage_class == COFF_SymStorageClass_External) { COFF_LibWriterSymbol lib_symbol = {0}; lib_symbol.name = symbol.name; From 81381f9a6d215bd7f4494f0079afb485e8e1eaa5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 15 Aug 2025 12:57:05 -0700 Subject: [PATCH 036/302] minor cleanups --- src/linker/lnk_obj.c | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 667f3e2b..8b990655 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -76,14 +76,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) COFF_SectionHeader *coff_section_table = (COFF_SectionHeader *)raw_coff_section_table.str; for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *coff_sect_header = &coff_section_table[sect_idx]; - - // read name - String8 sect_name = coff_name_from_section_header(raw_coff_string_table, coff_sect_header); - + String8 sect_name = coff_name_from_section_header(raw_coff_string_table, coff_sect_header); if (~coff_sect_header->flags & COFF_SectionFlag_CntUninitializedData) { if (coff_sect_header->fsize > 0) { Rng1U64 sect_range = rng_1u64(coff_sect_header->foff, coff_sect_header->foff + coff_sect_header->fsize); - if (contains_1u64(header.header_range, coff_sect_header->foff) || (coff_sect_header->fsize > 0 && contains_1u64(header.header_range, sect_range.max-1))) { lnk_error_input_obj(LNK_Error_IllData, input, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1); @@ -412,44 +408,23 @@ internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs) { ProfBeginFunction(); - LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs }; tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task); tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task); - ProfEnd(); } internal COFF_ParsedSymbol lnk_obj_match_symbol(LNK_Obj *obj, String8 match_name) { - COFF_ParsedSymbol result = {0}; - - COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(obj->data); - - String8 raw_coff_symbol_table = str8_substr(obj->data, coff_info.symbol_table_range); - String8 raw_coff_string_table = str8_substr(obj->data, coff_info.string_table_range); - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < coff_info.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - void *symbol_ptr; - if (coff_info.is_big_obj) { - symbol_ptr = &((COFF_Symbol32 *)raw_coff_symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol32(raw_coff_string_table, symbol_ptr); - } else { - symbol_ptr = &((COFF_Symbol16 *)raw_coff_symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol16(raw_coff_string_table, symbol_ptr); - } - - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); if (str8_match(symbol.name, match_name, 0)) { - result = symbol; - break; + return symbol; } } - - return result; + return (COFF_ParsedSymbol){0}; } internal MSCRT_FeatFlags From 04d2877b40e038dc653139e381e7473d17e0ffe4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 15 Aug 2025 12:57:33 -0700 Subject: [PATCH 037/302] strip leading white space --- src/linker/scripts/obj_paths_from_pdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linker/scripts/obj_paths_from_pdb.py b/src/linker/scripts/obj_paths_from_pdb.py index da7d2ab3..a4d3de02 100644 --- a/src/linker/scripts/obj_paths_from_pdb.py +++ b/src/linker/scripts/obj_paths_from_pdb.py @@ -5,7 +5,7 @@ import os def get_sorted_objs(pdb_path): result = subprocess.run(["llvm-pdbutil", "dump", "--modules", pdb_path], stdout=subprocess.PIPE, text=True) lines = result.stdout.strip().split('\n') - filtered_lines = [line for line in lines if line.startswith("Mod ")] + filtered_lines = [line for line in lines if line.lstrip().startswith("Mod ")] # sort by the obj_path portion (line format: "Mod ") def extract_path(line): return line.split(maxsplit=2)[2].lower() sorted_lines = sorted(filtered_lines, key=extract_path) @@ -13,4 +13,4 @@ def get_sorted_objs(pdb_path): if __name__ == "__main__": sorted_objs = get_sorted_objs(sys.argv[1]) - for l in sorted_objs: print(l) + for l in sorted_objs: print(l.lstrip()) From a3582332ee84281d8235f3ce13e9fc691403658a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 17 Aug 2025 16:10:13 -0700 Subject: [PATCH 038/302] push a null symbol as a terminator for /alternatename weak symbol chain --- src/linker/lnk.c | 5 ++++- src/linker/lnk.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a2588938..c1b28c35 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -462,7 +462,10 @@ lnk_make_null_obj(Arena *arena) { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_Unknown); - // make import stub + // push null symbol + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External); + + // push import stub { COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("RAD_IMPORT_STUB_NULL"), 0, COFF_SymStorageClass_Static); coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_AntiDependency, tag); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 2aa1dc61..20fc27be 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -6,6 +6,7 @@ // --- Link -------------------------------------------------------------------- #define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" +#define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***" #define LNK_SECTION_FLAG_IS_LIVE (1 << 0) typedef struct LNK_LinkContext From 1ce2fbfd1addcf8d47b2f1f78e5c233eeca86262 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 17 Aug 2025 16:10:46 -0700 Subject: [PATCH 039/302] helper for setting default symbol --- src/coff/coff_obj_writer.c | 10 +++++++++- src/coff/coff_obj_writer.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 3770fb12..016b2364 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -103,7 +103,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) if (s->aux_symbols.node_count > 0) { COFF_ObjSymbolWeak *s_weak = (COFF_ObjSymbolWeak *)s->aux_symbols.first->string.str; COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1); - d_weak->tag_index = s_weak->tag->idx; + d_weak->tag_index = s_weak->tag ? s_weak->tag->idx : max_U32; d_weak->characteristics = s_weak->characteristics; str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak)); @@ -415,6 +415,14 @@ coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 return s; } +internal void +coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol) +{ + AssertAlways(weak_symbol->storage_class == COFF_SymStorageClass_WeakExternal); + COFF_ObjSymbolWeak *w = (COFF_ObjSymbolWeak *)weak_symbol->aux_symbols.first->string.str; + w->tag = default_symbol; +} + internal COFF_ObjReloc* coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type) { diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 9068822a..5b5e0248 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -115,6 +115,8 @@ internal COFF_ObjSymbol * coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter internal COFF_ObjSymbol * coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect); internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj_writer, String8 name, U32 size); +internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol); + internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type); internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol); internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol); From e1786d0a11a232746972a446924defab37f91695 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 17 Aug 2025 16:12:16 -0700 Subject: [PATCH 040/302] discard delay loads in the config before they get to link context builder --- src/linker/lnk_config.c | 14 ++++++++++++-- src/linker/lnk_config.h | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index ae28b190..b11430fe 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -933,6 +933,12 @@ lnk_is_section_removed(LNK_Config *config, String8 section_name) return is_removed; } +internal B32 +lnk_is_dll_delay_load(LNK_Config *config, String8 dll_name) +{ + return hash_table_search_path_u64(config->delay_load_ht, dll_name, 0); +} + internal void lnk_print_build_info() { @@ -1195,8 +1201,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_DelayLoad: { - String8List delay_load_dll_list = str8_list_copy(arena, &value_strings); - str8_list_concat_in_place(&config->delay_load_dll_list, &delay_load_dll_list); + for (String8Node *name_n = value_strings.first; name_n != 0; name_n = name_n->next) { + if (hash_table_search_path_u64(config->delay_load_ht, name_n->string, 0)) { continue; } + String8 name = push_str8_copy(arena, name_n->string); + hash_table_push_path_u64(arena, config->delay_load_ht, name, 0); + str8_list_push(arena, &config->delay_load_dll_list, name); + } } break; case LNK_CmdSwitch_Dll: { diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index aa6cdba1..bc0bce05 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -390,11 +390,13 @@ typedef struct LNK_Config String8 temp_pdb_name; String8 temp_rad_debug_name; String8 temp_rad_chunk_map_name; + String8 delay_load_helper_name; String8List remove_sections; LNK_IO_Flags io_flags; HashTable *export_ht; HashTable *alt_name_ht; HashTable *include_symbol_ht; + HashTable *delay_load_ht; } LNK_Config; // --- MSVC Error Codes -------------------------------------------------------- @@ -579,8 +581,8 @@ internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, CO internal B32 lnk_do_debug_info (LNK_Config *config); internal B32 lnk_is_thread_pool_shared(LNK_Config *config); - -internal B32 lnk_is_section_removed(LNK_Config *config, String8 section_name); +internal B32 lnk_is_section_removed (LNK_Config *config, String8 section_name); +internal B32 lnk_is_dll_delay_load (LNK_Config *config, String8 dll_name); // --- Config ------------------------------------------------------------------ From 1bca83610f2df5639dd6c96519e569fdf62ec333 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 17 Aug 2025 16:22:08 -0700 Subject: [PATCH 041/302] changed symbol search logic to run in three steps: undefined, weak, and anti-dependency weak, allowing linking to proceed only after symbols from previous step are added to the symbol table this solves the problem of anti-dependency symbols because they are searched in libraries if the dependency is unresolved weak symbol --- src/linker/lnk.c | 751 ++++++++++++++++++++++++----------------------- 1 file changed, 386 insertions(+), 365 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index c1b28c35..a2d2e1ab 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -966,12 +966,12 @@ lnk_make_linker_obj(Arena *arena, LNK_Config *config) } internal void -lnk_queue_lib_member_input(Arena *arena, - LNK_Config *config, - LNK_Symbol *pull_in_ref, - LNK_Symbol *member_symbol, - LNK_InputImportList *input_import_list, - LNK_InputObjList *input_obj_list) +lnk_queue_lib_member_for_input(Arena *arena, + LNK_Config *config, + LNK_Symbol *pull_in_ref, + LNK_Symbol *member_symbol, + LNK_InputImportList *input_import_list, + LNK_InputObjList *input_obj_list) { // lookup member in the lib where pull-in reference is declared LNK_Symbol *best_match = member_symbol; @@ -1039,16 +1039,10 @@ lnk_queue_lib_member_input(Arena *arena, } internal void -lnk_find_refs(Arena *arena, - TP_Context *tp, - LNK_SymbolTable *symtab, - LNK_Config *config, - LNK_ObjList objs, - LNK_InputImportList *imports_out, - LNK_InputObjList *objs_out) +lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs) { ProfBeginFunction(); - Temp scratch = scratch_begin(&arena,1); + Temp scratch = scratch_begin(0,0); struct Task { struct Task *next; LNK_Obj *obj; COFF_RelocArray relocs; U32 section_number; }; struct Task *task_stack = 0; @@ -1097,9 +1091,9 @@ lnk_find_refs(Arena *arena, COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); // is section eligible for walking? - if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } - if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - if (config->opt_ref == LNK_SwitchState_Yes && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } + if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } // divide relocs and push task for each reloc block COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number); @@ -1132,87 +1126,31 @@ lnk_find_refs(Arena *arena, for (;;) { COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); - if (ref_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); - COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); - if (defn_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *member_symbol = 0; - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(ref_parsed, ref_symbol.obj->header.is_big_obj); - switch (weak_ext->characteristics) { - case COFF_WeakExt_NoLibrary: { - // NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member. - } break; - case COFF_WeakExt_AntiDependency: - case COFF_WeakExt_SearchLibrary: { - member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); - } break; - case COFF_WeakExt_SearchAlias: { - member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); - if (member_symbol == 0) { - if (str8_match_lit(".weak.", ref_parsed.name, StringMatchFlag_RightSideSloppy)) { - // TODO: Clang and MingGW encode extra info in alias - // - // __attribute__((weak,alias("foo"))) void bar(void); - // static void foo() {} - // - // Clang write these COFF symbols in obj for code above: - // - // 30 00000000 0000000001 0 FUNC NULL EXTERNAL foo - // ... - // 33 00000000 UNDEF 1 NULL NULL WEAK_EXTERNAL bar - // Tag Index 35, Characteristics SEARCH_ALIAS - // 35 00000000 0000000001 0 NULL NULL EXTERNAL .weak.bar.default.foo - // - // In this case linker needs to parse .weak.bar.default.foo and search for bar and foo as well. - Assert("TODO: MinGW weak symbol"); - } else { - COFF_ParsedSymbol tag = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, weak_ext->tag_index); - member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, tag.name); - } - } - } break; - default: { NotImplemented; } break; - } - if (member_symbol) { - lnk_queue_lib_member_input(arena, config, defn, member_symbol, imports_out, objs_out); - MemoryZeroStruct(&ref_symbol); - break; - } else { - ref_symbol = lnk_resolve_weak_symbol(symtab, ref_symbol); - } - } else { - ref_symbol = defn->u.defined; - } - } - else if (ref_interp == COFF_SymbolValueInterp_Undefined) { - if (ref_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn); - COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed); - - if (defn_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, ref_parsed.name); - if (member_symbol) { - lnk_queue_lib_member_input(arena, config, defn, member_symbol, imports_out, objs_out); - } - break; - } else { - ref_symbol = defn->u.defined; - } - } else { - break; - } - } else if (ref_interp == COFF_SymbolValueInterp_Regular) { + LNK_SymbolDefined next_ref = {0}; + if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { ref_symbol = symlink->u.defined; } break; + } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { + if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + next_ref = defn->u.defined; + } + } else if (ref_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); + next_ref = defn->u.defined; } else { break; } + + if (MemoryMatchStruct(&next_ref, &ref_symbol)) { + MemoryZeroStruct(&ref_symbol); + break; + } + ref_symbol = next_ref; } // skip unresolved symbol @@ -1241,8 +1179,8 @@ lnk_find_refs(Arena *arena, COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number); // is section eligible for walking? - if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } if (lnk_is_coff_section_debug(ref_obj, section_number-1)) { continue; } // mark section @@ -1265,22 +1203,71 @@ lnk_find_refs(Arena *arena, } } + ProfBegin("Remove Unreachable Sections"); + for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + LNK_Obj *obj = &obj_n->data; + for EachIndex(sect_idx, obj->header.section_count_no_null) { + U32 section_number = sect_idx+1; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + + if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } + + // remove unreferenced sections + if (~section_header->flags & LNK_SECTION_FLAG_IS_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { + section_header->flags |= COFF_SectionFlag_LnkRemove; + } + + // TODO: Reset reserved flag so it does not get propagated to the image sections. + // We need to mask out reserved flags when gathering section definitions to actually + // prevent propagation. + section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; + + if (section_header->flags & COFF_SectionFlag_LnkRemove) { + for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { + U32 section_number = section_number_n->data; + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + section_header->flags |= COFF_SectionFlag_LnkRemove; + } + } + } + } + ProfEnd(); + scratch_end(scratch); ProfEnd(); } internal -THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbol_task) +THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) { - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - symbol->u.defined = lnk_resolve_weak_symbol(symtab, symbol->u.defined); + LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->u.defined); + COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); + COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); + if (resolve_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->u.defined.obj->header.is_big_obj); + COFF_SymStorageClass storage_class = weak_ext->characteristics == COFF_WeakExt_AntiDependency ? COFF_SymStorageClass_Null : COFF_SymStorageClass_External; + if (symbol->u.defined.obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; + symbol32->section_number = COFF_Symbol_UndefinedSection; + symbol32->value = 0; + symbol32->storage_class = storage_class; + } else { + COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; + symbol16->section_number = COFF_Symbol_UndefinedSection; + symbol16->value = 0; + symbol16->storage_class = storage_class; + } + } else { + symbol->u.defined = resolve; + } } } } @@ -1288,20 +1275,20 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbol_task) internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { - enum State { + enum { State_Null, State_InputDisallowLibs, State_InputImports, - State_InputSymbols, + State_InputInclude, State_InputObjs, State_InputLibs, State_InputAlternateNames, - State_PushDllHelperUndefSymbol, + State_InputDelayLoadDlls, State_InputLinkerObjs, - State_PushLoadConfigUndefSymbol, - State_FindRefs, - State_LookupEntryPoint, - State_ReportUnresolvedSymbols, + State_SearchUndefined, + State_SearchWeak, + State_SearchWeakAntiDep, + State_SearchEntryPoint, }; struct StateNode { struct StateNode *next; enum State state; }; struct StateList { U64 count; struct StateNode *first; struct StateNode *last; }; @@ -1312,75 +1299,68 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) l.count += 1; \ } while (0) #define state_list_pop(l) (l).first->state; SLLQueuePop((l).first, (l).last); (l).count -= 1 + typedef enum { + SearchFlag_Undefined = (1 << 0), + SearchFlag_Weak = (1 << 1), + SearchFlag_WeakAntiDep = (1 << 2), + SearchFlag_All = (SearchFlag_Undefined|SearchFlag_Weak|SearchFlag_WeakAntiDep) + } SearchFlags; ProfBeginFunction(); Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); - - // inputs - String8Node **last_include_symbol = &config->include_symbol_list.first; - String8Node **last_disallow_lib = &config->disallow_lib_list.first; - LNK_AltNameNode **last_alt_name = &config->alt_name_list.first; - LNK_InputObjList input_obj_list = {0}; - LNK_InputImportList input_import_list = {0}; - LNK_InputLib **input_libs[LNK_InputSource_Count] = { - &config->input_list[LNK_Input_Lib].first, - &config->input_default_lib_list.first, - &config->input_obj_lib_list.first - }; - // input :null_obj + // + // state + // + LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); + String8Node **last_include_symbol = &config->include_symbol_list.first; + String8Node **last_disallow_lib = &config->disallow_lib_list.first; + String8Node **last_delay_load_dll = &config->delay_load_dll_list.first; + LNK_AltNameNode **last_alt_name = &config->alt_name_list.first; + LNK_InputObjList input_obj_list = {0}; + LNK_InputImportList input_import_list = {0}; + LNK_InputLib **input_libs[LNK_InputSource_Count] = { &config->input_list[LNK_Input_Lib].first, &config->input_default_lib_list.first, &config->input_obj_lib_list.first }; + LNK_ObjList obj_list = {0}; + LNK_LibList lib_index[LNK_InputSource_Count] = {0}; + U64 entry_point_search_attempts = 0; + SearchFlags search_flags = SearchFlag_All; + B32 input_linker_objs = 1; + HashTable *static_imports = hash_table_init(scratch.arena, 512); + HashTable *delayed_imports = hash_table_init(scratch.arena, 512); + HashTable *import_stub_ht = hash_table_init(scratch.arena, 0x1000); + // TODO: move disallow_lib, loaded_lib, missing_lib, and loaded_obj to config + Arena *ht_arena = arena_alloc(); + HashTable *disallow_lib_ht = hash_table_init(scratch.arena, 0x100); + HashTable *loaded_lib_ht = hash_table_init(scratch.arena, 0x100); + HashTable *missing_lib_ht = hash_table_init(scratch.arena, 0x100); + HashTable *loaded_obj_ht = hash_table_init(scratch.arena, 0x4000); + + // TODO: this should happen in the config before state machine setup { + // input :null_obj LNK_InputObj *null_obj_input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); null_obj_input->exclude_from_debug_info = 1; null_obj_input->path = str8_lit("* Null Obj *"); null_obj_input->dedup_id = null_obj_input->path; null_obj_input->data = lnk_make_null_obj(tp_arena->v[0]); - } - - // input command line objs - LNK_InputObjList cmd_line_obj_inputs = lnk_input_obj_list_from_string_list(scratch.arena, config->input_list[LNK_Input_Obj]); - lnk_input_obj_list_concat_in_place(&input_obj_list, &cmd_line_obj_inputs); - // state - LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); - LNK_SectionTable *sectab = 0; - HashTable *static_imports = hash_table_init(scratch.arena, 512); - HashTable *delayed_imports = hash_table_init(scratch.arena, 512); - LNK_ObjList obj_list = {0}; - LNK_LibList lib_index[LNK_InputSource_Count] = {0}; - Arena *ht_arena = arena_alloc(); - String8 delay_load_helper_name = {0}; - HashTable *disallow_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *delay_load_dll_ht = hash_table_init(scratch.arena, 0x100); - HashTable *loaded_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *missing_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *loaded_obj_ht = hash_table_init(scratch.arena, 0x4000); - U64 entry_point_lookup_attempts = 0; - B32 input_linker_objs = 1; - B32 pending_refs = 0; + // input command line objs + LNK_InputObjList cmd_line_obj_inputs = lnk_input_obj_list_from_string_list(scratch.arena, config->input_list[LNK_Input_Obj]); + lnk_input_obj_list_concat_in_place(&input_obj_list, &cmd_line_obj_inputs); + } + + // TODO: MSVC does not need this flag to include load config + if (config->guard_flags != LNK_Guard_None) { + // TODO: config_refactor + String8List value_strings = {0}; + str8_list_push(scratch.arena, &value_strings, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); + lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); + } // - // Init state machine + // run states // struct StateList state_list = {0}; - state_list_push(scratch.arena, state_list, State_InputDisallowLibs); - state_list_push(scratch.arena, state_list, State_InputObjs); - state_list_push(scratch.arena, state_list, State_InputLibs); - if (config->delay_load_dll_list.node_count) { - for (String8Node *delay_load_dll_node = config->delay_load_dll_list.first; - delay_load_dll_node != 0; - delay_load_dll_node = delay_load_dll_node->next) { - hash_table_push_path_u64(scratch.arena, delay_load_dll_ht, delay_load_dll_node->string, 0); - } - state_list_push(scratch.arena, state_list, State_PushDllHelperUndefSymbol); - } - if (config->guard_flags != LNK_Guard_None) { - state_list_push(scratch.arena, state_list, State_PushLoadConfigUndefSymbol); - } - - // - // Run states - // for (;;) { for (; state_list.count > 0; ) { enum State state = state_list_pop(state_list); @@ -1410,6 +1390,10 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) continue; } + // skip duplicate import inputs + if (hash_table_search_string_raw(import_stub_ht, import_header.func_name, 0)) { continue; } + hash_table_push_string_raw(ht_arena, import_stub_ht, import_header.func_name, 0); + // create import stubs (later replaced with acutal imports generated by linker) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(LNK_IMPORT_STUB)); LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); @@ -1418,15 +1402,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, imp_symbol); // pick imports hash table - HashTable *imports_ht; - { - B32 is_delay_load_dll = hash_table_search_path_u64(delay_load_dll_ht, import_header.dll_name, 0); - if (is_delay_load_dll) { - imports_ht = delayed_imports; - } else { - imports_ht = static_imports; - } - } + HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? delayed_imports : static_imports; // search DLL symbol list String8List *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); @@ -1444,8 +1420,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); } break; - case State_InputSymbols: { - ProfBegin("Input Symbols"); + case State_InputInclude: { + ProfBegin("Input Include"); // push a relocation which references an undefined include symbol COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); @@ -1524,7 +1500,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // if the machine was omitted on the command line, derive machine from obj if (config->machine == COFF_MachineType_Unknown) { - for (U64 obj_idx = 0; obj_idx < obj_node_arr.count; obj_idx += 1) { + for EachIndex(obj_idx, obj_node_arr.count) { if (obj_node_arr.v[obj_idx].data.header.machine != COFF_MachineType_Unknown) { config->machine = obj_node_arr.v[obj_idx].data.header.machine; break; @@ -1532,12 +1508,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } } - // infer minimal padding size for functions from the target machine - if (config->machine != COFF_MachineType_Unknown && config->infer_function_pad_min) { - config->function_pad_min = lnk_get_default_function_pad_min(config->machine); - config->infer_function_pad_min = 0; - } - ProfBegin("Apply Directives"); for EachIndex(obj_idx, obj_node_arr.count) { LNK_Obj *obj = &obj_node_arr.v[obj_idx].data; @@ -1555,7 +1525,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) lnk_input_obj_symbols(tp, tp_arena, symtab, obj_node_arr); // schedule symbol input - pending_refs = 1; + search_flags = SearchFlag_All; // reset input objs MemoryZeroStruct(&input_obj_list); @@ -1641,7 +1611,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (lnk_get_log_status(LNK_Log_InputLib)) { if (libs.count > 0) { U64 input_size = 0; - for (U64 i = 0; i < libs.count; ++i) { input_size += libs.v[i].data.data.size; } + for EachIndex(i, libs.count) { input_size += libs.v[i].data.data.size; } lnk_log(LNK_Log_InputObj, "[ Lib Input Size %M ]", input_size); } } @@ -1651,76 +1621,129 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } // schedule symbol input - pending_refs = 1; + search_flags = SearchFlag_All; ProfEnd(); } break; case State_InputAlternateNames: { ProfBegin("Input Alternate Names"); - COFF_ObjWriter *obj_writer = 0; - for (; *last_alt_name; last_alt_name = &(*last_alt_name)->next) { - // make object writer if it was reset - if (obj_writer == 0) { - obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); + + // linker is not allowed to create a new alternate name if the "from" symbol already exists + // (MSVC silently ignores the directive) + { + LNK_Symbol *extant_from = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, (*last_alt_name)->data.from); + if (extant_from) { + COFF_SymbolValueInterpType extant_interp = lnk_interp_from_symbol(extant_from); + if (extant_interp != COFF_SymbolValueInterp_Undefined) { break; } } + } - // append weak symbol - COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_undef(obj_writer, (*last_alt_name)->data.to); - coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.from, COFF_WeakExt_AntiDependency, tag); + // make & input alternate name obj + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - // flush on last directive or next directive is issued from a different obj - if ((*last_alt_name)->next == 0 || (*last_alt_name)->data.obj != (*last_alt_name)->next->data.obj) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK"); - input->exclude_from_debug_info = 1; - input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S *", input->path); - input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); - input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0; + COFF_ObjSymbol *null_symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit(LNK_NULL_SYMBOL)); + COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.from, COFF_WeakExt_Rad_WeakSearchLibrary, null_symbol); + COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.to, COFF_WeakExt_Rad_WeakSearchLibrary, from_symbol); - // reset obj writer - coff_obj_writer_release(&obj_writer); - obj_writer = 0; + String8 alt_name_obj = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); + coff_obj_writer_release(&obj_writer); + + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK"); + input->exclude_from_debug_info = 1; + input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S * %u", input->path, obj_list.count); + input->data = alt_name_obj; + input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0; + } + + // advance to next alt name + last_alt_name = &(*last_alt_name)->next; + + ProfEnd(); + } break; + case State_InputDelayLoadDlls: { + ProfBegin("Input Delay Load Dlls"); + + for (; *last_delay_load_dll; last_delay_load_dll = &(*last_delay_load_dll)->next); + + // TODO: config_refactor + String8List value_strings = {0}; + str8_list_push(scratch.arena, &value_strings, config->delay_load_helper_name); + lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); + + ProfEnd(); + } break; + case State_SearchUndefined: { + ProfBegin("Search Undefined"); + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); + if (member_symbol) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); + } + } + } } } ProfEnd(); } break; - case State_PushDllHelperUndefSymbol: { - ProfBegin("Push Dll Helper Undef Symbol"); - delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); - - // TODO: config_refactor - String8List value_strings = {0}; - str8_list_push(scratch.arena, &value_strings, delay_load_helper_name); - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - + case State_SearchWeak: { + ProfBegin("Search Weak"); + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); + if (member_symbol) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); + } + } + } + } + } + } ProfEnd(); } break; - case State_PushLoadConfigUndefSymbol: { - ProfBegin("Push Load Config Undef Symbol"); - String8 load_config_name = str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME); - - // TODO: config_refactor - String8List value_strings = {0}; - str8_list_push(scratch.arena, &value_strings, load_config_name); - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - + case State_SearchWeakAntiDep: { + ProfBegin("Search Weak AntiDep"); + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->u.defined); + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol_parsed.name); + if (member_symbol) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); + } + } + } + } + } + } + } ProfEnd(); } break; - case State_FindRefs: { - ProfBegin("Find Refs"); - - LNK_InputImportList new_imports = {0}; - LNK_InputObjList new_objs = {0}; - lnk_find_refs(scratch.arena, tp, symtab, config, obj_list, &new_imports, &new_objs); - - // schedule new inputs - lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); - lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); - - ProfEnd(); - } break; - case State_LookupEntryPoint: { - ProfBegin("Lookup Entry Point"); + case State_SearchEntryPoint: { + ProfBegin("Search Entry Point"); LNK_Symbol *entry_point_symbol = 0; B32 is_entry_point_unspecified = config->entry_point_name.size == 0; @@ -1729,9 +1752,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // we don't have a subsystem and entry point name, // so we loop over every subsystem and search potential entry // points in the symbol table - for (U64 subsys_idx = 0; subsys_idx < PE_WindowsSubsystem_COUNT; subsys_idx += 1) { + for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for (U64 entry_idx = 0; entry_idx < name_arr.count; entry_idx += 1) { + for EachIndex(entry_idx, name_arr.count) { entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); if (entry_point_symbol) { config->subsystem = (PE_WindowsSubsystem)subsys_idx; @@ -1742,9 +1765,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // search for potential entry points in libs if (!entry_point_symbol) { - for (U64 subsys_idx = 0; subsys_idx < PE_WindowsSubsystem_COUNT; subsys_idx += 1) { + for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for (U64 entry_idx = 0; entry_idx < name_arr.count; entry_idx += 1) { + for EachIndex(entry_idx, name_arr.count) { entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); if (entry_point_symbol) { config->subsystem = (PE_WindowsSubsystem)subsys_idx; @@ -1759,7 +1782,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // we have subsystem but no entry point name, get potential entry point names // and see which is in the symbol table String8Array name_arr = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); - for (U64 entry_idx = 0; entry_idx < name_arr.count; entry_idx += 1) { + for EachIndex(entry_idx, name_arr.count) { LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); if (symbol) { if (entry_point_symbol) { @@ -1775,7 +1798,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // search for entry point in libs if (!entry_point_symbol) { - for (U64 entry_idx = 0; entry_idx < name_arr.count; entry_idx += 1) { + for EachIndex(entry_idx, name_arr.count) { entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); if (entry_point_symbol) { break; @@ -1869,11 +1892,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); - for (U64 dll_idx = 0; dll_idx < delayed_imports->count; dll_idx += 1) { + for EachIndex(dll_idx, delayed_imports->count) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = obj_list.count; - input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); + input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], config->delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); input->path = dll_names[dll_idx]; input->dedup_id = input->path; } @@ -1905,7 +1928,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); - for (U64 dll_idx = 0; dll_idx < static_imports->count; dll_idx += 1) { + for EachIndex(dll_idx, static_imports->count) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = obj_list.count; @@ -2090,7 +2113,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } } - if (*last_disallow_lib != 0) { + if (*last_disallow_lib) { state_list_push(scratch.arena, state_list, State_InputDisallowLibs); continue; } @@ -2098,17 +2121,17 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputImports); continue; } - if (*last_include_symbol != 0) { - state_list_push(scratch.arena, state_list, State_InputSymbols); + if (*last_include_symbol) { + state_list_push(scratch.arena, state_list, State_InputInclude); continue; } - if (*last_alt_name != 0) { + if (*last_alt_name) { state_list_push(scratch.arena, state_list, State_InputAlternateNames); continue; } { B32 have_pending_lib_inputs = 0; - for (U64 i = 0; i < ArrayCount(input_libs); ++i) { + for EachIndex(i, ArrayCount(input_libs)) { if (*input_libs[i] != 0) { have_pending_lib_inputs = 1; break; @@ -2123,14 +2146,28 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputObjs); continue; } - if (pending_refs) { - pending_refs = 0; - state_list_push(scratch.arena, state_list, State_FindRefs); + if (*last_delay_load_dll) { + state_list_push(scratch.arena, state_list, State_InputDelayLoadDlls); continue; } - if (entry_point_lookup_attempts == 0) { - state_list_push(scratch.arena, state_list, State_LookupEntryPoint); - entry_point_lookup_attempts += 1; + if (search_flags & SearchFlag_Undefined) { + search_flags &= ~SearchFlag_Undefined; + state_list_push(scratch.arena, state_list, State_SearchUndefined); + continue; + } + if (search_flags & SearchFlag_Weak) { + search_flags &= ~SearchFlag_Weak; + state_list_push(scratch.arena, state_list, State_SearchWeak); + continue; + } + if (search_flags & SearchFlag_WeakAntiDep) { + search_flags &= ~SearchFlag_WeakAntiDep; + state_list_push(scratch.arena, state_list, State_SearchWeakAntiDep); + continue; + } + if (entry_point_search_attempts == 0) { + state_list_push(scratch.arena, state_list, State_SearchEntryPoint); + entry_point_search_attempts += 1; continue; } if (input_linker_objs) { @@ -2142,104 +2179,83 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) break; } - ProfBegin("Report Unresolved Symbols"); - { - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], tp->worker_count, &chunks_count); - - U64 undefs_count = 0; - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - if (symbol->is_live) { - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - if (coff_is_undefined_data_symbol(symbol_parsed)) { - undefs_count += 1; - } - } - } - } - - U64 undefs_cursor = 0; - LNK_Symbol **undefs = push_array(scratch.arena, LNK_Symbol *, undefs_count); - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - if (symbol->is_live) { - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - if (coff_is_undefined_data_symbol(symbol_parsed)) { - undefs[undefs_cursor++] = chunk->v[i].symbol; - } - } - } - } - - radsort(undefs, undefs_count, lnk_symbol_defined_ptr_is_before); - - for EachIndex(i, undefs_count) { - LNK_Symbol *s = undefs[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, s->u.defined.obj, "unresolved symbol %S", s->name); - } - - if (undefs_count > 0) { - lnk_exit(LNK_Error_UnresolvedSymbol); - } - } - ProfEnd(); - - ProfBegin("Remove Unreachable Sections"); - { - for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { - LNK_Obj *obj = &obj_n->data; - for EachIndex(sect_idx, obj->header.section_count_no_null) { - U32 section_number = sect_idx+1; - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); - - if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } - - if (config->opt_ref == LNK_SwitchState_Yes) { - // remove unreferenced sections - if (~section_header->flags & LNK_SECTION_FLAG_IS_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { - section_header->flags |= COFF_SectionFlag_LnkRemove; - } - } - - // TODO: Reset reserved flag so it does not get propagated to the image sections. - // We need to mask out reserved flags when gathering section definitions to actually - // prevent propagation. - section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; - - if (section_header->flags & COFF_SectionFlag_LnkRemove) { - for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { - U32 section_number = section_number_n->data; - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); - section_header->flags |= COFF_SectionFlag_LnkRemove; - } - } - } - } - } - ProfEnd(); - - ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); { U64 chunks_count = 0; LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_symbols_with_default_symbol_task, &task); + + ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); + { + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); +#if BUILD_DEBUG + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); + } + } +#endif + } + ProfEnd(); + + ProfBegin("Report Unresolved Symbols"); + { + U64 count = 0; + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + count += 1; + } + } + } + + U64 cursor = 0; + LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + unresolved[cursor++] = chunk->v[i].symbol; + } + } + } + + radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); + + for EachIndex(i, count) { + LNK_Symbol *symbol = unresolved[i]; + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->u.defined.obj, "unresolved symbol %S", symbol->name); + } + + // TODO: /FORCE + if (count) { + lnk_exit(LNK_Error_UnresolvedSymbol); + } + } + ProfEnd(); } - ProfEnd(); // - // fill out link context + // discard COMDAT sections that are not referenced // - LNK_LinkContext link_ctx = {0}; - link_ctx.symtab = symtab; - link_ctx.objs_count = obj_list.count; - link_ctx.objs = lnk_array_from_obj_list(tp_arena->v[0], obj_list); - MemoryCopyTyped(&link_ctx.lib_index[0], &lib_index[0], ArrayCount(lib_index)); + if (config->opt_ref == LNK_SwitchState_Yes) { + lnk_opt_ref(tp, symtab, config, obj_list); + } + + // + // infer minimal padding size for functions from the target machine + // + if (config->machine != COFF_MachineType_Unknown && config->infer_function_pad_min) { + config->function_pad_min = lnk_get_default_function_pad_min(config->machine); + config->infer_function_pad_min = 0; + } // // log @@ -2251,13 +2267,22 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } if (lnk_get_log_status(LNK_Log_InputLib)) { U64 total_input_size = 0; - for (U64 i = 0; i < ArrayCount(lib_index); ++i) { + for EachIndex(i, ArrayCount(lib_index)) { LNK_LibList list = lib_index[i]; for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; } } lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); } + // + // fill out link context + // + LNK_LinkContext link_ctx = {0}; + link_ctx.symtab = symtab; + link_ctx.objs_count = obj_list.count; + link_ctx.objs = lnk_array_from_obj_list(tp_arena->v[0], obj_list); + MemoryCopyTyped(&link_ctx.lib_index[0], &lib_index[0], ArrayCount(lib_index)); + ProfEnd(); scratch_end(scratch); return link_ctx; @@ -2410,25 +2435,6 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task) scratch_end(scratch); } -internal -THREAD_POOL_TASK_FUNC(lnk_flag_debug_symbols_task) -{ - LNK_BuildImageTask *task = raw_task; - U64 obj_idx = task_id; - LNK_Obj *obj = task->objs[obj_idx]; - - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular) { - if (lnk_is_coff_section_debug(obj, symbol.section_number-1)) { - task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; - } - } - } -} - internal THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) { @@ -2452,6 +2458,25 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) ProfEnd(); } +internal +THREAD_POOL_TASK_FUNC(lnk_flag_debug_symbols_task) +{ + LNK_BuildImageTask *task = raw_task; + U64 obj_idx = task_id; + LNK_Obj *obj = task->objs[obj_idx]; + + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_Regular) { + if (lnk_is_coff_section_debug(obj, symbol.section_number-1)) { + task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; + } + } + } +} + internal THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) { @@ -2676,14 +2701,10 @@ lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patch if (is_resolved) { COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx); COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class); - AssertAlways(fixup_type == COFF_SymbolValueInterp_Regular || - fixup_type == COFF_SymbolValueInterp_Abs || - fixup_type == COFF_SymbolValueInterp_Common || - fixup_type == COFF_SymbolValueInterp_Undefined); U32 section_number; U32 value; - if (fixup_type == COFF_SymbolValueInterp_Undefined) { + if (fixup_type == COFF_SymbolValueInterp_Undefined || fixup_type == COFF_SymbolValueInterp_Weak) { section_number = lnk_obj_get_removed_section_number(obj); value = 0; } else { From 873aa475e812525f4f8688eb7d46b27a25053a67 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:33:10 -0700 Subject: [PATCH 042/302] update tests to conform to new linking rules --- src/torture/torture.c | 66 +++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/src/torture/torture.c b/src/torture/torture.c index b7b960d3..cd01bbf3 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -802,9 +802,7 @@ t_link_unref_undef(void) String8 entry_obj; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - U8 text[] = { - 0xC3 // ret - }; + U8 text[] = { 0xc3 }; COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); @@ -816,7 +814,7 @@ t_link_unref_undef(void) // try linking unreferenced unresolved symbol, this must link int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj undef.obj"); - if (linker_exit_code != 0) { goto exit; } + if (linker_exit_code == 0) { goto exit; } result = T_Result_Pass; exit:; @@ -1184,74 +1182,58 @@ internal T_Result t_undef_weak(void) { Temp scratch = scratch_begin(0,0); - T_Result result = T_Result_Fail; - String8 entry_symbol_name = str8_lit("my_entry"); - String8 shared_symbol_name = str8_lit("foo"); - - U8 weak_payload[] = { 0xDE, 0xAD, 0xBE, 0xEF }; - String8 weak_obj_name = str8_lit("weak.obj"); + String8 weak_obj; { + U8 weak_payload[] = { 0xDE, 0xAD, 0xBE, 0xEF }; COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); COFF_ObjSection *weak_sect = t_push_data_section(obj_writer, str8_array_fixed(weak_payload)); COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("ptr")); - coff_obj_writer_push_symbol_weak(obj_writer, shared_symbol_name, COFF_WeakExt_SearchAlias, tag); - String8 weak_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("foo"), COFF_WeakExt_SearchAlias, tag); + weak_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); - if (!t_write_file(weak_obj_name, weak_obj)) { - goto exit; - } } - String8 ptr_obj_name = str8_lit("ptr.obj"); + String8 ptr_obj; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_undef(obj_writer, entry_symbol_name); + COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("entry")); coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("ptr"), COFF_WeakExt_SearchAlias, tag); - String8 ptr_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + ptr_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); - if (!t_write_file(ptr_obj_name, ptr_obj)) { - goto exit; - } } - U8 undef_obj_payload[] = { 0x00, 0x00, 0x00, 0x00 }; - String8 undef_obj_name = str8_lit("undef.obj"); + String8 undef_obj; { + U8 undef_obj_payload[] = { 0x00, 0x00, 0x00, 0x00 }; COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); COFF_ObjSection *undef_sect = t_push_data_section(obj_writer, str8_array_fixed(undef_obj_payload)); - COFF_ObjSymbol *undef_symbol = coff_obj_writer_push_symbol_undef(obj_writer, shared_symbol_name); + COFF_ObjSymbol *undef_symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("foo")); coff_obj_writer_section_push_reloc(obj_writer, undef_sect, 0, undef_symbol, COFF_Reloc_X64_Addr32Nb); - String8 undef_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + undef_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); - if (!t_write_file(undef_obj_name, undef_obj)) { - goto exit; - } } - U8 entry_payload[] = {0xC3}; - String8 entry_obj_name = str8_lit("entry.obj"); + String8 entry_obj; { + U8 entry_payload[] = {0xC3}; COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); COFF_ObjSection *text_sect = t_push_text_section(obj_writer, str8_array_fixed(entry_payload)); - coff_obj_writer_push_symbol_extern(obj_writer, entry_symbol_name, 0, text_sect); - String8 entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, text_sect); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); - if (!t_write_file(entry_obj_name, entry_obj)) { - goto exit; - } } - int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:%S /out:a.exe %S %S %S %S", entry_symbol_name, weak_obj_name, entry_obj_name, ptr_obj_name, undef_obj_name); + if (!t_write_file(str8_lit("weak.obj"), weak_obj)) { goto exit; } + if (!t_write_file(str8_lit("ptr.obj"), ptr_obj)) { goto exit; } + if (!t_write_file(str8_lit("undef.obj"), undef_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } - T_Linker link_ident = t_ident_linker(); - if (linker_exit_code != 0) { - goto exit; - } + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe weak.obj entry.obj ptr.obj undef.obj"); + if (linker_exit_code != 0) { goto exit; } result = T_Result_Pass; - exit:; scratch_end(scratch); return result; @@ -4033,8 +4015,6 @@ entry_point(CmdLine *cmdline) { "empty_section", t_empty_section }, { "removed_section", t_removed_section }, { "function_pad_min", t_function_pad_min }, - //{ "opt_ref_dangling_section", t_opt_ref_dangling_section }, - //{ "import_export", t_import_export }, }; // From 31b2b1c0f7528253c8445c753887d7fc97da52ef Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:36:55 -0700 Subject: [PATCH 043/302] add replacement cases for weak vs. undefined and vice versa --- src/linker/lnk_symbol_table.c | 49 +++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index e27d4bf3..7d04d353 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -145,9 +145,30 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { can_replace = 1; } - // undefined vs weak - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak) { - can_replace = 1; + // (weak vs undefined) or (undefined vs weak) + else if ((dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Undefined) || (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak)) { + LNK_Symbol *weak, *undef; + COFF_ParsedSymbol weak_parsed; + if (dst_interp == COFF_SymbolValueInterp_Weak) { + weak = dst; + undef = src; + weak_parsed = dst_parsed; + } else { + weak = src; + undef = dst; + weak_parsed = src_parsed; + } + + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + can_replace = lnk_symbol_defined_is_before(weak, undef); + } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; + } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { + can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; + } else { + can_replace = lnk_symbol_defined_is_before(src, dst); + } } // undefined vs undefined else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { @@ -165,7 +186,7 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { can_replace = 1; } - // regular/weak/common/abs/debug vs undefined + // regular/common/abs/debug vs undefined else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { can_replace = 0; } @@ -197,7 +218,25 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) } // weak vs weak else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - can_replace = lnk_symbol_defined_is_before(src, dst); + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_defined(dst); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_defined(src); + COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->u.defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->u.defined.obj->header.is_big_obj); + if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + // TODO: test + lnk_error_multiply_defined_symbol(dst, src); + } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias) { + // TODO: test + can_replace = 0; + } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + // TODO: test + can_replace = 1; + } else if (dst_ext->characteristics == COFF_WeakExt_NoLibrary && src_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 1; + can_replace = lnk_symbol_defined_is_before(src, dst); + } else { + can_replace = lnk_symbol_defined_is_before(src, dst); + } } // weak vs regular/abs/common else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) { From b05237ceecdd31a06eca9372612dabcd70f4e2ca Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:38:06 -0700 Subject: [PATCH 044/302] handle anti-dependency weak symbol --- src/linker/lnk_symbol_table.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 7d04d353..81bd8e92 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -579,15 +579,10 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); if (current_interp == COFF_SymbolValueInterp_Weak) { - // check for anti dependency - for (struct S *s = sf; s != 0; s = s->next) { - if (s->is_anti_dep) { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol.obj, "unresolved symbol %S", parsed_symbol.name); - MemoryZeroStruct(¤t_symbol); - break; - } - } + // record visited symbol + struct S *s = push_array(scratch.arena, struct S, 1); + s->symbol = current_symbol; + SLLQueuePush(sf, sl, s); // does weak symbol have a definition? LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); @@ -600,16 +595,18 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); - // record visited symbol - struct S *s = push_array(scratch.arena, struct S, 1); - s->symbol = current_symbol; - s->is_anti_dep = weak_ext->characteristics == COFF_WeakExt_AntiDependency; - SLLQueuePush(sf, sl, s); - - // no definition fallback to default symbol + // no definition -- fallback to default symbol COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; + + if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, tag_parsed.name); + tag_interp = lnk_interp_from_symbol(dep_symbol); + } + if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } + } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); @@ -622,6 +619,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) } else { break; } } +exit:; scratch_end(scratch); return current_symbol; } From 0983915f40f6bac8abf90544c9376704c12bb7e1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:40:31 -0700 Subject: [PATCH 045/302] oops forgot to init the delay load dll hash table and the established name string --- src/linker/lnk.c | 3 +++ src/linker/lnk_config.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a2d2e1ab..0a2621ee 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1665,8 +1665,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) case State_InputDelayLoadDlls: { ProfBegin("Input Delay Load Dlls"); + // skip input delay load dlls for (; *last_delay_load_dll; last_delay_load_dll = &(*last_delay_load_dll)->next); + // establish delay load helper name + config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); // TODO: config_refactor String8List value_strings = {0}; str8_list_push(scratch.arena, &value_strings, config->delay_load_helper_name); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index b11430fe..78799391 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -2006,6 +2006,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd config->export_ht = hash_table_init(arena, max_U16/2); config->alt_name_ht = hash_table_init(arena, 0x100); config->include_symbol_ht = hash_table_init(arena, 0x100); + config->delay_load_ht = hash_table_init(arena, 0x100); // process command line switches for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { From cdf515793f839021850f29d3923d7f4fd7c33482 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:42:47 -0700 Subject: [PATCH 046/302] stop walking on reaching an undefined symbol --- src/linker/lnk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 0a2621ee..6a62f2ca 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1138,6 +1138,9 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); next_ref = defn->u.defined; + } else { + MemoryZeroStruct(&ref_symbol); + break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); From b19f73b93a999d0bb0813ae891904eab5489661d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:45:53 -0700 Subject: [PATCH 047/302] change unresolved weak symbol type to undefined --- src/linker/lnk.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 6a62f2ca..0e7879de 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1255,18 +1255,17 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->u.defined.obj->header.is_big_obj); - COFF_SymStorageClass storage_class = weak_ext->characteristics == COFF_WeakExt_AntiDependency ? COFF_SymStorageClass_Null : COFF_SymStorageClass_External; + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->u.defined.obj->header.is_big_obj); if (symbol->u.defined.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; symbol32->section_number = COFF_Symbol_UndefinedSection; symbol32->value = 0; - symbol32->storage_class = storage_class; + symbol32->storage_class = COFF_SymStorageClass_External; } else { COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; symbol16->section_number = COFF_Symbol_UndefinedSection; symbol16->value = 0; - symbol16->storage_class = storage_class; + symbol16->storage_class = COFF_SymStorageClass_External; } } else { symbol->u.defined = resolve; From 257914da2f724e5a41127ae36040435ee1e6b7d5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 15:46:21 -0700 Subject: [PATCH 048/302] handle alternate name directive after obj input --- src/linker/lnk.c | 88 ++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 0e7879de..7bf2fae5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1220,11 +1220,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj section_header->flags |= COFF_SectionFlag_LnkRemove; } - // TODO: Reset reserved flag so it does not get propagated to the image sections. - // We need to mask out reserved flags when gathering section definitions to actually - // prevent propagation. - section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; - + // remove associated sections if (section_header->flags & COFF_SectionFlag_LnkRemove) { for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { U32 section_number = section_number_n->data; @@ -1232,6 +1228,11 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj section_header->flags |= COFF_SectionFlag_LnkRemove; } } + + // TODO: Reset reserved flag so it does not get propagated to the image sections. + // We need to mask out reserved flags when gathering section definitions to actually + // prevent propagation. + section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; } } ProfEnd(); @@ -1284,7 +1285,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) State_InputInclude, State_InputObjs, State_InputLibs, - State_InputAlternateNames, State_InputDelayLoadDlls, State_InputLinkerObjs, State_SearchUndefined, @@ -1318,7 +1318,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) String8Node **last_include_symbol = &config->include_symbol_list.first; String8Node **last_disallow_lib = &config->disallow_lib_list.first; String8Node **last_delay_load_dll = &config->delay_load_dll_list.first; - LNK_AltNameNode **last_alt_name = &config->alt_name_list.first; LNK_InputObjList input_obj_list = {0}; LNK_InputImportList input_import_list = {0}; LNK_InputLib **input_libs[LNK_InputSource_Count] = { &config->input_list[LNK_Input_Lib].first, &config->input_default_lib_list.first, &config->input_obj_lib_list.first }; @@ -1531,6 +1530,39 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // reset input objs MemoryZeroStruct(&input_obj_list); + + // replace undefined symbols that have an alternate name with a weak symbol + for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, LNK_SymbolScope_Defined, alt_name_n->data.from); + if (symbol_ht) { + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); + if (interp == COFF_SymbolValueInterp_Undefined) { + // clear slot for the weak alternate name that replaces an undefined symbol + symbol_ht->symbol = 0; + + // make obj with alternamte name symbol + String8 alt_name_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); + COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.from, COFF_WeakExt_SearchLibrary, 0); + COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.to, COFF_WeakExt_AntiDependency, from_symbol); + coff_obj_writer_set_default_symbol(from_symbol, to_symbol); + alt_name_obj = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); + coff_obj_writer_release(&obj_writer); + } + + // input alt name obj + { + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = alt_name_n->data.obj ? alt_name_n->data.obj->path : str8_lit("RADLINK"); + input->exclude_from_debug_info = 1; + input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAME FOR %S=%S *", alt_name_n->data.from, alt_name_n->data.to, obj_list.count); + input->data = alt_name_obj; + input->lib = alt_name_n->data.obj ? alt_name_n->data.obj->lib : 0; + } + } + } + } ProfEnd(); } break; @@ -1627,43 +1659,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); } break; - case State_InputAlternateNames: { - ProfBegin("Input Alternate Names"); - - // linker is not allowed to create a new alternate name if the "from" symbol already exists - // (MSVC silently ignores the directive) - { - LNK_Symbol *extant_from = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, (*last_alt_name)->data.from); - if (extant_from) { - COFF_SymbolValueInterpType extant_interp = lnk_interp_from_symbol(extant_from); - if (extant_interp != COFF_SymbolValueInterp_Undefined) { break; } - } - } - - // make & input alternate name obj - { - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - - COFF_ObjSymbol *null_symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit(LNK_NULL_SYMBOL)); - COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.from, COFF_WeakExt_Rad_WeakSearchLibrary, null_symbol); - COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, (*last_alt_name)->data.to, COFF_WeakExt_Rad_WeakSearchLibrary, from_symbol); - - String8 alt_name_obj = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); - coff_obj_writer_release(&obj_writer); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->path : str8_lit("RADLINK"); - input->exclude_from_debug_info = 1; - input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAMES FOR %S * %u", input->path, obj_list.count); - input->data = alt_name_obj; - input->lib = (*last_alt_name)->data.obj ? (*last_alt_name)->data.obj->lib : 0; - } - - // advance to next alt name - last_alt_name = &(*last_alt_name)->next; - - ProfEnd(); - } break; case State_InputDelayLoadDlls: { ProfBegin("Input Delay Load Dlls"); @@ -1672,6 +1667,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // establish delay load helper name config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); + // TODO: config_refactor String8List value_strings = {0}; str8_list_push(scratch.arena, &value_strings, config->delay_load_helper_name); @@ -2130,10 +2126,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputInclude); continue; } - if (*last_alt_name) { - state_list_push(scratch.arena, state_list, State_InputAlternateNames); - continue; - } { B32 have_pending_lib_inputs = 0; for EachIndex(i, ArrayCount(input_libs)) { From b56ce72b7f29348d6eea0e1ad365f180431847de Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 19:06:27 -0700 Subject: [PATCH 049/302] test cases for weak vs weak --- src/linker/lnk_symbol_table.c | 34 +- src/torture/torture.c | 1048 ++++++++++++++++++++++++++++++--- 2 files changed, 996 insertions(+), 86 deletions(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 81bd8e92..4e7a6a98 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -150,18 +150,16 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) LNK_Symbol *weak, *undef; COFF_ParsedSymbol weak_parsed; if (dst_interp == COFF_SymbolValueInterp_Weak) { - weak = dst; - undef = src; + weak = dst, undef = src; weak_parsed = dst_parsed; } else { - weak = src; - undef = dst; + weak = src, undef = dst; weak_parsed = src_parsed; } COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = lnk_symbol_defined_is_before(weak, undef); + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { @@ -218,22 +216,22 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) } // weak vs weak else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_defined(dst); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_defined(src); COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->u.defined.obj->header.is_big_obj); COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->u.defined.obj->header.is_big_obj); - if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - // TODO: test - lnk_error_multiply_defined_symbol(dst, src); - } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias) { - // TODO: test - can_replace = 0; + if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { + if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 0; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - // TODO: test - can_replace = 1; - } else if (dst_ext->characteristics == COFF_WeakExt_NoLibrary && src_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 1; - can_replace = lnk_symbol_defined_is_before(src, dst); + if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 1; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + lnk_error_multiply_defined_symbol(dst, src); } else { can_replace = lnk_symbol_defined_is_before(src, dst); } diff --git a/src/torture/torture.c b/src/torture/torture.c index cd01bbf3..d5cd912f 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -823,7 +823,7 @@ t_link_unref_undef(void) } internal T_Result -t_weak_vs_weak(void) +t_weak_lib_vs_weak_lib(void) { Temp scratch = scratch_begin(0,0); T_Result result = T_Result_Fail; @@ -831,23 +831,11 @@ t_weak_vs_weak(void) String8 a_obj; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".a"), PE_DATA_SECTION_FLAGS, str8_lit("a")); - COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_a"), 0, sect); - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); } - - String8 b_obj; - { - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".b"), PE_DATA_SECTION_FLAGS, str8_lit("b")); - COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_b"), 0, sect); - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol); - b_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); - coff_obj_writer_release(&obj_writer); - } - String8 entry_obj; { @@ -858,19 +846,888 @@ t_weak_vs_weak(void) }; COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); - COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("w")); - coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, symbol); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); } - if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } - if (!t_write_file(str8_lit("b.obj"), b_obj)) { goto exit; } + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code; + + // linker must pick weak symbol from a.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj entry.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + // linker must pick weak symbol from entry.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from a.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *qwe = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("qwe"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("sym"), COFF_WeakExt_SearchAlias, qwe); + a = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 b; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *ewq = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("ewq"), 0x222, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("sym"), COFF_WeakExt_SearchAlias, ewq); + b = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("sym")); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a)) { goto exit; } + if (!t_write_file(str8_lit("b.obj"), b)) { goto exit; } if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj b.obj entry.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); if (linker_exit_code != 0) { goto exit; } + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code; + + // linker must pick weak symbol from a.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj entry.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + // linker must pick weak symbol from entry.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + result = T_Result_Pass; exit:; scratch_end(scratch); @@ -1179,7 +2036,46 @@ exit:; } internal T_Result -t_undef_weak(void) +t_undef_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 weak; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + COFF_ObjSymbol *b = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("b"), 0xc3000000, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("a"), COFF_WeakExt_SearchLibrary, b); + weak = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("a")); + U8 text[4] = {0}; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, sym); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + entry = coff_obj_writer_serialize(scratch.arena, obj_writer); + } + + if (!t_write_file(str8_lit("weak.obj"), weak)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry)) { goto exit; } + + // undefined symbol must always replace weak symbol with search library + int linker_exit_code = t_invoke_linkerf("/subsystem:console /out:a.exe /entry:entry entry.obj weak.obj"); + if (linker_exit_code != LNK_Error_UnresolvedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_undef_weak_search_alias(void) { Temp scratch = scratch_begin(0,0); T_Result result = T_Result_Fail; @@ -3967,54 +4863,70 @@ entry_point(CmdLine *cmdline) static struct { char *label; T_Result (*r)(void); } target_array[] = { - { "simple_link_test", t_simple_link_test }, - { "machine_compat_check", t_machine_compat_check }, - { "out_of_bounds_section_number", t_out_of_bounds_section_number }, - { "merge", t_merge }, - { "undef_section", t_undef_section }, - { "undef_reloc_section", t_undef_reloc_section }, - { "link_undef", t_link_undef }, - { "link_unref_undef", t_link_unref_undef }, - { "weak_vs_weak", t_weak_vs_weak }, - { "weak_vs_common", t_weak_vs_common }, - { "abs_vs_weak", t_abs_vs_weak }, - { "abs_vs_regular", t_abs_vs_regular }, - { "abs_vs_common", t_abs_vs_common }, - { "abs_vs_abs", t_abs_vs_abs }, - { "undef_weak", t_undef_weak }, - { "sect_symbol", t_sect_symbol }, - { "weak_cycle", t_weak_cycle }, - { "weak_tag", t_weak_tag }, - { "find_merged_pdata", t_find_merged_pdata }, - { "section_sort", t_section_sort }, - { "flag_conf", t_flag_conf }, - { "invalid_bss", t_invalid_bss }, - { "common_block", t_common_block }, - { "base_relocs", t_base_relocs }, - { "simple_lib_test", t_simple_lib_test }, - { "sect_align", t_sect_align }, - { "image_base", t_image_base }, - { "comdat_any", t_comdat_any }, - { "comdat_no_duplicates", t_comdat_no_duplicates }, - { "comdat_same_size", t_comdat_same_size }, - { "comdat_exact_match", t_comdat_exact_match }, - { "comdat_largest", t_comdat_largest }, - { "comdat_associative", t_comdat_associative }, - { "comdat_associative_loop", t_comdat_associative_loop }, - { "comdat_associative_non_comdat", t_comdat_associative_non_comdat }, - { "comdat_associative_out_of_bounds", t_comdat_associative_out_of_bounds }, - { "comdat_with_offset", t_comdat_with_offset }, - { "reloc_against_removed_comdat", t_reloc_against_removed_comdat }, - { "alt_name", t_alt_name }, - { "include", t_include }, - { "communal_var_vs_regular_comdat", t_communal_var_vs_regular_comdat }, - { "communal_var_vs_regular", t_communal_var_vs_regular }, - { "import_kernel32", t_import_kernel32 }, - { "delay_import_user32", t_delay_import_user32 }, - { "delay_import", t_delay_import }, - { "empty_section", t_empty_section }, - { "removed_section", t_removed_section }, - { "function_pad_min", t_function_pad_min }, + { "simple_link_test", t_simple_link_test }, + { "machine_compat_check", t_machine_compat_check }, + { "out_of_bounds_section_number", t_out_of_bounds_section_number }, + { "merge", t_merge }, + { "undef_section", t_undef_section }, + { "undef_reloc_section", t_undef_reloc_section }, + { "link_undef", t_link_undef }, + { "link_unref_undef", t_link_unref_undef }, + { "weak_lib_vs_weak_lib", t_weak_lib_vs_weak_lib }, + { "weak_lib_vs_weak_nolib", t_weak_lib_vs_weak_nolib }, + { "weak_lib_vs_weak_alias", t_weak_lib_vs_weak_alias }, + { "weak_lib_vs_weak_antidep", t_weak_lib_vs_weak_antidep }, + { "weak_alias_vs_weak_alias", t_weak_alias_vs_weak_alias }, + { "weak_alias_vs_weak_lib", t_weak_alias_vs_weak_lib }, + { "weak_alias_vs_weak_nolib", t_weak_alias_vs_weak_nolib }, + { "weak_alias_vs_weak_antidep", t_weak_alias_vs_weak_antidep }, + { "weak_nolib_vs_weak_nolib", t_weak_nolib_vs_weak_nolib }, + { "weak_nolib_vs_weak_lib", t_weak_nolib_vs_weak_lib }, + { "weak_nolib_vs_weak_alias", t_weak_nolib_vs_weak_alias }, + { "weak_nolib_vs_weak_antidep", t_weak_nolib_vs_weak_antidep }, + { "weak_antidep_vs_weak_antidep", t_weak_antidep_vs_weak_antidep }, + { "weak_antidep_vs_weak_nolib", t_weak_antidep_vs_weak_nolib }, + { "weak_antidep_vs_weak_lib", t_weak_antidep_vs_weak_lib }, + { "weak_antidep_vs_weak_alias", t_weak_antidep_vs_weak_alias }, + { "weak_vs_common", t_weak_vs_common }, + { "abs_vs_weak", t_abs_vs_weak }, + { "abs_vs_regular", t_abs_vs_regular }, + { "abs_vs_common", t_abs_vs_common }, + { "abs_vs_abs", t_abs_vs_abs }, + { "undef_weak_lib", t_undef_weak_lib }, + { "undef_weak_search_alias", t_undef_weak_search_alias }, + { "sect_symbol", t_sect_symbol }, + { "weak_cycle", t_weak_cycle }, + { "weak_tag", t_weak_tag }, + { "find_merged_pdata", t_find_merged_pdata }, + { "section_sort", t_section_sort }, + { "flag_conf", t_flag_conf }, + { "invalid_bss", t_invalid_bss }, + { "common_block", t_common_block }, + { "base_relocs", t_base_relocs }, + { "simple_lib_test", t_simple_lib_test }, + { "sect_align", t_sect_align }, + { "image_base", t_image_base }, + { "comdat_any", t_comdat_any }, + { "comdat_no_duplicates", t_comdat_no_duplicates }, + { "comdat_same_size", t_comdat_same_size }, + { "comdat_exact_match", t_comdat_exact_match }, + { "comdat_largest", t_comdat_largest }, + { "comdat_associative", t_comdat_associative }, + { "comdat_associative_loop", t_comdat_associative_loop }, + { "comdat_associative_non_comdat", t_comdat_associative_non_comdat }, + { "comdat_associative_out_of_bounds", t_comdat_associative_out_of_bounds }, + { "comdat_with_offset", t_comdat_with_offset }, + { "reloc_against_removed_comdat", t_reloc_against_removed_comdat }, + { "alt_name", t_alt_name }, + { "include", t_include }, + { "communal_var_vs_regular_comdat", t_communal_var_vs_regular_comdat }, + { "communal_var_vs_regular", t_communal_var_vs_regular }, + { "import_kernel32", t_import_kernel32 }, + { "delay_import_user32", t_delay_import_user32 }, + { "delay_import", t_delay_import }, + { "empty_section", t_empty_section }, + { "removed_section", t_removed_section }, + { "function_pad_min", t_function_pad_min }, }; // From eee6a9c08a74cc3a0dc398ddc515d421601a6db8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 19:07:07 -0700 Subject: [PATCH 050/302] natvis for obj list --- src/linker/linker.natvis | 1 + 1 file changed, 1 insertion(+) diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index 3c82cf96..d1031fa1 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -32,6 +32,7 @@ + {{count={count} first={first} }} From 429ba8b080d24217cd97ef0088e11818814a2502 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 19:09:19 -0700 Subject: [PATCH 051/302] helper for writing 32-bit address relocation --- src/coff/coff_obj_writer.c | 12 ++++++++++++ src/coff/coff_obj_writer.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 016b2364..4bf384a4 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -438,6 +438,18 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection * return reloc; } +internal COFF_ObjReloc * +coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol) +{ + COFF_RelocType reloc_type = 0; + switch (obj_writer->machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32; break; + default: { NotImplemented; } break; + } + return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type); +} + internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol) { diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 5b5e0248..1419396a 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -118,6 +118,7 @@ internal COFF_ObjSymbol * coff_obj_writer_push_symbol_common(COFF_ObjWriter *obj internal void coff_obj_writer_set_default_symbol(COFF_ObjSymbol *weak_symbol, COFF_ObjSymbol *default_symbol); internal COFF_ObjReloc * coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type); +internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol); internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol); internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol); From 0656020ab334467ed513e6929a757ff92e0842b5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 18 Aug 2025 19:26:35 -0700 Subject: [PATCH 052/302] sync primitive fixes --- src/linker/base_ext/base_core.h | 4 ---- src/linker/lnk_config.c | 21 +++++++++++++-------- src/linker/lnk_debug_info.c | 4 ++-- src/linker/thread_pool/thread_pool.c | 10 +++++----- src/linker/thread_pool/thread_pool.h | 6 +++--- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/linker/base_ext/base_core.h b/src/linker/base_ext/base_core.h index deb18e8c..e3d53292 100644 --- a/src/linker/base_ext/base_core.h +++ b/src/linker/base_ext/base_core.h @@ -110,10 +110,6 @@ //////////////////////////////// -#define MemoryIsZeroStruct(p) memory_is_zero(p, sizeof(*p)) - -//////////////////////////////// - typedef struct { U64 major; diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 78799391..6bedf521 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -333,15 +333,20 @@ internal String8 lnk_error_check_and_strip_quotes(LNK_ErrorCode error_code, LNK_Obj *obj, LNK_CmdSwitchType cmd_switch, String8 string) { String8 result = string; - B32 starts_with_quote = str8_match_lit("\"", string, StringMatchFlag_RightSideSloppy); - if (starts_with_quote) { - if (str8_ends_with_lit(string, "\"", 0)) { - result = str8_skip(result, 1); - result = str8_chop(result, 1); - } else { - lnk_error_cmd_switch(error_code, obj, cmd_switch, "detected unmatched \" in \"%S\"", string); - } + + B32 starts_with_quote = str8_match(str8_substr(string, rng_1u64(0,1)), str8_lit("\""), 0); + B32 ends_with_quote = 0; + if (string.size > 2) { + ends_with_quote = str8_match(str8_substr(string, rng_1u64(string.size-1,string.size)), str8_lit("\""), 0); } + + if (starts_with_quote && ends_with_quote) { + result = str8_skip(result, 1); + result = str8_chop(result, 1); + } else if (starts_with_quote && !ends_with_quote) { + lnk_error_cmd_switch(error_code, obj, cmd_switch, "detected unmatched \" in \"%S\"", string); + } + return result; } diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index ff4d2d72..4905bae5 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -4201,7 +4201,7 @@ lnk_src_file_hash_table_lookup_slot(LNK_SourceFileBucket **buckets, if (buckets[bucket_idx] == 0) { break; } - if (rdib_source_file_match(buckets[bucket_idx]->src_file, &temp, operating_system_from_context())) { + if (rdib_source_file_match(buckets[bucket_idx]->src_file, &temp, OperatingSystem_CURRENT)) { return buckets[bucket_idx]; } bucket_idx = (bucket_idx + 1) % cap; @@ -4233,7 +4233,7 @@ lnk_src_file_insert_or_update(LNK_SourceFileBucket **buckets, U64 cap, U64 hash, // another thread took the bucket... goto retry; - } else if (rdib_source_file_match(curr_bucket->src_file, new_bucket->src_file, operating_system_from_context())) { + } else if (rdib_source_file_match(curr_bucket->src_file, new_bucket->src_file, OperatingSystem_CURRENT)) { // do we need to update value in the bucket? int cmp = u64_compar(&curr_bucket->obj_idx, &new_bucket->obj_idx); if (cmp <= 0) { diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index a99c821e..4a171756 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -63,9 +63,9 @@ tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name) B32 is_shared = (name.size > 0); // alloc semaphores - OS_Handle main_semaphore = {0}; - OS_Handle task_semaphore = {0}; - OS_Handle exec_semaphore = {0}; + Semaphore main_semaphore = {0}; + Semaphore task_semaphore = {0}; + Semaphore exec_semaphore = {0}; if (worker_count > 1) { main_semaphore = os_semaphore_alloc(0, 1, str8_zero()); if (is_shared) { @@ -111,7 +111,7 @@ tp_release(TP_Context *pool) { pool->is_live = 0; - B32 is_shared = !os_handle_match(pool->exec_semaphore, os_handle_zero()); + B32 is_shared = pool->exec_semaphore.u64[0] != 0; if (is_shared) { for (U64 i = 0; i < pool->worker_count; ++i) { os_semaphore_drop(pool->exec_semaphore); @@ -209,7 +209,7 @@ tp_for_parallel(TP_Context *pool, TP_Arena *task_arena, U64 task_count, TP_TaskF U64 drop_count = Min(task_count, pool->worker_count); // if we are in shared mode ping local semaphore - if (!os_handle_match(pool->exec_semaphore, os_handle_zero())) { + if (pool->exec_semaphore.u64[0] != 0) { for (U64 worker_idx = 0; worker_idx < drop_count; worker_idx +=1) { os_semaphore_drop(pool->exec_semaphore); } diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index abea5cbd..e2487560 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -28,9 +28,9 @@ typedef struct TP_Worker typedef struct TP_Context { B32 is_live; - OS_Handle exec_semaphore; - OS_Handle task_semaphore; - OS_Handle main_semaphore; + Semaphore exec_semaphore; + Semaphore task_semaphore; + Semaphore main_semaphore; U32 worker_count; TP_Worker *worker_arr; From cdec8d5980bcc1f8351abaa9e6c9570486d87988 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 19 Aug 2025 16:47:12 -0700 Subject: [PATCH 053/302] ctrl/demon: fastfail exception codes / notes; p2r2: finish symbol conversion etc. in new wavefront-style version --- src/base/base_thread_context.c | 2 +- src/ctrl/ctrl.mdesk | 80 +- src/demon/win32/demon_core_win32.c | 7 + src/demon/win32/demon_core_win32.h | 76 ++ src/pdb/pdb_parse.h | 5 + src/raddbg/raddbg_main.c | 2 + src/rdi_from_pdb/rdi_from_pdb_2.c | 1322 ++++++++++++++++++++++++++-- src/rdi_from_pdb/rdi_from_pdb_2.h | 49 +- 8 files changed, 1439 insertions(+), 104 deletions(-) diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 8d0e23c1..7b28d474 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -86,7 +86,7 @@ internal void tctx_lane_barrier_wait(void) { ProfBeginFunction(); - ProfColor(0xff0000ff); + ProfColor(0x00000ff); TCTX *tctx = tctx_selected(); os_barrier_wait(tctx->lane_ctx.barrier); ProfEnd(); diff --git a/src/ctrl/ctrl.mdesk b/src/ctrl/ctrl.mdesk index 9684baeb..9f5d3fa6 100644 --- a/src/ctrl/ctrl.mdesk +++ b/src/ctrl/ctrl.mdesk @@ -16,8 +16,8 @@ CTRL_EntityKindTable: {DebugInfoPath debug_info_path "Debug Info Path" } {PendingThreadName pending_thread_name "Pending Thread Name" } {PendingThreadColor pending_thread_color "Pending Thread Color" } - {Breakpoint breakpoint "Breakpoint" } - {AddressRangeAnnotation address_range_annotation "Address Range Annotation" } + {Breakpoint breakpoint "Breakpoint" } + {AddressRangeAnnotation address_range_annotation "Address Range Annotation" } } @enum CTRL_EntityKind: @@ -114,3 +114,79 @@ CTRL_ExceptionCodeKindTable: `0`; @expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`; } + +//////////////////////////////// +//~ rjf: Exception Sub-Codes + +@table(name, value) +CTRL_ExceptionSubCodeKindTable: +{ + { W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 } + { W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 } + { W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 } + { W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 } + { W32_FAST_FAIL_INCORRECT_STACK 4 } + { W32_FAST_FAIL_INVALID_ARG 5 } + { W32_FAST_FAIL_GS_COOKIE_INIT 6 } + { W32_FAST_FAIL_FATAL_APP_EXIT 7 } + { W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 } + { W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 } + { W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 } + { W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 } + { W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 } + { W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 } + { W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 } + { W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 } + { W32_FAST_FAIL_MRDATA_MODIFIED 19 } + { W32_FAST_FAIL_CERTIFICATION_FAILURE 20 } + { W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 } + { W32_FAST_FAIL_CRYPTO_LIBRARY 22 } + { W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 } + { W32_FAST_FAIL_INVALID_IMAGE_BASE 24 } + { W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 } + { W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 } + { W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 } + { W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 } + { W32_FAST_FAIL_INVALID_BALANCED_TREE 29 } + { W32_FAST_FAIL_INVALID_NEXT_THREAD 30 } + { W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 } + { W32_FAST_FAIL_APCS_DISABLED 32 } + { W32_FAST_FAIL_INVALID_IDLE_STATE 33 } + { W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 } + { W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 } + { W32_FAST_FAIL_INVALID_LOCK_STATE 36 } + { W32_FAST_FAIL_GUARD_JUMPTABLE 37 } + { W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 } + { W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 } + { W32_FAST_FAIL_INVALID_THREAD 40 } + { W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 } + { W32_FAST_FAIL_INVALID_FILE_OPERATION 42 } + { W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 } + { W32_FAST_FAIL_GUARD_SS_FAILURE 44 } + { W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 } + { W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 } + { W32_FAST_FAIL_INVALID_CONTROL_STACK 47 } + { W32_FAST_FAIL_SET_CONTEXT_DENIED 48 } + { W32_FAST_FAIL_INVALID_IAT 49 } + { W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 } + { W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 } + { W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 } + { W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 } + { W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 } + { W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 } + { W32_FAST_FAIL_UNEXPECTED_CALL 56 } + { W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 } + { W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 } + { W32_FAST_FAIL_FLAGS_CORRUPTION 59 } + { W32_FAST_FAIL_VEH_CORRUPTION 60 } + { W32_FAST_FAIL_ETW_CORRUPTION 61 } + { W32_FAST_FAIL_RIO_ABORT 62 } + { W32_FAST_FAIL_INVALID_PFN 63 } + { W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 } + { W32_FAST_FAIL_CAST_GUARD 65 } + { W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 } + { W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 } + { W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 } + { W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 } + { W32_FAST_FAIL_INVALID_FLS_DATA 70 } +} diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index a4ee8974..e3305ca2 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -2404,6 +2404,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN: { e->kind = DMN_EventKind_Trap; + if(exception->ExceptionInformation[0] == DMN_W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS) + { + // TODO(rjf): this is a shadow stack violation - this can imply that the spoof was hit. + // need to handle this correctly in the ctrl layer when stepping w/ a spoof set. + // + // @shadow_stack_step + } }break; //- rjf: fill single-step event info diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h index 01aa3523..c33f71c6 100644 --- a/src/demon/win32/demon_core_win32.h +++ b/src/demon/win32/demon_core_win32.h @@ -60,6 +60,82 @@ #define DMN_W32_EXCEPTION_RADDBG_SET_BREAKPOINT 0x00524145u #define DMN_W32_EXCEPTION_RADDBG_SET_VADDR_RANGE_NOTE 0x00524156u +//////////////////////////////// +//~ rjf: Win32 Exception ExceptionInformation Codes +// +// used as a subcode, apparently in all cases, for DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN. +// need to somehow pipe this through & interpret it correctly in outer layers... @fastfail + +#define DMN_W32_FAST_FAIL_LEGACY_GS_VIOLATION 0 +#define DMN_W32_FAST_FAIL_VTGUARD_CHECK_FAILURE 1 +#define DMN_W32_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE 2 +#define DMN_W32_FAST_FAIL_CORRUPT_LIST_ENTRY 3 +#define DMN_W32_FAST_FAIL_INCORRECT_STACK 4 +#define DMN_W32_FAST_FAIL_INVALID_ARG 5 +#define DMN_W32_FAST_FAIL_GS_COOKIE_INIT 6 +#define DMN_W32_FAST_FAIL_FATAL_APP_EXIT 7 +#define DMN_W32_FAST_FAIL_RANGE_CHECK_FAILURE 8 +#define DMN_W32_FAST_FAIL_UNSAFE_REGISTRY_ACCESS 9 +#define DMN_W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE 10 +#define DMN_W32_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE 11 +#define DMN_W32_FAST_FAIL_INVALID_FIBER_SWITCH 12 +#define DMN_W32_FAST_FAIL_INVALID_SET_OF_CONTEXT 13 +#define DMN_W32_FAST_FAIL_INVALID_REFERENCE_COUNT 14 +#define DMN_W32_FAST_FAIL_INVALID_JUMP_BUFFER 18 +#define DMN_W32_FAST_FAIL_MRDATA_MODIFIED 19 +#define DMN_W32_FAST_FAIL_CERTIFICATION_FAILURE 20 +#define DMN_W32_FAST_FAIL_INVALID_EXCEPTION_CHAIN 21 +#define DMN_W32_FAST_FAIL_CRYPTO_LIBRARY 22 +#define DMN_W32_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT 23 +#define DMN_W32_FAST_FAIL_INVALID_IMAGE_BASE 24 +#define DMN_W32_FAST_FAIL_DLOAD_PROTECTION_FAILURE 25 +#define DMN_W32_FAST_FAIL_UNSAFE_EXTENSION_CALL 26 +#define DMN_W32_FAST_FAIL_DEPRECATED_SERVICE_INVOKED 27 +#define DMN_W32_FAST_FAIL_INVALID_BUFFER_ACCESS 28 +#define DMN_W32_FAST_FAIL_INVALID_BALANCED_TREE 29 +#define DMN_W32_FAST_FAIL_INVALID_NEXT_THREAD 30 +#define DMN_W32_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED 31 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_APCS_DISABLED 32 +#define DMN_W32_FAST_FAIL_INVALID_IDLE_STATE 33 +#define DMN_W32_FAST_FAIL_MRDATA_PROTECTION_FAILURE 34 +#define DMN_W32_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION 35 +#define DMN_W32_FAST_FAIL_INVALID_LOCK_STATE 36 +#define DMN_W32_FAST_FAIL_GUARD_JUMPTABLE 37 // Known to compiler, must retain value 37 +#define DMN_W32_FAST_FAIL_INVALID_LONGJUMP_TARGET 38 +#define DMN_W32_FAST_FAIL_INVALID_DISPATCH_CONTEXT 39 +#define DMN_W32_FAST_FAIL_INVALID_THREAD 40 +#define DMN_W32_FAST_FAIL_INVALID_SYSCALL_NUMBER 41 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_INVALID_FILE_OPERATION 42 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_LPAC_ACCESS_DENIED 43 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_GUARD_SS_FAILURE 44 +#define DMN_W32_FAST_FAIL_LOADER_CONTINUITY_FAILURE 45 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE 46 +#define DMN_W32_FAST_FAIL_INVALID_CONTROL_STACK 47 +#define DMN_W32_FAST_FAIL_SET_CONTEXT_DENIED 48 +#define DMN_W32_FAST_FAIL_INVALID_IAT 49 +#define DMN_W32_FAST_FAIL_HEAP_METADATA_CORRUPTION 50 +#define DMN_W32_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION 51 +#define DMN_W32_FAST_FAIL_LOW_LABEL_ACCESS_DENIED 52 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_ENCLAVE_CALL_FAILURE 53 +#define DMN_W32_FAST_FAIL_UNHANDLED_LSS_EXCEPTON 54 +#define DMN_W32_FAST_FAIL_ADMINLESS_ACCESS_DENIED 55 // Telemetry, nonfatal +#define DMN_W32_FAST_FAIL_UNEXPECTED_CALL 56 +#define DMN_W32_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS 57 +#define DMN_W32_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR 58 +#define DMN_W32_FAST_FAIL_FLAGS_CORRUPTION 59 +#define DMN_W32_FAST_FAIL_VEH_CORRUPTION 60 +#define DMN_W32_FAST_FAIL_ETW_CORRUPTION 61 +#define DMN_W32_FAST_FAIL_RIO_ABORT 62 +#define DMN_W32_FAST_FAIL_INVALID_PFN 63 +#define DMN_W32_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG 64 +#define DMN_W32_FAST_FAIL_CAST_GUARD 65 // Known to compiler, must retain value 65 +#define DMN_W32_FAST_FAIL_HOST_VISIBILITY_CHANGE 66 +#define DMN_W32_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST 67 +#define DMN_W32_FAST_FAIL_PATCH_CALLBACK_FAILED 68 +#define DMN_W32_FAST_FAIL_NTDLL_PATCH_FAILED 69 +#define DMN_W32_FAST_FAIL_INVALID_FLS_DATA 70 +#define DMN_W32_FAST_FAIL_INVALID_FAST_FAIL_CODE 0xFFFFFFFF + //////////////////////////////// //~ rjf: Win32 Register Codes diff --git a/src/pdb/pdb_parse.h b/src/pdb/pdb_parse.h index 9474c1a3..51d20f31 100644 --- a/src/pdb/pdb_parse.h +++ b/src/pdb/pdb_parse.h @@ -184,6 +184,11 @@ typedef struct PDB_GsiParsed PDB_GsiBucket buckets[4096]; } PDB_GsiParsed; +//////////////////////////////// +//~ rjf: Globals + +read_only global PDB_CompUnit pdb_comp_unit_nil = {0}; + //////////////////////////////// //~ PDB Parser Functions diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index fcbcda8d..78ae10ed 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -5,6 +5,8 @@ //~ rjf: post-0.9.20 TODO notes // //- urgent fixes +// [ ] (use msvc assert as an example) show fastfail exception info (code, name, etc.) - comes from ExceptionInformation @fastfail +// [ ] stepping w/ spoofs & shadow stack enabled - writing spoof will send a stack buffer overrun event @shadow_stack_step // [ ] hardware breakpoints regression (global eval in ctrl) // [ ] native filesystem dialog, resizing raddbg window -> crash! // diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index e0e90df5..af599c8d 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -58,15 +58,21 @@ p2r2_convert_thread_entry_point(void *p) p2r2_shared->msf->page_count = p2r2_shared->msf_raw_stream_table->total_page_count; p2r2_shared->msf->stream_count = p2r2_shared->msf_raw_stream_table->stream_count; p2r2_shared->msf->streams = push_array(arena, String8, p2r2_shared->msf->stream_count); + p2r2_shared->msf_stream_lane_counter = 0; } lane_sync(); // rjf: do wide fill { - Rng1U64 range = lane_range(p2r2_shared->msf->stream_count); - for EachInRange(idx, range) + for(;;) { - p2r2_shared->msf->streams[idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, idx); + U64 stream_num = ins_atomic_u64_inc_eval(&p2r2_shared->msf_stream_lane_counter); + if(stream_num < 1 || p2r2_shared->msf->stream_count < stream_num) + { + break; + } + U64 stream_idx = stream_num-1; + p2r2_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, stream_idx); } } } @@ -190,17 +196,12 @@ p2r2_convert_thread_entry_point(void *p) String8 leaf_data = pdb_leaf_data_from_tpi(ipi); p2r2_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse global symbol stream") - { - String8 sym_data = msf_data_from_stream(msf, dbi->sym_sn); - p2r2_shared->sym = cv_sym_from_data(arena, sym_data, 4); - } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation units") + if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") { String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); p2r2_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); } - if(lane_idx() == lane_from_task_idx(7)) ProfScope("parse compilation unit contributions") + if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") { String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); p2r2_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); @@ -212,7 +213,6 @@ p2r2_convert_thread_entry_point(void *p) CV_LeafParsed *tpi_leaf = p2r2_shared->tpi_leaf; PDB_TpiHashParsed *ipi_hash = p2r2_shared->ipi_hash; CV_LeafParsed *ipi_leaf = p2r2_shared->ipi_leaf; - CV_SymParsed *sym = p2r2_shared->sym; PDB_CompUnitArray *comp_units = p2r2_shared->comp_units; PDB_CompUnitContributionArray *comp_unit_contributions = p2r2_shared->comp_unit_contributions; @@ -236,34 +236,51 @@ p2r2_convert_thread_entry_point(void *p) RDIM_Rng1U64ChunkList *unit_ranges = p2r2_shared->unit_ranges; ////////////////////////////////////////////////////////////// - //- rjf: parse syms & line info for each compilation unit + //- rjf: parse all syms & c13 line info streams // - ProfScope("parse syms & line info for each compilation unit") + ProfScope("parse all syms & c13 line info streams") { //- rjf: setup outputs if(lane_idx() == 0) { - p2r2_shared->sym_for_unit = push_array(arena, CV_SymParsed *, comp_units->count); - p2r2_shared->c13_for_unit = push_array(arena, CV_C13Parsed *, comp_units->count); + p2r2_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI + p2r2_shared->all_syms = push_array(arena, CV_SymParsed *, p2r2_shared->all_syms_count); + p2r2_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r2_shared->all_syms_count); + p2r2_shared->sym_c13_unit_lane_counter = 0; } lane_sync(); //- rjf: wide fill { - Rng1U64 range = lane_range(comp_units->count); - for EachInRange(idx, range) + U64 task_count = p2r2_shared->all_syms_count; + for(;;) { - PDB_CompUnit *unit = comp_units->units[idx]; - String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); - String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - p2r2_shared->sym_for_unit[idx] = cv_sym_from_data(arena, unit_sym_data, 4); - p2r2_shared->c13_for_unit[idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + U64 task_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_c13_unit_lane_counter); + if(task_num == 0 || task_count < task_num) + { + break; + } + U64 task_idx = task_num-1; + if(task_idx > 0) + { + PDB_CompUnit *unit = comp_units->units[task_idx-1]; + String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); + String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); + p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); + p2r2_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + } + else + { + String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); + p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); + } } } } lane_sync(); - CV_SymParsed **sym_for_unit = p2r2_shared->sym_for_unit; - CV_C13Parsed **c13_for_unit = p2r2_shared->c13_for_unit; + U64 all_syms_count = p2r2_shared->all_syms_count; + CV_SymParsed **all_syms = p2r2_shared->all_syms; + CV_C13Parsed **all_c13s = p2r2_shared->all_c13s; ////////////////////////////////////////////////////////////// //- rjf: calculate EXE's max voff @@ -300,9 +317,9 @@ p2r2_convert_thread_entry_point(void *p) // of info, but to use the appropriate compilation unit's architecture when // possible. assuming, of course, that we care about supporting that case. // - for(U64 comp_unit_idx = 0; comp_unit_idx < comp_units->count; comp_unit_idx += 1) + for EachIndex(idx, all_syms_count) { - p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(sym_for_unit[comp_unit_idx]->info.arch); + p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); if(p2r2_shared->arch != RDI_Arch_NULL) { break; @@ -313,6 +330,85 @@ p2r2_convert_thread_entry_point(void *p) RDI_Arch arch = RDI_Arch_NULL; U64 arch_addr_size = rdi_addr_size_from_arch(arch); + ////////////////////////////////////////////////////////////// + //- rjf: predict total symbol count + // + if(lane_idx() == 0) + { + U64 rec_range_count = 0; + for EachIndex(idx, all_syms_count) + { + rec_range_count += all_syms[idx]->sym_ranges.count; + } + p2r2_shared->symbol_count_prediction = rec_range_count/8; + p2r2_shared->symbol_count_prediction = Max(p2r2_shared->symbol_count_prediction, 256); + } + lane_sync(); + U64 symbol_count_prediction = p2r2_shared->symbol_count_prediction; + + ////////////////////////////////////////////////////////////// + //- rjf: build link name map + // + ProfScope("build link name map") if(lane_idx() == 0 && all_syms_count != 0) + { + // rjf: set up + { + p2r2_shared->link_name_map.buckets_count = symbol_count_prediction; + p2r2_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r2_shared->link_name_map.buckets_count); + } + + // rjf: fill + { + CV_SymParsed *sym = all_syms[0]; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first + sym->sym_ranges.count; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: unpack symbol range info + CV_SymKind kind = rec_range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_sym_kind(kind); + U8 *sym_first = sym->data.str + rec_range->off + 2; + U8 *sym_opl = sym_first + rec_range->hdr.size; + + //- rjf: skip bad ranges + if(sym_opl > sym->data.str + sym->data.size || sym_first + header_struct_size > sym->data.str + sym->data.size) + { + continue; + } + + //- rjf: consume symbol + switch(kind) + { + default:{}break; + case CV_SymKind_PUB32: + { + // rjf: unpack sym + CV_SymPub32 *pub32 = (CV_SymPub32 *)sym_first; + String8 name = str8_cstring_capped(pub32+1, sym_opl); + COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= coff_sections.count) ? &coff_sections.v[pub32->sec-1] : 0; + U64 voff = 0; + if(section != 0) + { + voff = section->voff + pub32->off; + } + + // rjf: commit to link name map + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%p2r2_shared->link_name_map.buckets_count; + P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); + SLLStackPush(p2r2_shared->link_name_map.buckets[bucket_idx], node); + node->voff = voff; + node->name = name; + }break; + } + } + } + } + lane_sync(); + P2R_LinkNameMap link_name_map = p2r2_shared->link_name_map; + ////////////////////////////////////////////////////////////// //- rjf: organize subsets of unit symbol streams by lane // @@ -321,11 +417,11 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: set up ProfScope("set up") if(lane_idx() == 0) { - p2r2_shared->lane_sym_blocks = push_array(arena, P2R2_UnitSymBlockList, lane_count()); + p2r2_shared->lane_sym_blocks = push_array(arena, P2R2_SymBlockList, lane_count()); p2r2_shared->total_sym_record_count = 0; - for EachIndex(unit_idx, comp_units->count) + for EachIndex(sym_idx, p2r2_shared->all_syms_count) { - p2r2_shared->total_sym_record_count += sym_for_unit[unit_idx]->sym_ranges.count; + p2r2_shared->total_sym_record_count += all_syms[sym_idx]->sym_ranges.count; } } lane_sync(); @@ -336,24 +432,33 @@ p2r2_convert_thread_entry_point(void *p) Rng1U64 lane_sym_range = lane_range(p2r2_shared->total_sym_record_count); { U64 scan_sym_idx = 0; - for EachIndex(idx, comp_units->count) + for EachIndex(idx, all_syms_count) { - Rng1U64 unit_sym_range = r1u64(scan_sym_idx, scan_sym_idx + sym_for_unit[idx]->sym_ranges.count); - Rng1U64 sym_range_in_unit = intersect_1u64(unit_sym_range, lane_sym_range); - if(sym_range_in_unit.max > sym_range_in_unit.min) + Rng1U64 stream_sym_range = r1u64(scan_sym_idx, scan_sym_idx + all_syms[idx]->sym_ranges.count); + Rng1U64 sym_range_in_stream = intersect_1u64(stream_sym_range, lane_sym_range); + if(sym_range_in_stream.max > sym_range_in_stream.min) { - P2R2_UnitSymBlock *block = push_array(arena, P2R2_UnitSymBlock, 1); + P2R2_SymBlock *block = push_array(arena, P2R2_SymBlock, 1); SLLQueuePush(p2r2_shared->lane_sym_blocks[lane_idx()].first, p2r2_shared->lane_sym_blocks[lane_idx()].last, block); - block->unit_idx = idx; - block->unit_rec_range = r1u64(sym_range_in_unit.min - scan_sym_idx, sym_range_in_unit.max - scan_sym_idx); + if(idx > 0) + { + block->unit = comp_units->units[idx-1]; + } + else + { + block->unit = &pdb_comp_unit_nil; + } + block->sym = all_syms[idx]; + block->c13 = all_c13s[idx]; + block->sym_rec_range = r1u64(sym_range_in_stream.min - scan_sym_idx, sym_range_in_stream.max - scan_sym_idx); } - scan_sym_idx += sym_for_unit[idx]->sym_ranges.count; + scan_sym_idx += all_syms[idx]->sym_ranges.count; } } } } lane_sync(); - P2R2_UnitSymBlockList *lane_sym_blocks = p2r2_shared->lane_sym_blocks; + P2R2_SymBlockList *lane_sym_blocks = p2r2_shared->lane_sym_blocks; ////////////////////////////////////////////////////////////// //- rjf: gather all file paths @@ -380,23 +485,25 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: iterate lane blocks & gather inline site file names ProfScope("gather inline site file names from this lane's symbols") - for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; lane_block != 0; lane_block = lane_block->next) { //- rjf: unpack unit - PDB_CompUnit *unit = comp_units->units[lane_block->unit_idx]; - CV_SymParsed *unit_sym = sym_for_unit[lane_block->unit_idx]; - CV_C13Parsed *unit_c13 = c13_for_unit[lane_block->unit_idx]; - CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.min; - CV_RecRange *rec_ranges_opl = unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.max; + PDB_CompUnit *unit = lane_block->unit; + CV_SymParsed *sym = lane_block->sym; + CV_C13Parsed *c13 = lane_block->c13; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + lane_block->sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + lane_block->sym_rec_range.max; //- rjf: produce obj name/path String8 obj_name = unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { - MemoryZeroStruct(&obj_name); + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } } String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); @@ -411,7 +518,7 @@ p2r2_convert_thread_entry_point(void *p) U64 sym_off_opl = rec_range->off + rec_range->hdr.size; //- rjf: skip invalid ranges - if(sym_off_opl > unit_sym->data.size || sym_off_first > unit_sym->data.size || sym_off_first > sym_off_opl) + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) { continue; } @@ -419,8 +526,8 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: unpack symbol info CV_SymKind kind = rec_range->hdr.kind; U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = unit_sym->data.str + sym_off_first; - void *sym_data_opl = unit_sym->data.str + sym_off_opl; + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; //- rjf: skip bad sizes if(sym_off_first + sym_header_struct_size > sym_off_opl) @@ -456,8 +563,8 @@ p2r2_convert_thread_entry_point(void *p) CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; { U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + U64 slot_idx = hash%c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) { if(n->v.inlinee == sym->inlinee) { @@ -471,7 +578,7 @@ p2r2_convert_thread_entry_point(void *p) if(inlinee_lines_parsed != 0) { // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; + CV_C13SubSectionNode *file_chksms = c13->file_chksms_sub_section; // rjf: gathered lines U32 last_file_off = max_U32; @@ -499,7 +606,7 @@ p2r2_convert_thread_entry_point(void *p) String8 seq_file_name = {0}; if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { - CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); + CV_C13Checksum *checksum = (CV_C13Checksum *)(c13->data.str + file_chksms->off + last_file_off); U32 name_off = checksum->name_off; seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); } @@ -569,8 +676,8 @@ p2r2_convert_thread_entry_point(void *p) for EachInRange(idx, range) { PDB_CompUnit *unit = comp_units->units[idx]; - CV_SymParsed *unit_sym = sym_for_unit[idx]; - CV_C13Parsed *unit_c13 = c13_for_unit[idx]; + CV_SymParsed *unit_sym = all_syms[idx+1]; + CV_C13Parsed *unit_c13 = all_c13s[idx+1]; CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; @@ -711,6 +818,80 @@ p2r2_convert_thread_entry_point(void *p) RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; + ////////////////////////////////////////////////////////////// + //- rjf: for each lane, figure out info for starting a sub-unit range + // + ProfScope("for each lane, figure out info for starting a sub-unit range") + { + // rjf: set up + if(lane_idx() == 0) + { + p2r2_shared->lane_unit_sub_start_pt_infos = push_array(arena, P2R2_UnitSubStartPtInfo, lane_count()); + } + lane_sync(); + + // rjf: fill + { + P2R2_UnitSubStartPtInfo *out_info = &p2r2_shared->lane_unit_sub_start_pt_infos[lane_idx()]; + P2R2_SymBlock *first_block = lane_sym_blocks[lane_idx()].first; + if(first_block != 0 && first_block->sym_rec_range.min > 0) + { + CV_SymParsed *sym = first_block->sym; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + first_block->sym_rec_range.min; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + // rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + // rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + // rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; + + // rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + // rjf: find range starters + switch(kind) + { + default:{}break; + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + out_info->last_proc_voff = section->voff + proc32->off; + } + }break; + case CV_SymKind_FRAMEPROC: + { + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; + out_info->last_frameproc = *frameproc; + }break; + } + } + } + } + } + lane_sync(); + P2R2_UnitSubStartPtInfo *lane_unit_sub_start_pt_infos = p2r2_shared->lane_unit_sub_start_pt_infos; + ////////////////////////////////////////////////////////////// //- rjf: convert unit info // @@ -723,8 +904,8 @@ p2r2_convert_thread_entry_point(void *p) { rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); } - p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); p2r2_shared->lanes_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); + p2r2_shared->lanes_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, lane_count()); } lane_sync(); RDIM_Unit *units = p2r2_shared->all_units.first->v; @@ -744,8 +925,8 @@ p2r2_convert_thread_entry_point(void *p) { Temp scratch = scratch_begin(&arena, 1); PDB_CompUnit *src_unit = comp_units->units[idx]; - CV_SymParsed *src_unit_sym = sym_for_unit[idx]; - CV_C13Parsed *src_unit_c13 = c13_for_unit[idx]; + CV_SymParsed *src_unit_sym = all_syms[idx+1]; + CV_C13Parsed *src_unit_c13 = all_c13s[idx+1]; RDIM_Unit *dst_unit = &units[idx]; // rjf: produce obj name/path @@ -824,23 +1005,14 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: build per-inline-site line tables ProfScope("build per-inline-site line tables") { - U64 last_unit_num_started_by_this_lane = 0; - for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; lane_block != 0; lane_block = lane_block->next) { Temp scratch = scratch_begin(&arena, 1); - if(lane_block->unit_rec_range.min == 0) - { - last_unit_num_started_by_this_lane = lane_block->unit_idx+1; - } - else if(last_unit_num_started_by_this_lane-1 != lane_block->unit_idx) - { - last_unit_num_started_by_this_lane = 0; - } - PDB_CompUnit *src_unit = comp_units->units[lane_block->unit_idx]; - CV_SymParsed *src_unit_sym = sym_for_unit[lane_block->unit_idx]; - CV_C13Parsed *src_unit_c13 = c13_for_unit[lane_block->unit_idx]; + PDB_CompUnit *src_unit = lane_block->unit; + CV_SymParsed *src_unit_sym = lane_block->sym; + CV_C13Parsed *src_unit_c13 = lane_block->c13; String8 obj_name = src_unit->obj_name; if(str8_match(obj_name, str8_lit("* Linker *"), 0) || str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) @@ -848,9 +1020,9 @@ p2r2_convert_thread_entry_point(void *p) MemoryZeroStruct(&obj_name); } String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.min; - CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + lane_block->unit_rec_range.max; - U64 base_voff = 0; + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges + lane_block->sym_rec_range.min; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + lane_block->sym_rec_range.max; + U64 base_voff = lane_unit_sub_start_pt_infos[lane_idx()].last_proc_voff; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; rec_range += 1) @@ -1021,12 +1193,9 @@ p2r2_convert_thread_entry_point(void *p) if(line_table == 0) { line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(last_unit_num_started_by_this_lane != 0) + if(p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] == 0) { - if(p2r2_shared->units_first_inline_site_line_tables[last_unit_num_started_by_this_lane-1] == 0) - { - p2r2_shared->units_first_inline_site_line_tables[last_unit_num_started_by_this_lane-1] = line_table; - } + p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] = line_table; } } rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); @@ -1074,7 +1243,7 @@ p2r2_convert_thread_entry_point(void *p) lane_sync(); RDIM_UnitChunkList *all_units = &p2r2_shared->all_units; RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; + RDIM_LineTable **lanes_first_inline_site_line_tables = p2r2_shared->lanes_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// //- rjf: join all line tables @@ -2115,14 +2284,14 @@ p2r2_convert_thread_entry_point(void *p) } p2r2_shared->itype_type_ptrs = itype_type_ptrs; p2r2_shared->basic_type_ptrs = basic_type_ptrs; - p2r2_shared->all_types = all_types; + p2r2_shared->all_types__pre_typedefs = all_types; #undef p2r_type_ptr_from_itype #undef p2r_builtin_type_ptr_from_kind } lane_sync(); RDIM_Type **itype_type_ptrs = p2r2_shared->itype_type_ptrs; RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; - RDIM_TypeChunkList all_types = p2r2_shared->all_types; + RDIM_TypeChunkList all_types__pre_typedefs = p2r2_shared->all_types__pre_typedefs; ////////////////////////////////////////////////////////////// //- rjf: types pass 4: build UDTs @@ -2766,13 +2935,31 @@ p2r2_convert_thread_entry_point(void *p) #undef p2r_type_ptr_from_itype } lane_sync(); + RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; + + ////////////////////////////////////////////////////////////// + //- rjf: join all UDTs + // + ProfScope("join all UDTs") if(lane_idx() == 0) + { + for EachIndex(idx, lane_count()) + { + rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); + } + } + lane_sync(); + RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams // ProfScope("produce symbols from all streams") { +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + + //////////////////////////// //- rjf: set up + // if(lane_idx() == 0) { p2r2_shared->lanes_procedures = push_array(arena, RDIM_SymbolChunkList, lane_count()); @@ -2785,12 +2972,918 @@ p2r2_convert_thread_entry_point(void *p) } lane_sync(); - //- rjf: wide fill - for(P2R2_UnitSymBlock *lane_block = lane_sym_blocks[lane_idx()].first; + //////////////////////////// + //- rjf: set up outputs for this sym stream + // + U64 sym_procedures_chunk_cap = 1024; + U64 sym_global_variables_chunk_cap = 1024; + U64 sym_thread_variables_chunk_cap = 1024; + U64 sym_constants_chunk_cap = 1024; + U64 sym_scopes_chunk_cap = 1024; + U64 sym_inline_sites_chunk_cap = 1024; + RDIM_SymbolChunkList sym_procedures = {0}; + RDIM_SymbolChunkList sym_global_variables = {0}; + RDIM_SymbolChunkList sym_thread_variables = {0}; + RDIM_SymbolChunkList sym_constants = {0}; + RDIM_ScopeChunkList sym_scopes = {0}; + RDIM_InlineSiteChunkList sym_inline_sites = {0}; + RDIM_TypeChunkList typedefs = {0}; + + //////////////////////////// + //- rjf: fill outputs for all unit sym blocks in this lane + // + for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; lane_block != 0; lane_block = lane_block->next) { + Temp scratch = scratch_begin(&arena, 1); + CV_SymParsed *sym = lane_block->sym; + Rng1U64 sym_rec_range = lane_block->sym_rec_range; + + ////////////////////////// + //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) + // + U64 procedure_frameprocs_count = 0; + U64 procedure_frameprocs_cap = dim_1u64(sym_rec_range); + CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); + ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") + { + U64 procedure_num = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: FRAMEPROC + case CV_SymKind_FRAMEPROC: + { + if(procedure_num == 0) { break; } + if(procedure_num > procedure_frameprocs_cap) { break; } + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; + procedure_frameprocs[procedure_num-1] = frameproc; + procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + procedure_num += 1; + }break; + } + } + U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); + arena_pop(scratch.arena, scratch_overkill); + } + + ////////////////////////// + //- rjf: symbols pass 2: construct all symbols, given procedure frame info map + // + ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") + { + RDIM_LocationSet *defrange_target = 0; + B32 defrange_target_is_param = 0; + U64 procedure_num = 0; + U64 procedure_base_voff = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + typedef struct P2R_ScopeNode P2R_ScopeNode; + struct P2R_ScopeNode + { + P2R_ScopeNode *next; + RDIM_Scope *scope; + }; + P2R_ScopeNode *top_scope_node = 0; + P2R_ScopeNode *free_scope_node = 0; + RDIM_LineTable *inline_site_line_table = lanes_first_inline_site_line_tables[lane_idx()]; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: END + case CV_SymKind_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: BLOCK32 + case CV_SymKind_BLOCK32: + { + // rjf: unpack sym + CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; + + // rjf: build scope, insert into current parent scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + { + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + block32->off; + U64 voff_last = voff_first + block32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + } + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + }break; + + //- rjf: LDATA32/GDATA32 + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + // rjf: unpack sym + CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(data32+1, sym_data_opl); + COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; + U64 voff = (section ? section->voff : 0) + data32->off; + + // rjf: determine if this is an exact duplicate global + // + // PDB likes to have duplicates of these spread across different + // symbol streams so we deduplicate across the entire translation + // context. + // + B32 is_duplicate = 0; + { + // TODO(rjf): @important global symbol dedup + } + + // rjf: is not duplicate -> push new global + if(!is_duplicate) + { + // rjf: unpack global variable's type + RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); + + // rjf: unpack global's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack global's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, &sym_global_variables, sym_global_variables_chunk_cap); + symbol->is_extern = (kind == CV_SymKind_GDATA32); + symbol->name = name; + symbol->type = type; + symbol->offset = voff; + symbol->container_symbol = container_symbol; + symbol->container_type = container_type; + } + }break; + + //- rjf: UDT (typedefs) + case CV_SymKind_UDT: + if(sym == all_syms[0] && top_scope_node == 0) + { + CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; + String8 name = str8_cstring_capped(udt+1, sym_data_opl); + RDIM_Type *type = rdim_type_chunk_list_push(arena, &typedefs, 4096); + type->kind = RDI_TypeKind_Alias; + type->name = name; + type->direct_type = p2r_type_ptr_from_itype(udt->itype); + if(type->direct_type != 0) + { + type->byte_size = type->direct_type->byte_size; + } + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + // rjf: unpack sym + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(proc32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); + + // rjf: unpack proc's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2 && tpi_hash != 0 && tpi_leaf != 0) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack proc's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build procedure's root scope + // + // NOTE: even if there could be a containing scope at this point (which should be + // illegal in C/C++ but not necessarily in another language) we would not use + // it here because these scopes refer to the ranges of code that make up a + // procedure *not* the namespaces, so a procedure's root scope always has + // no parent. + RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + { + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + proc32->off; + U64 voff_last = voff_first + proc32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, &sym_scopes, procedure_root_scope, voff_range); + procedure_base_voff = voff_first; + } + } + + // rjf: root scope voff minimum range -> link name + String8 link_name = {0}; + if(procedure_root_scope->voff_ranges.min != 0) + { + U64 voff = procedure_root_scope->voff_ranges.min; + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%link_name_map.buckets_count; + P2R_LinkNameNode *node = 0; + for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) + { + if(n->voff == voff) + { + link_name = n->name; + break; + } + } + } + + // rjf: build procedure symbol + RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, &sym_procedures, sym_procedures_chunk_cap); + procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); + procedure_symbol->name = name; + procedure_symbol->link_name = link_name; + procedure_symbol->type = type; + procedure_symbol->container_symbol = container_symbol; + procedure_symbol->container_type = container_type; + procedure_symbol->root_scope = procedure_root_scope; + + // rjf: fill root scope's symbol + procedure_root_scope->symbol = procedure_symbol; + + // rjf: push scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = procedure_root_scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: increment procedure counter + procedure_num += 1; + }break; + + //- rjf: REGREL32 + case CV_SymKind_REGREL32: + { + // TODO(rjf): apparently some of the information here may end up being + // redundant with "better" information from CV_SymKind_LOCAL record. + // we don't currently handle this, but if those cases arise then it + // will obviously be better to prefer the better information from both + // records. + + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); + CV_Reg cv_reg = regrel32->reg; + U32 var_off = regrel32->reg_off; + + // rjf: determine if this is a parameter + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + { + B32 is_stack_reg = 0; + switch(arch) + { + default:{}break; + case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; + case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + } + if(is_stack_reg) + { + U32 frame_size = 0xFFFFFFFF; + if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) + { + CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; + frame_size = frameproc->frame_size; + } + if(var_off > frame_size) + { + local_kind = RDI_LocalKind_Parameter; + } + } + } + + // TODO(rjf): is this correct? + // rjf: redirect type, if 0, and if outside frame, to the return type of the + // containing procedure + if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && + top_scope_node->scope->symbol != 0 && + top_scope_node->scope->symbol->type != 0) + { + type = top_scope_node->scope->symbol->type->direct_type; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: add location info to local + if(type != 0) + { + // rjf: determine if we need an extra indirection to the value + B32 extra_indirection_to_value = 0; + switch(arch) + { + case RDI_Arch_X86: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); + }break; + case RDI_Arch_X64: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); + }break; + } + + // rjf: get raddbg register code + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + // TODO(rjf): real byte_size & byte_pos from cv_reg goes here + U32 byte_size = 8; + U32 byte_pos = 0; + + // rjf: set location case + RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, &sym_scopes, &local->locset, voff_range, loc); + } + }break; + + //- rjf: LTHREAD32/GTHREAD32 + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + { + // rjf: unpack sym + CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(thread32+1, sym_data_opl); + U32 tls_off = thread32->tls_off; + RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); + + // rjf: unpack thread variable's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack thread variable's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, &sym_thread_variables, sym_thread_variables_chunk_cap); + tvar->name = name; + tvar->type = type; + tvar->is_extern = (kind == CV_SymKind_GTHREAD32); + tvar->offset = tls_off; + tvar->container_type = container_type; + tvar->container_symbol = container_symbol; + }break; + + //- rjf: LOCAL + case CV_SymKind_LOCAL: + { + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; + String8 name = str8_cstring_capped(slocal+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); + + // rjf: determine if this symbol encodes the beginning of a global modification + B32 is_global_modification = 0; + if((slocal->flags & CV_LocalFlag_Global) || + (slocal->flags & CV_LocalFlag_Static)) + { + is_global_modification = 1; + } + + // rjf: is global modification -> emit global modification symbol + if(is_global_modification) + { + // TODO(rjf): add global modification symbols + defrange_target = 0; + defrange_target_is_param = 0; + } + + // rjf: is not a global modification -> emit a local variable + if(!is_global_modification) + { + // rjf: determine local kind + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + if(slocal->flags & CV_LocalFlag_Param) + { + local_kind = RDI_LocalKind_Parameter; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: save defrange target, for subsequent defrange symbols + defrange_target = &local->locset; + defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); + } + }break; + + //- rjf: DEFRANGE_REGISTESR + case CV_SymKind_DEFRANGE_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register->reg; + CV_LvarAddrRange *range = &defrange_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: build location + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; + CV_LvarAddrRange *range = &defrange_fprel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel->off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_SUBFIELD_REGISTER + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_subfield_register->reg; + CV_LvarAddrRange *range = &defrange_subfield_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: skip "subfield" location info - currently not supported + if(defrange_subfield_register->field_offset != 0) + { + break; + } + + // rjf: build location + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel_full_scope->off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + + // rjf: emit location over ranges + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, &sym_scopes, defrange_target, voff_range, location); + }break; + + //- rjf: DEFRANGE_REGISTER_REL + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register_rel->reg; + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + CV_LvarAddrRange *range = &defrange_register_rel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: build location + // TODO(rjf): offset & size from cv_reg code + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + B32 extra_indirection_to_value = 0; + S64 var_off = defrange_register_rel->reg_off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: FILESTATIC + case CV_SymKind_FILESTATIC: + { + CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; + String8 name = str8_cstring_capped(file_static+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); + // TODO(rjf): emit a global modifier symbol + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: extract external info about inline site + String8 name = str8_zero(); + RDIM_Type *type = 0; + RDIM_Type *owner = 0; + if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) + { + CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; + String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); + void *raw_leaf = rec_data.str + sizeof(U16); + + // rjf: extract method inline info + if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) + { + CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; + name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(mfunc_id->itype); + owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; + } + + // rjf: extract non-method function inline info + else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafFuncId)) + { + CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; + name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(func_id->itype); + owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; + } + } + + // rjf: build inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &sym_inline_sites, sym_inline_sites_chunk_cap); + inline_site->name = name; + inline_site->type = type; + inline_site->owner = owner; + inline_site->line_table = inline_site_line_table; + + // rjf: increment to next inline site line table in this unit + if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) + { + RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; + U64 current_idx = (U64)(inline_site_line_table - chunk->v); + if(current_idx+1 < chunk->count) + { + inline_site_line_table += 1; + } + else + { + chunk = chunk->next; + inline_site_line_table = 0; + if(chunk != 0) + { + inline_site_line_table = chunk->v; + } + } + } + + // rjf: build scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + scope->inline_site = inline_site; + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: parse offset ranges of this inline site - attach to scope + { + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); + for(;;) + { + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) + { + // rjf: build new range & add to scope + RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; + rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) + { + if(scope->voff_ranges.last != 0) + { + scope->voff_ranges.last->v.max = step.range.max; + } + } + + if(step.flags == 0) + { + break; + } + } + } + }break; + + //- rjf: INLINESITE_END + case CV_SymKind_INLINESITE_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: CONSTANT + case CV_SymKind_CONSTANT: + { + // rjf: unpack + CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; + RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); + U8 *val_ptr = (U8 *)(sym+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, sym_data_opl); + String8 val_data = str8_struct(&val64); + U64 container_name_opl = 0; + if(type != 0) + { + container_name_opl = p2r_end_of_cplusplus_container_name(type->name); + } + String8 name_qualified = name; + if(container_name_opl != 0) + { + name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); + } + + // rjf: build constant symbol + if(name_qualified.size != 0) + { + RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, &sym_constants, sym_constants_chunk_cap); + cnst->name = name_qualified; + cnst->type = type; + rdim_symbol_push_value_data(arena, &sym_constants, cnst, val_data); + } + }break; + } + } + } + + scratch_end(scratch); } + + //////////////////////////// + //- rjf: output this lane's symbols + // + p2r2_shared->lanes_procedures[lane_idx()] = sym_procedures; + p2r2_shared->lanes_global_variables[lane_idx()] = sym_global_variables; + p2r2_shared->lanes_thread_variables[lane_idx()] = sym_thread_variables; + p2r2_shared->lanes_constants[lane_idx()] = sym_constants; + p2r2_shared->lanes_scopes[lane_idx()] = sym_scopes; + p2r2_shared->lanes_inline_sites[lane_idx()] = sym_inline_sites; + p2r2_shared->lanes_typedefs[lane_idx()] = typedefs; + +#undef p2r_type_ptr_from_itype } lane_sync(); @@ -2798,8 +3891,65 @@ p2r2_convert_thread_entry_point(void *p) //- rjf: join all lane symbols // { - // TODO(rjf) + if(lane_idx() == lane_from_task_idx(0)) ProfScope("join procedures") + { + for EachIndex(idx, lane_count()) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->lanes_procedures[idx]); + } + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("join global variables") + { + for EachIndex(idx, lane_count()) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->lanes_global_variables[idx]); + } + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("join thread variables") + { + for EachIndex(idx, lane_count()) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->lanes_thread_variables[idx]); + } + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("join constants") + { + for EachIndex(idx, lane_count()) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->lanes_constants[idx]); + } + } + if(lane_idx() == lane_from_task_idx(4)) ProfScope("join scopes") + { + for EachIndex(idx, lane_count()) + { + rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->lanes_scopes[idx]); + } + } + if(lane_idx() == lane_from_task_idx(5)) ProfScope("join inline sites") + { + for EachIndex(idx, lane_count()) + { + rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->lanes_inline_sites[idx]); + } + } + if(lane_idx() == lane_from_task_idx(6)) ProfScope("join typedefs") + { + for EachIndex(idx, lane_count()) + { + rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->lanes_typedefs[idx]); + } + p2r2_shared->all_types = p2r2_shared->all_types__pre_typedefs; + } } + lane_sync(); + RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; + RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; + RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; + RDIM_SymbolChunkList all_constants = p2r2_shared->all_constants; + RDIM_ScopeChunkList all_scopes = p2r2_shared->all_scopes; + RDIM_InlineSiteChunkList all_inline_sites = p2r2_shared->all_inline_sites; + RDIM_TypeChunkList all_types = p2r2_shared->all_types; //- //- diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 051a8ac1..1e9f0696 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -16,25 +16,35 @@ struct P2R2_ConvertThreadParams B32 deterministic; }; -typedef struct P2R2_UnitSymBlock P2R2_UnitSymBlock; -struct P2R2_UnitSymBlock +typedef struct P2R2_SymBlock P2R2_SymBlock; +struct P2R2_SymBlock { - P2R2_UnitSymBlock *next; - U64 unit_idx; - Rng1U64 unit_rec_range; + P2R2_SymBlock *next; + PDB_CompUnit *unit; + CV_SymParsed *sym; + CV_C13Parsed *c13; + Rng1U64 sym_rec_range; }; -typedef struct P2R2_UnitSymBlockList P2R2_UnitSymBlockList; -struct P2R2_UnitSymBlockList +typedef struct P2R2_SymBlockList P2R2_SymBlockList; +struct P2R2_SymBlockList { - P2R2_UnitSymBlock *first; - P2R2_UnitSymBlock *last; + P2R2_SymBlock *first; + P2R2_SymBlock *last; +}; + +typedef struct P2R2_UnitSubStartPtInfo P2R2_UnitSubStartPtInfo; +struct P2R2_UnitSubStartPtInfo +{ + CV_SymFrameproc last_frameproc; + U64 last_proc_voff; }; typedef struct P2R2_Shared P2R2_Shared; struct P2R2_Shared { MSF_RawStreamTable *msf_raw_stream_table; + U64 msf_stream_lane_counter; MSF_Parsed *msf; PDB_Info *pdb_info; @@ -55,19 +65,25 @@ struct P2R2_Shared CV_LeafParsed *tpi_leaf; PDB_TpiHashParsed *ipi_hash; CV_LeafParsed *ipi_leaf; - CV_SymParsed *sym; PDB_CompUnitArray *comp_units; PDB_CompUnitContributionArray *comp_unit_contributions; RDIM_Rng1U64ChunkList *unit_ranges; - CV_SymParsed **sym_for_unit; - CV_C13Parsed **c13_for_unit; + U64 sym_c13_unit_lane_counter; + U64 all_syms_count; + CV_SymParsed **all_syms; // [0] -> global; rest are unit nums + CV_C13Parsed **all_c13s; // [0] -> blank (global); rest are unit nums U64 exe_voff_max; RDI_Arch arch; + U64 symbol_count_prediction; + + P2R_LinkNameMap link_name_map; U64 total_sym_record_count; - P2R2_UnitSymBlockList *lane_sym_blocks; + P2R2_SymBlockList *lane_sym_blocks; + + P2R2_UnitSubStartPtInfo *lane_unit_sub_start_pt_infos; String8Array *lane_file_paths; U64Array *lane_file_paths_hashes; @@ -78,8 +94,8 @@ struct P2R2_Shared P2R_SrcFileMap src_file_map; RDIM_UnitChunkList all_units; - RDIM_LineTable **units_first_inline_site_line_tables; RDIM_LineTableChunkList *lanes_line_tables; + RDIM_LineTable **lanes_first_inline_site_line_tables; RDIM_LineTableChunkList all_line_tables; @@ -91,10 +107,12 @@ struct P2R2_Shared RDIM_Type **itype_type_ptrs; RDIM_Type **basic_type_ptrs; - RDIM_TypeChunkList all_types; + RDIM_TypeChunkList all_types__pre_typedefs; RDIM_UDTChunkList *lanes_udts; + RDIM_UDTChunkList all_udts; + RDIM_SymbolChunkList *lanes_procedures; RDIM_SymbolChunkList *lanes_global_variables; RDIM_SymbolChunkList *lanes_thread_variables; @@ -109,6 +127,7 @@ struct P2R2_Shared RDIM_SymbolChunkList all_constants; RDIM_ScopeChunkList all_scopes; RDIM_InlineSiteChunkList all_inline_sites; + RDIM_TypeChunkList all_types; }; global P2R2_Shared *p2r2_shared = 0; From be5634c44867a2e31f6a109df5e574930992df01 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 19 Aug 2025 17:02:05 -0700 Subject: [PATCH 054/302] p2r2 - final conversion output bundling --- src/rdi_from_pdb/rdi_from_pdb_2.c | 85 ++++++++++++++++++------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 1 + 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index af599c8d..540645d5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -21,6 +21,7 @@ p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in) thread_params[idx].input_pdb_name = in->input_pdb_name; thread_params[idx].input_pdb_data = in->input_pdb_data; thread_params[idx].deterministic = in->deterministic; + thread_params[idx].out_bake_params = &result; } for EachIndex(idx, thread_count) { @@ -1241,7 +1242,7 @@ p2r2_convert_thread_entry_point(void *p) } } lane_sync(); - RDIM_UnitChunkList *all_units = &p2r2_shared->all_units; + RDIM_UnitChunkList all_units = p2r2_shared->all_units; RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; RDIM_LineTable **lanes_first_inline_site_line_tables = p2r2_shared->lanes_first_inline_site_line_tables; @@ -1272,11 +1273,13 @@ p2r2_convert_thread_entry_point(void *p) RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) { - rdim_src_file_push_line_sequence(arena, &all_src_files__sequenceless, s->v.src_file, &s->v); + rdim_src_file_push_line_sequence(arena, &p2r2_shared->all_src_files__sequenceless, s->v.src_file, &s->v); } } } } + lane_sync(); + RDIM_SrcFileChunkList all_src_files = p2r2_shared->all_src_files__sequenceless; ////////////////////////////////////////////////////////////// //- rjf: types pass 1: produce type forward resolution map @@ -3951,45 +3954,57 @@ p2r2_convert_thread_entry_point(void *p) RDIM_InlineSiteChunkList all_inline_sites = p2r2_shared->all_inline_sites; RDIM_TypeChunkList all_types = p2r2_shared->all_types; - //- - //- - //-- - ////////////////////////////////////////////////////////////// - //- rjf: produce top-level-info + //- rjf: bundle all outputs // - RDIM_TopLevelInfo top_level_info = {0}; + if(lane_idx() == 0) { - top_level_info.arch = arch; - top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); - top_level_info.exe_hash = exe_hash; - top_level_info.voff_max = exe_voff_max; - if(params->deterministic) + //- rjf: produce top-level-info + RDIM_TopLevelInfo top_level_info = {0}; { - top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + top_level_info.arch = arch; + top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + if(params->deterministic) + { + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + } } - } - - ////////////////////////////////////////////////////////////// - //- rjf: build binary sections list - // - RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") - { - COFF_SectionHeader *coff_ptr = coff_sections.v; - COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; - for(;coff_ptr < coff_opl; coff_ptr += 1) + + //- rjf: build binary sections list + RDIM_BinarySectionList binary_sections = {0}; + ProfScope("build binary section list") { - char *name_first = (char *)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); - sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - sec->voff_first = coff_ptr->voff; - sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; - sec->foff_first = coff_ptr->foff; - sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; + COFF_SectionHeader *coff_ptr = coff_sections.v; + COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; + for(;coff_ptr < coff_opl; coff_ptr += 1) + { + char *name_first = (char *)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + sec->name = str8_cstring_capped(name_first, name_opl); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->voff_first = coff_ptr->voff; + sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; + sec->foff_first = coff_ptr->foff; + sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; + } } + + //- rjf: fill + params->out_bake_params->top_level_info = top_level_info; + params->out_bake_params->binary_sections = binary_sections; + params->out_bake_params->units = all_units; + params->out_bake_params->types = all_types; + params->out_bake_params->udts = all_udts; + params->out_bake_params->src_files = all_src_files; + params->out_bake_params->line_tables = all_line_tables; + params->out_bake_params->global_variables = all_global_variables; + params->out_bake_params->thread_variables = all_thread_variables; + params->out_bake_params->constants = all_constants; + params->out_bake_params->procedures = all_procedures; + params->out_bake_params->scopes = all_scopes; + params->out_bake_params->inline_sites = all_inline_sites; } - } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 1e9f0696..d77cabd3 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -14,6 +14,7 @@ struct P2R2_ConvertThreadParams String8 input_pdb_name; String8 input_pdb_data; B32 deterministic; + RDIM_BakeParams *out_bake_params; }; typedef struct P2R2_SymBlock P2R2_SymBlock; From c35c14dadb5ee98c991f9ea307162a5032890f63 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 30 Aug 2025 12:04:39 -0700 Subject: [PATCH 055/302] prefer last match to first in debug info, to gracefully avoid stale debug info in pdbs --- src/dbgi/dbgi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 75609497..87bb07ec 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -1873,7 +1873,7 @@ ASYNC_WORK_DEF(di_match_work) // rjf: atomically update the node's primary match ins_atomic_u64_eval_assign(&node->primary_match.dbgi_idx, dbgi_idx); ins_atomic_u32_eval_assign(&node->primary_match.section, name_map_section_kinds[name_map_kind_idx]); - ins_atomic_u32_eval_assign(&node->primary_match.idx, run[0]); + ins_atomic_u32_eval_assign(&node->primary_match.idx, run[num-1]); // rjf: gather all alternate matches for(U32 match_idx = 1; match_idx < num; match_idx += 1) From d8bb8c76c6729ef2adc7f2f0c3449ccaff6fb910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81rti=C5=86=C5=A1=20Mo=C5=BEeiko?= Date: Tue, 19 Aug 2025 18:53:47 -0700 Subject: [PATCH 056/302] add shadow stack register and read it in win32 thread context --- src/demon/win32/demon_core_win32.c | 16 ++++++++++++++-- src/lib_rdi/rdi.h | 4 ++++ src/rdi/rdi.mdesk | 2 ++ src/regs/generated/regs.meta.c | 12 +++++++++--- src/regs/generated/regs.meta.h | 10 +++++++--- src/regs/rdi/generated/regs_rdi.meta.c | 4 ++++ src/regs/regs.mdesk | 2 ++ 7 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index e3305ca2..a1a023e2 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -690,7 +690,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) //- rjf: unpack info about available features U32 feature_mask = GetEnabledXStateFeatures(); - B32 xstate_enabled = (feature_mask & (XSTATE_MASK_AVX | XSTATE_MASK_AVX512)) != 0; + B32 xstate_enabled = (feature_mask & (XSTATE_MASK_AVX | XSTATE_MASK_AVX512 | XSTATE_MASK_CET_U)) != 0; //- rjf: set up context CONTEXT *ctx = 0; @@ -709,7 +709,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) //- rjf: unpack features available on this context if (xstate_enabled) { - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512); + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512 | XSTATE_MASK_CET_U); } //- rjf: get thread context @@ -866,6 +866,18 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) MemoryZero(zmm_d, sizeof(*zmm_d)); } } + + // CET / Shadow Stack + if(xstate_mask & XSTATE_MASK_CET_U) + { + DWORD cet_length = 0; + XSAVE_CET_U_FORMAT *cet = LocateXStateFeature(ctx, XSTATE_CET_U, &cet_length); + if (cet_length == sizeof(*cet)) + { + dst->cetmsr.u64 = cet->Ia32CetUMsr; + dst->cetssp.u64 = cet->Ia32Pl3SspMsr; + } + } scratch_end(scratch); }break; diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 5692f306..550a26b9 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -293,6 +293,8 @@ RDI_RegCodeX64_fds = 97, RDI_RegCodeX64_fip = 98, RDI_RegCodeX64_fdp = 99, RDI_RegCodeX64_mxcsr_mask = 100, +RDI_RegCodeX64_cetmsr = 101, +RDI_RegCodeX64_cetssp = 102, } RDI_RegCodeX64Enum; typedef RDI_U32 RDI_BinarySectionFlags; @@ -765,6 +767,8 @@ X(fds, 97)\ X(fip, 98)\ X(fdp, 99)\ X(mxcsr_mask, 100)\ +X(cetmsr, 101)\ +X(cetssp, 102)\ #define RDI_TopLevelInfo_XList \ X(RDI_Arch, arch)\ diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 7dcd4eb0..49a22dc9 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -438,6 +438,8 @@ RDI_RegCodeX64Table: {fip 98} {fdp 99} {mxcsr_mask 100} + {cetmsr 101} + {cetssp 102} } @enum(RDI_U32) RDI_Arch: diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index 61b2632f..fab1e6c9 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -103,7 +103,7 @@ case Arch_x86:{result = regs_g_alias_code_x86_usage_kind_table;}break; return result; } C_LINKAGE_BEGIN -REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[101] = +REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[103] = { REGS_UsageKind_Normal, REGS_UsageKind_Normal, @@ -206,6 +206,8 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, }; REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[96] = @@ -308,7 +310,7 @@ REGS_UsageKind_Normal, REGS_UsageKind_Normal, }; -String8 regs_g_reg_code_x64_string_table[101] = +String8 regs_g_reg_code_x64_string_table[103] = { str8_lit_comp(""), str8_lit_comp("rax"), @@ -411,6 +413,8 @@ str8_lit_comp("k4"), str8_lit_comp("k5"), str8_lit_comp("k6"), str8_lit_comp("k7"), +str8_lit_comp("cetmsr"), +str8_lit_comp("cetssp"), }; String8 regs_g_alias_code_x64_string_table[96] = @@ -513,7 +517,7 @@ str8_lit_comp("mm6"), str8_lit_comp("mm7"), }; -REGS_Rng regs_g_reg_code_x64_rng_table[101] = +REGS_Rng regs_g_reg_code_x64_rng_table[103] = { {0}, {(U16)OffsetOf(REGS_RegBlockX64, rax), 8}, @@ -616,6 +620,8 @@ REGS_Rng regs_g_reg_code_x64_rng_table[101] = {(U16)OffsetOf(REGS_RegBlockX64, k5), 8}, {(U16)OffsetOf(REGS_RegBlockX64, k6), 8}, {(U16)OffsetOf(REGS_RegBlockX64, k7), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, cetmsr), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, cetssp), 8}, }; REGS_Slice regs_g_alias_code_x64_slice_table[96] = diff --git a/src/regs/generated/regs.meta.h b/src/regs/generated/regs.meta.h index 4adc08d4..1f1316dc 100644 --- a/src/regs/generated/regs.meta.h +++ b/src/regs/generated/regs.meta.h @@ -109,6 +109,8 @@ REGS_RegCodeX64_k4, REGS_RegCodeX64_k5, REGS_RegCodeX64_k6, REGS_RegCodeX64_k7, +REGS_RegCodeX64_cetmsr, +REGS_RegCodeX64_cetssp, REGS_RegCodeX64_COUNT, } REGS_RegCodeX64; @@ -423,6 +425,8 @@ REGS_Reg64 k4; REGS_Reg64 k5; REGS_Reg64 k6; REGS_Reg64 k7; +REGS_Reg64 cetmsr; +REGS_Reg64 cetssp; }; typedef struct REGS_RegBlockX86 REGS_RegBlockX86; @@ -491,11 +495,11 @@ REGS_Reg256 ymm7; }; C_LINKAGE_BEGIN -extern REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[101]; +extern REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[103]; extern REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[96]; -extern String8 regs_g_reg_code_x64_string_table[101]; +extern String8 regs_g_reg_code_x64_string_table[103]; extern String8 regs_g_alias_code_x64_string_table[96]; -extern REGS_Rng regs_g_reg_code_x64_rng_table[101]; +extern REGS_Rng regs_g_reg_code_x64_rng_table[103]; extern REGS_Slice regs_g_alias_code_x64_slice_table[96]; extern REGS_UsageKind regs_g_reg_code_x86_usage_kind_table[61]; extern REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[36]; diff --git a/src/regs/rdi/generated/regs_rdi.meta.c b/src/regs/rdi/generated/regs_rdi.meta.c index de284856..686b8049 100644 --- a/src/regs/rdi/generated/regs_rdi.meta.c +++ b/src/regs/rdi/generated/regs_rdi.meta.c @@ -114,6 +114,8 @@ case REGS_RegCodeX64_k4:{result = RDI_RegCodeX64_k4;}break; case REGS_RegCodeX64_k5:{result = RDI_RegCodeX64_k5;}break; case REGS_RegCodeX64_k6:{result = RDI_RegCodeX64_k6;}break; case REGS_RegCodeX64_k7:{result = RDI_RegCodeX64_k7;}break; +case REGS_RegCodeX64_cetmsr:{result = RDI_RegCodeX64_cetmsr;}break; +case REGS_RegCodeX64_cetssp:{result = RDI_RegCodeX64_cetssp;}break; } }break; case Arch_x86: @@ -297,6 +299,8 @@ case RDI_RegCodeX64_k4:{result = REGS_RegCodeX64_k4;}break; case RDI_RegCodeX64_k5:{result = REGS_RegCodeX64_k5;}break; case RDI_RegCodeX64_k6:{result = REGS_RegCodeX64_k6;}break; case RDI_RegCodeX64_k7:{result = REGS_RegCodeX64_k7;}break; +case RDI_RegCodeX64_cetmsr:{result = REGS_RegCodeX64_cetmsr;}break; +case RDI_RegCodeX64_cetssp:{result = REGS_RegCodeX64_cetssp;}break; } }break; case Arch_x86: diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 56076b33..25d35691 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -107,6 +107,8 @@ REGS_RegTableX64: {k5 64 Normal} {k6 64 Normal} {k7 64 Normal} + {cetmsr 64 Normal} + {cetssp 64 Normal} } @table(name base off size usage) From 69d0da95865b34f52b9d11e3fe191bd1b078102a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 08:38:13 -0700 Subject: [PATCH 057/302] checkpoint on moving all of radbin to wavefront-style, first step to going wide on rdi baking as well --- src/base/base_thread_context.c | 4 +- src/base/base_thread_context.h | 2 +- src/radbin/radbin.c | 162 +++++++++++++++++----------- src/radbin/radbin.h | 28 ++++- src/rdi_from_dwarf/rdi_from_dwarf.c | 2 +- src/rdi_from_dwarf/rdi_from_dwarf.h | 2 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 73 +++---------- src/rdi_from_pdb/rdi_from_pdb_2.h | 3 +- 8 files changed, 150 insertions(+), 126 deletions(-) diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 7b28d474..7fade9d3 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -75,11 +75,13 @@ tctx_get_scratch(Arena **conflicts, U64 count) //- rjf: lane metadata -internal void +internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx) { TCTX *tctx = tctx_selected(); + LaneCtx restore = tctx->lane_ctx; tctx->lane_ctx = lane_ctx; + return restore; } internal void diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 519f85fb..2394b98b 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -51,7 +51,7 @@ internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); #define scratch_end(scratch) temp_end(scratch) //- rjf: lane metadata -internal void tctx_set_lane_ctx(LaneCtx lane_ctx); +internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx); internal void tctx_lane_barrier_wait(void); internal Rng1U64 tctx_lane_idx_range_from_count(U64 count); #define lane_idx() (tctx_selected()->lane_ctx.lane_idx) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 7b7f885d..eb7e21cd 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -7,22 +7,56 @@ #include "radbin/generated/radbin.meta.c" //////////////////////////////// -//~ rjf: Top-Level Entry Point +//~ rjf: Top-Level Entry Points internal void rb_entry_point(CmdLine *cmdline) { + Temp scratch = scratch_begin(0, 0); + U64 threads_count = os_get_system_info()->logical_processor_count; + OS_Handle *threads = push_array(scratch.arena, OS_Handle, threads_count); + RB_ThreadParams *threads_params = push_array(scratch.arena, RB_ThreadParams, threads_count); + Barrier barrier = barrier_alloc(threads_count); + for EachIndex(idx, threads_count) + { + threads_params[idx].cmdline = cmdline; + threads_params[idx].lane_ctx.lane_idx = idx; + threads_params[idx].lane_ctx.lane_count = threads_count; + threads_params[idx].lane_ctx.barrier = barrier; + threads[idx] = os_thread_launch(rb_thread_entry_point, &threads_params[idx], 0); + } + for EachIndex(idx, threads_count) + { + os_thread_join(threads[idx], max_U64); + } + scratch_end(scratch); +} + +internal void +rb_thread_entry_point(void *p) +{ + RB_ThreadParams *params = (RB_ThreadParams *)p; + CmdLine *cmdline = params->cmdline; + LaneCtx lctx = params->lane_ctx; + lane_ctx(lctx); Arena *arena = arena_alloc(); - ASYNC_Root *async_root = async_root_alloc(); Log *log = log_alloc(); log_select(log); log_scope_begin(); + ////////////////////////////// + //- rjf: set up shared state + // + if(lane_idx() == 0) + { + rb_shared = push_array(arena, RB_Shared, 1); + } + lane_sync(); + ////////////////////////////// //- rjf: analyze & load command line input files // - RB_FileList input_files = {0}; - ProfScope("analyze & load command line input files") + ProfScope("analyze & load command line input files") if(lane_idx() == 0) { String8List input_file_path_tasks = str8_list_copy(arena, &cmdline->inputs); for(String8Node *n = input_file_path_tasks.first; n != 0; n = n->next) @@ -318,23 +352,29 @@ rb_entry_point(CmdLine *cmdline) f->data = file_data; RB_FileNode *file_n = push_array(arena, RB_FileNode, 1); file_n->v = f; - SLLQueuePush(input_files.first, input_files.last, file_n); - input_files.count += 1; + SLLQueuePush(rb_shared->input_files.first, rb_shared->input_files.last, file_n); + rb_shared->input_files.count += 1; } } } + lane_sync(); + RB_FileList input_files = rb_shared->input_files; ////////////////////////////// //- rjf: bucket input files by format // - RB_FileList input_files_from_format_table[RB_FileFormat_COUNT] = {0}; - for(RB_FileNode *n = input_files.first; n != 0; n = n->next) + ProfScope("bucket input files by format") if(lane_idx() == 0) { - RB_FileNode *file_n = push_array(arena, RB_FileNode, 1); - file_n->v = n->v; - SLLQueuePush(input_files_from_format_table[n->v->format].first, input_files_from_format_table[n->v->format].last, file_n); - input_files_from_format_table[n->v->format].count += 1; + for(RB_FileNode *n = input_files.first; n != 0; n = n->next) + { + RB_FileNode *file_n = push_array(arena, RB_FileNode, 1); + file_n->v = n->v; + SLLQueuePush(rb_shared->input_files_from_format_table[n->v->format].first, rb_shared->input_files_from_format_table[n->v->format].last, file_n); + rb_shared->input_files_from_format_table[n->v->format].count += 1; + } } + lane_sync(); + RB_FileList *input_files_from_format_table = rb_shared->input_files_from_format_table; ////////////////////////////// //- rjf: unpack which kind of output we're producing, and to where @@ -400,17 +440,21 @@ rb_entry_point(CmdLine *cmdline) ////////////////////////////// //- rjf: print help preamble // - if(output_kind == OutputKind_Null || cmdline->inputs.node_count == 0) + if(lane_idx() == 0) { - fprintf(stderr, "%s\n", BUILD_TITLE); - fprintf(stderr, "%s\n\n", BUILD_VERSION_STRING_LITERAL); - if(output_kind != OutputKind_Null) + if(output_kind == OutputKind_Null || cmdline->inputs.node_count == 0) { - fprintf(stderr, "%.*s Help\n", str8_varg(output_kind_info[output_kind].title)); - fprintf(stderr, "To see top-level options for radbin, run the binary with no arguments.\n\n"); + fprintf(stderr, "%s\n", BUILD_TITLE); + fprintf(stderr, "%s\n\n", BUILD_VERSION_STRING_LITERAL); + if(output_kind != OutputKind_Null) + { + fprintf(stderr, "%.*s Help\n", str8_varg(output_kind_info[output_kind].title)); + fprintf(stderr, "To see top-level options for radbin, run the binary with no arguments.\n\n"); + } + fprintf(stderr, "-------------------------------------------------------------------------------\n\n"); } - fprintf(stderr, "-------------------------------------------------------------------------------\n\n"); } + lane_sync(); ////////////////////////////// //- rjf: perform operation based on output kind @@ -423,6 +467,7 @@ rb_entry_point(CmdLine *cmdline) // default: case OutputKind_Null: + if(lane_idx() == 0) { fprintf(stderr, "USAGE EXAMPLES\n\n"); @@ -479,7 +524,7 @@ rb_entry_point(CmdLine *cmdline) case OutputKind_Breakpad: { //- rjf: no inputs => help - if(cmdline->inputs.node_count == 0) switch(output_kind) + if(lane_idx() == 0 && cmdline->inputs.node_count == 0) switch(output_kind) { default: case OutputKind_RDI: @@ -638,7 +683,7 @@ rb_entry_point(CmdLine *cmdline) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - ProfScope("convert") bake_params = d2r_convert(arena, async_root, &convert_params); + ProfScope("convert") bake_params = d2r_convert(arena, &convert_params); // rjf: no output path? -> pick one based on debug if(output_path.size == 0) @@ -672,23 +717,7 @@ rb_entry_point(CmdLine *cmdline) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - if(cmd_line_has_flag(cmdline, str8_lit("p2r2"))) - { - ProfScope("convert (2)") - { - U64 thread_count = os_get_system_info()->logical_processor_count; - Arena **thread_arenas = push_array(arena, Arena *, thread_count); - for EachIndex(idx, thread_count) - { - thread_arenas[idx] = arena_alloc(); - } - bake_params = p2r2_convert(thread_arenas, thread_count, &convert_params); - } - } - else - { - ProfScope("convert") bake_params = p2r_convert(arena, async_root, &convert_params); - } + bake_params = p2r2_convert(arena, &convert_params); // rjf: no output path? -> pick one based on PDB if(output_path.size == 0) switch(output_kind) @@ -838,7 +867,7 @@ rb_entry_point(CmdLine *cmdline) B32 deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); //- rjf: no inputs => help - if(cmdline->inputs.node_count == 0) + if(lane_idx() == 0 && cmdline->inputs.node_count == 0) { fprintf(stderr, "All input files specified on the command line will be dumped. Currently, only\n"); fprintf(stderr, "RDI files are supported.\n\n"); @@ -1028,43 +1057,50 @@ rb_entry_point(CmdLine *cmdline) ////////////////////////////// //- rjf: write outputs // - if(output_path.size != 0) ProfScope("write outputs [file]") + if(lane_idx() == 0) { - os_write_data_list_to_file_path(output_path, output_blobs); - log_infof("Results written to %S", output_path); - } - else ProfScope("write outputs [stdout]") - { - for(String8Node *n = output_blobs.first; n != 0; n = n->next) + if(output_path.size != 0) ProfScope("write outputs [file]") { - for(U64 off = 0; off < n->string.size;) - { - U64 size_to_write = Min(n->string.size - off, GB(2)); - fwrite(n->string.str + off, size_to_write, 1, stdout); - off += size_to_write; - } + os_write_data_list_to_file_path(output_path, output_blobs); + log_infof("Results written to %S", output_path); + } + else ProfScope("write outputs [stdout]") + { + for(String8Node *n = output_blobs.first; n != 0; n = n->next) + { + for(U64 off = 0; off < n->string.size;) + { + U64 size_to_write = Min(n->string.size - off, GB(2)); + fwrite(n->string.str + off, size_to_write, 1, stdout); + off += size_to_write; + } + } + log_info(str8_lit("Results written to stdout")); } - log_info(str8_lit("Results written to stdout")); } + lane_sync(); ////////////////////////////// //- rjf: write info & errors // LogScopeResult log_scope = log_scope_end(arena); - if(cmd_line_has_flag(cmdline, str8_lit("verbose")) && log_scope.strings[LogMsgKind_Info].size != 0) + if(lane_idx() == 0) { - String8List lines = wrapped_lines_from_string(arena, log_scope.strings[LogMsgKind_Info], 80, 80, 0); - for(String8Node *n = lines.first; n != 0; n = n->next) + if(cmd_line_has_flag(cmdline, str8_lit("verbose")) && log_scope.strings[LogMsgKind_Info].size != 0) { - fprintf(stderr, "%.*s\n", str8_varg(n->string)); + String8List lines = wrapped_lines_from_string(arena, log_scope.strings[LogMsgKind_Info], 80, 80, 0); + for(String8Node *n = lines.first; n != 0; n = n->next) + { + fprintf(stderr, "%.*s\n", str8_varg(n->string)); + } } - } - if(log_scope.strings[LogMsgKind_UserError].size != 0) - { - String8List lines = wrapped_lines_from_string(arena, log_scope.strings[LogMsgKind_UserError], 80, 80, 0); - for(String8Node *n = lines.first; n != 0; n = n->next) + if(log_scope.strings[LogMsgKind_UserError].size != 0) { - fprintf(stderr, "%.*s\n", str8_varg(n->string)); + String8List lines = wrapped_lines_from_string(arena, log_scope.strings[LogMsgKind_UserError], 80, 80, 0); + for(String8Node *n = lines.first; n != 0; n = n->next) + { + fprintf(stderr, "%.*s\n", str8_varg(n->string)); + } } } } diff --git a/src/radbin/radbin.h b/src/radbin/radbin.h index fc98e130..7e7265fc 100644 --- a/src/radbin/radbin.h +++ b/src/radbin/radbin.h @@ -9,6 +9,16 @@ #include "radbin/generated/radbin.meta.h" +//////////////////////////////// +//~ rjf: Thread Parameters + +typedef struct RB_ThreadParams RB_ThreadParams; +struct RB_ThreadParams +{ + CmdLine *cmdline; + LaneCtx lane_ctx; +}; + //////////////////////////////// //~ rjf: File Types @@ -46,8 +56,24 @@ read_only global RB_File rb_file_nil = {0}; #define rb_file_list_first(list) ((list)->first ? (list)->first->v : &rb_file_nil) //////////////////////////////// -//~ rjf: Top-Level Entry Point +//~ rjf: Cross-Thread State + +typedef struct RB_Shared RB_Shared; +struct RB_Shared +{ + RB_FileList input_files; + RB_FileList input_files_from_format_table[RB_FileFormat_COUNT]; +}; + +//////////////////////////////// +//~ rjf: Globals + +global RB_Shared *rb_shared = 0; + +//////////////////////////////// +//~ rjf: Top-Level Entry Points internal void rb_entry_point(CmdLine *cmdline); +internal void rb_thread_entry_point(void *p); #endif //RADBIN_H diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 963a7164..58b2d51c 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1123,7 +1123,7 @@ d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D //~ rjf: Main Conversion Entry Point internal RDIM_BakeParams -d2r_convert(Arena *arena, ASYNC_Root *async_root, D2R_ConvertParams *params) +d2r_convert(Arena *arena, D2R_ConvertParams *params) { Temp scratch = scratch_begin(&arena, 1); diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 50ee8d8e..0c7ceff6 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -100,4 +100,4 @@ internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitCont //////////////////////////////// //~ rjf: Main Conversion Entry Point -internal RDIM_BakeParams d2r_convert(Arena *arena, ASYNC_Root *async_root, D2R_ConvertParams *params); +internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 540645d5..790a694c 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2,49 +2,8 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal RDIM_BakeParams -p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in) +p2r2_convert(Arena *arena, P2R_ConvertParams *params) { - RDIM_BakeParams result = {0}; - Temp scratch = scratch_begin(thread_arenas, thread_count); - Barrier barrier = barrier_alloc(thread_count); - { - P2R2_ConvertThreadParams *thread_params = push_array(scratch.arena, P2R2_ConvertThreadParams, thread_count); - OS_Handle *threads = push_array(scratch.arena, OS_Handle, thread_count); - for EachIndex(idx, thread_count) - { - thread_params[idx].arena = thread_arenas[idx]; - thread_params[idx].lane_ctx.lane_idx = idx; - thread_params[idx].lane_ctx.lane_count = thread_count; - thread_params[idx].lane_ctx.barrier = barrier; - thread_params[idx].input_exe_name = in->input_exe_name; - thread_params[idx].input_exe_data = in->input_exe_data; - thread_params[idx].input_pdb_name = in->input_pdb_name; - thread_params[idx].input_pdb_data = in->input_pdb_data; - thread_params[idx].deterministic = in->deterministic; - thread_params[idx].out_bake_params = &result; - } - for EachIndex(idx, thread_count) - { - threads[idx] = os_thread_launch(p2r2_convert_thread_entry_point, &thread_params[idx], 0); - } - for EachIndex(idx, thread_count) - { - os_thread_join(threads[idx], max_U64); - } - } - barrier_release(barrier); - scratch_end(scratch); - return result; -} - -internal void -p2r2_convert_thread_entry_point(void *p) -{ - P2R2_ConvertThreadParams *params = (P2R2_ConvertThreadParams *)p; - Arena *arena = params->arena; - lane_ctx(params->lane_ctx); - ThreadNameF("p2r2_convert_thread_%I64u", lane_idx()); - ////////////////////////////////////////////////////////////// //- rjf: do base MSF parse // @@ -3957,7 +3916,7 @@ p2r2_convert_thread_entry_point(void *p) ////////////////////////////////////////////////////////////// //- rjf: bundle all outputs // - if(lane_idx() == 0) + RDIM_BakeParams result = {0}; { //- rjf: produce top-level-info RDIM_TopLevelInfo top_level_info = {0}; @@ -3993,18 +3952,20 @@ p2r2_convert_thread_entry_point(void *p) } //- rjf: fill - params->out_bake_params->top_level_info = top_level_info; - params->out_bake_params->binary_sections = binary_sections; - params->out_bake_params->units = all_units; - params->out_bake_params->types = all_types; - params->out_bake_params->udts = all_udts; - params->out_bake_params->src_files = all_src_files; - params->out_bake_params->line_tables = all_line_tables; - params->out_bake_params->global_variables = all_global_variables; - params->out_bake_params->thread_variables = all_thread_variables; - params->out_bake_params->constants = all_constants; - params->out_bake_params->procedures = all_procedures; - params->out_bake_params->scopes = all_scopes; - params->out_bake_params->inline_sites = all_inline_sites; + result.top_level_info = top_level_info; + result.binary_sections = binary_sections; + result.units = all_units; + result.types = all_types; + result.udts = all_udts; + result.src_files = all_src_files; + result.line_tables = all_line_tables; + result.global_variables = all_global_variables; + result.thread_variables = all_thread_variables; + result.constants = all_constants; + result.procedures = all_procedures; + result.scopes = all_scopes; + result.inline_sites = all_inline_sites; } + + return result; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index d77cabd3..b3a0aa8a 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -133,7 +133,6 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; -internal RDIM_BakeParams p2r2_convert(Arena **thread_arenas, U64 thread_count, P2R_ConvertParams *in); -internal void p2r2_convert_thread_entry_point(void *p); +internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); #endif // RDI_FROM_PDB_2_H From 66ec3e834b825acd2b83efb5ec542a19c789f8a9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 09:07:59 -0700 Subject: [PATCH 058/302] rdi baking: wide line table gathering/joining & sorting --- src/lib_rdi_make/rdi_make.c | 8 --- src/lib_rdi_make/rdi_make.h | 11 +++ src/radbin/radbin.c | 3 +- src/radbin/radbin_main.c | 2 + src/rdi_make/rdi_make_local_2.c | 118 ++++++++++++++++++++++++++++++++ src/rdi_make/rdi_make_local_2.h | 36 ++++++++++ 6 files changed, 168 insertions(+), 10 deletions(-) create mode 100644 src/rdi_make/rdi_make_local_2.c create mode 100644 src/rdi_make/rdi_make_local_2.h diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 54d402ad..674bdacc 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -3124,14 +3124,6 @@ rdim_bake_line_tables(RDIM_Arena *arena, RDIM_LineTableChunkList *src) // [1] keys: sortable array; pairs voffs with line info records; null records are sequence enders // [2] recs: contains all the source coordinates for a range of voffs // - typedef struct RDIM_LineRec RDIM_LineRec; - struct RDIM_LineRec - { - RDI_U32 file_id; - RDI_U32 line_num; - RDI_U16 col_first; - RDI_U16 col_opl; - }; RDI_U64 line_count = src_line_table->line_count; RDI_U64 seq_count = src_line_table->seq_count; RDI_U64 key_count = line_count + seq_count; diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 7dd6a216..0c49298b 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1150,6 +1150,17 @@ struct RDIM_VMapMarker RDI_U32 begin_range; }; +//- rjf: line table records + +typedef struct RDIM_LineRec RDIM_LineRec; +struct RDIM_LineRec +{ + RDI_U32 file_id; + RDI_U32 line_num; + RDI_U16 col_first; + RDI_U16 col_opl; +}; + //- rjf: baking results typedef struct RDIM_TopLevelInfoBakeResult RDIM_TopLevelInfoBakeResult; diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index eb7e21cd..a53206a3 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -751,7 +751,7 @@ rb_thread_entry_point(void *p) { // rjf: bake RDIM_BakeResults bake_results = {0}; - ProfScope("bake") bake_results = rdim_bake(arena, async_root, &bake_params); + ProfScope("bake") bake_results = rdim2_bake(arena, &bake_params); // rjf: serialize RDIM_SerializedSectionBundle serialized_section_bundle = {0}; @@ -772,7 +772,6 @@ rb_thread_entry_point(void *p) //- rjf: generate breakpad text case OutputKind_Breakpad: { - p2b_async_root = async_root; String8List dump = {0}; //- rjf: kick off unit vmap baking diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index 4053d23c..f0b9d280 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -17,6 +17,7 @@ #include "async/async.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" +#include "rdi_make/rdi_make_local_2.h" #include "coff/coff_inc.h" #include "pe/pe.h" #include "elf/elf.h" @@ -44,6 +45,7 @@ #include "async/async.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" +#include "rdi_make/rdi_make_local_2.c" #include "coff/coff_inc.c" #include "pe/pe.c" #include "elf/elf.c" diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c new file mode 100644 index 00000000..8838efe5 --- /dev/null +++ b/src/rdi_make/rdi_make_local_2.c @@ -0,0 +1,118 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal RDIM_BakeResults +rdim2_bake(Arena *arena, RDIM_BakeParams *params) +{ + ////////////////////////////////////////////////////////////// + //- rjf: set up shared state + // + if(lane_idx() == 0) + { + rdim2_shared = push_array(arena, RDIM2_Shared, 1); + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: gather all unsorted, joined, line table info + // + ProfScope("gather all unsorted, joined, line table info") + { + //- rjf: set up outputs + if(lane_idx() == 0) + { + rdim2_shared->line_tables_count = params->line_tables.total_count; + rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + { + U64 joined_idx = 0; + for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) + { + for EachIndex(idx, n->count) + { + rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; + joined_idx += 1; + } + } + } + rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + rdim2_shared->line_table_take_counter = 0; + } + lane_sync(); + + //- rjf: wide gather + { + for(;;) + { + U64 line_table_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_take_counter); + if(0 == line_table_num || rdim2_shared->line_tables_count < line_table_num) + { + break; + } + U64 line_table_idx = line_table_num-1; + RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + dst->line_count = src->line_count; + dst->seq_count = src->seq_count; + dst->key_count = dst->line_count + dst->seq_count; + dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); + dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); + { + RDIM_SortKey *key_ptr = dst->line_keys; + RDIM_LineRec *rec_ptr = dst->line_recs; + for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) + { + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + { + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + } + } + } + lane_sync(); + RDI_U64 line_tables_count = rdim2_shared->line_tables_count; + RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; + + ////////////////////////////////////////////////////////////// + //- rjf: sort all unsorted line table info + // + ProfScope("sort all unsorted line table info") + { + if(lane_idx() == 0) + { + rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, line_tables_count); + rdim2_shared->line_table_take_counter = 0; + } + lane_sync(); + for(;;) + { + U64 line_table_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_take_counter); + if(0 == line_table_num || line_tables_count < line_table_num) + { + break; + } + U64 line_table_idx = line_table_num-1; + rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, unsorted_joined_line_tables[line_table_idx].line_keys, unsorted_joined_line_tables[line_table_idx].key_count); + } + } + lane_sync(); + + RDIM_BakeResults result = {0}; + return result; +} diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h new file mode 100644 index 00000000..a6de79e6 --- /dev/null +++ b/src/rdi_make/rdi_make_local_2.h @@ -0,0 +1,36 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RDI_MAKE_LOCAL_2_H +#define RDI_MAKE_LOCAL_2_H + +//- rjf: unsorted joined line table info + +typedef struct RDIM_UnsortedJoinedLineTable RDIM_UnsortedJoinedLineTable; +struct RDIM_UnsortedJoinedLineTable +{ + RDI_U64 line_count; + RDI_U64 seq_count; + RDI_U64 key_count; + RDIM_SortKey *line_keys; + RDIM_LineRec *line_recs; +}; + +//- rjf: shared state bundle + +typedef struct RDIM2_Shared RDIM2_Shared; +struct RDIM2_Shared +{ + RDI_U64 line_tables_count; + RDI_U64 line_table_take_counter; + RDIM_LineTable **src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables; + + RDIM_SortKey **sorted_line_table_keys; +}; + +global RDIM2_Shared *rdim2_shared = 0; + +internal RDIM_BakeResults rdim2_bake(Arena *arena, RDIM_BakeParams *params); + +#endif // RDI_MAKE_LOCAL_2_H From b169090dc696a14171abf7a65170074164282130 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 16:29:05 -0700 Subject: [PATCH 059/302] checkpoint on new rdi baking; line table baking, string map building, plug in radsort over bad radix sort; arena tweak to aovoid unnecessary zeroes --- project.4coder | 2 +- src/base/base_arena.c | 13 +- src/base/base_arena.h | 6 +- src/lib_rdi_make/rdi_make.c | 92 ++------- src/lib_rdi_make/rdi_make.h | 8 +- src/radbin/radbin.c | 3 +- src/raddbg/raddbg_main.c | 3 + src/rdi_from_pdb/rdi_from_pdb_2.c | 12 +- src/rdi_make/rdi_make_local_2.c | 333 ++++++++++++++++++++++++++---- src/rdi_make/rdi_make_local_2.h | 16 +- 10 files changed, 353 insertions(+), 135 deletions(-) diff --git a/project.4coder b/project.4coder index f878de39..57de31db 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/base/base_arena.c b/src/base/base_arena.c index 314fcd9e..0d9300e2 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -83,7 +83,7 @@ arena_release(Arena *arena) //- rjf: arena push/pop core functions internal void * -arena_push(Arena *arena, U64 size, U64 align) +arena_push(Arena *arena, U64 size, U64 align, B32 zero) { Arena *current = arena->current; U64 pos_pre = AlignPow2(current->pos, align); @@ -139,6 +139,13 @@ arena_push(Arena *arena, U64 size, U64 align) pos_pst = pos_pre + size; } + // rjf: compute the size we need to zero + U64 size_to_zero = 0; + if(zero) + { + size_to_zero = Min(current->cmt, pos_pst) - pos_pre; + } + // rjf: commit new pages, if needed if(current->cmt < pos_pst) { @@ -165,6 +172,10 @@ arena_push(Arena *arena, U64 size, U64 align) result = (U8 *)current+pos_pre; current->pos = pos_pst; AsanUnpoisonMemoryRegion(result, size); + if(size_to_zero != 0) + { + MemoryZero(result, size_to_zero); + } } // rjf: panic on failure diff --git a/src/base/base_arena.h b/src/base/base_arena.h index a98066ed..589d67bf 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -68,7 +68,7 @@ internal Arena *arena_alloc_(ArenaParams *params); internal void arena_release(Arena *arena); //- rjf: arena push/pop/pos core functions -internal void *arena_push(Arena *arena, U64 size, U64 align); +internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero); internal U64 arena_pos(Arena *arena); internal void arena_pop_to(Arena *arena, U64 pos); @@ -81,8 +81,8 @@ internal Temp temp_begin(Arena *arena); internal void temp_end(Temp temp); //- rjf: push helper macros -#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align)) -#define push_array_aligned(a, T, c, align) (T *)MemoryZero(push_array_no_zero_aligned(a, T, c, align), sizeof(T)*(c)) +#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0)) +#define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1)) #define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T))) #define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T))) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 674bdacc..afd48835 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -62,7 +62,7 @@ rdim_arena_pos_fallback(RDIM_Arena *arena) } RDI_PROC void * -rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size) +rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size, RDI_U64 align, RDI_U32 zero) { // TODO(rjf) return 0; @@ -1485,7 +1485,7 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So //- rjf: fill result RDIM_BakeVMap result = {0}; result.vmap = vmap; - result.count = vmap_entry_count-1; + result.count = vmap_entry_count; rdim_scratch_end(scratch); return result; } @@ -1534,6 +1534,12 @@ rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_ rdim_memzero_struct(to_push); } + +RSFORCEINLINE int rdim_bake_string_hash_is_before(void *elementa, void *elementb) +{ + return ((RDIM_BakeString *)elementa)->hash < ((RDIM_BakeString *)elementb)->hash; +} + RDI_PROC RDIM_BakeStringChunkList rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStringChunkList *src) { @@ -1552,68 +1558,7 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr //- rjf: sort chunk node if(dst.first != 0) { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - typedef struct SortTask SortTask; - struct SortTask - { - SortTask *next; - RDI_U64 string_off; - RDIM_BakeString *v; - RDI_U64 count; - }; - SortTask start_task = {0, 0, dst.first->v, dst.first->count}; - SortTask *first_task = &start_task; - SortTask *last_task = &start_task; - - //- rjf: for each sort task range: - for(SortTask *t = first_task; t != 0; t = t->next) - { - //- rjf: loop through range, drop each element into bucket according to byte in string at task offset - RDIM_BakeStringChunkList *buckets = rdim_push_array(scratch.arena, RDIM_BakeStringChunkList, 256); - for(RDI_U64 idx = 0; idx < t->count; idx += 1) - { - U8 byte = t->string_off < t->v[idx].string.size ? t->v[idx].string.str[t->string_off] : 0; - RDIM_BakeStringChunkList *bucket = &buckets[byte]; - RDIM_BakeString *bstr = rdim_bake_string_chunk_list_push(scratch.arena, bucket, 8); - rdim_memcpy_struct(bstr, &t->v[idx]); - } - - //- rjf: in-place mutate the original source array to reflect the order per the buckets. - // build new sort tasks for buckets with many elements - { - RDI_U64 write_idx = 0; - for(RDI_U64 bucket_idx = 0; bucket_idx < 256; bucket_idx += 1) - { - // rjf: write each chunk node's array into original array, detect if there is size left to sort - RDI_U64 bucket_base_idx = write_idx; - RDI_U64 need_next_char_sort = 0; - for(RDIM_BakeStringChunkNode *n = buckets[bucket_idx].first; n != 0; n = n->next) - { - rdim_memcpy(t->v+write_idx, n->v, sizeof(n->v[0])*n->count); - write_idx += n->count; - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - if(n->v[idx].string.size > t->string_off+1) - { - need_next_char_sort = 1; - } - } - } - - // rjf: if any bucket has >1 element & has some amount of size left to sort, push new task for this - // bucket's region in the array, and for remainder of keys - if(buckets[bucket_idx].total_count > 1 && need_next_char_sort) - { - SortTask *new_task = rdim_push_array(scratch.arena, SortTask, 1); - RDIM_SLLQueuePush(first_task, last_task, new_task); - new_task->string_off = t->string_off+1; - new_task->v = t->v + bucket_base_idx; - new_task->count = write_idx-bucket_base_idx; - } - } - } - } - rdim_scratch_end(scratch); + radsort(dst.first->v, dst.first->count, rdim_bake_string_hash_is_before); } //- rjf: iterate sorted chunk node, remove duplicates, count # of duplicates @@ -2692,12 +2637,11 @@ rdim_bake_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RD { RDIM_TopLevelInfoBakeResult result = {0}; { - result.top_level_info = rdim_push_array(arena, RDI_TopLevelInfo, 1); - result.top_level_info->arch = src->arch; - result.top_level_info->exe_name_string_idx = rdim_bake_idx_from_string(strings, src->exe_name); - result.top_level_info->exe_hash = src->exe_hash; - result.top_level_info->voff_max = src->voff_max; - result.top_level_info->producer_name_string_idx = rdim_bake_idx_from_string(strings, src->producer_name); + result.top_level_info.arch = src->arch; + result.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(strings, src->exe_name); + result.top_level_info.exe_hash = src->exe_hash; + result.top_level_info.voff_max = src->voff_max; + result.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(strings, src->producer_name); } return result; } @@ -4007,7 +3951,7 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) { RDIM_SerializedSectionBundle bundle; rdim_memzero_struct(&bundle); - bundle.sections[RDI_SectionKind_TopLevelInfo] = rdim_serialized_section_make_unpacked_struct(results->top_level_info.top_level_info); + bundle.sections[RDI_SectionKind_TopLevelInfo] = rdim_serialized_section_make_unpacked_struct(&results->top_level_info.top_level_info); bundle.sections[RDI_SectionKind_StringData] = rdim_serialized_section_make_unpacked_array(results->strings.string_data, results->strings.string_data_size); bundle.sections[RDI_SectionKind_StringTable] = rdim_serialized_section_make_unpacked_array(results->strings.string_offs, results->strings.string_offs_count); bundle.sections[RDI_SectionKind_IndexRuns] = rdim_serialized_section_make_unpacked_array(results->idx_runs.idx_runs, results->idx_runs.idx_count); @@ -4023,19 +3967,19 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) bundle.sections[RDI_SectionKind_SourceLineMapRanges] = rdim_serialized_section_make_unpacked_array(results->src_files.source_line_map_rngs, results->src_files.source_line_map_rngs_count); bundle.sections[RDI_SectionKind_SourceLineMapVOffs] = rdim_serialized_section_make_unpacked_array(results->src_files.source_line_map_voffs, results->src_files.source_line_map_voffs_count); bundle.sections[RDI_SectionKind_Units] = rdim_serialized_section_make_unpacked_array(results->units.units, results->units.units_count); - bundle.sections[RDI_SectionKind_UnitVMap] = rdim_serialized_section_make_unpacked_array(results->unit_vmap.vmap.vmap, results->unit_vmap.vmap.count+1); + bundle.sections[RDI_SectionKind_UnitVMap] = rdim_serialized_section_make_unpacked_array(results->unit_vmap.vmap.vmap, results->unit_vmap.vmap.count); bundle.sections[RDI_SectionKind_TypeNodes] = rdim_serialized_section_make_unpacked_array(results->type_nodes.type_nodes, results->type_nodes.type_nodes_count); bundle.sections[RDI_SectionKind_UDTs] = rdim_serialized_section_make_unpacked_array(results->udts.udts, results->udts.udts_count); bundle.sections[RDI_SectionKind_Members] = rdim_serialized_section_make_unpacked_array(results->udts.members, results->udts.members_count); bundle.sections[RDI_SectionKind_EnumMembers] = rdim_serialized_section_make_unpacked_array(results->udts.enum_members, results->udts.enum_members_count); bundle.sections[RDI_SectionKind_GlobalVariables] = rdim_serialized_section_make_unpacked_array(results->global_variables.global_variables, results->global_variables.global_variables_count); - bundle.sections[RDI_SectionKind_GlobalVMap] = rdim_serialized_section_make_unpacked_array(results->global_vmap.vmap.vmap, results->global_vmap.vmap.count+1); + bundle.sections[RDI_SectionKind_GlobalVMap] = rdim_serialized_section_make_unpacked_array(results->global_vmap.vmap.vmap, results->global_vmap.vmap.count); bundle.sections[RDI_SectionKind_ThreadVariables] = rdim_serialized_section_make_unpacked_array(results->thread_variables.thread_variables, results->thread_variables.thread_variables_count); bundle.sections[RDI_SectionKind_Constants] = rdim_serialized_section_make_unpacked_array(results->constants.constants, results->constants.constants_count); bundle.sections[RDI_SectionKind_Procedures] = rdim_serialized_section_make_unpacked_array(results->procedures.procedures, results->procedures.procedures_count); bundle.sections[RDI_SectionKind_Scopes] = rdim_serialized_section_make_unpacked_array(results->scopes.scopes, results->scopes.scopes_count); bundle.sections[RDI_SectionKind_ScopeVOffData] = rdim_serialized_section_make_unpacked_array(results->scopes.scope_voffs, results->scopes.scope_voffs_count); - bundle.sections[RDI_SectionKind_ScopeVMap] = rdim_serialized_section_make_unpacked_array(results->scope_vmap.vmap.vmap, results->scope_vmap.vmap.count+1); + bundle.sections[RDI_SectionKind_ScopeVMap] = rdim_serialized_section_make_unpacked_array(results->scope_vmap.vmap.vmap, results->scope_vmap.vmap.count); bundle.sections[RDI_SectionKind_InlineSites] = rdim_serialized_section_make_unpacked_array(results->inline_sites.inline_sites, results->inline_sites.inline_sites_count); bundle.sections[RDI_SectionKind_Locals] = rdim_serialized_section_make_unpacked_array(results->scopes.locals, results->scopes.locals_count); bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.str, results->location_blocks.size); diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 0c49298b..f3d86b53 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -127,7 +127,7 @@ enum // #define rdim_arena_alloc Arena*> // #define rdim_arena_release void> // #define rdim_arena_pos U64> -// #define rdim_arena_push void*> +// #define rdim_arena_push void*> // #define rdim_arena_pop_to void> #if !defined(RDIM_Arena) @@ -1166,7 +1166,7 @@ struct RDIM_LineRec typedef struct RDIM_TopLevelInfoBakeResult RDIM_TopLevelInfoBakeResult; struct RDIM_TopLevelInfoBakeResult { - RDI_TopLevelInfo *top_level_info; + RDI_TopLevelInfo top_level_info; }; typedef struct RDIM_BinarySectionBakeResult RDIM_BinarySectionBakeResult; @@ -1404,8 +1404,8 @@ RDI_PROC RDI_U64 rdim_arena_pos_fallback(RDIM_Arena *arena); RDI_PROC void *rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 align, RDI_U64 size); RDI_PROC void rdim_arena_pop_to_fallback(RDIM_Arena *arena, RDI_U64 pos); #endif -#define rdim_push_array_no_zero(a,T,c) (T*)rdim_arena_push((a), sizeof(T)*(c), RDIM_AlignOf(T)) -#define rdim_push_array(a,T,c) (T*)rdim_memzero(rdim_push_array_no_zero(a,T,c), sizeof(T)*(c)) +#define rdim_push_array_no_zero(a,T,c) (T*)rdim_arena_push((a), sizeof(T)*(c), RDIM_AlignOf(T), (0)) +#define rdim_push_array(a,T,c) (T*)rdim_arena_push((a), sizeof(T)*(c), RDIM_AlignOf(T), (1)) //- rjf: thread-local scratch arenas #if !defined (RDIM_SCRATCH_OVERRIDE) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index a53206a3..c8aa38cc 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -38,6 +38,7 @@ rb_thread_entry_point(void *p) RB_ThreadParams *params = (RB_ThreadParams *)p; CmdLine *cmdline = params->cmdline; LaneCtx lctx = params->lane_ctx; + ThreadNameF("radbin_thread_%I64u", lctx.lane_idx); lane_ctx(lctx); Arena *arena = arena_alloc(); Log *log = log_alloc(); @@ -717,7 +718,7 @@ rb_thread_entry_point(void *p) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - bake_params = p2r2_convert(arena, &convert_params); + ProfScope("convert") bake_params = p2r2_convert(arena, &convert_params); // rjf: no output path? -> pick one based on PDB if(output_path.size == 0) switch(output_kind) diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 78ae10ed..374427dc 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -9,6 +9,7 @@ // [ ] stepping w/ spoofs & shadow stack enabled - writing spoof will send a stack buffer overrun event @shadow_stack_step // [ ] hardware breakpoints regression (global eval in ctrl) // [ ] native filesystem dialog, resizing raddbg window -> crash! +// [ ] stdout/stderr path target setting is now busted >:( // //- memory view // [ ] have smaller visible range than entire memory @@ -220,6 +221,7 @@ #include "async/async.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" +#include "rdi_make/rdi_make_local_2.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" @@ -271,6 +273,7 @@ #include "async/async.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" +#include "rdi_make/rdi_make_local_2.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 790a694c..cb8e373d 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2937,12 +2937,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: set up outputs for this sym stream // - U64 sym_procedures_chunk_cap = 1024; - U64 sym_global_variables_chunk_cap = 1024; - U64 sym_thread_variables_chunk_cap = 1024; - U64 sym_constants_chunk_cap = 1024; - U64 sym_scopes_chunk_cap = 1024; - U64 sym_inline_sites_chunk_cap = 1024; + U64 sym_procedures_chunk_cap = 16384; + U64 sym_global_variables_chunk_cap = 16384; + U64 sym_thread_variables_chunk_cap = 16384; + U64 sym_constants_chunk_cap = 16384; + U64 sym_scopes_chunk_cap = 16384; + U64 sym_inline_sites_chunk_cap = 16384; RDIM_SymbolChunkList sym_procedures = {0}; RDIM_SymbolChunkList sym_global_variables = {0}; RDIM_SymbolChunkList sym_thread_variables = {0}; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 8838efe5..f9c19247 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -14,15 +14,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: gather all unsorted, joined, line table info + //- rjf: gather all unsorted, joined, line table info; & sort // - ProfScope("gather all unsorted, joined, line table info") + ProfScope("gather all unsorted, joined, line table info; & sort") { //- rjf: set up outputs - if(lane_idx() == 0) + ProfScope("set up outputs") if(lane_idx() == 0) { rdim2_shared->line_tables_count = params->line_tables.total_count; rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + ProfScope("flatten chunk list") { U64 joined_idx = 0; for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) @@ -34,51 +35,122 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); - rdim2_shared->line_table_take_counter = 0; + rdim2_shared->final_line_tables_count = params->line_tables.total_count + 1; + rdim2_shared->final_line_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim2_shared->final_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim2_shared->final_cols_count = 1; + ProfScope("allocate outputs") + { + rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); + rdim2_shared->final_line_tables = push_array(arena, RDI_LineTable, rdim2_shared->final_line_tables_count); + rdim2_shared->final_line_voffs = push_array(arena, RDI_U64, rdim2_shared->final_line_voffs_count); + rdim2_shared->final_lines = push_array(arena, RDI_Line, rdim2_shared->final_lines_count); + rdim2_shared->final_cols = push_array(arena, RDI_Column, rdim2_shared->final_cols_count); + } + U64 voffs_base_idx = 0; + U64 lines_base_idx = 0; + U64 cols_base_idx = 0; + ProfScope("lay out line tables") for EachIndex(idx, rdim2_shared->line_tables_count) + { + U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil + RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; + RDI_LineTable *dst = &rdim2_shared->final_line_tables[final_idx]; + dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 + dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 + voffs_base_idx += src->line_count + 2*src->seq_count; + lines_base_idx += src->line_count + 1*src->seq_count; + } + rdim2_shared->line_table_block_take_counter = 0; } lane_sync(); - //- rjf: wide gather + //- rjf: wide bake + ProfScope("wide bake") { + U64 line_table_block_size = 4; + U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; for(;;) { - U64 line_table_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_take_counter); - if(0 == line_table_num || rdim2_shared->line_tables_count < line_table_num) + U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); + if(0 == line_table_block_num || line_table_block_count < line_table_block_num) { break; } - U64 line_table_idx = line_table_num-1; - RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; - RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; - dst->line_count = src->line_count; - dst->seq_count = src->seq_count; - dst->key_count = dst->line_count + dst->seq_count; - dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); - dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); + U64 line_table_block_idx = line_table_block_num-1; + Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); + line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); + for EachInRange(line_table_idx, line_table_range) { - RDIM_SortKey *key_ptr = dst->line_keys; - RDIM_LineRec *rec_ptr = dst->line_recs; - for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) + RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + + //- rjf: gather + dst->line_count = src->line_count; + dst->seq_count = src->seq_count; + dst->key_count = dst->line_count + dst->seq_count; + dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); + dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); { - RDIM_LineSequence *seq = &seq_n->v; - for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + RDIM_SortKey *key_ptr = dst->line_keys; + RDIM_LineRec *rec_ptr = dst->line_recs; + for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) { - key_ptr->key = seq->voffs[line_idx]; - key_ptr->val = rec_ptr; - key_ptr += 1; - rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 - rec_ptr->line_num = seq->line_nums[line_idx]; - if(seq->col_nums != 0) + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) { - rec_ptr->col_first = seq->col_nums[line_idx*2]; - rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + + //- rjf: sort + rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); + + //- rjf: fill + RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; + U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; + RDI_LineTable *dst_line_table = &rdim2_shared->final_line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim2_shared->final_line_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim2_shared->final_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim2_shared->final_cols + dst_line_table->cols_base_idx; + { + for EachIndex(idx, sorted_line_keys_count) + { + arranged_voffs[idx] = sorted_line_keys[idx].key; + } + arranged_voffs[sorted_line_keys_count] = ~0ull; + for EachIndex(idx, sorted_line_keys_count) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; + if(rec != 0) + { + arranged_lines[idx].file_idx = rec->file_id; + arranged_lines[idx].line_num = rec->line_num; + } + else + { + arranged_lines[idx].file_idx = 0; + arranged_lines[idx].line_num = 0; } - rec_ptr += 1; } - key_ptr->key = seq->voffs[seq->line_count]; - key_ptr->val = 0; - key_ptr += 1; } } } @@ -88,31 +160,204 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDI_U64 line_tables_count = rdim2_shared->line_tables_count; RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; + RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; ////////////////////////////////////////////////////////////// - //- rjf: sort all unsorted line table info + //- rjf: build string map // - ProfScope("sort all unsorted line table info") + ProfScope("build string map") { - if(lane_idx() == 0) + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, line_tables_count); - rdim2_shared->line_table_take_counter = 0; + rdim2_shared->bake_string_map_topology.slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); } lane_sync(); - for(;;) + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") { - U64 line_table_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_take_counter); - if(0 == line_table_num || line_tables_count < line_table_num) + rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; + + //- rjf: push all strings into this lane's map + ProfScope("push all strings into this lane's map") + { + //- rjf: push strings from source files + ProfScope("src files") { - break; + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } } - U64 line_table_idx = line_table_num-1; - rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, unsorted_joined_line_tables[line_table_idx].line_keys, unsorted_joined_line_tables[line_table_idx].key_count); + + //- rjf: push strings from units + ProfScope("units") + { + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from types + ProfScope("types") + { + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from udts + ProfScope("udts") + { + for(RDIM_UDTChunkNode *n = params->udts.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from symbols + RDIM_SymbolChunkList *symbol_lists[] = + { + ¶ms->global_variables, + ¶ms->thread_variables, + ¶ms->procedures, + ¶ms->constants, + }; + ProfScope("symbols") + { + for EachElement(list_idx, symbol_lists) + { + ProfScope("symbols (%I64u)", list_idx) + { + for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + } + } + + //- rjf: push strings from inline sites + ProfScope("inline sites") + { + for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from scopes + ProfScope("scopes") + { + for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + } + + //- rjf: join & sort + if(lane_idx() == 0) + { + rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + lane_sync(); + ProfScope("join & sort") + { + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort string table + ProfScope("sort string table") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + lane_sync(); + + //- rjf: tighten string table + if(lane_idx() == 0) ProfScope("tighten string table") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_strings = rdim_bake_string_map_tight_from_loose(arena, map_top, &bake_string_map_base_idxes, map); +#if 1 + for EachIndex(idx, rdim2_shared->bake_strings.slots_count) + { + for(RDIM_BakeStringChunkNode *n = rdim2_shared->bake_strings.slots[idx].first; n != 0; n = n->next) + { + for EachIndex(n_idx, n->count) + { + fprintf(stdout, "%.*s\n", str8_varg(n->v[n_idx].string)); + } + } + } + fflush(stdout); +#endif } } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: package results + // RDIM_BakeResults result = {0}; + { + result.line_tables.line_tables = rdim2_shared->final_line_tables; + result.line_tables.line_tables_count = rdim2_shared->final_line_tables_count; + result.line_tables.line_table_voffs = rdim2_shared->final_line_voffs; + result.line_tables.line_table_voffs_count = rdim2_shared->final_line_voffs_count; + result.line_tables.line_table_lines = rdim2_shared->final_lines; + result.line_tables.line_table_lines_count = rdim2_shared->final_lines_count; + result.line_tables.line_table_columns = rdim2_shared->final_cols; + result.line_tables.line_table_columns_count = rdim2_shared->final_cols_count; + } + return result; } diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index a6de79e6..b2ac1056 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -22,11 +22,25 @@ typedef struct RDIM2_Shared RDIM2_Shared; struct RDIM2_Shared { RDI_U64 line_tables_count; - RDI_U64 line_table_take_counter; + RDI_U64 line_table_block_take_counter; RDIM_LineTable **src_line_tables; RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables; RDIM_SortKey **sorted_line_table_keys; + + RDI_U64 final_line_tables_count; + RDI_U64 final_line_voffs_count; + RDI_U64 final_lines_count; + RDI_U64 final_cols_count; + RDI_LineTable *final_line_tables; + RDI_U64 *final_line_voffs; + RDI_Line *final_lines; + RDI_Column *final_cols; + + RDIM_BakeStringMapTopology bake_string_map_topology; + RDIM_BakeStringMapLoose **lane_bake_string_maps__loose; + RDIM_BakeStringMapLoose *bake_string_map__loose; + RDIM_BakeStringMapTight bake_strings; }; global RDIM2_Shared *rdim2_shared = 0; From 595270bdab515ea689bf72ead44cd327e15df989 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 16:39:18 -0700 Subject: [PATCH 060/302] path tree baking --- src/rdi_make/rdi_make_local_2.c | 23 ++++++++++------------- src/rdi_make/rdi_make_local_2.h | 2 ++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index f9c19247..2b333db8 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -13,6 +13,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: build interned path tree + // + if(lane_idx() == 0) ProfScope("build interned path tree") + { + rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); + } + lane_sync(); + RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; + ////////////////////////////////////////////////////////////// //- rjf: gather all unsorted, joined, line table info; & sort // @@ -327,19 +337,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); rdim2_shared->bake_strings = rdim_bake_string_map_tight_from_loose(arena, map_top, &bake_string_map_base_idxes, map); -#if 1 - for EachIndex(idx, rdim2_shared->bake_strings.slots_count) - { - for(RDIM_BakeStringChunkNode *n = rdim2_shared->bake_strings.slots[idx].first; n != 0; n = n->next) - { - for EachIndex(n_idx, n->count) - { - fprintf(stdout, "%.*s\n", str8_varg(n->v[n_idx].string)); - } - } - } - fflush(stdout); -#endif } } lane_sync(); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index b2ac1056..c5c6cfda 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -21,6 +21,8 @@ struct RDIM_UnsortedJoinedLineTable typedef struct RDIM2_Shared RDIM2_Shared; struct RDIM2_Shared { + RDIM_BakePathTree *path_tree; + RDI_U64 line_tables_count; RDI_U64 line_table_block_take_counter; RDIM_LineTable **src_line_tables; From 618233eba1470cc438357e9943f54dbc9d3099f0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 20:16:27 -0700 Subject: [PATCH 061/302] checkpoint on new baker; globals, threads, inline sites --- src/base/base_core.h | 1 + src/rdi_make/rdi_make_local_2.c | 246 ++++++++++++++++++++++++++++---- src/rdi_make/rdi_make_local_2.h | 23 +-- 3 files changed, 235 insertions(+), 35 deletions(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index 42e7a918..bc3a95a4 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -137,6 +137,7 @@ #define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1)) #define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1)) #define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1) +#define EachNode(it, T, first) (T *n = first; n != 0; n = n->next) //////////////////////////////// //~ rjf: Memory Operation Macros diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 2b333db8..34b90699 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -28,7 +28,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // ProfScope("gather all unsorted, joined, line table info; & sort") { - //- rjf: set up outputs + //- rjf: set up outputsw ProfScope("set up outputs") if(lane_idx() == 0) { rdim2_shared->line_tables_count = params->line_tables.total_count; @@ -45,18 +45,18 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - rdim2_shared->final_line_tables_count = params->line_tables.total_count + 1; - rdim2_shared->final_line_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; - rdim2_shared->final_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; - rdim2_shared->final_cols_count = 1; + rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; + rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_columns_count= 1; ProfScope("allocate outputs") { rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); - rdim2_shared->final_line_tables = push_array(arena, RDI_LineTable, rdim2_shared->final_line_tables_count); - rdim2_shared->final_line_voffs = push_array(arena, RDI_U64, rdim2_shared->final_line_voffs_count); - rdim2_shared->final_lines = push_array(arena, RDI_Line, rdim2_shared->final_lines_count); - rdim2_shared->final_cols = push_array(arena, RDI_Column, rdim2_shared->final_cols_count); + rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); + rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); + rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); } U64 voffs_base_idx = 0; U64 lines_base_idx = 0; @@ -65,7 +65,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; - RDI_LineTable *dst = &rdim2_shared->final_line_tables[final_idx]; + RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 @@ -137,10 +137,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: fill RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; - RDI_LineTable *dst_line_table = &rdim2_shared->final_line_tables[line_table_idx+1]; - U64 *arranged_voffs = rdim2_shared->final_line_voffs + dst_line_table->voffs_base_idx; - RDI_Line *arranged_lines = rdim2_shared->final_lines + dst_line_table->lines_base_idx; - RDI_Column *arranged_cols = rdim2_shared->final_cols + dst_line_table->cols_base_idx; + RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; { for EachIndex(idx, sorted_line_keys_count) { @@ -200,7 +200,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: push all strings into this lane's map ProfScope("push all strings into this lane's map") { - //- rjf: push strings from source files + // rjf: push strings from source files ProfScope("src files") { for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) @@ -210,7 +210,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: push strings from units + // rjf: push strings from units ProfScope("units") { for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) @@ -220,7 +220,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: push strings from types + // rjf: push strings from types ProfScope("types") { for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) @@ -230,7 +230,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: push strings from udts + // rjf: push strings from udts ProfScope("udts") { for(RDIM_UDTChunkNode *n = params->udts.first; n != 0; n = n->next) @@ -240,7 +240,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: push strings from symbols + // rjf: push strings from symbols RDIM_SymbolChunkList *symbol_lists[] = { ¶ms->global_variables, @@ -340,20 +340,212 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); + RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + + ////////////////////////////////////////////////////////////// + //- rjf: bake units, src files, symbols, UDTs + // + { + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_units.units_count = params->units.total_count+1; + rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; + rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; + rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + } + if(lane_idx() == lane_from_task_idx(6)) + { + rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; + rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); + } + if(lane_idx() == lane_from_task_idx(7)) + { + rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; + rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); + } + if(lane_idx() == lane_from_task_idx(8)) + { + rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + } + if(lane_idx() == lane_from_task_idx(9)) + { + rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + } + if(lane_idx() == lane_from_task_idx(10)) + { + rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + } + if(lane_idx() == lane_from_task_idx(11)) + { + rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + } + if(lane_idx() == lane_from_task_idx(12)) + { + rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; + rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + } + lane_sync(); + + //- rjf: bake units + ProfScope("bake units") + { + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Unit *src = &n->v[n_idx]; + RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; + dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); + dst->language = src->language; + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + + //- rjf: bake global variables + ProfScope("bake global variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->voff = src->offset; + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake thread variables + ProfScope("bake thread variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake inline sites + ProfScope("bake inline sites") + { + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; + RDIM_InlineSite *src = &n->v[n_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + } + lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: package results // RDIM_BakeResults result = {0}; { - result.line_tables.line_tables = rdim2_shared->final_line_tables; - result.line_tables.line_tables_count = rdim2_shared->final_line_tables_count; - result.line_tables.line_table_voffs = rdim2_shared->final_line_voffs; - result.line_tables.line_table_voffs_count = rdim2_shared->final_line_voffs_count; - result.line_tables.line_table_lines = rdim2_shared->final_lines; - result.line_tables.line_table_lines_count = rdim2_shared->final_lines_count; - result.line_tables.line_table_columns = rdim2_shared->final_cols; - result.line_tables.line_table_columns_count = rdim2_shared->final_cols_count; + // result.top_level_info = rdim2_shared->baked_top_level_info; + // result.binary_sections = rdim2_shared->baked_binary_sections; + result.units = rdim2_shared->baked_units; + result.unit_vmap = rdim2_shared->baked_unit_vmap; + result.src_files = rdim2_shared->baked_src_files; + result.line_tables = rdim2_shared->baked_line_tables; + // result.type_nodes = rdim2_shared->baked_type_nodes; + result.udts = rdim2_shared->baked_udts; + result.global_variables = rdim2_shared->baked_global_variables; + result.global_vmap = rdim2_shared->baked_global_vmap; + result.thread_variables = rdim2_shared->baked_thread_variables; + result.constants = rdim2_shared->baked_constants; + result.procedures = rdim2_shared->baked_procedures; + // result.scopes = rdim2_shared->baked_scopes; + result.inline_sites = rdim2_shared->baked_inline_sites; + result.scope_vmap = rdim2_shared->baked_scope_vmap; + // result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; + // result.name_maps = rdim2_shared->baked_name_maps; + // result.file_paths = rdim2_shared->baked_file_paths; + result.strings = rdim2_shared->baked_strings; + // result.idx_runs = rdim2_shared->baked_idx_runs; + // result.location_blocks = rdim2_shared->baked_location_blocks; + // result.location_data = rdim2_shared->baked_location_data; } return result; diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index c5c6cfda..ad52af1d 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -30,19 +30,26 @@ struct RDIM2_Shared RDIM_SortKey **sorted_line_table_keys; - RDI_U64 final_line_tables_count; - RDI_U64 final_line_voffs_count; - RDI_U64 final_lines_count; - RDI_U64 final_cols_count; - RDI_LineTable *final_line_tables; - RDI_U64 *final_line_voffs; - RDI_Line *final_lines; - RDI_Column *final_cols; + RDIM_LineTableBakeResult baked_line_tables; RDIM_BakeStringMapTopology bake_string_map_topology; RDIM_BakeStringMapLoose **lane_bake_string_maps__loose; RDIM_BakeStringMapLoose *bake_string_map__loose; RDIM_BakeStringMapTight bake_strings; + + RDIM_UnitBakeResult baked_units; + RDIM_UnitVMapBakeResult baked_unit_vmap; + RDIM_SrcFileBakeResult baked_src_files; + RDIM_UDTBakeResult baked_udts; + RDIM_GlobalVariableBakeResult baked_global_variables; + RDIM_GlobalVMapBakeResult baked_global_vmap; + RDIM_ThreadVariableBakeResult baked_thread_variables; + RDIM_ConstantsBakeResult baked_constants; + RDIM_ProcedureBakeResult baked_procedures; + RDIM_ScopeVMapBakeResult baked_scope_vmap; + RDIM_InlineSiteBakeResult baked_inline_sites; + + RDIM_StringBakeResult baked_strings; }; global RDIM2_Shared *rdim2_shared = 0; From 95e88e92e76bfbddbeedb3b73799bfd05ae1c4c5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 26 Aug 2025 20:57:54 -0700 Subject: [PATCH 062/302] top-level info string baking --- src/rdi_make/rdi_make_local_2.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 34b90699..cb3a48c2 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -200,6 +200,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: push all strings into this lane's map ProfScope("push all strings into this lane's map") { + // rjf: push small top-level strings + if(lane_idx() == 0) ProfScope("push small top-level strings") + { + rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); + rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); + } + // rjf: push strings from source files ProfScope("src files") { @@ -314,8 +322,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: sort string table - ProfScope("sort string table") + //- rjf: sort + ProfScope("sort") { RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); From b22f6d3544ab481ff9df8902390292db416c0022 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 27 Aug 2025 13:41:20 -0700 Subject: [PATCH 063/302] fully wide name map baking, joining, & sorting --- src/lib_rdi_make/rdi_make.c | 185 +++++++++++++++++++++++++++++++- src/lib_rdi_make/rdi_make.h | 51 +++++++++ src/rdi_make/rdi_make_local_2.c | 147 ++++++++++++++++++++++++- src/rdi_make/rdi_make_local_2.h | 4 + 4 files changed, 381 insertions(+), 6 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index afd48835..9dd34f37 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1534,10 +1534,10 @@ rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_ rdim_memzero_struct(to_push); } - -RSFORCEINLINE int rdim_bake_string_hash_is_before(void *elementa, void *elementb) +RSFORCEINLINE int +rdim_bake_string_is_before(void *l, void *r) { - return ((RDIM_BakeString *)elementa)->hash < ((RDIM_BakeString *)elementb)->hash; + return ((RDIM_BakeString *)l)->hash < ((RDIM_BakeString *)r)->hash; } RDI_PROC RDIM_BakeStringChunkList @@ -1558,7 +1558,7 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr //- rjf: sort chunk node if(dst.first != 0) { - radsort(dst.first->v, dst.first->count, rdim_bake_string_hash_is_before); + radsort(dst.first->v, dst.first->count, rdim_bake_string_is_before); } //- rjf: iterate sorted chunk node, remove duplicates, count # of duplicates @@ -1611,7 +1611,6 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr } } - return dst; } @@ -1737,6 +1736,173 @@ rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string) return idx; } +//- rjf: bake name chunk list + +RDI_PROC RDIM_BakeName * +rdim_bake_name_chunk_list_push(RDIM_Arena *arena, RDIM_BakeNameChunkList *list, RDI_U64 cap) +{ + RDIM_BakeNameChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_BakeNameChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_BakeName, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_BakeName *result = &n->v[n->count]; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC void +rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_BakeNameChunkList *to_push) +{ + for(RDIM_BakeNameChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RSFORCEINLINE int +rdim_bake_name_is_before(void *l, void *r) +{ + return ((RDIM_BakeName *)l)->hash < ((RDIM_BakeName *)r)->hash; +} + +RDI_PROC RDIM_BakeNameChunkList +rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameChunkList *src) +{ + //- rjf: produce unsorted destination list with single chunk node + RDIM_BakeNameChunkList dst = {0}; + for(RDIM_BakeNameChunkNode *n = src->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_BakeName *src_str = &n->v[idx]; + RDIM_BakeName *dst_str = rdim_bake_name_chunk_list_push(arena, &dst, src->total_count); + rdim_memcpy_struct(dst_str, src_str); + } + } + + //- rjf: sort chunk node + if(dst.first != 0) + { + radsort(dst.first->v, dst.first->count, rdim_bake_name_is_before); + } + + //- rjf: iterate sorted chunk node, remove duplicates, count # of duplicates + RDI_U64 num_duplicates = 0; + if(dst.first != 0) + { + RDI_U64 last_idx = 0; + for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) + { + if(rdim_str8_match(dst.first->v[last_idx].string, dst.first->v[idx].string, 0)) + { + rdim_memzero_struct(&dst.first->v[idx]); + num_duplicates += 1; + } + else + { + last_idx = idx; + } + } + } + + //- rjf: iterate sorted chunk node, make non-empty elements contiguous + if(num_duplicates != 0) + { + RDI_U64 last_idx = 0; + for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) + { + if(last_idx == 0 && + dst.first->v[idx].string.RDIM_String8_SizeMember == 0 && + dst.first->v[idx].hash == 0) + { + last_idx = idx; + } + if(last_idx != 0 && dst.first->v[idx].string.RDIM_String8_SizeMember != 0) + { + rdim_memcpy_struct(&dst.first->v[last_idx], &dst.first->v[idx]); + rdim_memzero_struct(&dst.first->v[idx]); + last_idx += 1; + } + } + + //- rjf: pop extras + if(num_duplicates != 0) + { + RDI_U64 arena_pos_pre_pop = rdim_arena_pos(arena); + rdim_arena_pop_to(arena, arena_pos_pre_pop - num_duplicates*sizeof(dst.first->v[0])); + dst.first->count -= num_duplicates; + dst.first->cap -= num_duplicates; + dst.total_count -= num_duplicates; + } + } + + return dst; +} + +//- rjf: bake name chunk list maps + +RDI_PROC RDIM_BakeNameMap2 * +rdim_bake_name_map_2_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top) +{ + RDIM_BakeNameMap2 *map = rdim_push_array(arena, RDIM_BakeNameMap2, 1); + map->slots = rdim_push_array(arena, RDIM_BakeNameChunkList *, top->slots_count); + return map; +} + +RDI_PROC void +rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap2 *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx) +{ + if(string.RDIM_String8_SizeMember != 0) + { + RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); + RDI_U64 slot_idx = hash%map_topology->slots_count; + RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + if(slot == 0) + { + slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeNameChunkList, 1); + } + RDI_S32 is_duplicate = 0; + for(RDIM_BakeNameChunkNode *n = slot->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + if(rdim_str8_match(n->v[idx].string, string, 0)) + { + is_duplicate = 1; + goto break_all; + } + } + } + break_all:; + if(!is_duplicate) + { + RDIM_BakeName *bstr = rdim_bake_name_chunk_list_push(arena, slot, chunk_cap); + bstr->string = string; + bstr->idx = idx; + bstr->hash = hash; + } + } +} + //- rjf: bake idx run map reading/writing RDI_PROC RDI_U64 @@ -1992,6 +2158,15 @@ rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_Stri //- rjf: bake name maps writing +RDI_PROC RDIM_BakeNameMap * +rdim_bake_name_map_make(RDIM_Arena *arena, RDI_U64 expected_count) +{ + RDIM_BakeNameMap *map = push_array(arena, RDIM_BakeNameMap, 1); + map->slots_count = Max(64, expected_count); + map->slots = push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + return map; +} + RDI_PROC void rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx) { diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index f3d86b53..eb9c4fc5 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1105,6 +1105,47 @@ struct RDIM_BakePathTree //- rjf: name maps +typedef struct RDIM_BakeName RDIM_BakeName; +struct RDIM_BakeName +{ + RDIM_String8 string; + RDI_U64 hash; + RDI_U64 idx; +}; + +typedef struct RDIM_BakeNameChunkNode RDIM_BakeNameChunkNode; +struct RDIM_BakeNameChunkNode +{ + RDIM_BakeNameChunkNode *next; + RDIM_BakeName *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_BakeNameChunkList RDIM_BakeNameChunkList; +struct RDIM_BakeNameChunkList +{ + RDIM_BakeNameChunkNode *first; + RDIM_BakeNameChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +typedef struct RDIM_BakeNameMapTopology RDIM_BakeNameMapTopology; +struct RDIM_BakeNameMapTopology +{ + RDI_U64 slots_count; +}; + +typedef struct RDIM_BakeNameMap2 RDIM_BakeNameMap2; +struct RDIM_BakeNameMap2 +{ + RDIM_BakeNameChunkList **slots; +}; + +//- rjf: name maps (OLD) + typedef struct RDIM_BakeNameMapValNode RDIM_BakeNameMapValNode; struct RDIM_BakeNameMapValNode { @@ -1558,6 +1599,15 @@ RDI_PROC RDIM_BakeStringMapBaseIndices rdim_bake_string_map_base_indices_from_ma RDI_PROC RDIM_BakeStringMapTight rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map); RDI_PROC RDI_U32 rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string); +//- rjf: bake name chunk list +RDI_PROC RDIM_BakeName *rdim_bake_name_chunk_list_push(RDIM_Arena *arena, RDIM_BakeNameChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_BakeNameChunkList *to_push); +RDI_PROC RDIM_BakeNameChunkList rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameChunkList *src); + +//- rjf: bake name chunk list maps +RDI_PROC RDIM_BakeNameMap2 *rdim_bake_name_map_2_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top); +RDI_PROC void rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap2 *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx); + //- rjf: bake idx run map reading/writing RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); @@ -1569,6 +1619,7 @@ RDI_PROC RDI_U32 rdim_bake_path_node_idx_from_string(RDIM_BakePathTree *tree, RD RDI_PROC RDIM_BakePathNode *rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string); //- rjf: bake name maps writing +RDI_PROC RDIM_BakeNameMap *rdim_bake_name_map_make(RDIM_Arena *arena, RDI_U64 expected_count); RDI_PROC void rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx); //////////////////////////////// diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index cb3a48c2..0f674453 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -28,7 +28,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // ProfScope("gather all unsorted, joined, line table info; & sort") { - //- rjf: set up outputsw + //- rjf: set up outputs ProfScope("set up outputs") if(lane_idx() == 0) { rdim2_shared->line_tables_count = params->line_tables.total_count; @@ -350,6 +350,151 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + ////////////////////////////////////////////////////////////// + //- rjf: bake name maps + // + ProfScope("bake name maps") + { + //- rjf: set up + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + U64 slot_count = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; +#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break + Case(GlobalVariables, params->global_variables.total_count); + Case(ThreadVariables, params->thread_variables.total_count); + Case(Constants, params->constants.total_count); + Case(Procedures, params->procedures.total_count); + Case(LinkNameProcedures, params->procedures.total_count); + Case(Types, params->types.total_count); + Case(NormalSourcePaths, params->src_files.total_count); +#undef Case + } + rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); + rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; + } + } + lane_sync(); + + //- rjf: wide build + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); + RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; + B32 link_names = 0; + RDIM_SymbolChunkList *symbols = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; + case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; + case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; + case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; + symbol_name_map_build:; + { + for EachNode(n, RDIM_SymbolChunkNode, symbols->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Symbol *symbol = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); + } + } + }break; + case RDI_NameMapKind_Types: + { + RDIM_TypeChunkList *types = ¶ms->types; + for EachNode(n, RDIM_TypeChunkNode, types->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Type *type = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); + } + } + }break; + case RDI_NameMapKind_NormalSourcePaths: + { + RDIM_SrcFileChunkList *src_files = ¶ms->src_files; + for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_SrcFile *src_file = &n->v[n_idx]; + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); + rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); + } + } + }break; + } + } + lane_sync(); + + //- rjf: join & sort + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap2 *dst_map = map; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: bake units, src files, symbols, UDTs // diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index ad52af1d..92586c9c 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -37,6 +37,10 @@ struct RDIM2_Shared RDIM_BakeStringMapLoose *bake_string_map__loose; RDIM_BakeStringMapTight bake_strings; + RDIM_BakeNameMapTopology bake_name_map_topology[RDI_NameMapKind_COUNT]; + RDIM_BakeNameMap2 **lane_bake_name_maps[RDI_NameMapKind_COUNT]; + RDIM_BakeNameMap2 *bake_name_maps[RDI_NameMapKind_COUNT]; + RDIM_UnitBakeResult baked_units; RDIM_UnitVMapBakeResult baked_unit_vmap; RDIM_SrcFileBakeResult baked_src_files; From ad4e57ec5aad892b3e45b382af3fc19f8908e5d7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 27 Aug 2025 16:14:55 -0700 Subject: [PATCH 064/302] idx run baking --- project.4coder | 4 +- src/base/base_core.h | 2 +- src/lib_rdi_make/rdi_make.c | 244 +++++++++++++++++++++++++++++++- src/lib_rdi_make/rdi_make.h | 89 +++++++++++- src/rdi_make/rdi_make_local_2.c | 171 ++++++++++++++++++++-- src/rdi_make/rdi_make_local_2.h | 6 + 6 files changed, 493 insertions(+), 23 deletions(-) diff --git a/project.4coder b/project.4coder index 57de31db..2d3325c2 100644 --- a/project.4coder +++ b/project.4coder @@ -47,13 +47,13 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [scratch] - .f2 = { .win = "build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f2 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [textperf] // .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/base/base_core.h b/src/base/base_core.h index bc3a95a4..b72a46f3 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -137,7 +137,7 @@ #define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1)) #define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1)) #define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1) -#define EachNode(it, T, first) (T *n = first; n != 0; n = n->next) +#define EachNode(it, T, first) (T *it = first; it != 0; it = it->next) //////////////////////////////// //~ rjf: Memory Operation Macros diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 9dd34f37..2e0629b6 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1491,9 +1491,9 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So } //////////////////////////////// -//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers +//~ rjf: [Baking Helpers] Deduplicated String Baking Map -//- rjf: bake string chunk lists +//- rjf: chunk lists RDI_PROC RDIM_BakeString * rdim_bake_string_chunk_list_push(RDIM_Arena *arena, RDIM_BakeStringChunkList *list, RDI_U64 cap) @@ -1614,7 +1614,7 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr return dst; } -//- rjf: bake string chunk list maps +//- rjf: loose map RDI_PROC RDIM_BakeStringMapLoose * rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top) @@ -1693,7 +1693,7 @@ rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStr return indices; } -//- rjf: finalized bake string map +//- rjf: finalized / tight map RDI_PROC RDIM_BakeStringMapTight rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map) @@ -1736,7 +1736,238 @@ rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string) return idx; } -//- rjf: bake name chunk list +//////////////////////////////// +//~ rjf: [Baking Helpers] Deduplicated Index Run Baking Map + +//- rjf: chunk lists + +RDI_PROC RDIM_BakeIdxRun * +rdim_bake_idx_run_chunk_list_push(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *list, RDI_U64 cap) +{ + RDIM_BakeIdxRunChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_BakeIdxRunChunkNode, 1); + n->cap = cap; + n->v = rdim_push_array(arena, RDIM_BakeIdxRun, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_BakeIdxRun *s = &n->v[n->count]; + n->count += 1; + list->total_count += 1; + return s; +} + +RDI_PROC void +rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM_BakeIdxRunChunkList *to_push) +{ + for(RDIM_BakeIdxRunChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RSFORCEINLINE int +rdim_bake_idx_run_is_before(void *l, void *r) +{ + return ((RDIM_BakeIdxRun *)l)->hash < ((RDIM_BakeIdxRun *)r)->hash; +} + +RDI_PROC RDIM_BakeIdxRunChunkList +rdim_bake_idx_run_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *src) +{ + //- rjf: produce unsorted destination list with single chunk node + RDIM_BakeIdxRunChunkList dst = {0}; + for(RDIM_BakeIdxRunChunkNode *n = src->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_BakeIdxRun *src_str = &n->v[idx]; + RDIM_BakeIdxRun *dst_str = rdim_bake_idx_run_chunk_list_push(arena, &dst, src->total_count); + rdim_memcpy_struct(dst_str, src_str); + } + } + + //- rjf: sort chunk node + if(dst.first != 0) + { + radsort(dst.first->v, dst.first->count, rdim_bake_idx_run_is_before); + } + + //- rjf: iterate sorted chunk node, remove duplicates, count # of duplicates + RDI_U64 num_duplicates = 0; + if(dst.first != 0) + { + RDI_U64 last_idx = 0; + for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) + { + if(dst.first->v[last_idx].hash == dst.first->v[idx].hash) + { + rdim_memzero_struct(&dst.first->v[idx]); + num_duplicates += 1; + } + else + { + last_idx = idx; + } + } + } + + //- rjf: iterate sorted chunk node, make non-empty elements contiguous + if(num_duplicates != 0) + { + RDI_U64 last_idx = 0; + for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) + { + if(last_idx == 0 && dst.first->v[idx].hash == 0) + { + last_idx = idx; + } + if(last_idx != 0 && dst.first->v[idx].hash != 0) + { + rdim_memcpy_struct(&dst.first->v[last_idx], &dst.first->v[idx]); + rdim_memzero_struct(&dst.first->v[idx]); + last_idx += 1; + } + } + + //- rjf: pop extras + if(num_duplicates != 0) + { + RDI_U64 arena_pos_pre_pop = rdim_arena_pos(arena); + rdim_arena_pop_to(arena, arena_pos_pre_pop - num_duplicates*sizeof(dst.first->v[0])); + dst.first->count -= num_duplicates; + dst.first->cap -= num_duplicates; + dst.total_count -= num_duplicates; + } + } + + return dst; +} + +//- rjf: loose map + +RDI_PROC RDIM_BakeIdxRunMapLoose * +rdim_bake_idx_run_map_loose_make(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *top) +{ + RDIM_BakeIdxRunMapLoose *map = rdim_push_array(arena, RDIM_BakeIdxRunMapLoose, 1); + map->slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList *, top->slots_count); + return map; +} + +RDI_PROC void +rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map, RDI_U64 chunk_cap, RDI_U32 *idxes, RDI_U32 count) +{ + if(count != 0) + { + RDI_U64 hash = rdim_hash_from_idx_run(idxes, count); + RDI_U64 slot_idx = hash%map_topology->slots_count; + RDIM_BakeIdxRunChunkList *slot = map->slots[slot_idx]; + if(slot == 0) + { + slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, 1); + } + RDI_S32 is_duplicate = 0; + for(RDIM_BakeIdxRunChunkNode *n = slot->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + if(n->v[idx].hash == hash) + { + is_duplicate = 1; + goto break_all; + } + } + } + break_all:; + if(!is_duplicate) + { + RDIM_BakeIdxRun *bir = rdim_bake_idx_run_chunk_list_push(arena, slot, chunk_cap); + bir->hash = hash; + bir->count = count; + bir->idxes = idxes; + } + } +} + +RDI_PROC RDIM_BakeIdxRunMapBaseIndices +rdim_bake_idx_run_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map) +{ + RDIM_BakeIdxRunMapBaseIndices indices = {0}; + indices.slots_base_idxs = rdim_push_array(arena, RDI_U64, map_topology->slots_count+1); + RDI_U64 total_count = 0; + for(RDI_U64 idx = 0; idx < map_topology->slots_count; idx += 1) + { + indices.slots_base_idxs[idx] += total_count; + if(map->slots[idx] != 0) + { + total_count += map->slots[idx]->total_count; + } + } + indices.slots_base_idxs[map_topology->slots_count] = total_count; + return indices; +} + +//- rjf: finalized / tight map + +RDI_PROC RDIM_BakeIdxRunMap2 * +rdim_bake_idx_run_map_from_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapBaseIndices *map_base_indices, RDIM_BakeIdxRunMapLoose *map) +{ + RDIM_BakeIdxRunMap2 *m = rdim_push_array(arena, RDIM_BakeIdxRunMap2, 1); + m->slots_count = map_topology->slots_count; + m->slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, m->slots_count); + m->slots_base_idxs = map_base_indices->slots_base_idxs; + for(RDI_U64 idx = 0; idx < m->slots_count; idx += 1) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&m->slots[idx], map->slots[idx]); + } + } + m->total_count = m->slots_base_idxs[m->slots_count]; + return m; +} + +RDI_PROC RDI_U32 +rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count) +{ + RDI_U32 idx = 0; + if(count != 0) + { + RDI_U64 hash = rdim_hash_from_idx_run(idxes, count); + RDI_U64 slot_idx = hash%map->slots_count; + for(RDIM_BakeIdxRunChunkNode *n = map->slots[slot_idx].first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + if(n->v[chunk_idx].hash == hash) + { + idx = map->slots_base_idxs[slot_idx] + n->base_idx + chunk_idx + 1; + break; + } + } + } + } + return idx; +} + +//////////////////////////////// +//~ rjf: [Baking Helpers] Deduplicated Name Map Baking Map + +//- rjf: chunk lists RDI_PROC RDIM_BakeName * rdim_bake_name_chunk_list_push(RDIM_Arena *arena, RDIM_BakeNameChunkList *list, RDI_U64 cap) @@ -1903,6 +2134,9 @@ rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_top } } +//////////////////////////////// +//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers + //- rjf: bake idx run map reading/writing RDI_PROC RDI_U64 diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index eb9c4fc5..8cb15186 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1049,6 +1049,62 @@ struct RDIM_BakeStringMapTight //- rjf: index runs +typedef struct RDIM_BakeIdxRun RDIM_BakeIdxRun; +struct RDIM_BakeIdxRun +{ + RDI_U64 hash; + RDI_U64 count; + RDI_U32 *idxes; +}; + +typedef struct RDIM_BakeIdxRunChunkNode RDIM_BakeIdxRunChunkNode; +struct RDIM_BakeIdxRunChunkNode +{ + RDIM_BakeIdxRunChunkNode *next; + RDIM_BakeIdxRun *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_BakeIdxRunChunkList RDIM_BakeIdxRunChunkList; +struct RDIM_BakeIdxRunChunkList +{ + RDIM_BakeIdxRunChunkNode *first; + RDIM_BakeIdxRunChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +typedef struct RDIM_BakeIdxRunMapTopology RDIM_BakeIdxRunMapTopology; +struct RDIM_BakeIdxRunMapTopology +{ + RDI_U64 slots_count; +}; + +typedef struct RDIM_BakeIdxRunMapBaseIndices RDIM_BakeIdxRunMapBaseIndices; +struct RDIM_BakeIdxRunMapBaseIndices +{ + RDI_U64 *slots_base_idxs; +}; + +typedef struct RDIM_BakeIdxRunMapLoose RDIM_BakeIdxRunMapLoose; +struct RDIM_BakeIdxRunMapLoose +{ + RDIM_BakeIdxRunChunkList **slots; +}; + +typedef struct RDIM_BakeIdxRunMap2 RDIM_BakeIdxRunMap2; +struct RDIM_BakeIdxRunMap2 +{ + RDIM_BakeIdxRunChunkList *slots; + RDI_U64 *slots_base_idxs; + RDI_U64 slots_count; + RDI_U64 total_count; +}; + +//- rjf: index runs (OLD) + typedef struct RDIM_BakeIdxRunNode RDIM_BakeIdxRunNode; struct RDIM_BakeIdxRunNode { @@ -1582,24 +1638,44 @@ RDI_PROC RDI_U32 rdim_count_from_location_block_chunk_list(RDIM_String8List *lis RDI_PROC RDIM_BakeVMap rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count); //////////////////////////////// -//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers +//~ rjf: [Baking Helpers] Deduplicated String Baking Map -//- rjf: bake string chunk lists +//- rjf: chunk lists RDI_PROC RDIM_BakeString *rdim_bake_string_chunk_list_push(RDIM_Arena *arena, RDIM_BakeStringChunkList *list, RDI_U64 cap); RDI_PROC void rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_BakeStringChunkList *to_push); RDI_PROC RDIM_BakeStringChunkList rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStringChunkList *src); -//- rjf: bake string chunk list maps +//- rjf: loose map RDI_PROC RDIM_BakeStringMapLoose *rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top); RDI_PROC void rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map, RDI_U64 chunk_cap, RDIM_String8 string); RDI_PROC void rdim_bake_string_map_loose_join_in_place(RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *dst, RDIM_BakeStringMapLoose *src); RDI_PROC RDIM_BakeStringMapBaseIndices rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map); -//- rjf: finalized bake string map +//- rjf: finalized / tight map RDI_PROC RDIM_BakeStringMapTight rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map); RDI_PROC RDI_U32 rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string); -//- rjf: bake name chunk list +//////////////////////////////// +//~ rjf: [Baking Helpers] Deduplicated Index Run Baking Map + +//- rjf: chunk lists +RDI_PROC RDIM_BakeIdxRun *rdim_bake_idx_run_chunk_list_push(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM_BakeIdxRunChunkList *to_push); +RDI_PROC RDIM_BakeIdxRunChunkList rdim_bake_idx_run_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *src); + +//- rjf: loose map +RDI_PROC RDIM_BakeIdxRunMapLoose *rdim_bake_idx_run_map_loose_make(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *top); +RDI_PROC void rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map, RDI_U64 chunk_cap, RDI_U32 *idxes, RDI_U32 count); +RDI_PROC RDIM_BakeIdxRunMapBaseIndices rdim_bake_idx_run_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map); + +//- rjf: finalized / tight map +RDI_PROC RDIM_BakeIdxRunMap2 *rdim_bake_idx_run_map_from_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapBaseIndices *map_base_indices, RDIM_BakeIdxRunMapLoose *map); +RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count); + +//////////////////////////////// +//~ rjf: [Baking Helpers] Deduplicated Name Map Baking Map + +//- rjf: chunk lists RDI_PROC RDIM_BakeName *rdim_bake_name_chunk_list_push(RDIM_Arena *arena, RDIM_BakeNameChunkList *list, RDI_U64 cap); RDI_PROC void rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_BakeNameChunkList *to_push); RDI_PROC RDIM_BakeNameChunkList rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameChunkList *src); @@ -1608,6 +1684,9 @@ RDI_PROC RDIM_BakeNameChunkList rdim_bake_name_chunk_list_sorted_from_unsorted(R RDI_PROC RDIM_BakeNameMap2 *rdim_bake_name_map_2_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top); RDI_PROC void rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap2 *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx); +//////////////////////////////// +//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers + //- rjf: bake idx run map reading/writing RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 0f674453..d8b80412 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -496,7 +496,153 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: bake units, src files, symbols, UDTs + //- rjf: bake index runs + // + ProfScope("bake index runs") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") + { + rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + + params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->types.total_count); + rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + + //- rjf: wide fill of all index runs + ProfScope("fill all lane index run maps") + { + //- rjf: bake runs of function-type parameter lists + ProfScope("bake runs of function-type parameter lists") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) + { + RDIM_Type *type = &n->v[n_idx]; + if(type->count == 0) + { + continue; + } + if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = type->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); + } + } + } + } + + //- rjf: bake runs of name map match lists + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 slot_idx_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + if(slot != 0) + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + U64 active_hash = 0; + RDIM_BakeNameChunkNode *n = slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + U64 hash = 0; + U64 idx = 0; + if(n != 0) + { + hash = n->v[n_idx].hash; + idx = n->v[n_idx].idx; + } + + // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list + if(hash != active_hash && active_idx_count != 0) + { + if(active_idx_count > 1) + { + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + } + active_hash = hash; + first_idx_run_node = 0; + last_idx_run_node = 0; + temp_end(scratch); + } + + // rjf: hash matches the active list -> push + if(hash != 0 && hash == active_hash) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: bake units, src files, symbols, types, UDTs // { //- rjf: setup outputs @@ -516,51 +662,56 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); } if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; + rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); + } + if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); } - if(lane_idx() == lane_from_task_idx(4)) + if(lane_idx() == lane_from_task_idx(5)) { rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); } - if(lane_idx() == lane_from_task_idx(5)) + if(lane_idx() == lane_from_task_idx(6)) { rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); } - if(lane_idx() == lane_from_task_idx(6)) + if(lane_idx() == lane_from_task_idx(7)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(7)) + if(lane_idx() == lane_from_task_idx(8)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(8)) + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(10)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(11)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(11)) + if(lane_idx() == lane_from_task_idx(12)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(12)) + if(lane_idx() == lane_from_task_idx(13)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 92586c9c..5b3dda53 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -41,9 +41,15 @@ struct RDIM2_Shared RDIM_BakeNameMap2 **lane_bake_name_maps[RDI_NameMapKind_COUNT]; RDIM_BakeNameMap2 *bake_name_maps[RDI_NameMapKind_COUNT]; + RDIM_BakeIdxRunMapTopology bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose **lane_bake_idx_run_maps__loose; + RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; + RDIM_BakeIdxRunMap2 *bake_idx_runs; + RDIM_UnitBakeResult baked_units; RDIM_UnitVMapBakeResult baked_unit_vmap; RDIM_SrcFileBakeResult baked_src_files; + RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_UDTBakeResult baked_udts; RDIM_GlobalVariableBakeResult baked_global_variables; RDIM_GlobalVMapBakeResult baked_global_vmap; From b8414c4bfd16e852759af7408fa42c994d407871 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 27 Aug 2025 17:01:11 -0700 Subject: [PATCH 065/302] type, first part of udt baking, string baking --- src/lib_rdi_make/rdi_make.h | 58 ++++++++ src/rdi_make/rdi_make_local_2.c | 244 +++++++++++++++++++++++++++++++- src/rdi_make/rdi_make_local_2.h | 5 +- 3 files changed, 300 insertions(+), 7 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 8cb15186..48c563e5 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -718,6 +718,8 @@ struct RDIM_TypeChunkList //////////////////////////////// //~ rjf: User-Defined-Type Info Types +//- rjf: UDT members + typedef struct RDIM_UDTMember RDIM_UDTMember; struct RDIM_UDTMember { @@ -728,6 +730,34 @@ struct RDIM_UDTMember RDI_U32 off; }; +typedef struct RDIM_UDTMemberNode RDIM_UDTMemberNode; +struct RDIM_UDTMemberNode +{ + RDIM_UDTMemberNode *next; + RDIM_UDTMember *v; +}; + +typedef struct RDIM_UDTMemberChunkNode RDIM_UDTMemberChunkNode; +struct RDIM_UDTMemberChunkNode +{ + RDIM_UDTMemberChunkNode *next; + RDIM_UDTMember *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_UDTMemberChunkList RDIM_UDTMemberChunkList; +struct RDIM_UDTMemberChunkList +{ + RDIM_UDTMemberChunkNode *first; + RDIM_UDTMemberChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//- rjf: UDT enum values + typedef struct RDIM_UDTEnumVal RDIM_UDTEnumVal; struct RDIM_UDTEnumVal { @@ -736,6 +766,34 @@ struct RDIM_UDTEnumVal RDI_U64 val; }; +typedef struct RDIM_UDTEnumValNode RDIM_UDTEnumValNode; +struct RDIM_UDTEnumValNode +{ + RDIM_UDTEnumValNode *next; + RDIM_UDTEnumVal *v; +}; + +typedef struct RDIM_UDTEnumValChunkNode RDIM_UDTEnumValChunkNode; +struct RDIM_UDTEnumValChunkNode +{ + RDIM_UDTEnumValChunkNode *next; + RDIM_UDTEnumVal *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_UDTEnumValChunkList RDIM_UDTEnumValChunkList; +struct RDIM_UDTEnumValChunkList +{ + RDIM_UDTEnumValChunkNode *first; + RDIM_UDTEnumValChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//- rjf: UDTs + typedef struct RDIM_UDT RDIM_UDT; struct RDIM_UDT { diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index d8b80412..b2eb1350 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -351,9 +351,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; ////////////////////////////////////////////////////////////// - //- rjf: bake name maps + //- rjf: build name maps // - ProfScope("bake name maps") + ProfScope("build name maps") { //- rjf: set up if(lane_idx() == 0) @@ -496,9 +496,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: bake index runs + //- rjf: build index runs // - ProfScope("bake index runs") + ProfScope("build index runs") { //- rjf: set up per-lane outputs if(lane_idx() == 0) ProfScope("set up per-lane outputs") @@ -637,9 +637,114 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } + + //- rjf: join & sort + if(lane_idx() == 0) + { + rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + lane_sync(); + ProfScope("join & sort") + { + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + lane_sync(); + + //- rjf: tighten idx run table + if(lane_idx() == 0) ProfScope("tighten idx run table") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_idxes = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_idx_runs = rdim_bake_idx_run_map_from_loose(arena, map_top, &bake_idx_run_map_base_idxes, map); + } } } lane_sync(); + RDIM_BakeIdxRunMap2 *bake_idx_runs = rdim2_shared->bake_idx_runs; + + ////////////////////////////////////////////////////////////// + //- rjf: bake strings + // + ProfScope("bake strings") + { + // rjf: set up + if(lane_idx() == 0) ProfScope("set up; lay out strings") + { + rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; + rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); + RDI_U64 off_cursor = 0; + for EachIndex(slot_idx, bake_strings->slots_count) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; + off_cursor += src->string.size; + } + } + } + rdim2_shared->baked_strings.string_data_size = off_cursor; + rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); + } + lane_sync(); + + // rjf: wide fill string data + ProfScope("wide fill") + { + Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; + rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); + } + } + } + } + } ////////////////////////////////////////////////////////////// //- rjf: bake units, src files, symbols, types, UDTs @@ -740,6 +845,135 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } + //- rjf: bake type nodes + ProfScope("bake type nodes") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Type *src = &n->v[n_idx]; + RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; + + //- rjf: fill shared type node info + dst->kind = src->kind; + dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 + dst->byte_size = src->byte_size; + + //- rjf: fill built-in-only type node info + if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) + { + dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + } + + //- rjf: fill array sizes + else if(dst->kind == RDI_TypeKind_Array) + { + U64 direct_byte_size = 1; + if(src->direct_type && src->direct_type->byte_size > 0) + { + direct_byte_size = src->direct_type->byte_size; + } + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); + dst->constructed.count = src->byte_size / direct_byte_size; + } + + //- rjf: fill constructed type node info + else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) + { + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->constructed.count = src->count; + if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = src->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); + } + else if(dst->kind == RDI_TypeKind_MemberPtr) + { + // TODO(rjf): member pointers not currently supported. + } + } + + //- rjf: fill user-defined-type info + else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) + { + dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 + dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill bitfield info + else if(dst->kind == RDI_TypeKind_Bitfield) + { + dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->bitfield.off = src->off; + dst->bitfield.size = src->count; + } + } + } + } + + //- rjf: bake UDTs + ProfScope("bake UDTs") + { + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDT *src_udt = &n->v[n_idx]; + RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + +#if 0 + //- rjf: fill members + if(src_udt->member_count != 0) + { + dst_udt->member_first = dst_member_idx; + dst_udt->member_count = src_udt->member_count; + for(RDIM_UDTMember *src_member = src_udt->first_member; + src_member != 0; + src_member = src_member->next, dst_member_idx += 1) + { + RDI_Member *dst_member = &members[dst_member_idx]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + } + } + + //- rjf: fill enum members + else if(src_udt->enum_val_count != 0) + { + dst_udt->flags |= RDI_UDTFlag_EnumMembers; + dst_udt->member_first = dst_enum_member_idx; + dst_udt->member_count = src_udt->enum_val_count; + for(RDIM_UDTEnumVal *src_member = src_udt->first_enum_val; + src_member != 0; + src_member = src_member->next, dst_enum_member_idx += 1) + { + RDI_EnumMember *dst_member = &enum_members[dst_enum_member_idx]; + dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); + dst_member->val = src_member->val; + } + } +#endif + } + } + } + //- rjf: bake global variables ProfScope("bake global variables") { @@ -833,7 +1067,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) result.unit_vmap = rdim2_shared->baked_unit_vmap; result.src_files = rdim2_shared->baked_src_files; result.line_tables = rdim2_shared->baked_line_tables; - // result.type_nodes = rdim2_shared->baked_type_nodes; + result.type_nodes = rdim2_shared->baked_type_nodes; result.udts = rdim2_shared->baked_udts; result.global_variables = rdim2_shared->baked_global_variables; result.global_vmap = rdim2_shared->baked_global_vmap; diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 5b3dda53..2a1d89a0 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -46,6 +46,9 @@ struct RDIM2_Shared RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; RDIM_BakeIdxRunMap2 *bake_idx_runs; + RDIM_StringBakeResult baked_strings; + RDIM_IndexRunBakeResult baked_idx_runs; + RDIM_UnitBakeResult baked_units; RDIM_UnitVMapBakeResult baked_unit_vmap; RDIM_SrcFileBakeResult baked_src_files; @@ -58,8 +61,6 @@ struct RDIM2_Shared RDIM_ProcedureBakeResult baked_procedures; RDIM_ScopeVMapBakeResult baked_scope_vmap; RDIM_InlineSiteBakeResult baked_inline_sites; - - RDIM_StringBakeResult baked_strings; }; global RDIM2_Shared *rdim2_shared = 0; From e4ac3febd003ae7819a28ca3a334f37d0096c90f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 28 Aug 2025 09:37:25 -0700 Subject: [PATCH 066/302] finish new udt baking; pull members & enum vals out of sub-udt lists, makes it much harder to layout & parallelize - instead pull them aside into their own chunk lists, require that UDTs just point to their first member; that way we can go wide when baking UDT members/enum-vals --- src/lib_rdi_make/rdi_make.c | 112 ++++++++++++++++++++++++++++++ src/lib_rdi_make/rdi_make.h | 32 +++++---- src/rdi_from_pdb/rdi_from_pdb_2.c | 79 ++++++++++++++++----- src/rdi_from_pdb/rdi_from_pdb_2.h | 4 ++ src/rdi_make/rdi_make_local_2.c | 64 ++++++++++------- 5 files changed, 236 insertions(+), 55 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 2e0629b6..7f379840 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -840,6 +840,8 @@ rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList //////////////////////////////// //~ rjf: [Building] Type Info Building +//- rjf: type nodes + RDI_PROC RDIM_Type ** rdim_array_from_type_list(RDIM_Arena *arena, RDIM_TypeList list) { @@ -914,6 +916,116 @@ rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList rdim_memzero_struct(to_push); } +//- rjf: UDT members + +RDI_PROC RDIM_UDTMember * +rdim_udt_member_chunk_list_push(RDIM_Arena *arena, RDIM_UDTMemberChunkList *list, RDI_U64 cap) +{ + RDIM_UDTMemberChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_UDTMemberChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_UDTMember, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_UDTMember *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_udt_member(RDIM_UDTMember *member) +{ + RDI_U64 idx = 0; + if(member != 0 && member->chunk != 0) + { + idx = member->chunk->base_idx + (member - member->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UDTMemberChunkList *to_push) +{ + for(RDIM_UDTMemberChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +//- rjf: UDT enum values + +RDI_PROC RDIM_UDTEnumVal * +rdim_udt_enum_val_chunk_list_push(RDIM_Arena *arena, RDIM_UDTEnumValChunkList *list, RDI_U64 cap) +{ + RDIM_UDTEnumValChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_UDTEnumValChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_UDTEnumVal, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_UDTEnumVal *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_udt_enum_val(RDIM_UDTEnumVal *enum_val) +{ + RDI_U64 idx = 0; + if(enum_val != 0 && enum_val->chunk != 0) + { + idx = enum_val->chunk->base_idx + (enum_val - enum_val->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM_UDTEnumValChunkList *to_push) +{ + for(RDIM_UDTEnumValChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +//- rjf: UDTs + RDI_PROC RDIM_UDT * rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap) { diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 48c563e5..1bfff058 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -723,6 +723,7 @@ struct RDIM_TypeChunkList typedef struct RDIM_UDTMember RDIM_UDTMember; struct RDIM_UDTMember { + struct RDIM_UDTMemberChunkNode *chunk; RDIM_UDTMember *next; RDI_MemberKind kind; RDIM_String8 name; @@ -730,13 +731,6 @@ struct RDIM_UDTMember RDI_U32 off; }; -typedef struct RDIM_UDTMemberNode RDIM_UDTMemberNode; -struct RDIM_UDTMemberNode -{ - RDIM_UDTMemberNode *next; - RDIM_UDTMember *v; -}; - typedef struct RDIM_UDTMemberChunkNode RDIM_UDTMemberChunkNode; struct RDIM_UDTMemberChunkNode { @@ -761,18 +755,12 @@ struct RDIM_UDTMemberChunkList typedef struct RDIM_UDTEnumVal RDIM_UDTEnumVal; struct RDIM_UDTEnumVal { + struct RDIM_UDTEnumValChunkNode *chunk; RDIM_UDTEnumVal *next; RDIM_String8 name; RDI_U64 val; }; -typedef struct RDIM_UDTEnumValNode RDIM_UDTEnumValNode; -struct RDIM_UDTEnumValNode -{ - RDIM_UDTEnumValNode *next; - RDIM_UDTEnumVal *v; -}; - typedef struct RDIM_UDTEnumValChunkNode RDIM_UDTEnumValChunkNode; struct RDIM_UDTEnumValChunkNode { @@ -1012,6 +1000,8 @@ struct RDIM_BakeParams RDIM_UnitChunkList units; RDIM_TypeChunkList types; RDIM_UDTChunkList udts; + RDIM_UDTMemberChunkList members; + RDIM_UDTEnumValChunkList enum_vals; RDIM_SrcFileChunkList src_files; RDIM_LineTableChunkList line_tables; RDIM_SymbolChunkList global_variables; @@ -1636,12 +1626,26 @@ RDI_PROC void rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM //////////////////////////////// //~ rjf: [Building] Type Info & UDT Building +//- rjf: type nodes RDI_PROC RDIM_Type *rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap); RDI_PROC RDI_U64 rdim_idx_from_type(RDIM_Type *type); RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push); + +//- rjf: UDT members +RDI_PROC RDIM_UDTMember *rdim_udt_member_chunk_list_push(RDIM_Arena *arena, RDIM_UDTMemberChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_udt_member(RDIM_UDTMember *member); +RDI_PROC void rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UDTMemberChunkList *to_push); + +//- rjf: UDT enum values +RDI_PROC RDIM_UDTEnumVal *rdim_udt_enum_val_chunk_list_push(RDIM_Arena *arena, RDIM_UDTEnumValChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_udt_enum_val(RDIM_UDTEnumVal *enum_val); +RDI_PROC void rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM_UDTEnumValChunkList *to_push); + +//- rjf: UDTs RDI_PROC RDIM_UDT *rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap); RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt); RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push); + RDI_PROC RDIM_UDTMember *rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); RDI_PROC RDIM_UDTEnumVal *rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index cb8e373d..eeb869c6 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2266,13 +2266,19 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) if(lane_idx() == 0) { p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); + p2r2_shared->lanes_members = push_array(arena, RDIM_UDTMemberChunkList, lane_count()); + p2r2_shared->lanes_enum_vals = push_array(arena, RDIM_UDTEnumValChunkList, lane_count()); } lane_sync(); //- rjf: do wide fill { - U64 udts_chunk_cap = 1024; + U64 udts_chunk_cap = 4096; + U64 members_chunk_cap = 4096; + U64 enum_vals_chunk_cap = 4096; RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; + RDIM_UDTMemberChunkList *members = &p2r2_shared->lanes_members[lane_idx()]; + RDIM_UDTEnumValChunkList *enum_vals = &p2r2_shared->lanes_enum_vals[lane_idx()]; Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { @@ -2404,6 +2410,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: process field + RDIM_UDTMember *new_member = 0; switch(field_kind) { //- rjf: unhandled/invalid cases @@ -2459,11 +2466,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_DataField; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); mem->off = (U32)offset64; + new_member = mem; }break; //- rjf: STMEMBER @@ -2480,10 +2488,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_StaticData; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); + new_member = mem; }break; //- rjf: METHOD @@ -2557,27 +2566,30 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { default: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; + new_member = mem; }break; case CV_MethodProp_Static: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; + new_member = mem; }break; case CV_MethodProp_Virtual: case CV_MethodProp_PureVirtual: case CV_MethodProp_Intro: case CV_MethodProp_PureIntro: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; + new_member = mem; }break; } } @@ -2612,29 +2624,30 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { default: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; + new_member = mem; }break; - case CV_MethodProp_Static: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; + new_member = mem; }break; - case CV_MethodProp_Virtual: case CV_MethodProp_PureVirtual: case CV_MethodProp_Intro: case CV_MethodProp_PureIntro: { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; + new_member = mem; }break; } }break; @@ -2651,10 +2664,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); + new_member = mem; }break; //- rjf: NESTTYPEEX @@ -2671,10 +2685,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); + new_member = mem; }break; //- rjf: BCLASS @@ -2692,10 +2707,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = offset_ptr+offset.encoded_size; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_Base; mem->type = p2r_type_ptr_from_itype(lf->itype); mem->off = (U32)offset64; + new_member = mem; }break; //- rjf: VBCLASS/IVBCLASS @@ -2717,9 +2733,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = (U8 *)(lf+1); // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); mem->kind = RDI_MemberKind_VirtualBase; mem->type = p2r_type_ptr_from_itype(lf->itype); + new_member = mem; }break; //- rjf: VFUNCTAB @@ -2735,6 +2752,16 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }break; } + // rjf: add member to UDT + if(new_member != 0) + { + if(dst_udt->first_member == 0) + { + dst_udt->first_member = new_member; + } + dst_udt->member_count += 1; + } + // rjf: align-up next field next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); } @@ -2825,6 +2852,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: process field + RDIM_UDTEnumVal *new_enum_val = 0; switch(field_kind) { //- rjf: unhandled/invalid cases @@ -2877,12 +2905,23 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); + RDIM_UDTEnumVal *enum_val = rdim_udt_enum_val_chunk_list_push(arena, enum_vals, enum_vals_chunk_cap); enum_val->name = name; enum_val->val = val64; + new_enum_val = enum_val; }break; } + // rjf: push new enum val to udt + if(new_enum_val != 0) + { + if(dst_udt->first_enum_val == 0) + { + dst_udt->first_enum_val = new_enum_val; + } + dst_udt->enum_val_count += 1; + } + // rjf: align-up next field next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); } @@ -2898,6 +2937,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } lane_sync(); RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; + RDIM_UDTMemberChunkList *lanes_members = p2r2_shared->lanes_members; + RDIM_UDTEnumValChunkList *lanes_enum_vals = p2r2_shared->lanes_enum_vals; ////////////////////////////////////////////////////////////// //- rjf: join all UDTs @@ -2907,10 +2948,14 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) for EachIndex(idx, lane_count()) { rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); + rdim_udt_member_chunk_list_concat_in_place(&p2r2_shared->all_members, &lanes_members[idx]); + rdim_udt_enum_val_chunk_list_concat_in_place(&p2r2_shared->all_enum_vals, &lanes_enum_vals[idx]); } } lane_sync(); RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; + RDIM_UDTMemberChunkList all_members = p2r2_shared->all_members; + RDIM_UDTEnumValChunkList all_enum_vals = p2r2_shared->all_enum_vals; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams @@ -3957,6 +4002,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) result.units = all_units; result.types = all_types; result.udts = all_udts; + result.members = all_members; + result.enum_vals = all_enum_vals; result.src_files = all_src_files; result.line_tables = all_line_tables; result.global_variables = all_global_variables; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index b3a0aa8a..709fa5b2 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -111,8 +111,12 @@ struct P2R2_Shared RDIM_TypeChunkList all_types__pre_typedefs; RDIM_UDTChunkList *lanes_udts; + RDIM_UDTMemberChunkList *lanes_members; + RDIM_UDTEnumValChunkList *lanes_enum_vals; RDIM_UDTChunkList all_udts; + RDIM_UDTMemberChunkList all_members; + RDIM_UDTEnumValChunkList all_enum_vals; RDIM_SymbolChunkList *lanes_procedures; RDIM_SymbolChunkList *lanes_global_variables; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index b2eb1350..6b765e19 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -778,12 +778,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(5)) { - rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; + rdim2_shared->baked_udts.members_count = params->members.total_count+1; rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); } if(lane_idx() == lane_from_task_idx(6)) { - rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; + rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); } if(lane_idx() == lane_from_task_idx(7)) @@ -919,6 +919,40 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } + //- rjf: bake UDT members + ProfScope("bake UDT members") + { + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTMember *src_member = &n->v[n_idx]; + RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + } + } + } + + //- rjf: bake UDT enum vals + ProfScope("bake UDT enum vals") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTEnumVal *src_member = &n->v[n_idx]; + RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->val = src_member->val; + } + } + } + //- rjf: bake UDTs ProfScope("bake UDTs") { @@ -936,40 +970,20 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) dst_udt->line = src_udt->line; dst_udt->col = src_udt->col; -#if 0 - //- rjf: fill members + //- rjf: fill member info if(src_udt->member_count != 0) { - dst_udt->member_first = dst_member_idx; + dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); dst_udt->member_count = src_udt->member_count; - for(RDIM_UDTMember *src_member = src_udt->first_member; - src_member != 0; - src_member = src_member->next, dst_member_idx += 1) - { - RDI_Member *dst_member = &members[dst_member_idx]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - } } //- rjf: fill enum members else if(src_udt->enum_val_count != 0) { dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = dst_enum_member_idx; + dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); dst_udt->member_count = src_udt->enum_val_count; - for(RDIM_UDTEnumVal *src_member = src_udt->first_enum_val; - src_member != 0; - src_member = src_member->next, dst_enum_member_idx += 1) - { - RDI_EnumMember *dst_member = &enum_members[dst_enum_member_idx]; - dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); - dst_member->val = src_member->val; - } } -#endif } } } From 71cbdba76eab9040fc92578dd114248463298004 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 28 Aug 2025 11:54:53 -0700 Subject: [PATCH 067/302] remove old section requirement part of rdi, since all sections are now fixed; unit/scope/global vmap baking; collapse chunk list impls --- src/lib_rdi/rdi.c | 44 --- src/lib_rdi/rdi.h | 1 - src/lib_rdi/rdi_parse.c | 21 -- src/lib_rdi/rdi_parse.h | 1 - src/lib_rdi_make/rdi_make.c | 497 ++++++++---------------------- src/lib_rdi_make/rdi_make.h | 36 +++ src/radbin/radbin.c | 1 - src/rdi/rdi.mdesk | 87 +++--- src/rdi_from_pdb/rdi_from_pdb_2.c | 21 ++ src/rdi_make/rdi_make_local_2.c | 74 ++++- src/rdi_make/rdi_make_local_2.h | 9 +- 11 files changed, 300 insertions(+), 492 deletions(-) diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 29e98bdb..7d6ffc4c 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -54,50 +54,6 @@ sizeof(RDI_NameMapNode), sizeof(RDI_U8), }; -RDI_U8 rdi_section_is_required_table[40] = -{ -0, -0, -1, -1, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -}; - RDI_U16 rdi_eval_op_ctrlbits_table[52] = { RDI_EVAL_CTRLBITS(0, 0, 0), diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 550a26b9..2be07ad4 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -1572,7 +1572,6 @@ RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTyp RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); extern RDI_U16 rdi_section_element_size_table[40]; -extern RDI_U8 rdi_section_is_required_table[40]; extern RDI_U16 rdi_eval_op_ctrlbits_table[52]; #endif // RDI_H diff --git a/src/lib_rdi/rdi_parse.c b/src/lib_rdi/rdi_parse.c index b4ebc551..b0ea1ff4 100644 --- a/src/lib_rdi/rdi_parse.c +++ b/src/lib_rdi/rdi_parse.c @@ -214,27 +214,6 @@ rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out) out->sections_count = dsec_count; } - ////////////////////////////// - //- rjf: validate results - // - if(result == RDI_ParseStatus_Good) - { - for(RDI_SectionKind k = (RDI_SectionKind)(RDI_SectionKind_NULL+1); k < RDI_SectionKind_COUNT; k = (RDI_SectionKind)(k+1)) - { - if(rdi_section_is_required_table[k]) - { - RDI_U64 data_size = 0; - RDI_SectionEncoding encoding = 0; - void *data = rdi_section_raw_data_from_kind(out, k, &encoding, &data_size); - if(data == 0 || data == &rdi_nil_element_union || data_size == 0) - { - result = RDI_ParseStatus_MissingRequiredSection; - break; - } - } - } - } - return result; } diff --git a/src/lib_rdi/rdi_parse.h b/src/lib_rdi/rdi_parse.h index 7ea6193c..b03f0bc4 100644 --- a/src/lib_rdi/rdi_parse.h +++ b/src/lib_rdi/rdi_parse.h @@ -50,7 +50,6 @@ typedef enum RDI_ParseStatus RDI_ParseStatus_HeaderDoesNotMatch = 1, RDI_ParseStatus_UnsupportedVersionNumber = 2, RDI_ParseStatus_InvalidDataSecionLayout = 3, - RDI_ParseStatus_MissingRequiredSection = 4, } RDI_ParseStatus; diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 7f379840..4d2d2f1d 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -4,8 +4,51 @@ //////////////////////////////// //~ rjf: API Implementation Helper Macros -#define rdim_require(root, b32, else_code, error_msg) do { if(!(b32)) {rdim_push_msg((root), (error_msg)); else_code;} }while(0) -#define rdim_requiref(root, b32, else_code, fmt, ...) do { if(!(b32)) {rdim_push_msgf((root), (fmt), __VA_ARGS__); else_code;} }while(0) +#define RDIM_IdxedChunkListPush(arena, list, chunk_type, element_type, cap_value, result) \ +element_type *result = 0;\ +do\ +{\ +chunk_type *n = list->last;\ +if(n == 0 || n->count >= n->cap)\ +{\ +n = rdim_push_array(arena, chunk_type, 1);\ +n->cap = cap_value;\ +n->base_idx = list->total_count;\ +n->v = rdim_push_array_no_zero(arena, element_type, n->cap);\ +RDIM_SLLQueuePush(list->first, list->last, n);\ +list->chunk_count += 1;\ +}\ +result = &n->v[n->count];\ +result->chunk = n;\ +n->count += 1;\ +list->total_count += 1;\ +}while(0) + +#define RDIM_IdxedChunkListElementGetIdx(ptr, result) \ +RDI_U64 idx = 0;\ +if(ptr != 0 && ptr->chunk != 0)\ +{\ +idx = ptr->chunk->base_idx + (ptr - ptr->chunk->v) + 1;\ +} + +#define RDIM_IdxedChunkListConcatInPlace(chunk_type, dst, to_push, ...) \ +for(chunk_type *n = to_push->first; n != 0; n = n->next)\ +{\ +n->base_idx += dst->total_count;\ +}\ +if(dst->last != 0 && to_push->first != 0)\ +{\ +dst->last->next = to_push->first;\ +dst->last = to_push->last;\ +dst->chunk_count += to_push->chunk_count;\ +dst->total_count += to_push->total_count;\ +__VA_ARGS__;\ +}\ +else if(dst->first == 0)\ +{\ +rdim_memcpy_struct(dst, to_push);\ +}\ +rdim_memzero_struct(to_push); //////////////////////////////// //~ rjf: Basic Helpers @@ -277,6 +320,12 @@ rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) //- rjf: sortable range sorting +RSFORCEINLINE int +rdim_sort_key_is_before(void *l, void *r) +{ + return ((RDIM_SortKey *)l)->key < ((RDIM_SortKey *)r)->key; +} + RDI_PROC RDIM_SortKey * rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) { @@ -286,6 +335,7 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) // Also - this sort should be a "stable" sort. In the use case of sorting vmap // ranges, we want to be able to rely on order, so it needs to be preserved here. + RDIM_ProfBegin("rdim_sort_key_array"); RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); RDIM_SortKey *result = 0; @@ -436,6 +486,7 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) #endif rdim_scratch_end(scratch); + RDIM_ProfEnd(); return result; } @@ -641,55 +692,23 @@ rdim_binary_section_list_push(RDIM_Arena *arena, RDIM_BinarySectionList *list) RDI_PROC RDIM_SrcFile * rdim_src_file_chunk_list_push(RDIM_Arena *arena, RDIM_SrcFileChunkList *list, RDI_U64 cap) { - RDIM_SrcFileChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_SrcFileChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_SrcFile, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_SrcFile *src_file = &n->v[n->count]; - src_file->chunk = n; - n->count += 1; - list->total_count += 1; - return src_file; + RDIM_IdxedChunkListPush(arena, list, RDIM_SrcFileChunkNode, RDIM_SrcFile, cap, result); + return result; } RDI_PROC RDI_U64 rdim_idx_from_src_file(RDIM_SrcFile *src_file) { - RDI_U64 idx = 0; - if(src_file != 0 && src_file->chunk != 0) - { - idx = (src_file->chunk->base_idx + (src_file - src_file->chunk->v) + 1); - } + RDIM_IdxedChunkListElementGetIdx(src_file, idx); return idx; } RDI_PROC void rdim_src_file_chunk_list_concat_in_place(RDIM_SrcFileChunkList *dst, RDIM_SrcFileChunkList *to_push) { - for(RDIM_SrcFileChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - dst->source_line_map_count += to_push->source_line_map_count; - dst->total_line_count += to_push->total_line_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_SrcFileChunkNode, dst, to_push, + dst->source_line_map_count += to_push->source_line_map_count, + dst->total_line_count += to_push->total_line_count); } RDI_PROC void @@ -711,56 +730,24 @@ rdim_src_file_push_line_sequence(RDIM_Arena *arena, RDIM_SrcFileChunkList *src_f RDI_PROC RDIM_LineTable * rdim_line_table_chunk_list_push(RDIM_Arena *arena, RDIM_LineTableChunkList *list, RDI_U64 cap) { - RDIM_LineTableChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_LineTableChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_LineTable, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_LineTable *line_table = &n->v[n->count]; - line_table->chunk = n; - n->count += 1; - list->total_count += 1; - return line_table; + RDIM_IdxedChunkListPush(arena, list, RDIM_LineTableChunkNode, RDIM_LineTable, cap, result); + return result; } RDI_PROC RDI_U64 rdim_idx_from_line_table(RDIM_LineTable *line_table) { - RDI_U64 idx = 0; - if(line_table != 0 && line_table->chunk != 0) - { - idx = line_table->chunk->base_idx + (line_table - line_table->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(line_table, idx); return idx; } RDI_PROC void rdim_line_table_chunk_list_concat_in_place(RDIM_LineTableChunkList *dst, RDIM_LineTableChunkList *to_push) { - for(RDIM_LineTableChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - dst->total_seq_count += to_push->total_seq_count; - dst->total_line_count += to_push->total_line_count; - dst->total_col_count += to_push->total_col_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_LineTableChunkNode, dst, to_push, + dst->total_seq_count += to_push->total_seq_count, + dst->total_line_count += to_push->total_line_count, + dst->total_col_count += to_push->total_col_count); } RDI_PROC RDIM_LineSequence * @@ -788,53 +775,21 @@ rdim_line_table_push_sequence(RDIM_Arena *arena, RDIM_LineTableChunkList *line_t RDI_PROC RDIM_Unit * rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDI_U64 cap) { - RDIM_UnitChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_UnitChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_Unit, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_Unit *unit = &n->v[n->count]; - unit->chunk = n; - n->count += 1; - list->total_count += 1; - return unit; + RDIM_IdxedChunkListPush(arena, list, RDIM_UnitChunkNode, RDIM_Unit, cap, result); + return result; } RDI_PROC RDI_U64 rdim_idx_from_unit(RDIM_Unit *unit) { - RDI_U64 idx = 0; - if(unit != 0 && unit->chunk != 0) - { - idx = unit->chunk->base_idx + (unit - unit->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(unit, idx); return idx; } RDI_PROC void rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push) { - for(RDIM_UnitChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_UnitChunkNode, dst, to_push); } //////////////////////////////// @@ -867,53 +822,21 @@ rdim_type_list_push(RDIM_Arena *arena, RDIM_TypeList *list, RDIM_Type *v) RDI_PROC RDIM_Type * rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap) { - RDIM_TypeChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_TypeChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_Type, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_Type *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_TypeChunkNode, RDIM_Type, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_type(RDIM_Type *type) { - RDI_U64 idx = 0; - if(type != 0 && type->chunk != 0) - { - idx = type->chunk->base_idx + (type - type->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(type, idx); return idx; } RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push) { - for(RDIM_TypeChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_TypeChunkNode, dst, to_push); } //- rjf: UDT members @@ -921,53 +844,21 @@ rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList RDI_PROC RDIM_UDTMember * rdim_udt_member_chunk_list_push(RDIM_Arena *arena, RDIM_UDTMemberChunkList *list, RDI_U64 cap) { - RDIM_UDTMemberChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_UDTMemberChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_UDTMember, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_UDTMember *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_UDTMemberChunkNode, RDIM_UDTMember, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_udt_member(RDIM_UDTMember *member) { - RDI_U64 idx = 0; - if(member != 0 && member->chunk != 0) - { - idx = member->chunk->base_idx + (member - member->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(member, idx); return idx; } RDI_PROC void rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UDTMemberChunkList *to_push) { - for(RDIM_UDTMemberChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_UDTMemberChunkNode, dst, to_push); } //- rjf: UDT enum values @@ -975,53 +866,21 @@ rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UD RDI_PROC RDIM_UDTEnumVal * rdim_udt_enum_val_chunk_list_push(RDIM_Arena *arena, RDIM_UDTEnumValChunkList *list, RDI_U64 cap) { - RDIM_UDTEnumValChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_UDTEnumValChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_UDTEnumVal, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_UDTEnumVal *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_UDTEnumValChunkNode, RDIM_UDTEnumVal, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_udt_enum_val(RDIM_UDTEnumVal *enum_val) { - RDI_U64 idx = 0; - if(enum_val != 0 && enum_val->chunk != 0) - { - idx = enum_val->chunk->base_idx + (enum_val - enum_val->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(enum_val, idx); return idx; } RDI_PROC void rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM_UDTEnumValChunkList *to_push) { - for(RDIM_UDTEnumValChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_UDTEnumValChunkNode, dst, to_push); } //- rjf: UDTs @@ -1029,55 +888,23 @@ rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM RDI_PROC RDIM_UDT * rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap) { - RDIM_UDTChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_UDTChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_UDT, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_UDT *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_UDTChunkNode, RDIM_UDT, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt) { - RDI_U64 idx = 0; - if(udt != 0 && udt->chunk != 0) - { - idx = udt->chunk->base_idx + (udt - udt->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(udt, idx); return idx; } RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push) { - for(RDIM_UDTChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - dst->total_member_count += to_push->total_member_count; - dst->total_enum_val_count += to_push->total_enum_val_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_UDTChunkNode, dst, to_push, + dst->total_member_count += to_push->total_member_count, + dst->total_enum_val_count += to_push->total_enum_val_count); } RDI_PROC RDIM_UDTMember * @@ -1106,54 +933,21 @@ rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt RDI_PROC RDIM_Symbol * rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U64 cap) { - RDIM_SymbolChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_SymbolChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_Symbol, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_Symbol *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_SymbolChunkNode, RDIM_Symbol, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_symbol(RDIM_Symbol *symbol) { - RDI_U64 idx = 0; - if(symbol != 0 && symbol->chunk != 0) - { - idx = symbol->chunk->base_idx + (symbol - symbol->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(symbol, idx); return idx; } RDI_PROC void rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push) { - for(RDIM_SymbolChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - dst->total_value_data_size += to_push->total_value_data_size; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_SymbolChunkNode, dst, to_push, dst->total_value_data_size += to_push->total_value_data_size); } internal void @@ -1169,53 +963,36 @@ rdim_symbol_push_value_data(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDIM_ RDI_PROC RDIM_InlineSite * rdim_inline_site_chunk_list_push(RDIM_Arena *arena, RDIM_InlineSiteChunkList *list, RDI_U64 cap) { - RDIM_InlineSiteChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_InlineSiteChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_InlineSite, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_InlineSite *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_InlineSiteChunkNode, RDIM_InlineSite, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_inline_site(RDIM_InlineSite *inline_site) { - RDI_U64 idx = 0; - if(inline_site != 0 && inline_site->chunk != 0) - { - idx = inline_site->chunk->base_idx + (inline_site - inline_site->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(inline_site, idx); return idx; } RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_InlineSiteChunkList *to_push) { - for(RDIM_InlineSiteChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_InlineSiteChunkNode, dst, to_push); +} + +//////////////////////////////// +//~ rjf: [Building] Location Info Building + +RDI_PROC RDIM_Location * +rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_Location *loc) +{ + +} + +RDI_PROC void +rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push) +{ + } //////////////////////////////// @@ -1226,56 +1003,24 @@ rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_ RDI_PROC RDIM_Scope * rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap) { - RDIM_ScopeChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) - { - n = rdim_push_array(arena, RDIM_ScopeChunkNode, 1); - n->cap = cap; - n->base_idx = list->total_count; - n->v = rdim_push_array(arena, RDIM_Scope, n->cap); - RDIM_SLLQueuePush(list->first, list->last, n); - list->chunk_count += 1; - } - RDIM_Scope *result = &n->v[n->count]; - result->chunk = n; - n->count += 1; - list->total_count += 1; + RDIM_IdxedChunkListPush(arena, list, RDIM_ScopeChunkNode, RDIM_Scope, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_scope(RDIM_Scope *scope) { - RDI_U64 idx = 0; - if(scope != 0 && scope->chunk != 0) - { - idx = scope->chunk->base_idx + (scope - scope->chunk->v) + 1; - } + RDIM_IdxedChunkListElementGetIdx(scope, idx); return idx; } RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push) { - for(RDIM_ScopeChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_count; - } - if(dst->last != 0 && to_push->first != 0) - { - dst->last->next = to_push->first; - dst->last = to_push->last; - dst->chunk_count += to_push->chunk_count; - dst->total_count += to_push->total_count; - dst->scope_voff_count += to_push->scope_voff_count; - dst->local_count += to_push->local_count; - dst->location_count += to_push->location_count; - } - else if(dst->first == 0) - { - rdim_memcpy_struct(dst, to_push); - } - rdim_memzero_struct(to_push); + RDIM_IdxedChunkListConcatInPlace(RDIM_ScopeChunkNode, dst, to_push, + dst->scope_voff_count += to_push->scope_voff_count, + dst->local_count += to_push->local_count, + dst->location_count += to_push->location_count); } RDI_PROC void @@ -1464,6 +1209,7 @@ rdim_count_from_location_block_chunk_list(RDIM_String8List *list) RDI_PROC RDIM_BakeVMap rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count) { + RDIM_ProfBegin("rdim_bake_vmap_from_markers"); RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); //- rjf: sort markers @@ -1599,6 +1345,7 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So result.vmap = vmap; result.count = vmap_entry_count; rdim_scratch_end(scratch); + RDIM_ProfEnd(); return result; } @@ -2684,6 +2431,24 @@ rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMap } } +RDI_PROC void +rdim_bake_string_map_loose_push_udt_member_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTMember *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_udt_enum_val_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTEnumVal *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); + } +} + RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count) { diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 1bfff058..2c48b916 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -822,6 +822,8 @@ struct RDIM_UDTChunkList //////////////////////////////// //~ rjf: Location Info Types +//- rjf: bytecode types + typedef struct RDIM_EvalBytecodeOp RDIM_EvalBytecodeOp; struct RDIM_EvalBytecodeOp { @@ -840,6 +842,8 @@ struct RDIM_EvalBytecode RDI_U32 encoded_size; }; +//- rjf: location types + typedef struct RDIM_Location RDIM_Location; struct RDIM_Location { @@ -849,6 +853,29 @@ struct RDIM_Location RDIM_EvalBytecode bytecode; }; +typedef struct RDIM_LocationChunkNode RDIM_LocationChunkNode; +struct RDIM_LocationChunkNode +{ + RDIM_LocationChunkNode *next; + RDIM_Location *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; + RDI_U64 base_encoding_off; +}; + +typedef struct RDIM_LocationChunkList RDIM_LocationChunkList; +struct RDIM_LocationChunkList +{ + RDIM_LocationChunkNode *first; + RDIM_LocationChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; + RDI_U64 total_encoded_size; +}; + +//- rjf: location case types (location * voff range) + typedef struct RDIM_LocationCase RDIM_LocationCase; struct RDIM_LocationCase { @@ -1646,6 +1673,7 @@ RDI_PROC RDIM_UDT *rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt); RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push); +//- TODO(rjf): to be removed: RDI_PROC RDIM_UDTMember *rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); RDI_PROC RDIM_UDTEnumVal *rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); @@ -1664,6 +1692,12 @@ RDI_PROC RDIM_InlineSite *rdim_inline_site_chunk_list_push(RDIM_Arena *arena, RD RDI_PROC RDI_U64 rdim_idx_from_inline_site(RDIM_InlineSite *inline_site); RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_InlineSiteChunkList *to_push); +//////////////////////////////// +//~ rjf: [Building] Location Info Building + +RDI_PROC RDIM_Location *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_Location *loc); +RDI_PROC void rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push); + //////////////////////////////// //~ rjf: [Building] Scope Info Building @@ -1782,6 +1816,8 @@ RDI_PROC void rdim_bake_string_map_loose_push_path_tree(RDIM_Arena *arena, RDIM_ RDI_PROC void rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFile *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Unit *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_udt_member_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTMember *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_udt_enum_val_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTEnumVal *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count); RDI_PROC void rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count); diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index c8aa38cc..5d2e2436 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -1031,7 +1031,6 @@ rb_thread_entry_point(void *p) case RDI_ParseStatus_HeaderDoesNotMatch: {log_user_errorf("RDI parse failure: header does not match\n");}break; case RDI_ParseStatus_UnsupportedVersionNumber:{log_user_errorf("RDI parse failure: unsupported version\n");}break; case RDI_ParseStatus_InvalidDataSecionLayout: {log_user_errorf("RDI parse failure: invalid data section layout\n");}break; - case RDI_ParseStatus_MissingRequiredSection: {log_user_errorf("RDI parse failure: missing required section\n");}break; case RDI_ParseStatus_Good: { String8List dump = rdi_dump_list_from_parsed(arena, &rdi, rdi_dump_subset_flags); diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 49a22dc9..726913c5 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -117,49 +117,49 @@ RDI_HeaderMemberTable: //////////////////////////////// //~ rjf: Format Section Tables -@table(name name_lower element_type value is_required index_base_type desc) +@table(name name_lower element_type value index_base_type desc) RDI_SectionTable: { - {NULL null RDI_U8 0x0000 - - ""} - {TopLevelInfo top_level_info RDI_TopLevelInfo 0x0001 - - ""} - {StringData string_data RDI_U8 0x0002 x - ""} - {StringTable string_table RDI_U32 0x0003 x U32 ""} - {IndexRuns index_runs RDI_U32 0x0004 x U32 ""} - {BinarySections binary_sections RDI_BinarySection 0x0005 - U32 ""} - {FilePathNodes file_path_nodes RDI_FilePathNode 0x0006 - U32 ""} - {SourceFiles source_files RDI_SourceFile 0x0007 - U32 ""} - {LineTables line_tables RDI_LineTable 0x0008 - U32 ""} - {LineInfoVOffs line_info_voffs RDI_U64 0x0009 - U32 ""} - {LineInfoLines line_info_lines RDI_Line 0x000A - U32 ""} - {LineInfoColumns line_info_columns RDI_Column 0x000B - U32 ""} - {SourceLineMaps source_line_maps RDI_SourceLineMap 0x000C - U32 ""} - {SourceLineMapNumbers source_line_map_numbers RDI_U32 0x000D - U32 ""} - {SourceLineMapRanges source_line_map_ranges RDI_U32 0x000E - U32 ""} - {SourceLineMapVOffs source_line_map_voffs RDI_U64 0x000F - U32 ""} - {Units units RDI_Unit 0x0010 - U32 ""} - {UnitVMap unit_vmap RDI_VMapEntry 0x0011 - - ""} - {TypeNodes type_nodes RDI_TypeNode 0x0012 - U32 ""} - {UDTs udts RDI_UDT 0x0013 - U32 ""} - {Members members RDI_Member 0x0014 - U32 ""} - {EnumMembers enum_members RDI_EnumMember 0x0015 - U32 ""} - {GlobalVariables global_variables RDI_GlobalVariable 0x0016 - U32 ""} - {GlobalVMap global_vmap RDI_VMapEntry 0x0017 - - ""} - {ThreadVariables thread_variables RDI_ThreadVariable 0x0018 - U32 ""} - {Constants constants RDI_Constant 0x0019 - U32 ""} - {Procedures procedures RDI_Procedure 0x001A - U32 ""} - {Scopes scopes RDI_Scope 0x001B - U32 ""} - {ScopeVOffData scope_voff_data RDI_U64 0x001C - U32 ""} - {ScopeVMap scope_vmap RDI_VMapEntry 0x001D - - ""} - {InlineSites inline_sites RDI_InlineSite 0x001E - U32 ""} - {Locals locals RDI_Local 0x001F - U32 ""} - {LocationBlocks location_blocks RDI_LocationBlock 0x0020 - U32 ""} - {LocationData location_data RDI_U8 0x0021 - U32 ""} - {ConstantValueData constant_value_data RDI_U8 0x0022 - U32 ""} - {ConstantValueTable constant_value_table RDI_U32 0x0023 - U32 ""} - {NameMaps name_maps RDI_NameMap 0x0024 - U32 ""} - {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0025 - U32 ""} - {NameMapNodes name_map_nodes RDI_NameMapNode 0x0026 - U32 ""} - {COUNT count RDI_U8 0x0027 - - ""} + {NULL null RDI_U8 0x0000 - ""} + {TopLevelInfo top_level_info RDI_TopLevelInfo 0x0001 - ""} + {StringData string_data RDI_U8 0x0002 - ""} + {StringTable string_table RDI_U32 0x0003 U32 ""} + {IndexRuns index_runs RDI_U32 0x0004 U32 ""} + {BinarySections binary_sections RDI_BinarySection 0x0005 U32 ""} + {FilePathNodes file_path_nodes RDI_FilePathNode 0x0006 U32 ""} + {SourceFiles source_files RDI_SourceFile 0x0007 U32 ""} + {LineTables line_tables RDI_LineTable 0x0008 U32 ""} + {LineInfoVOffs line_info_voffs RDI_U64 0x0009 U32 ""} + {LineInfoLines line_info_lines RDI_Line 0x000A U32 ""} + {LineInfoColumns line_info_columns RDI_Column 0x000B U32 ""} + {SourceLineMaps source_line_maps RDI_SourceLineMap 0x000C U32 ""} + {SourceLineMapNumbers source_line_map_numbers RDI_U32 0x000D U32 ""} + {SourceLineMapRanges source_line_map_ranges RDI_U32 0x000E U32 ""} + {SourceLineMapVOffs source_line_map_voffs RDI_U64 0x000F U32 ""} + {Units units RDI_Unit 0x0010 U32 ""} + {UnitVMap unit_vmap RDI_VMapEntry 0x0011 - ""} + {TypeNodes type_nodes RDI_TypeNode 0x0012 U32 ""} + {UDTs udts RDI_UDT 0x0013 U32 ""} + {Members members RDI_Member 0x0014 U32 ""} + {EnumMembers enum_members RDI_EnumMember 0x0015 U32 ""} + {GlobalVariables global_variables RDI_GlobalVariable 0x0016 U32 ""} + {GlobalVMap global_vmap RDI_VMapEntry 0x0017 - ""} + {ThreadVariables thread_variables RDI_ThreadVariable 0x0018 U32 ""} + {Constants constants RDI_Constant 0x0019 U32 ""} + {Procedures procedures RDI_Procedure 0x001A U32 ""} + {Scopes scopes RDI_Scope 0x001B U32 ""} + {ScopeVOffData scope_voff_data RDI_U64 0x001C U32 ""} + {ScopeVMap scope_vmap RDI_VMapEntry 0x001D - ""} + {InlineSites inline_sites RDI_InlineSite 0x001E U32 ""} + {Locals locals RDI_Local 0x001F U32 ""} + {LocationBlocks location_blocks RDI_LocationBlock 0x0020 U32 ""} + {LocationData location_data RDI_U8 0x0021 U32 ""} + {ConstantValueData constant_value_data RDI_U8 0x0022 U32 ""} + {ConstantValueTable constant_value_table RDI_U32 0x0023 U32 ""} + {NameMaps name_maps RDI_NameMap 0x0024 U32 ""} + {NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0025 U32 ""} + {NameMapNodes name_map_nodes RDI_NameMapNode 0x0026 U32 ""} + {COUNT count RDI_U8 0x0027 - ""} } @table(name value) @@ -232,11 +232,6 @@ RDI_SectionMemberTable: @expand(RDI_SectionTable a) `sizeof($(a.element_type))`; } -@data(RDI_U8) rdi_section_is_required_table: -{ - @expand(RDI_SectionTable a) `$(a.is_required == 'x' -> 1)$(a.is_required != 'x' -> 0)`; -} - //////////////////////////////// //~ rjf: Common Type Tables diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index eeb869c6..e5130135 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -889,6 +889,17 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) CV_C13Parsed *src_unit_c13 = all_c13s[idx+1]; RDIM_Unit *dst_unit = &units[idx]; + // rjf: produce unit name + String8 unit_name = src_unit->obj_name; + if(unit_name.size != 0) + { + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) + { + unit_name = unit_name_past_last_slash; + } + } + // rjf: produce obj name/path String8 obj_name = src_unit->obj_name; if(str8_match(obj_name, str8_lit("* Linker *"), 0) || @@ -958,6 +969,16 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } } } + + // rjf: fill unit + dst_unit->unit_name = unit_name; + dst_unit->compiler_name = src_unit_sym->info.compiler_name; + dst_unit->object_file = obj_name; + dst_unit->archive_file = src_unit->group_name; + dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); + dst_unit->line_table = line_table; + dst_unit->voff_ranges = unit_ranges[idx]; + scratch_end(scratch); } } diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 6b765e19..2bd4c0b0 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -238,13 +238,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - // rjf: push strings from udts - ProfScope("udts") + // rjf: push strings from udt members + ProfScope("udt members") { - for(RDIM_UDTChunkNode *n = params->udts.first; n != 0; n = n->next) + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from udt enum values + ProfScope("udt enum values") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } } @@ -339,12 +349,30 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); //- rjf: tighten string table - if(lane_idx() == 0) ProfScope("tighten string table") + ProfScope("tighten string table") { RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; - RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_strings = rdim_bake_string_map_tight_from_loose(arena, map_top, &bake_string_map_base_idxes, map); + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_strings.slots_count = map_top->slots_count; + rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); + rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; + rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + for EachInRange(idx, slot_range) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + } + } + } } } lane_sync(); @@ -1070,13 +1098,41 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: do final baking tasks + // + ProfScope("do final baking tasks") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") + { + rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") + { + rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("bake unit vmap") + { + rdim2_shared->baked_unit_vmap = rdim_bake_unit_vmap(arena, ¶ms->units); + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("bake scope vmap") + { + rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); + } + if(lane_idx() == lane_from_task_idx(4)) ProfScope("bake global vmap") + { + rdim2_shared->baked_global_vmap = rdim_bake_global_vmap(arena, ¶ms->global_variables); + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: package results // RDIM_BakeResults result = {0}; { - // result.top_level_info = rdim2_shared->baked_top_level_info; - // result.binary_sections = rdim2_shared->baked_binary_sections; + result.top_level_info = rdim2_shared->baked_top_level_info; + result.binary_sections = rdim2_shared->baked_binary_sections; result.units = rdim2_shared->baked_units; result.unit_vmap = rdim2_shared->baked_unit_vmap; result.src_files = rdim2_shared->baked_src_files; diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 2a1d89a0..d4d16932 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -50,17 +50,20 @@ struct RDIM2_Shared RDIM_IndexRunBakeResult baked_idx_runs; RDIM_UnitBakeResult baked_units; - RDIM_UnitVMapBakeResult baked_unit_vmap; RDIM_SrcFileBakeResult baked_src_files; RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_UDTBakeResult baked_udts; RDIM_GlobalVariableBakeResult baked_global_variables; - RDIM_GlobalVMapBakeResult baked_global_vmap; RDIM_ThreadVariableBakeResult baked_thread_variables; RDIM_ConstantsBakeResult baked_constants; RDIM_ProcedureBakeResult baked_procedures; - RDIM_ScopeVMapBakeResult baked_scope_vmap; RDIM_InlineSiteBakeResult baked_inline_sites; + + RDIM_TopLevelInfoBakeResult baked_top_level_info; + RDIM_BinarySectionBakeResult baked_binary_sections; + RDIM_UnitVMapBakeResult baked_unit_vmap; + RDIM_ScopeVMapBakeResult baked_scope_vmap; + RDIM_GlobalVMapBakeResult baked_global_vmap; }; global RDIM2_Shared *rdim2_shared = 0; From 3b1aae44d0e1ae0bcbe993dd8dd09068af171b00 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 28 Aug 2025 14:48:28 -0700 Subject: [PATCH 068/302] location info baking --- src/lib_rdi_make/rdi_make.c | 86 ++++++++++++++++++++++-- src/lib_rdi_make/rdi_make.h | 77 ++++++++++++++++++++-- src/rdi_from_pdb/rdi_from_pdb_2.c | 104 ++++++++++++++++++++++++++---- src/rdi_from_pdb/rdi_from_pdb_2.h | 7 ++ src/rdi_make/rdi_make_local_2.c | 60 +++++++++++++++-- src/rdi_make/rdi_make_local_2.h | 1 + 6 files changed, 309 insertions(+), 26 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 4d2d2f1d..e19ad8bb 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -983,16 +983,94 @@ rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_ //////////////////////////////// //~ rjf: [Building] Location Info Building -RDI_PROC RDIM_Location * -rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_Location *loc) +RDI_PROC RDI_U64 +rdim_encoded_size_from_location_info(RDIM_LocationInfo *info) { - + RDI_U64 result = 0; + switch((RDI_LocationKindEnum)info->kind) + { + case RDI_LocationKind_NULL:{}break; + + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + result = sizeof(RDI_LocationBytecodeStream) + info->bytecode.encoded_size + 1; + }break; + + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + result = sizeof(RDI_LocationRegPlusU16); + }break; + + case RDI_LocationKind_ValReg: + { + result = sizeof(RDI_LocationReg); + }break; + } + return result; +} + +RDI_PROC RDIM_Location2 * +rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info) +{ + RDIM_IdxedChunkListPush(arena, list, RDIM_LocationChunkNode, RDIM_Location2, cap, result); + { + RDI_U64 encoded_size = rdim_encoded_size_from_location_info(info); + rdim_memcpy_struct(&result->info, info); + result->relative_encoding_off = list->last->encoded_size; + list->last->encoded_size += encoded_size; + list->total_encoded_size += encoded_size; + } + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_location(RDIM_Location2 *location) +{ + RDIM_IdxedChunkListElementGetIdx(location, idx); + return idx; +} + +RDI_PROC RDI_U64 +rdim_off_from_location(RDIM_Location2 *location) +{ + RDI_U64 off = 0; + if(location != 0 && location->chunk != 0) + { + off = location->chunk->base_encoding_off + location->relative_encoding_off + 1; + } + return off; } RDI_PROC void rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push) { - + for(RDIM_LocationChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_encoding_off += dst->total_encoded_size; + } + RDIM_IdxedChunkListConcatInPlace(RDIM_LocationChunkNode, dst, to_push, dst->total_encoded_size += to_push->total_encoded_size); +} + +RDI_PROC RDIM_LocationCase2 * +rdim_location_case_chunk_list_push(RDIM_Arena *arena, RDIM_LocationCaseChunkList *list, RDI_U64 cap) +{ + RDIM_IdxedChunkListPush(arena, list, RDIM_LocationCaseChunkNode, RDIM_LocationCase2, cap, result); + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_location_case(RDIM_LocationCase2 *location_case) +{ + RDIM_IdxedChunkListElementGetIdx(location_case, idx); + return idx; +} + +RDI_PROC void +rdim_location_case_chunk_list_concat_in_place(RDIM_LocationCaseChunkList *dst, RDIM_LocationCaseChunkList *to_push) +{ + RDIM_IdxedChunkListConcatInPlace(RDIM_LocationCaseChunkNode, dst, to_push); } //////////////////////////////// diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 2c48b916..105060fd 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -844,8 +844,8 @@ struct RDIM_EvalBytecode //- rjf: location types -typedef struct RDIM_Location RDIM_Location; -struct RDIM_Location +typedef struct RDIM_LocationInfo RDIM_LocationInfo; +struct RDIM_LocationInfo { RDI_LocationKind kind; RDI_U8 reg_code; @@ -853,15 +853,24 @@ struct RDIM_Location RDIM_EvalBytecode bytecode; }; +typedef struct RDIM_Location2 RDIM_Location2; +struct RDIM_Location2 +{ + struct RDIM_LocationChunkNode *chunk; + RDIM_LocationInfo info; + RDI_U64 relative_encoding_off; +}; + typedef struct RDIM_LocationChunkNode RDIM_LocationChunkNode; struct RDIM_LocationChunkNode { RDIM_LocationChunkNode *next; - RDIM_Location *v; + RDIM_Location2 *v; RDI_U64 count; RDI_U64 cap; RDI_U64 base_idx; RDI_U64 base_encoding_off; + RDI_U64 encoded_size; }; typedef struct RDIM_LocationChunkList RDIM_LocationChunkList; @@ -874,7 +883,47 @@ struct RDIM_LocationChunkList RDI_U64 total_encoded_size; }; -//- rjf: location case types (location * voff range) +//- rjf: location cases + +typedef struct RDIM_LocationCase2 RDIM_LocationCase2; +struct RDIM_LocationCase2 +{ + struct RDIM_LocationCaseChunkNode *chunk; + RDIM_Location2 *location; + RDIM_Rng1U64 voff_range; +}; + +typedef struct RDIM_LocationCaseChunkNode RDIM_LocationCaseChunkNode; +struct RDIM_LocationCaseChunkNode +{ + RDIM_LocationCaseChunkNode *next; + RDIM_LocationCase2 *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_LocationCaseChunkList RDIM_LocationCaseChunkList; +struct RDIM_LocationCaseChunkList +{ + RDIM_LocationCaseChunkNode *first; + RDIM_LocationCaseChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//- rjf: locations (OLD) + +typedef struct RDIM_Location RDIM_Location; +struct RDIM_Location +{ + RDI_LocationKind kind; + RDI_U8 reg_code; + RDI_U16 offset; + RDIM_EvalBytecode bytecode; +}; + +//- rjf: location case types (location * voff range) (OLD) typedef struct RDIM_LocationCase RDIM_LocationCase; struct RDIM_LocationCase @@ -974,6 +1023,8 @@ struct RDIM_Local RDIM_String8 name; RDIM_Type *type; RDIM_LocationSet locset; + RDIM_LocationCase2 *first_location_case; + RDI_U64 location_case_count; }; typedef struct RDIM_Scope RDIM_Scope; @@ -1031,6 +1082,8 @@ struct RDIM_BakeParams RDIM_UDTEnumValChunkList enum_vals; RDIM_SrcFileChunkList src_files; RDIM_LineTableChunkList line_tables; + RDIM_LocationChunkList locations; + RDIM_LocationCaseChunkList location_cases; RDIM_SymbolChunkList global_variables; RDIM_SymbolChunkList thread_variables; RDIM_SymbolChunkList constants; @@ -1407,6 +1460,13 @@ struct RDIM_UDTBakeResult RDI_U64 enum_members_count; }; +typedef struct RDIM_LocationBakeResult RDIM_LocationBakeResult; +struct RDIM_LocationBakeResult +{ + RDI_U8 *location_data; + RDI_U64 location_data_size; +}; + typedef struct RDIM_GlobalVariableBakeResult RDIM_GlobalVariableBakeResult; struct RDIM_GlobalVariableBakeResult { @@ -1695,9 +1755,16 @@ RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkLi //////////////////////////////// //~ rjf: [Building] Location Info Building -RDI_PROC RDIM_Location *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_Location *loc); +RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info); +RDI_PROC RDIM_Location2 *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info); +RDI_PROC RDI_U64 rdim_idx_from_location(RDIM_Location2 *location); +RDI_PROC RDI_U64 rdim_off_from_location(RDIM_Location2 *location); RDI_PROC void rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push); +RDI_PROC RDIM_LocationCase2 *rdim_location_case_chunk_list_push(RDIM_Arena *arena, RDIM_LocationCaseChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_location_case(RDIM_LocationCase2 *location_case); +RDI_PROC void rdim_location_case_chunk_list_concat_in_place(RDIM_LocationCaseChunkList *dst, RDIM_LocationCaseChunkList *to_push); + //////////////////////////////// //~ rjf: [Building] Scope Info Building diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index e5130135..063b4bdb 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -1,6 +1,49 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal RDIM_LocationInfo +p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) +{ + RDIM_LocationInfo result = {0}; + if(0 <= offset && offset <= (S64)max_U16) + { + if(extra_indirection) + { + result.kind = RDI_LocationKind_AddrAddrRegPlusU16; + result.reg_code = reg_code; + result.offset = offset; + } + else + { + result.kind = RDI_LocationKind_AddrRegPlusU16; + result.reg_code = reg_code; + result.offset = offset; + } + } + else + { + RDIM_EvalBytecode bytecode = {0}; + U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); + rdim_bytecode_push_sconst(arena, &bytecode, offset); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); + if(extra_indirection) + { + U64 addr_size = rdi_addr_size_from_arch(arch); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); + } + result.kind = RDI_LocationKind_AddrBytecodeStream; + result.bytecode = bytecode; + } + return result; +} + +internal void +p2r2_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +{ + +} + internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params) { @@ -2990,6 +3033,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // if(lane_idx() == 0) { + p2r2_shared->lanes_locations = push_array(arena, RDIM_LocationChunkList, lane_count()); + p2r2_shared->lanes_location_cases = push_array(arena, RDIM_LocationCaseChunkList, lane_count()); p2r2_shared->lanes_procedures = push_array(arena, RDIM_SymbolChunkList, lane_count()); p2r2_shared->lanes_global_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); p2r2_shared->lanes_thread_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); @@ -3003,12 +3048,16 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: set up outputs for this sym stream // + U64 sym_locations_chunk_cap = 16384; + U64 sym_location_cases_chunk_cap = 16384; U64 sym_procedures_chunk_cap = 16384; U64 sym_global_variables_chunk_cap = 16384; U64 sym_thread_variables_chunk_cap = 16384; U64 sym_constants_chunk_cap = 16384; U64 sym_scopes_chunk_cap = 16384; U64 sym_inline_sites_chunk_cap = 16384; + RDIM_LocationChunkList sym_locations = {0}; + RDIM_LocationCaseChunkList sym_location_cases = {0}; RDIM_SymbolChunkList sym_procedures = {0}; RDIM_SymbolChunkList sym_global_variables = {0}; RDIM_SymbolChunkList sym_thread_variables = {0}; @@ -3444,6 +3493,18 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_size = 8; U32 byte_pos = 0; + // rjf: build location + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, &sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_LocationCase2 *loc_case = rdim_location_case_chunk_list_push(arena, &sym_location_cases, sym_locations_chunk_cap); + loc_case->location = loc2; + loc_case->voff_range.min = 0; + loc_case->voff_range.max = max_U64; + + // rjf: equip location case to local + local->first_location_case = loc_case; + local->location_case_count = 1; + // rjf: set location case RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Rng1U64 voff_range = {0, max_U64}; @@ -3542,7 +3603,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } }break; - //- rjf: DEFRANGE_REGISTESR + //- rjf: DEFRANGE_REGISTER case CV_SymKind_DEFRANGE_REGISTER: { // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing @@ -3608,10 +3669,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_size = rdi_addr_size_from_arch(arch); U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel->off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, &sym_locations, sym_locations_chunk_cap, &location_info); // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_SUBFIELD_REGISTER @@ -3903,6 +3965,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: output this lane's symbols // + p2r2_shared->lanes_locations[lane_idx()] = sym_locations; + p2r2_shared->lanes_location_cases[lane_idx()] = sym_location_cases; p2r2_shared->lanes_procedures[lane_idx()] = sym_procedures; p2r2_shared->lanes_global_variables[lane_idx()] = sym_global_variables; p2r2_shared->lanes_thread_variables[lane_idx()] = sym_thread_variables; @@ -3919,49 +3983,63 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: join all lane symbols // { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("join procedures") + if(lane_idx() == lane_from_task_idx(0)) ProfScope("join locations") + { + for EachIndex(idx, lane_count()) + { + rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->lanes_locations[idx]); + } + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("join location cases") + { + for EachIndex(idx, lane_count()) + { + rdim_location_case_chunk_list_concat_in_place(&p2r2_shared->all_location_cases, &p2r2_shared->lanes_location_cases[idx]); + } + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("join procedures") { for EachIndex(idx, lane_count()) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->lanes_procedures[idx]); } } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("join global variables") + if(lane_idx() == lane_from_task_idx(3)) ProfScope("join global variables") { for EachIndex(idx, lane_count()) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->lanes_global_variables[idx]); } } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("join thread variables") + if(lane_idx() == lane_from_task_idx(4)) ProfScope("join thread variables") { for EachIndex(idx, lane_count()) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->lanes_thread_variables[idx]); } } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("join constants") + if(lane_idx() == lane_from_task_idx(5)) ProfScope("join constants") { for EachIndex(idx, lane_count()) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->lanes_constants[idx]); } } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("join scopes") + if(lane_idx() == lane_from_task_idx(6)) ProfScope("join scopes") { for EachIndex(idx, lane_count()) { rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->lanes_scopes[idx]); } } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("join inline sites") + if(lane_idx() == lane_from_task_idx(7)) ProfScope("join inline sites") { for EachIndex(idx, lane_count()) { rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->lanes_inline_sites[idx]); } } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("join typedefs") + if(lane_idx() == lane_from_task_idx(8)) ProfScope("join typedefs") { for EachIndex(idx, lane_count()) { @@ -3971,6 +4049,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); + RDIM_LocationChunkList all_locations = p2r2_shared->all_locations; + RDIM_LocationCaseChunkList all_location_cases = p2r2_shared->all_location_cases; RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; @@ -3991,7 +4071,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); top_level_info.exe_hash = exe_hash; top_level_info.voff_max = exe_voff_max; - if(params->deterministic) + if(!params->deterministic) { top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); } @@ -4027,6 +4107,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) result.enum_vals = all_enum_vals; result.src_files = all_src_files; result.line_tables = all_line_tables; + result.locations = all_locations; + result.location_cases = all_location_cases; result.global_variables = all_global_variables; result.thread_variables = all_thread_variables; result.constants = all_constants; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 709fa5b2..02e6495c 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -118,6 +118,8 @@ struct P2R2_Shared RDIM_UDTMemberChunkList all_members; RDIM_UDTEnumValChunkList all_enum_vals; + RDIM_LocationChunkList *lanes_locations; + RDIM_LocationCaseChunkList *lanes_location_cases; RDIM_SymbolChunkList *lanes_procedures; RDIM_SymbolChunkList *lanes_global_variables; RDIM_SymbolChunkList *lanes_thread_variables; @@ -126,6 +128,8 @@ struct P2R2_Shared RDIM_InlineSiteChunkList *lanes_inline_sites; RDIM_TypeChunkList *lanes_typedefs; + RDIM_LocationChunkList all_locations; + RDIM_LocationCaseChunkList all_location_cases; RDIM_SymbolChunkList all_procedures; RDIM_SymbolChunkList all_global_variables; RDIM_SymbolChunkList all_thread_variables; @@ -137,6 +141,9 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; +internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); +internal void p2r2_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); + internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); #endif // RDI_FROM_PDB_2_H diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 2bd4c0b0..efbb8569 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -815,36 +815,41 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); } if(lane_idx() == lane_from_task_idx(7)) + { + rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + } + if(lane_idx() == lane_from_task_idx(8)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(8)) + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(10)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(11)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(11)) + if(lane_idx() == lane_from_task_idx(12)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(12)) + if(lane_idx() == lane_from_task_idx(13)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(13)) + if(lane_idx() == lane_from_task_idx(14)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -1016,6 +1021,49 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } + //- rjf: bake locations + ProfScope("bake locations") + { + for EachNode(n, RDIM_LocationChunkNode, params->locations.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Location2 *loc = &n->v[n_idx]; + RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + switch((RDI_LocationKindEnum)loc->info.kind) + { + case RDI_LocationKind_NULL:{}break; + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); + RDI_U64 write_off = sizeof(loc->info.kind); + for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) + { + MemoryCopy(dst + write_off, &op_node->op, 1); + write_off += 1; + MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); + write_off += op_node->p_size; + } + dst[write_off] = 0; + }break; + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + case RDI_LocationKind_ValReg: + { + RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + } + } + } + } + //- rjf: bake global variables ProfScope("bake global variables") { diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index d4d16932..9e679f6a 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -53,6 +53,7 @@ struct RDIM2_Shared RDIM_SrcFileBakeResult baked_src_files; RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_UDTBakeResult baked_udts; + RDIM_LocationBakeResult baked_locations; RDIM_GlobalVariableBakeResult baked_global_variables; RDIM_ThreadVariableBakeResult baked_thread_variables; RDIM_ConstantsBakeResult baked_constants; From f065ca33a2d1de40e0feb61e6ec447b346302852 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 28 Aug 2025 14:53:43 -0700 Subject: [PATCH 069/302] location block baking --- src/lib_rdi_make/rdi_make.h | 7 +++++++ src/rdi_make/rdi_make_local_2.c | 34 +++++++++++++++++++++++++++------ src/rdi_make/rdi_make_local_2.h | 1 + 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 105060fd..f5a0fe5c 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1467,6 +1467,13 @@ struct RDIM_LocationBakeResult RDI_U64 location_data_size; }; +typedef struct RDIM_LocationBlockBakeResult RDIM_LocationBlockBakeResult; +struct RDIM_LocationBlockBakeResult +{ + RDI_LocationBlock *location_blocks; + RDI_U64 location_blocks_count; +}; + typedef struct RDIM_GlobalVariableBakeResult RDIM_GlobalVariableBakeResult; struct RDIM_GlobalVariableBakeResult { diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index efbb8569..b06b6bdd 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -820,36 +820,41 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); } if(lane_idx() == lane_from_task_idx(8)) + { + rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; + rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + } + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(10)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(11)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(11)) + if(lane_idx() == lane_from_task_idx(12)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(12)) + if(lane_idx() == lane_from_task_idx(13)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(13)) + if(lane_idx() == lane_from_task_idx(14)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(14)) + if(lane_idx() == lane_from_task_idx(15)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -1064,6 +1069,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } + //- rjf: bake location blocks + ProfScope("bake location blocks") + { + for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_LocationCase2 *src = &n->v[n_idx]; + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = rdim_off_from_location(src->location); + } + } + } + //- rjf: bake global variables ProfScope("bake global variables") { diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 9e679f6a..be4a09a4 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -54,6 +54,7 @@ struct RDIM2_Shared RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_UDTBakeResult baked_udts; RDIM_LocationBakeResult baked_locations; + RDIM_LocationBlockBakeResult baked_location_blocks; RDIM_GlobalVariableBakeResult baked_global_variables; RDIM_ThreadVariableBakeResult baked_thread_variables; RDIM_ConstantsBakeResult baked_constants; From 8fe4b3524f3356f9a8d4ebc02d09c5cbef6454dd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 29 Aug 2025 13:01:44 -0700 Subject: [PATCH 070/302] with sufficient threads, split baking threads into two groups: small # of threads to do expensive 'background' baking tasks, use the rest to do wide predictable baking stuff --- src/lib_rdi/rdi.h | 4 - src/lib_rdi_make/rdi_make.c | 12 +- src/os/core/win32/os_core_win32.c | 2 +- src/rdi/rdi.mdesk | 2 - src/rdi_make/rdi_make_local_2.c | 2246 +++++++++++++++-------------- src/rdi_make/rdi_make_local_2.h | 5 + 6 files changed, 1193 insertions(+), 1078 deletions(-) diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index 2be07ad4..e6449d20 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -996,8 +996,6 @@ X(RDI_U32, voff_range_first)\ X(RDI_U32, voff_range_opl)\ X(RDI_U32, local_first)\ X(RDI_U32, local_count)\ -X(RDI_U32, static_local_idx_run_first)\ -X(RDI_U32, static_local_count)\ X(RDI_U32, inline_site_idx)\ #define RDI_InlineSite_XList \ @@ -1446,8 +1444,6 @@ RDI_U32 voff_range_first; RDI_U32 voff_range_opl; RDI_U32 local_first; RDI_U32 local_count; -RDI_U32 static_local_idx_run_first; -RDI_U32 static_local_count; RDI_U32 inline_site_idx; }; diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index e19ad8bb..06a087ac 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -335,7 +335,6 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) // Also - this sort should be a "stable" sort. In the use case of sorting vmap // ranges, we want to be able to rely on order, so it needs to be preserved here. - RDIM_ProfBegin("rdim_sort_key_array"); RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); RDIM_SortKey *result = 0; @@ -486,7 +485,6 @@ rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) #endif rdim_scratch_end(scratch); - RDIM_ProfEnd(); return result; } @@ -1291,7 +1289,15 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); //- rjf: sort markers +#if 0 RDIM_SortKey *sorted_keys = rdim_sort_key_array(scratch.arena, keys, marker_count); +#else + ProfBegin("sort markers"); + RDIM_SortKey *sorted_keys = rdim_push_array(scratch.arena, RDIM_SortKey, marker_count); + rdim_memcpy(sorted_keys, keys, marker_count*sizeof(keys[0])); + radsort(sorted_keys, marker_count, rdim_sort_key_is_before); + ProfEnd(); +#endif //- rjf: determine if an extra vmap entry for zero is needed RDI_U32 extra_vmap_entry = 0; @@ -1304,6 +1310,7 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So RDI_U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw + 1); RDI_U32 vmap_entry_count_pass_1 = 0; + ProfScope("fill output vmap entries") { typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; struct RDIM_VMapRangeTracker @@ -1402,6 +1409,7 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So //- rjf: combine duplicate neighbors RDI_U32 vmap_entry_count = 0; + ProfScope("combine duplicate neighbors") { RDI_VMapEntry *vmap_ptr = vmap; RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 676a4ccd..0abd840e 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1355,7 +1355,7 @@ internal Barrier os_barrier_alloc(U64 count) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Barrier); - InitializeSynchronizationBarrier(&entity->sb, count, -1); + BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1); Barrier result = {IntFromPtr(entity)}; return result; } diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 726913c5..bb1e2421 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1056,8 +1056,6 @@ RDI_ScopeMemberTable: {voff_range_opl RDI_U32 ""} {local_first RDI_U32 ""} {local_count RDI_U32 ""} - {static_local_idx_run_first RDI_U32 ""} - {static_local_count RDI_U32 ""} {inline_site_idx RDI_U32 ""} } diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index b06b6bdd..ab22530c 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -10,658 +10,396 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { rdim2_shared = push_array(arena, RDIM2_Shared, 1); + rdim2_shared->group_split = (lane_count() >= 2); + if(rdim2_shared->group_split) + { + rdim2_shared->group_0_lane_count = Clamp(1, lane_count()/2, 2); + rdim2_shared->group_0_barrier = barrier_alloc(rdim2_shared->group_0_lane_count); + rdim2_shared->group_1_barrier = barrier_alloc(lane_count() - rdim2_shared->group_0_lane_count); + } } lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: build interned path tree + //- rjf: with sufficient threads, split lanes into two groups: // - if(lane_idx() == 0) ProfScope("build interned path tree") - { - rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); - } - lane_sync(); - RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; - - ////////////////////////////////////////////////////////////// - //- rjf: gather all unsorted, joined, line table info; & sort + // - group 0: one small group for many heterogeneous 'background' baking tasks + // - group 1: one large group for wide work we can reliably distribute // - ProfScope("gather all unsorted, joined, line table info; & sort") + B32 group_0 = 1; + B32 group_1 = 1; + LaneCtx lane_ctx_restore = {0}; + if(rdim2_shared->group_split) { - //- rjf: set up outputs - ProfScope("set up outputs") if(lane_idx() == 0) + if(lane_idx() < rdim2_shared->group_0_lane_count) { - rdim2_shared->line_tables_count = params->line_tables.total_count; - rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); - ProfScope("flatten chunk list") + LaneCtx group_0_lane_ctx = { - U64 joined_idx = 0; - for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) - { - for EachIndex(idx, n->count) - { - rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; - joined_idx += 1; - } - } - } - rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; - rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_columns_count= 1; - ProfScope("allocate outputs") - { - rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); - rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); - rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); - rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); - rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); - rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); - } - U64 voffs_base_idx = 0; - U64 lines_base_idx = 0; - U64 cols_base_idx = 0; - ProfScope("lay out line tables") for EachIndex(idx, rdim2_shared->line_tables_count) - { - U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil - RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; - RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; - dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 - dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 - voffs_base_idx += src->line_count + 2*src->seq_count; - lines_base_idx += src->line_count + 1*src->seq_count; - } - rdim2_shared->line_table_block_take_counter = 0; - } - lane_sync(); - - //- rjf: wide bake - ProfScope("wide bake") - { - U64 line_table_block_size = 4; - U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; - for(;;) - { - U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); - if(0 == line_table_block_num || line_table_block_count < line_table_block_num) - { - break; - } - U64 line_table_block_idx = line_table_block_num-1; - Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); - line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); - for EachInRange(line_table_idx, line_table_range) - { - RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; - RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; - - //- rjf: gather - dst->line_count = src->line_count; - dst->seq_count = src->seq_count; - dst->key_count = dst->line_count + dst->seq_count; - dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); - dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); - { - RDIM_SortKey *key_ptr = dst->line_keys; - RDIM_LineRec *rec_ptr = dst->line_recs; - for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) - { - RDIM_LineSequence *seq = &seq_n->v; - for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) - { - key_ptr->key = seq->voffs[line_idx]; - key_ptr->val = rec_ptr; - key_ptr += 1; - rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 - rec_ptr->line_num = seq->line_nums[line_idx]; - if(seq->col_nums != 0) - { - rec_ptr->col_first = seq->col_nums[line_idx*2]; - rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; - } - rec_ptr += 1; - } - key_ptr->key = seq->voffs[seq->line_count]; - key_ptr->val = 0; - key_ptr += 1; - } - } - - //- rjf: sort - rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); - - //- rjf: fill - RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; - U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; - RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; - U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; - RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; - RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; - { - for EachIndex(idx, sorted_line_keys_count) - { - arranged_voffs[idx] = sorted_line_keys[idx].key; - } - arranged_voffs[sorted_line_keys_count] = ~0ull; - for EachIndex(idx, sorted_line_keys_count) - { - RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; - if(rec != 0) - { - arranged_lines[idx].file_idx = rec->file_id; - arranged_lines[idx].line_num = rec->line_num; - } - else - { - arranged_lines[idx].file_idx = 0; - arranged_lines[idx].line_num = 0; - } - } - } - } - } - } - } - lane_sync(); - RDI_U64 line_tables_count = rdim2_shared->line_tables_count; - RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; - RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; - RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; - - ////////////////////////////////////////////////////////////// - //- rjf: build string map - // - ProfScope("build string map") - { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") - { - rdim2_shared->bake_string_map_topology.slots_count = (64 + - params->procedures.total_count*1 + - params->global_variables.total_count*1 + - params->thread_variables.total_count*1 + - params->types.total_count/2); - rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); - } - lane_sync(); - - //- rjf: set up this lane's map - ProfScope("set up this lane's map") - { - rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); - } - RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; - RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; - - //- rjf: push all strings into this lane's map - ProfScope("push all strings into this lane's map") - { - // rjf: push small top-level strings - if(lane_idx() == 0) ProfScope("push small top-level strings") - { - rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); - rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); - rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); - } - - // rjf: push strings from source files - ProfScope("src files") - { - for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from units - ProfScope("units") - { - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from types - ProfScope("types") - { - for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from udt members - ProfScope("udt members") - { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from udt enum values - ProfScope("udt enum values") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from symbols - RDIM_SymbolChunkList *symbol_lists[] = - { - ¶ms->global_variables, - ¶ms->thread_variables, - ¶ms->procedures, - ¶ms->constants, + lane_idx(), + rdim2_shared->group_0_lane_count, + rdim2_shared->group_0_barrier }; - ProfScope("symbols") - { - for EachElement(list_idx, symbol_lists) - { - ProfScope("symbols (%I64u)", list_idx) - { - for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - } - } - - //- rjf: push strings from inline sites - ProfScope("inline sites") - { - for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - //- rjf: push strings from scopes - ProfScope("scopes") - { - for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } + lane_ctx_restore = lane_ctx(group_0_lane_ctx); + group_0 = 1; + group_1 = 0; } - - //- rjf: join & sort - if(lane_idx() == 0) + else { - rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + LaneCtx group_1_lane_ctx = + { + lane_idx() - rdim2_shared->group_0_lane_count, + lane_count() - rdim2_shared->group_0_lane_count, + rdim2_shared->group_1_barrier + }; + lane_ctx_restore = lane_ctx(group_1_lane_ctx); + group_0 = 0; + group_1 = 1; } - lane_sync(); - ProfScope("join & sort") + } + + ////////////////////////////////////////////////////////////// + //- rjf: group 0 + // + if(group_0) + { + ProfScope("bake all vmaps") { - //- rjf: join - ProfScope("join") + if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake unit vmap") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } + rdim2_shared->baked_unit_vmap = rdim_bake_unit_vmap(arena, ¶ms->units); } - - //- rjf: sort - ProfScope("sort") + if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake scope vmap") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } - } + rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("bake global vmap") + { + rdim2_shared->baked_global_vmap = rdim_bake_global_vmap(arena, ¶ms->global_variables); } } lane_sync(); - - //- rjf: tighten string table - ProfScope("tighten string table") + } + + ////////////////////////////////////////////////////////////// + //- rjf: group 1 + // + if(group_1) + { + ////////////////////////////////////////////////////////////// + //- rjf: build interned path tree + // + if(lane_idx() == 0) ProfScope("build interned path tree") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; - if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); + } + lane_sync(); + RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; + + ////////////////////////////////////////////////////////////// + //- rjf: gather all unsorted, joined, line table info; & sort + // + ProfScope("gather all unsorted, joined, line table info; & sort") + { + //- rjf: set up outputs + ProfScope("set up outputs") { - RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_strings.slots_count = map_top->slots_count; - rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); - rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; - rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + // rjf: calculate header info + if(lane_idx() == 0) + { + rdim2_shared->line_tables_count = params->line_tables.total_count; + rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + ProfScope("flatten chunk list") + { + U64 joined_idx = 0; + for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) + { + for EachIndex(idx, n->count) + { + rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; + joined_idx += 1; + } + } + } + rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; + rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_columns_count= 1; + rdim2_shared->line_table_block_take_counter = 0; + } + lane_sync(); + + // rjf: allocate outputs + ProfScope("allocate outputs") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); + + // rjf: lay out line tables in joined info + ProfScope("lay out line tables") + { + U64 voffs_base_idx = 0; + U64 lines_base_idx = 0; + U64 cols_base_idx = 0; + for EachIndex(idx, rdim2_shared->line_tables_count) + { + U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil + RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; + RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; + dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 + dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 + voffs_base_idx += src->line_count + 2*src->seq_count; + lines_base_idx += src->line_count + 1*src->seq_count; + } + } + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); + } + } } lane_sync(); - ProfScope("fill tight map") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); - for EachInRange(idx, slot_range) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); - } - } - } - } - } - lane_sync(); - RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; - - ////////////////////////////////////////////////////////////// - //- rjf: build name maps - // - ProfScope("build name maps") - { - //- rjf: set up - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - U64 slot_count = 0; - switch((RDI_NameMapKindEnum)k) - { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; -#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break - Case(GlobalVariables, params->global_variables.total_count); - Case(ThreadVariables, params->thread_variables.total_count); - Case(Constants, params->constants.total_count); - Case(Procedures, params->procedures.total_count); - Case(LinkNameProcedures, params->procedures.total_count); - Case(Types, params->types.total_count); - Case(NormalSourcePaths, params->src_files.total_count); -#undef Case - } - rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); - rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; - } - } - lane_sync(); - - //- rjf: wide build - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); - RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; - B32 link_names = 0; - RDIM_SymbolChunkList *symbols = 0; - switch((RDI_NameMapKindEnum)k) - { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; - case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; - case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; - case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; - symbol_name_map_build:; - { - for EachNode(n, RDIM_SymbolChunkNode, symbols->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Symbol *symbol = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); - } - } - }break; - case RDI_NameMapKind_Types: - { - RDIM_TypeChunkList *types = ¶ms->types; - for EachNode(n, RDIM_TypeChunkNode, types->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Type *type = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); - } - } - }break; - case RDI_NameMapKind_NormalSourcePaths: - { - RDIM_SrcFileChunkList *src_files = ¶ms->src_files; - for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_SrcFile *src_file = &n->v[n_idx]; - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); - rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); - } - } - }break; - } - } - lane_sync(); - - //- rjf: join & sort - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); - } - } - lane_sync(); - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - //- rjf: join - ProfScope("join") + //- rjf: wide bake + ProfScope("wide bake") { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) + U64 line_table_block_size = 4096; + U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; + for(;;) { - for EachIndex(src_lane_idx, lane_count()) + U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); + if(0 == line_table_block_num || line_table_block_count < line_table_block_num) { - RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; - RDIM_BakeNameMap2 *dst_map = map; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } + break; } - } - } - - //- rjf: sort - ProfScope("sort") - { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + U64 line_table_block_idx = line_table_block_num-1; + Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); + line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); + for EachInRange(line_table_idx, line_table_range) { - *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: build index runs - // - ProfScope("build index runs") - { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") - { - rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + - params->procedures.total_count + - params->global_variables.total_count + - params->thread_variables.total_count + - params->types.total_count); - rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); - } - lane_sync(); - - //- rjf: set up this lane's map - ProfScope("set up this lane's map") - { - rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; - - //- rjf: wide fill of all index runs - ProfScope("fill all lane index run maps") - { - //- rjf: bake runs of function-type parameter lists - ProfScope("bake runs of function-type parameter lists") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) - { - RDIM_Type *type = &n->v[n_idx]; - if(type->count == 0) + RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + + //- rjf: gather + dst->line_count = src->line_count; + dst->seq_count = src->seq_count; + dst->key_count = dst->line_count + dst->seq_count; + dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); + dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); { - continue; - } - if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = type->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + RDIM_SortKey *key_ptr = dst->line_keys; + RDIM_LineRec *rec_ptr = dst->line_recs; + for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); - } - } - } - } - - //- rjf: bake runs of name map match lists - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - Rng1U64 slot_idx_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_idx_range) - { - RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; - if(slot != 0) - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct IdxRunNode IdxRunNode; - struct IdxRunNode - { - IdxRunNode *next; - RDI_U64 idx; - }; - IdxRunNode *first_idx_run_node = 0; - IdxRunNode *last_idx_run_node = 0; - U64 active_idx_count = 0; - U64 active_hash = 0; - RDIM_BakeNameChunkNode *n = slot->first; - U64 n_idx = 0; - for(;;) - { - // rjf: advance chunk - if(n != 0 && n_idx >= n->count) - { - n = n->next; - n_idx = 0; - } - - // rjf: grab next element - U64 hash = 0; - U64 idx = 0; - if(n != 0) - { - hash = n->v[n_idx].hash; - idx = n->v[n_idx].idx; - } - - // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash && active_idx_count != 0) - { - if(active_idx_count > 1) + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) { - RDI_U64 idxs_count = active_idx_count; - RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) { - U64 write_idx = 0; - for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) - { - idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 - write_idx += 1; - } + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + rec_ptr += 1; } - active_hash = hash; - first_idx_run_node = 0; - last_idx_run_node = 0; - temp_end(scratch); - } - - // rjf: hash matches the active list -> push - if(hash != 0 && hash == active_hash) - { - IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); - idx_run_n->idx = idx; - SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); - active_idx_count += 1; - } - - // rjf: advance index - n_idx += 1; - - // rjf: end on zero node - if(n == 0) - { - break; + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; } } - scratch_end(scratch); + + //- rjf: sort + rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); + + //- rjf: fill + RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; + U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; + RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; + { + for EachIndex(idx, sorted_line_keys_count) + { + arranged_voffs[idx] = sorted_line_keys[idx].key; + } + arranged_voffs[sorted_line_keys_count] = ~0ull; + for EachIndex(idx, sorted_line_keys_count) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; + if(rec != 0) + { + arranged_lines[idx].file_idx = rec->file_id; + arranged_lines[idx].line_num = rec->line_num; + } + else + { + arranged_lines[idx].file_idx = 0; + arranged_lines[idx].line_num = 0; + } + } + } + } + } + } + } + lane_sync(); + RDI_U64 line_tables_count = rdim2_shared->line_tables_count; + RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; + RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; + + ////////////////////////////////////////////////////////////// + //- rjf: build string map + // + ProfScope("build string map") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") + { + rdim2_shared->bake_string_map_topology.slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; + + //- rjf: push all strings into this lane's map + ProfScope("push all strings into this lane's map") + { + // rjf: push small top-level strings + if(lane_idx() == 0) ProfScope("push small top-level strings") + { + rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); + rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); + } + + // rjf: push strings from source files + ProfScope("src files") + { + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from units + ProfScope("units") + { + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from types + ProfScope("types") + { + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from udt members + ProfScope("udt members") + { + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from udt enum values + ProfScope("udt enum values") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + // rjf: push strings from symbols + RDIM_SymbolChunkList *symbol_lists[] = + { + ¶ms->global_variables, + ¶ms->thread_variables, + ¶ms->procedures, + ¶ms->constants, + }; + ProfScope("symbols") + { + for EachElement(list_idx, symbol_lists) + { + ProfScope("symbols (%I64u)", list_idx) + { + for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + } + } + + //- rjf: push strings from inline sites + ProfScope("inline sites") + { + for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from scopes + ProfScope("scopes") + { + for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } } } @@ -669,7 +407,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join & sort if(lane_idx() == 0) { - rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); } lane_sync(); ProfScope("join & sort") @@ -677,20 +415,20 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; } else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) { - rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } @@ -699,500 +437,870 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) { - *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); } } } } lane_sync(); - //- rjf: tighten idx run table - if(lane_idx() == 0) ProfScope("tighten idx run table") + //- rjf: tighten string table + ProfScope("tighten string table") { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_idxes = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_idx_runs = rdim_bake_idx_run_map_from_loose(arena, map_top, &bake_idx_run_map_base_idxes, map); - } - } - } - lane_sync(); - RDIM_BakeIdxRunMap2 *bake_idx_runs = rdim2_shared->bake_idx_runs; - - ////////////////////////////////////////////////////////////// - //- rjf: bake strings - // - ProfScope("bake strings") - { - // rjf: set up - if(lane_idx() == 0) ProfScope("set up; lay out strings") - { - rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; - rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); - RDI_U64 off_cursor = 0; - for EachIndex(slot_idx, bake_strings->slots_count) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { - for EachIndex(n_idx, n->count) + RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_strings.slots_count = map_top->slots_count; + rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); + rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; + rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + for EachInRange(idx, slot_range) { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; - off_cursor += src->string.size; + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + } + } + } + } + } + lane_sync(); + RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + + ////////////////////////////////////////////////////////////// + //- rjf: build name maps + // + ProfScope("build name maps") + { + //- rjf: set up + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + U64 slot_count = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; +#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break + Case(GlobalVariables, params->global_variables.total_count); + Case(ThreadVariables, params->thread_variables.total_count); + Case(Constants, params->constants.total_count); + Case(Procedures, params->procedures.total_count); + Case(LinkNameProcedures, params->procedures.total_count); + Case(Types, params->types.total_count); + Case(NormalSourcePaths, params->src_files.total_count); +#undef Case + } + rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); + rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; + } + } + lane_sync(); + + //- rjf: wide build + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); + RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; + B32 link_names = 0; + RDIM_SymbolChunkList *symbols = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; + case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; + case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; + case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; + symbol_name_map_build:; + { + for EachNode(n, RDIM_SymbolChunkNode, symbols->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Symbol *symbol = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); + } + } + }break; + case RDI_NameMapKind_Types: + { + RDIM_TypeChunkList *types = ¶ms->types; + for EachNode(n, RDIM_TypeChunkNode, types->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Type *type = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); + } + } + }break; + case RDI_NameMapKind_NormalSourcePaths: + { + RDIM_SrcFileChunkList *src_files = ¶ms->src_files; + for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_SrcFile *src_file = &n->v[n_idx]; + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); + rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); + } + } + }break; + } + } + lane_sync(); + + //- rjf: join & sort + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap2 *dst_map = map; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } } } } - rdim2_shared->baked_strings.string_data_size = off_cursor; - rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); } lane_sync(); - // rjf: wide fill string data - ProfScope("wide fill") + ////////////////////////////////////////////////////////////// + //- rjf: build index runs + // + ProfScope("build index runs") { - Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); - for EachInRange(slot_idx, slot_idx_range) + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + + params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->types.total_count); + rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + + //- rjf: wide fill of all index runs + ProfScope("fill all lane index run maps") + { + //- rjf: bake runs of function-type parameter lists + ProfScope("bake runs of function-type parameter lists") { - for EachIndex(n_idx, n->count) + for EachNode(n, RDIM_TypeChunkNode, params->types.first) { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; - rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); + Rng1U64 range = lane_range(n->count); + ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) + { + RDIM_Type *type = &n->v[n_idx]; + if(type->count == 0) + { + continue; + } + if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = type->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); + } + } + } + } + + //- rjf: bake runs of name map match lists + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 slot_idx_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + if(slot != 0) + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + U64 active_hash = 0; + RDIM_BakeNameChunkNode *n = slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + U64 hash = 0; + U64 idx = 0; + if(n != 0) + { + hash = n->v[n_idx].hash; + idx = n->v[n_idx].idx; + } + + // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list + if(hash != active_hash && active_idx_count != 0) + { + if(active_idx_count > 1) + { + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + } + active_hash = hash; + first_idx_run_node = 0; + last_idx_run_node = 0; + temp_end(scratch); + } + + // rjf: hash matches the active list -> push + if(hash != 0 && hash == active_hash) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); + } + } + } + + //- rjf: join & sort + if(lane_idx() == 0) + { + rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + lane_sync(); + ProfScope("join & sort") + { + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + lane_sync(); + + //- rjf: tighten idx run table + if(lane_idx() == 0) ProfScope("tighten idx run table") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_idxes = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_idx_runs = rdim_bake_idx_run_map_from_loose(arena, map_top, &bake_idx_run_map_base_idxes, map); + } + } + } + lane_sync(); + RDIM_BakeIdxRunMap2 *bake_idx_runs = rdim2_shared->bake_idx_runs; + + ////////////////////////////////////////////////////////////// + //- rjf: bake strings + // + ProfScope("bake strings") + { + // rjf: set up + if(lane_idx() == 0) ProfScope("set up; lay out strings") + { + rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; + rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); + RDI_U64 off_cursor = 0; + for EachIndex(slot_idx, bake_strings->slots_count) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; + off_cursor += src->string.size; + } + } + } + rdim2_shared->baked_strings.string_data_size = off_cursor; + rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); + } + lane_sync(); + + // rjf: wide fill string data + ProfScope("wide fill") + { + Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; + rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); + } } } } } - } - - ////////////////////////////////////////////////////////////// - //- rjf: bake units, src files, symbols, types, UDTs - // - { - //- rjf: setup outputs - if(lane_idx() == lane_from_task_idx(0)) + + ////////////////////////////////////////////////////////////// + //- rjf: bake units, src files, symbols, types, UDTs + // { - rdim2_shared->baked_units.units_count = params->units.total_count+1; - rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - } - if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; - rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); - } - if(lane_idx() == lane_from_task_idx(4)) - { - rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; - rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); - } - if(lane_idx() == lane_from_task_idx(5)) - { - rdim2_shared->baked_udts.members_count = params->members.total_count+1; - rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); - } - if(lane_idx() == lane_from_task_idx(6)) - { - rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; - rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); - } - if(lane_idx() == lane_from_task_idx(7)) - { - rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; - rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); - } - if(lane_idx() == lane_from_task_idx(8)) - { - rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; - rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); - } - if(lane_idx() == lane_from_task_idx(9)) - { - rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; - rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); - } - if(lane_idx() == lane_from_task_idx(10)) - { - rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; - rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); - } - if(lane_idx() == lane_from_task_idx(11)) - { - rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); - } - if(lane_idx() == lane_from_task_idx(12)) - { - rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); - } - if(lane_idx() == lane_from_task_idx(13)) - { - rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; - rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); - } - if(lane_idx() == lane_from_task_idx(14)) - { - rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; - rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); - } - if(lane_idx() == lane_from_task_idx(15)) - { - rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; - rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_units.units_count = params->units.total_count+1; + rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; + rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_udts.members_count = params->members.total_count+1; + rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + } + if(lane_idx() == lane_from_task_idx(6)) + { + rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; + rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + } + if(lane_idx() == lane_from_task_idx(7)) + { + rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + } + if(lane_idx() == lane_from_task_idx(8)) + { + rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; + rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + } + if(lane_idx() == lane_from_task_idx(9)) + { + rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; + rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); + } + if(lane_idx() == lane_from_task_idx(10)) + { + rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; + rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); + } + if(lane_idx() == lane_from_task_idx(11)) + { + rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + } + if(lane_idx() == lane_from_task_idx(12)) + { + rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + } + if(lane_idx() == lane_from_task_idx(13)) + { + rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + } + if(lane_idx() == lane_from_task_idx(14)) + { + rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + } + if(lane_idx() == lane_from_task_idx(15)) + { + rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; + rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + } + lane_sync(); + + //- rjf: bake units + ProfScope("bake units") + { + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Unit *src = &n->v[n_idx]; + RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; + dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); + dst->language = src->language; + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + + //- rjf: bake type nodes + ProfScope("bake type nodes") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Type *src = &n->v[n_idx]; + RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; + + //- rjf: fill shared type node info + dst->kind = src->kind; + dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 + dst->byte_size = src->byte_size; + + //- rjf: fill built-in-only type node info + if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) + { + dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + } + + //- rjf: fill array sizes + else if(dst->kind == RDI_TypeKind_Array) + { + U64 direct_byte_size = 1; + if(src->direct_type && src->direct_type->byte_size > 0) + { + direct_byte_size = src->direct_type->byte_size; + } + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); + dst->constructed.count = src->byte_size / direct_byte_size; + } + + //- rjf: fill constructed type node info + else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) + { + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->constructed.count = src->count; + if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = src->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); + } + else if(dst->kind == RDI_TypeKind_MemberPtr) + { + // TODO(rjf): member pointers not currently supported. + } + } + + //- rjf: fill user-defined-type info + else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) + { + dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 + dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill bitfield info + else if(dst->kind == RDI_TypeKind_Bitfield) + { + dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->bitfield.off = src->off; + dst->bitfield.size = src->count; + } + } + } + } + + //- rjf: bake UDT members + ProfScope("bake UDT members") + { + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTMember *src_member = &n->v[n_idx]; + RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + } + } + } + + //- rjf: bake UDT enum vals + ProfScope("bake UDT enum vals") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTEnumVal *src_member = &n->v[n_idx]; + RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->val = src_member->val; + } + } + } + + //- rjf: bake UDTs + ProfScope("bake UDTs") + { + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDT *src_udt = &n->v[n_idx]; + RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + + //- rjf: fill member info + if(src_udt->member_count != 0) + { + dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); + dst_udt->member_count = src_udt->member_count; + } + + //- rjf: fill enum members + else if(src_udt->enum_val_count != 0) + { + dst_udt->flags |= RDI_UDTFlag_EnumMembers; + dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); + dst_udt->member_count = src_udt->enum_val_count; + } + } + } + } + + //- rjf: bake locations + ProfScope("bake locations") + { + for EachNode(n, RDIM_LocationChunkNode, params->locations.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Location2 *loc = &n->v[n_idx]; + RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + switch((RDI_LocationKindEnum)loc->info.kind) + { + case RDI_LocationKind_NULL:{}break; + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); + RDI_U64 write_off = sizeof(loc->info.kind); + for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) + { + MemoryCopy(dst + write_off, &op_node->op, 1); + write_off += 1; + MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); + write_off += op_node->p_size; + } + dst[write_off] = 0; + }break; + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + case RDI_LocationKind_ValReg: + { + RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + } + } + } + } + + //- rjf: bake location blocks + ProfScope("bake location blocks") + { + for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_LocationCase2 *src = &n->v[n_idx]; + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = rdim_off_from_location(src->location); + } + } + } + + //- rjf: bake global variables + ProfScope("bake global variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->voff = src->offset; + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake thread variables + ProfScope("bake thread variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake inline sites + ProfScope("bake inline sites") + { + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; + RDIM_InlineSite *src = &n->v[n_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } } lane_sync(); - //- rjf: bake units - ProfScope("bake units") + ////////////////////////////////////////////////////////////// + //- rjf: do final baking tasks + // + ProfScope("do final baking tasks") { - for EachNode(n, RDIM_UnitChunkNode, params->units.first) + if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Unit *src = &n->v[n_idx]; - RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; - dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); - dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); - dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); - dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); - dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); - dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); - dst->language = src->language; - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - - //- rjf: bake type nodes - ProfScope("bake type nodes") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Type *src = &n->v[n_idx]; - RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; - - //- rjf: fill shared type node info - dst->kind = src->kind; - dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 - dst->byte_size = src->byte_size; - - //- rjf: fill built-in-only type node info - if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) - { - dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - } - - //- rjf: fill array sizes - else if(dst->kind == RDI_TypeKind_Array) - { - U64 direct_byte_size = 1; - if(src->direct_type && src->direct_type->byte_size > 0) - { - direct_byte_size = src->direct_type->byte_size; - } - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); - dst->constructed.count = src->byte_size / direct_byte_size; - } - - //- rjf: fill constructed type node info - else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) - { - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->constructed.count = src->count; - if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = src->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); - } - else if(dst->kind == RDI_TypeKind_MemberPtr) - { - // TODO(rjf): member pointers not currently supported. - } - } - - //- rjf: fill user-defined-type info - else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) - { - dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 - dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill bitfield info - else if(dst->kind == RDI_TypeKind_Bitfield) - { - dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->bitfield.off = src->off; - dst->bitfield.size = src->count; - } - } - } - } - - //- rjf: bake UDT members - ProfScope("bake UDT members") - { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTMember *src_member = &n->v[n_idx]; - RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - } - } - } - - //- rjf: bake UDT enum vals - ProfScope("bake UDT enum vals") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTEnumVal *src_member = &n->v[n_idx]; - RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->val = src_member->val; - } - } - } - - //- rjf: bake UDTs - ProfScope("bake UDTs") - { - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDT *src_udt = &n->v[n_idx]; - RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; - - //- rjf: fill basics - dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 - dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 - dst_udt->line = src_udt->line; - dst_udt->col = src_udt->col; - - //- rjf: fill member info - if(src_udt->member_count != 0) - { - dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); - dst_udt->member_count = src_udt->member_count; - } - - //- rjf: fill enum members - else if(src_udt->enum_val_count != 0) - { - dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); - dst_udt->member_count = src_udt->enum_val_count; - } - } - } - } - - //- rjf: bake locations - ProfScope("bake locations") - { - for EachNode(n, RDIM_LocationChunkNode, params->locations.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Location2 *loc = &n->v[n_idx]; - RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; - switch((RDI_LocationKindEnum)loc->info.kind) - { - case RDI_LocationKind_NULL:{}break; - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); - RDI_U64 write_off = sizeof(loc->info.kind); - for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) - { - MemoryCopy(dst + write_off, &op_node->op, 1); - write_off += 1; - MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); - write_off += op_node->p_size; - } - dst[write_off] = 0; - }break; - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - case RDI_LocationKind_ValReg: - { - RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - } - } - } - } - - //- rjf: bake location blocks - ProfScope("bake location blocks") - { - for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_LocationCase2 *src = &n->v[n_idx]; - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; - dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 - dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 - dst->location_data_off = rdim_off_from_location(src->location); - } - } - } - - //- rjf: bake global variables - ProfScope("bake global variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->voff = src->offset; - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake thread variables - ProfScope("bake thread variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake inline sites - ProfScope("bake inline sites") - { - for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; - RDIM_InlineSite *src = &n->v[n_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } + rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") + { + rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); } } + lane_sync(); } - lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: do final baking tasks + //- rjf: on group split -> pop sub-lane-ctx, release barriers, join all lanes // - ProfScope("do final baking tasks") + if(rdim2_shared->group_split) { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") + if(group_0 && lane_idx() == 0) { - rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); + barrier_release(rdim2_shared->group_0_barrier); } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") + if(group_1 && lane_idx() == 0) { - rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("bake unit vmap") - { - rdim2_shared->baked_unit_vmap = rdim_bake_unit_vmap(arena, ¶ms->units); - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("bake scope vmap") - { - rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); - } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("bake global vmap") - { - rdim2_shared->baked_global_vmap = rdim_bake_global_vmap(arena, ¶ms->global_variables); + barrier_release(rdim2_shared->group_1_barrier); } + lane_ctx(lane_ctx_restore); } lane_sync(); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index be4a09a4..7e4390cb 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -21,6 +21,11 @@ struct RDIM_UnsortedJoinedLineTable typedef struct RDIM2_Shared RDIM2_Shared; struct RDIM2_Shared { + B32 group_split; + U64 group_0_lane_count; + Barrier group_0_barrier; + Barrier group_1_barrier; + RDIM_BakePathTree *path_tree; RDI_U64 line_tables_count; From a44fbb0909ca6d880e11155f8473ff1d5e2aef15 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 29 Aug 2025 17:41:22 -0700 Subject: [PATCH 071/302] parallel radix sort for scope vmap baking --- .../eval_visualization_core.c | 3 +- src/rdi_make/rdi_make_local_2.c | 213 +++++++++++++++++- src/rdi_make/rdi_make_local_2.h | 9 +- 3 files changed, 214 insertions(+), 11 deletions(-) diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index 669f4703..295b3237 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -2068,8 +2068,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) // rjf: [read only] if we did prefix content, do a parenthesized pointer value if(!(params->flags & EV_StringFlag_DisableAddresses) && params->flags & EV_StringFlag_ReadOnlyDisplayRules && - ptr_data->did_prefix_content && - (!ptr_data->did_prefix_string || ptr_data->value_eval.value.u64 == 0)) + ptr_data->did_prefix_content) { *out_string = push_str8f(arena, " (%S)", ptr_value_string); } diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index ab22530c..38241fbe 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -28,6 +28,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // B32 group_0 = 1; B32 group_1 = 1; +#if 0 LaneCtx lane_ctx_restore = {0}; if(rdim2_shared->group_split) { @@ -56,6 +57,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) group_1 = 1; } } +#endif ////////////////////////////////////////////////////////////// //- rjf: group 0 @@ -70,7 +72,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake scope vmap") { - rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); + // rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("bake global vmap") { @@ -85,6 +87,183 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // if(group_1) { + ////////////////////////////////////////////////////////////// + //- rjf: bake scope vmap + // + ProfScope("bake scope vmap") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; + rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); + ProfScope("fill keys/markers") + { + RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; + RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; + for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) + { + RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; + RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 + for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) + { + key_ptr->key = n->v.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = n->v.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + } + } + rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); + rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); + } + lane_sync(); + + // rjf: sort + ProfScope("sort") + { + U64 digits_count = 8; + U64 num_possible_values_per_digit = 1<lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + RDIM_SortKey *src = rdim2_shared->scope_vmap_keys; + RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys__swap; + U64 element_count = rdim2_shared->scope_vmap_count; + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + RDIM_SortKey *sort_key = &src[idx]; + U8 byte_value = (U8)(sort_key->key >> (digit_idx*8)); + digit_counts[byte_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table +#if 1 + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; + } + last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; + } + AssertAlways(last_off == element_count); +#if 0 + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + U64 prev = 0; + if(lane_idx > 0) + { + prev = rdim2_shared->lane_digit_offsets[lane_idx-1][value_idx] + rdim2_shared->lane_digit_counts[lane_idx-1][value_idx]; + } + else if(value_idx > 0) + { + prev = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx-1] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx-1]; + } + AssertAlways(rdim2_shared->lane_digit_offsets[lane_idx][value_idx] == prev); + } + } +#endif + } + lane_sync(); +#else + if(lane_idx() == 0) + { + U64 last_off = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = last_off; + last_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; + } + } + AssertAlways(last_off == element_count); + } + lane_sync(); +#endif + + // rjf: move + { + U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + RDIM_SortKey *src_key = &src[idx]; + U8 byte_value = (U8)(src_key->key >> (digit_idx*8)); + U64 dst_off = lane_digit_offsets[byte_value]; + lane_digit_offsets[byte_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_key); + } + } + lane_sync(); + + // rjf: swap + { + RDIM_SortKey *swap = src; + src = dst; + dst = swap; + } + } + } + lane_sync(); + + // rjf: assert sortedness + { + RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys; + U64 element_count = rdim2_shared->scope_vmap_count; + for EachIndex(idx, element_count) + { + if(idx > 0) + { + AssertAlways(dst[idx-1].key <= dst[idx].key); + } + } + } + } + ////////////////////////////////////////////////////////////// //- rjf: build interned path tree // @@ -141,9 +320,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); - - // rjf: lay out line tables in joined info + rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); ProfScope("lay out line tables") { U64 voffs_base_idx = 0; @@ -815,17 +992,35 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); //- rjf: tighten idx run table - if(lane_idx() == 0) ProfScope("tighten idx run table") + ProfScope("tighten idx run table") { RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_idxes = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_idx_runs = rdim_bake_idx_run_map_from_loose(arena, map_top, &bake_idx_run_map_base_idxes, map); + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_indices = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); + rdim2_shared->bake_idx_runs.slots_base_idxs = bake_idx_run_map_base_indices.slots_base_idxs; + rdim2_shared->bake_idx_runs.total_count = rdim2_shared->bake_idx_runs.slots_base_idxs[rdim2_shared->bake_idx_runs.slots_count]; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); + for EachInRange(idx, slot_range) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); + } + } + } } } } lane_sync(); - RDIM_BakeIdxRunMap2 *bake_idx_runs = rdim2_shared->bake_idx_runs; + RDIM_BakeIdxRunMap2 *bake_idx_runs = &rdim2_shared->bake_idx_runs; ////////////////////////////////////////////////////////////// //- rjf: bake strings @@ -1300,7 +1495,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { barrier_release(rdim2_shared->group_1_barrier); } +#if 0 lane_ctx(lane_ctx_restore); +#endif } lane_sync(); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 7e4390cb..f0e2b9bd 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -26,6 +26,13 @@ struct RDIM2_Shared Barrier group_0_barrier; Barrier group_1_barrier; + RDI_U64 scope_vmap_count; + RDIM_SortKey *scope_vmap_keys; + RDIM_SortKey *scope_vmap_keys__swap; + RDIM_VMapMarker *scope_vmap_markers; + U32 **lane_digit_counts; + U32 **lane_digit_offsets; + RDIM_BakePathTree *path_tree; RDI_U64 line_tables_count; @@ -49,7 +56,7 @@ struct RDIM2_Shared RDIM_BakeIdxRunMapTopology bake_idx_run_map_topology; RDIM_BakeIdxRunMapLoose **lane_bake_idx_run_maps__loose; RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; - RDIM_BakeIdxRunMap2 *bake_idx_runs; + RDIM_BakeIdxRunMap2 bake_idx_runs; RDIM_StringBakeResult baked_strings; RDIM_IndexRunBakeResult baked_idx_runs; From 1d7cd4f4d24fcad36cb5e9ac3ec08ac02e7eb423 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 29 Aug 2025 18:04:53 -0700 Subject: [PATCH 072/302] cleanup / radix sort experimentation --- src/rdi_make/rdi_make_local_2.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 38241fbe..9084212b 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -136,8 +136,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: sort ProfScope("sort") { - U64 digits_count = 8; - U64 num_possible_values_per_digit = 1<lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); RDIM_SortKey *src = rdim2_shared->scope_vmap_keys; @@ -153,14 +154,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(idx, range) { RDIM_SortKey *sort_key = &src[idx]; - U8 byte_value = (U8)(sort_key->key >> (digit_idx*8)); - digit_counts[byte_value] += 1; + U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); + digit_counts[digit_value] += 1; } } lane_sync(); // rjf: compute thread * digit value *relative* offset table -#if 1 { Rng1U64 range = lane_range(num_possible_values_per_digit); for EachInRange(value_idx, range) @@ -179,6 +179,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { U64 last_off = 0; + U64 num_of_nonzero_digit = 0; for EachIndex(value_idx, num_possible_values_per_digit) { for EachIndex(lane_idx, lane_count()) @@ -208,22 +209,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) #endif } lane_sync(); -#else - if(lane_idx() == 0) - { - U64 last_off = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = last_off; - last_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; - } - } - AssertAlways(last_off == element_count); - } - lane_sync(); -#endif // rjf: move { @@ -232,9 +217,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(idx, range) { RDIM_SortKey *src_key = &src[idx]; - U8 byte_value = (U8)(src_key->key >> (digit_idx*8)); - U64 dst_off = lane_digit_offsets[byte_value]; - lane_digit_offsets[byte_value] += 1; + U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; MemoryCopyStruct(&dst[dst_off], src_key); } } From cc0d707eb23c7e5a6066b12f65c1513065f78878 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 30 Aug 2025 11:11:29 -0700 Subject: [PATCH 073/302] eliminate 'lane groups', since we can go wide on the sorts now --- src/rdi_make/rdi_make_local_2.c | 2481 +++++++++++++++---------------- src/rdi_make/rdi_make_local_2.h | 5 - 2 files changed, 1195 insertions(+), 1291 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 9084212b..dd448635 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -10,59 +10,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { rdim2_shared = push_array(arena, RDIM2_Shared, 1); - rdim2_shared->group_split = (lane_count() >= 2); - if(rdim2_shared->group_split) - { - rdim2_shared->group_0_lane_count = Clamp(1, lane_count()/2, 2); - rdim2_shared->group_0_barrier = barrier_alloc(rdim2_shared->group_0_lane_count); - rdim2_shared->group_1_barrier = barrier_alloc(lane_count() - rdim2_shared->group_0_lane_count); - } } lane_sync(); - ////////////////////////////////////////////////////////////// - //- rjf: with sufficient threads, split lanes into two groups: - // - // - group 0: one small group for many heterogeneous 'background' baking tasks - // - group 1: one large group for wide work we can reliably distribute - // - B32 group_0 = 1; - B32 group_1 = 1; #if 0 - LaneCtx lane_ctx_restore = {0}; - if(rdim2_shared->group_split) - { - if(lane_idx() < rdim2_shared->group_0_lane_count) - { - LaneCtx group_0_lane_ctx = - { - lane_idx(), - rdim2_shared->group_0_lane_count, - rdim2_shared->group_0_barrier - }; - lane_ctx_restore = lane_ctx(group_0_lane_ctx); - group_0 = 1; - group_1 = 0; - } - else - { - LaneCtx group_1_lane_ctx = - { - lane_idx() - rdim2_shared->group_0_lane_count, - lane_count() - rdim2_shared->group_0_lane_count, - rdim2_shared->group_1_barrier - }; - lane_ctx_restore = lane_ctx(group_1_lane_ctx); - group_0 = 0; - group_1 = 1; - } - } -#endif - - ////////////////////////////////////////////////////////////// - //- rjf: group 0 - // - if(group_0) { ProfScope("bake all vmaps") { @@ -81,487 +32,829 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); } +#endif ////////////////////////////////////////////////////////////// - //- rjf: group 1 + //- rjf: bake scope vmap // - if(group_1) + ProfScope("bake scope vmap") { - ////////////////////////////////////////////////////////////// - //- rjf: bake scope vmap - // - ProfScope("bake scope vmap") + // rjf: set up + if(lane_idx() == 0) { - // rjf: set up - if(lane_idx() == 0) + rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; + rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); + ProfScope("fill keys/markers") { - rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; - rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); - ProfScope("fill keys/markers") + RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; + RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; + for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) { - RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; - RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; - for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) + for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) { - for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) + RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; + RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 + for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) { - RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 - for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) - { - key_ptr->key = n->v.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = n->v.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } + key_ptr->key = n->v.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = n->v.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; } } } - rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); - rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); } - lane_sync(); - - // rjf: sort - ProfScope("sort") - { - U64 bits_per_digit = 8; - U64 digits_count = 64 / bits_per_digit; - U64 num_possible_values_per_digit = 1 << bits_per_digit; - rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - RDIM_SortKey *src = rdim2_shared->scope_vmap_keys; - RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys__swap; - U64 element_count = rdim2_shared->scope_vmap_count; - for EachIndex(digit_idx, digits_count) - { - // rjf: count digit value occurrences per-lane - { - U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; - MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *sort_key = &src[idx]; - U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); - digit_counts[digit_value] += 1; - } - } - lane_sync(); - - // rjf: compute thread * digit value *relative* offset table - { - Rng1U64 range = lane_range(num_possible_values_per_digit); - for EachInRange(value_idx, range) - { - U64 layout_off = 0; - for EachIndex(lane_idx, lane_count()) - { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; - layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; - } - } - } - lane_sync(); - - // rjf: convert relative offsets -> absolute offsets - if(lane_idx() == 0) - { - U64 last_off = 0; - U64 num_of_nonzero_digit = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; - } - last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; - } - AssertAlways(last_off == element_count); -#if 0 - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - U64 prev = 0; - if(lane_idx > 0) - { - prev = rdim2_shared->lane_digit_offsets[lane_idx-1][value_idx] + rdim2_shared->lane_digit_counts[lane_idx-1][value_idx]; - } - else if(value_idx > 0) - { - prev = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx-1] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx-1]; - } - AssertAlways(rdim2_shared->lane_digit_offsets[lane_idx][value_idx] == prev); - } - } -#endif - } - lane_sync(); - - // rjf: move - { - U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *src_key = &src[idx]; - U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); - U64 dst_off = lane_digit_offsets[digit_value]; - lane_digit_offsets[digit_value] += 1; - MemoryCopyStruct(&dst[dst_off], src_key); - } - } - lane_sync(); - - // rjf: swap - { - RDIM_SortKey *swap = src; - src = dst; - dst = swap; - } - } - } - lane_sync(); - - // rjf: assert sortedness - { - RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys; - U64 element_count = rdim2_shared->scope_vmap_count; - for EachIndex(idx, element_count) - { - if(idx > 0) - { - AssertAlways(dst[idx-1].key <= dst[idx].key); - } - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: build interned path tree - // - if(lane_idx() == 0) ProfScope("build interned path tree") - { - rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); + rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); + rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); } lane_sync(); - RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; - ////////////////////////////////////////////////////////////// - //- rjf: gather all unsorted, joined, line table info; & sort - // - ProfScope("gather all unsorted, joined, line table info; & sort") + // rjf: sort + ProfScope("sort") { - //- rjf: set up outputs - ProfScope("set up outputs") + U64 bits_per_digit = 8; + U64 digits_count = 64 / bits_per_digit; + U64 num_possible_values_per_digit = 1 << bits_per_digit; + rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + RDIM_SortKey *src = rdim2_shared->scope_vmap_keys; + RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys__swap; + U64 element_count = rdim2_shared->scope_vmap_count; + for EachIndex(digit_idx, digits_count) { - // rjf: calculate header info - if(lane_idx() == 0) + // rjf: count digit value occurrences per-lane { - rdim2_shared->line_tables_count = params->line_tables.total_count; - rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); - ProfScope("flatten chunk list") + U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) { - U64 joined_idx = 0; - for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) - { - for EachIndex(idx, n->count) - { - rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; - joined_idx += 1; - } - } + RDIM_SortKey *sort_key = &src[idx]; + U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); + digit_counts[digit_value] += 1; } - rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; - rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_columns_count= 1; - rdim2_shared->line_table_block_take_counter = 0; } lane_sync(); - // rjf: allocate outputs - ProfScope("allocate outputs") + // rjf: compute thread * digit value *relative* offset table { - if(lane_idx() == lane_from_task_idx(0)) + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) { - rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); - ProfScope("lay out line tables") + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) { - U64 voffs_base_idx = 0; - U64 lines_base_idx = 0; - U64 cols_base_idx = 0; - for EachIndex(idx, rdim2_shared->line_tables_count) - { - U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil - RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; - RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; - dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 - dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 - voffs_base_idx += src->line_count + 2*src->seq_count; - lines_base_idx += src->line_count + 1*src->seq_count; - } + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; } } - if(lane_idx() == lane_from_task_idx(3)) + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) { - rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; + } + last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; } - if(lane_idx() == lane_from_task_idx(4)) + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) { - rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); - } - if(lane_idx() == lane_from_task_idx(5)) - { - rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); + RDIM_SortKey *src_key = &src[idx]; + U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_key); } } + lane_sync(); + + // rjf: swap + { + RDIM_SortKey *swap = src; + src = dst; + dst = swap; + } + } + } + lane_sync(); + + // rjf: assert sortedness + { + RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys; + U64 element_count = rdim2_shared->scope_vmap_count; + for EachIndex(idx, element_count) + { + if(idx > 0) + { + AssertAlways(dst[idx-1].key <= dst[idx].key); + } + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: build interned path tree + // + if(lane_idx() == 0) ProfScope("build interned path tree") + { + rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); + } + lane_sync(); + RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; + + ////////////////////////////////////////////////////////////// + //- rjf: gather all unsorted, joined, line table info; & sort + // + ProfScope("gather all unsorted, joined, line table info; & sort") + { + //- rjf: set up outputs + ProfScope("set up outputs") + { + // rjf: calculate header info + if(lane_idx() == 0) + { + rdim2_shared->line_tables_count = params->line_tables.total_count; + rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + ProfScope("flatten chunk list") + { + U64 joined_idx = 0; + for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) + { + for EachIndex(idx, n->count) + { + rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; + joined_idx += 1; + } + } + } + rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; + rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_columns_count= 1; + rdim2_shared->line_table_block_take_counter = 0; } lane_sync(); - //- rjf: wide bake - ProfScope("wide bake") + // rjf: allocate outputs + ProfScope("allocate outputs") { - U64 line_table_block_size = 4096; - U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; - for(;;) + if(lane_idx() == lane_from_task_idx(0)) { - U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); - if(0 == line_table_block_num || line_table_block_count < line_table_block_num) + rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); + ProfScope("lay out line tables") { - break; - } - U64 line_table_block_idx = line_table_block_num-1; - Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); - line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); - for EachInRange(line_table_idx, line_table_range) - { - RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; - RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; - - //- rjf: gather - dst->line_count = src->line_count; - dst->seq_count = src->seq_count; - dst->key_count = dst->line_count + dst->seq_count; - dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); - dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); + U64 voffs_base_idx = 0; + U64 lines_base_idx = 0; + U64 cols_base_idx = 0; + for EachIndex(idx, rdim2_shared->line_tables_count) { - RDIM_SortKey *key_ptr = dst->line_keys; - RDIM_LineRec *rec_ptr = dst->line_recs; - for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) - { - RDIM_LineSequence *seq = &seq_n->v; - for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) - { - key_ptr->key = seq->voffs[line_idx]; - key_ptr->val = rec_ptr; - key_ptr += 1; - rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 - rec_ptr->line_num = seq->line_nums[line_idx]; - if(seq->col_nums != 0) - { - rec_ptr->col_first = seq->col_nums[line_idx*2]; - rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; - } - rec_ptr += 1; - } - key_ptr->key = seq->voffs[seq->line_count]; - key_ptr->val = 0; - key_ptr += 1; - } + U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil + RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; + RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; + dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 + dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 + voffs_base_idx += src->line_count + 2*src->seq_count; + lines_base_idx += src->line_count + 1*src->seq_count; } - - //- rjf: sort - rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); - - //- rjf: fill - RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; - U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; - RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; - U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; - RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; - RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; + } + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); + } + } + } + lane_sync(); + + //- rjf: wide bake + ProfScope("wide bake") + { + U64 line_table_block_size = 4096; + U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; + for(;;) + { + U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); + if(0 == line_table_block_num || line_table_block_count < line_table_block_num) + { + break; + } + U64 line_table_block_idx = line_table_block_num-1; + Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); + line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); + for EachInRange(line_table_idx, line_table_range) + { + RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + + //- rjf: gather + dst->line_count = src->line_count; + dst->seq_count = src->seq_count; + dst->key_count = dst->line_count + dst->seq_count; + dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); + dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); + { + RDIM_SortKey *key_ptr = dst->line_keys; + RDIM_LineRec *rec_ptr = dst->line_recs; + for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) { - for EachIndex(idx, sorted_line_keys_count) + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) { - arranged_voffs[idx] = sorted_line_keys[idx].key; + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; } - arranged_voffs[sorted_line_keys_count] = ~0ull; - for EachIndex(idx, sorted_line_keys_count) + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + + //- rjf: sort + rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); + + //- rjf: fill + RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; + U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; + RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; + { + for EachIndex(idx, sorted_line_keys_count) + { + arranged_voffs[idx] = sorted_line_keys[idx].key; + } + arranged_voffs[sorted_line_keys_count] = ~0ull; + for EachIndex(idx, sorted_line_keys_count) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; + if(rec != 0) { - RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; - if(rec != 0) - { - arranged_lines[idx].file_idx = rec->file_id; - arranged_lines[idx].line_num = rec->line_num; - } - else - { - arranged_lines[idx].file_idx = 0; - arranged_lines[idx].line_num = 0; - } + arranged_lines[idx].file_idx = rec->file_id; + arranged_lines[idx].line_num = rec->line_num; + } + else + { + arranged_lines[idx].file_idx = 0; + arranged_lines[idx].line_num = 0; } } } } } } - lane_sync(); - RDI_U64 line_tables_count = rdim2_shared->line_tables_count; - RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; - RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; - RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; - - ////////////////////////////////////////////////////////////// - //- rjf: build string map - // - ProfScope("build string map") + } + lane_sync(); + RDI_U64 line_tables_count = rdim2_shared->line_tables_count; + RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; + RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; + + ////////////////////////////////////////////////////////////// + //- rjf: build string map + // + ProfScope("build string map") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") + rdim2_shared->bake_string_map_topology.slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; + + //- rjf: push all strings into this lane's map + ProfScope("push all strings into this lane's map") + { + // rjf: push small top-level strings + if(lane_idx() == 0) ProfScope("push small top-level strings") { - rdim2_shared->bake_string_map_topology.slots_count = (64 + - params->procedures.total_count*1 + - params->global_variables.total_count*1 + - params->thread_variables.total_count*1 + - params->types.total_count/2); - rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); + rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); } - lane_sync(); - //- rjf: set up this lane's map - ProfScope("set up this lane's map") + // rjf: push strings from source files + ProfScope("src files") { - rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } } - RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; - RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; - //- rjf: push all strings into this lane's map - ProfScope("push all strings into this lane's map") + // rjf: push strings from units + ProfScope("units") { - // rjf: push small top-level strings - if(lane_idx() == 0) ProfScope("push small top-level strings") + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) { - rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); - rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); - rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } - - // rjf: push strings from source files - ProfScope("src files") + } + + // rjf: push strings from types + ProfScope("types") + { + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) { - for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } - - // rjf: push strings from units - ProfScope("units") + } + + // rjf: push strings from udt members + ProfScope("udt members") + { + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) { - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } - - // rjf: push strings from types - ProfScope("types") + } + + // rjf: push strings from udt enum values + ProfScope("udt enum values") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) { - for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } - - // rjf: push strings from udt members - ProfScope("udt members") + } + + // rjf: push strings from symbols + RDIM_SymbolChunkList *symbol_lists[] = + { + ¶ms->global_variables, + ¶ms->thread_variables, + ¶ms->procedures, + ¶ms->constants, + }; + ProfScope("symbols") + { + for EachElement(list_idx, symbol_lists) { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + ProfScope("symbols (%I64u)", list_idx) { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from udt enum values - ProfScope("udt enum values") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from symbols - RDIM_SymbolChunkList *symbol_lists[] = - { - ¶ms->global_variables, - ¶ms->thread_variables, - ¶ms->procedures, - ¶ms->constants, - }; - ProfScope("symbols") - { - for EachElement(list_idx, symbol_lists) - { - ProfScope("symbols (%I64u)", list_idx) + for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) { - for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); } } } - - //- rjf: push strings from inline sites - ProfScope("inline sites") + } + + //- rjf: push strings from inline sites + ProfScope("inline sites") + { + for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) { - for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + + //- rjf: push strings from scopes + ProfScope("scopes") + { + for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) + { + Rng1U64 range = lane_range(n->count); + rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + } + } + } + + //- rjf: join & sort + if(lane_idx() == 0) + { + rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + lane_sync(); + ProfScope("join & sort") + { + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } } } - - //- rjf: push strings from scopes - ProfScope("scopes") + } + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) { - for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + lane_sync(); + + //- rjf: tighten string table + ProfScope("tighten string table") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_strings.slots_count = map_top->slots_count; + rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); + rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; + rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + for EachInRange(idx, slot_range) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + } + } + } + } + } + lane_sync(); + RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + + ////////////////////////////////////////////////////////////// + //- rjf: build name maps + // + ProfScope("build name maps") + { + //- rjf: set up + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + U64 slot_count = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; +#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break + Case(GlobalVariables, params->global_variables.total_count); + Case(ThreadVariables, params->thread_variables.total_count); + Case(Constants, params->constants.total_count); + Case(Procedures, params->procedures.total_count); + Case(LinkNameProcedures, params->procedures.total_count); + Case(Types, params->types.total_count); + Case(NormalSourcePaths, params->src_files.total_count); +#undef Case + } + rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); + rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; + } + } + lane_sync(); + + //- rjf: wide build + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); + RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; + B32 link_names = 0; + RDIM_SymbolChunkList *symbols = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; + case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; + case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; + case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; + symbol_name_map_build:; + { + for EachNode(n, RDIM_SymbolChunkNode, symbols->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Symbol *symbol = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); + } + } + }break; + case RDI_NameMapKind_Types: + { + RDIM_TypeChunkList *types = ¶ms->types; + for EachNode(n, RDIM_TypeChunkNode, types->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Type *type = &n->v[n_idx]; + rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); + } + } + }break; + case RDI_NameMapKind_NormalSourcePaths: + { + RDIM_SrcFileChunkList *src_files = ¶ms->src_files; + for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_SrcFile *src_file = &n->v[n_idx]; + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); + rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); + } + } + }break; + } + } + lane_sync(); + + //- rjf: join & sort + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap2 *dst_map = map; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: build index runs + // + ProfScope("build index runs") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") + { + rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + + params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->types.total_count); + rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + + //- rjf: wide fill of all index runs + ProfScope("fill all lane index run maps") + { + //- rjf: bake runs of function-type parameter lists + ProfScope("bake runs of function-type parameter lists") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) + { + RDIM_Type *type = &n->v[n_idx]; + if(type->count == 0) + { + continue; + } + if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = type->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); + } + } + } + } + + //- rjf: bake runs of name map match lists + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 slot_idx_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + if(slot != 0) + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + U64 active_hash = 0; + RDIM_BakeNameChunkNode *n = slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + U64 hash = 0; + U64 idx = 0; + if(n != 0) + { + hash = n->v[n_idx].hash; + idx = n->v[n_idx].idx; + } + + // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list + if(hash != active_hash && active_idx_count != 0) + { + if(active_idx_count > 1) + { + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + } + active_hash = hash; + first_idx_run_node = 0; + last_idx_run_node = 0; + temp_end(scratch); + } + + // rjf: hash matches the active list -> push + if(hash != 0 && hash == active_hash) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); } } } @@ -569,7 +862,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join & sort if(lane_idx() == 0) { - rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); } lane_sync(); ProfScope("join & sort") @@ -577,20 +870,20 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; } else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) { - rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } @@ -599,890 +892,506 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) { - *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); } } } } lane_sync(); - //- rjf: tighten string table - ProfScope("tighten string table") + //- rjf: tighten idx run table + ProfScope("tighten idx run table") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { - RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_strings.slots_count = map_top->slots_count; - rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); - rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; - rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_indices = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); + rdim2_shared->bake_idx_runs.slots_base_idxs = bake_idx_run_map_base_indices.slots_base_idxs; + rdim2_shared->bake_idx_runs.total_count = rdim2_shared->bake_idx_runs.slots_base_idxs[rdim2_shared->bake_idx_runs.slots_count]; } lane_sync(); ProfScope("fill tight map") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); for EachInRange(idx, slot_range) { if(map->slots[idx] != 0) { - rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); } } } } } - lane_sync(); - RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; - - ////////////////////////////////////////////////////////////// - //- rjf: build name maps - // - ProfScope("build name maps") + } + lane_sync(); + RDIM_BakeIdxRunMap2 *bake_idx_runs = &rdim2_shared->bake_idx_runs; + + ////////////////////////////////////////////////////////////// + //- rjf: bake strings + // + ProfScope("bake strings") + { + // rjf: set up + if(lane_idx() == 0) ProfScope("set up; lay out strings") { - //- rjf: set up - if(lane_idx() == 0) + rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; + rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); + RDI_U64 off_cursor = 0; + for EachIndex(slot_idx, bake_strings->slots_count) { - for EachNonZeroEnumVal(RDI_NameMapKind, k) + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) { - U64 slot_count = 0; - switch((RDI_NameMapKindEnum)k) + for EachIndex(n_idx, n->count) { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; -#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break - Case(GlobalVariables, params->global_variables.total_count); - Case(ThreadVariables, params->thread_variables.total_count); - Case(Constants, params->constants.total_count); - Case(Procedures, params->procedures.total_count); - Case(LinkNameProcedures, params->procedures.total_count); - Case(Types, params->types.total_count); - Case(NormalSourcePaths, params->src_files.total_count); -#undef Case - } - rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); - rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; - } - } - lane_sync(); - - //- rjf: wide build - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); - RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; - B32 link_names = 0; - RDIM_SymbolChunkList *symbols = 0; - switch((RDI_NameMapKindEnum)k) - { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; - case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; - case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; - case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; - symbol_name_map_build:; - { - for EachNode(n, RDIM_SymbolChunkNode, symbols->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Symbol *symbol = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); - } - } - }break; - case RDI_NameMapKind_Types: - { - RDIM_TypeChunkList *types = ¶ms->types; - for EachNode(n, RDIM_TypeChunkNode, types->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Type *type = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); - } - } - }break; - case RDI_NameMapKind_NormalSourcePaths: - { - RDIM_SrcFileChunkList *src_files = ¶ms->src_files; - for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_SrcFile *src_file = &n->v[n_idx]; - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); - rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); - } - } - }break; - } - } - lane_sync(); - - //- rjf: join & sort - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); - } - } - lane_sync(); - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - - //- rjf: join - ProfScope("join") - { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; - RDIM_BakeNameMap2 *dst_map = map; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } - } - - //- rjf: sort - ProfScope("sort") - { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; + off_cursor += src->string.size; } } } + rdim2_shared->baked_strings.string_data_size = off_cursor; + rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); } lane_sync(); - ////////////////////////////////////////////////////////////// - //- rjf: build index runs - // - ProfScope("build index runs") + // rjf: wide fill string data + ProfScope("wide fill") { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") + Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); + for EachInRange(slot_idx, slot_idx_range) { - rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + - params->procedures.total_count + - params->global_variables.total_count + - params->thread_variables.total_count + - params->types.total_count); - rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); - } - lane_sync(); - - //- rjf: set up this lane's map - ProfScope("set up this lane's map") - { - rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; - - //- rjf: wide fill of all index runs - ProfScope("fill all lane index run maps") - { - //- rjf: bake runs of function-type parameter lists - ProfScope("bake runs of function-type parameter lists") + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) + for EachIndex(n_idx, n->count) { - Rng1U64 range = lane_range(n->count); - ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) - { - RDIM_Type *type = &n->v[n_idx]; - if(type->count == 0) - { - continue; - } - if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = type->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); - } - } - } - } - - //- rjf: bake runs of name map match lists - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - Rng1U64 slot_idx_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_idx_range) - { - RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; - if(slot != 0) - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct IdxRunNode IdxRunNode; - struct IdxRunNode - { - IdxRunNode *next; - RDI_U64 idx; - }; - IdxRunNode *first_idx_run_node = 0; - IdxRunNode *last_idx_run_node = 0; - U64 active_idx_count = 0; - U64 active_hash = 0; - RDIM_BakeNameChunkNode *n = slot->first; - U64 n_idx = 0; - for(;;) - { - // rjf: advance chunk - if(n != 0 && n_idx >= n->count) - { - n = n->next; - n_idx = 0; - } - - // rjf: grab next element - U64 hash = 0; - U64 idx = 0; - if(n != 0) - { - hash = n->v[n_idx].hash; - idx = n->v[n_idx].idx; - } - - // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash && active_idx_count != 0) - { - if(active_idx_count > 1) - { - RDI_U64 idxs_count = active_idx_count; - RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); - { - U64 write_idx = 0; - for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) - { - idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 - write_idx += 1; - } - } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); - } - active_hash = hash; - first_idx_run_node = 0; - last_idx_run_node = 0; - temp_end(scratch); - } - - // rjf: hash matches the active list -> push - if(hash != 0 && hash == active_hash) - { - IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); - idx_run_n->idx = idx; - SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); - active_idx_count += 1; - } - - // rjf: advance index - n_idx += 1; - - // rjf: end on zero node - if(n == 0) - { - break; - } - } - scratch_end(scratch); - } - } - } - - //- rjf: join & sort - if(lane_idx() == 0) - { - rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - lane_sync(); - ProfScope("join & sort") - { - //- rjf: join - ProfScope("join") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } - } - - //- rjf: sort - ProfScope("sort") - { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } - } - } - } - lane_sync(); - - //- rjf: tighten idx run table - ProfScope("tighten idx run table") - { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; - if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") - { - RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_indices = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; - rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); - rdim2_shared->bake_idx_runs.slots_base_idxs = bake_idx_run_map_base_indices.slots_base_idxs; - rdim2_shared->bake_idx_runs.total_count = rdim2_shared->bake_idx_runs.slots_base_idxs[rdim2_shared->bake_idx_runs.slots_count]; - } - lane_sync(); - ProfScope("fill tight map") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); - for EachInRange(idx, slot_range) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); - } - } + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; + rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); } } } } - lane_sync(); - RDIM_BakeIdxRunMap2 *bake_idx_runs = &rdim2_shared->bake_idx_runs; - - ////////////////////////////////////////////////////////////// - //- rjf: bake strings - // - ProfScope("bake strings") - { - // rjf: set up - if(lane_idx() == 0) ProfScope("set up; lay out strings") - { - rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; - rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); - RDI_U64 off_cursor = 0; - for EachIndex(slot_idx, bake_strings->slots_count) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) - { - for EachIndex(n_idx, n->count) - { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; - off_cursor += src->string.size; - } - } - } - rdim2_shared->baked_strings.string_data_size = off_cursor; - rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); - } - lane_sync(); - - // rjf: wide fill string data - ProfScope("wide fill") - { - Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); - for EachInRange(slot_idx, slot_idx_range) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) - { - for EachIndex(n_idx, n->count) - { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; - rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); - } - } - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: bake units, src files, symbols, types, UDTs - // - { - //- rjf: setup outputs - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_units.units_count = params->units.total_count+1; - rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - } - if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; - rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); - } - if(lane_idx() == lane_from_task_idx(4)) - { - rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; - rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); - } - if(lane_idx() == lane_from_task_idx(5)) - { - rdim2_shared->baked_udts.members_count = params->members.total_count+1; - rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); - } - if(lane_idx() == lane_from_task_idx(6)) - { - rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; - rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); - } - if(lane_idx() == lane_from_task_idx(7)) - { - rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; - rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); - } - if(lane_idx() == lane_from_task_idx(8)) - { - rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; - rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); - } - if(lane_idx() == lane_from_task_idx(9)) - { - rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; - rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); - } - if(lane_idx() == lane_from_task_idx(10)) - { - rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; - rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); - } - if(lane_idx() == lane_from_task_idx(11)) - { - rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); - } - if(lane_idx() == lane_from_task_idx(12)) - { - rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); - } - if(lane_idx() == lane_from_task_idx(13)) - { - rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; - rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); - } - if(lane_idx() == lane_from_task_idx(14)) - { - rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; - rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); - } - if(lane_idx() == lane_from_task_idx(15)) - { - rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; - rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); - } - lane_sync(); - - //- rjf: bake units - ProfScope("bake units") - { - for EachNode(n, RDIM_UnitChunkNode, params->units.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Unit *src = &n->v[n_idx]; - RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; - dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); - dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); - dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); - dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); - dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); - dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); - dst->language = src->language; - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - - //- rjf: bake type nodes - ProfScope("bake type nodes") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Type *src = &n->v[n_idx]; - RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; - - //- rjf: fill shared type node info - dst->kind = src->kind; - dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 - dst->byte_size = src->byte_size; - - //- rjf: fill built-in-only type node info - if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) - { - dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - } - - //- rjf: fill array sizes - else if(dst->kind == RDI_TypeKind_Array) - { - U64 direct_byte_size = 1; - if(src->direct_type && src->direct_type->byte_size > 0) - { - direct_byte_size = src->direct_type->byte_size; - } - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); - dst->constructed.count = src->byte_size / direct_byte_size; - } - - //- rjf: fill constructed type node info - else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) - { - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->constructed.count = src->count; - if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = src->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); - } - else if(dst->kind == RDI_TypeKind_MemberPtr) - { - // TODO(rjf): member pointers not currently supported. - } - } - - //- rjf: fill user-defined-type info - else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) - { - dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 - dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill bitfield info - else if(dst->kind == RDI_TypeKind_Bitfield) - { - dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->bitfield.off = src->off; - dst->bitfield.size = src->count; - } - } - } - } - - //- rjf: bake UDT members - ProfScope("bake UDT members") - { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTMember *src_member = &n->v[n_idx]; - RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - } - } - } - - //- rjf: bake UDT enum vals - ProfScope("bake UDT enum vals") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTEnumVal *src_member = &n->v[n_idx]; - RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->val = src_member->val; - } - } - } - - //- rjf: bake UDTs - ProfScope("bake UDTs") - { - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDT *src_udt = &n->v[n_idx]; - RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; - - //- rjf: fill basics - dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 - dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 - dst_udt->line = src_udt->line; - dst_udt->col = src_udt->col; - - //- rjf: fill member info - if(src_udt->member_count != 0) - { - dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); - dst_udt->member_count = src_udt->member_count; - } - - //- rjf: fill enum members - else if(src_udt->enum_val_count != 0) - { - dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); - dst_udt->member_count = src_udt->enum_val_count; - } - } - } - } - - //- rjf: bake locations - ProfScope("bake locations") - { - for EachNode(n, RDIM_LocationChunkNode, params->locations.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Location2 *loc = &n->v[n_idx]; - RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; - switch((RDI_LocationKindEnum)loc->info.kind) - { - case RDI_LocationKind_NULL:{}break; - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); - RDI_U64 write_off = sizeof(loc->info.kind); - for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) - { - MemoryCopy(dst + write_off, &op_node->op, 1); - write_off += 1; - MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); - write_off += op_node->p_size; - } - dst[write_off] = 0; - }break; - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - case RDI_LocationKind_ValReg: - { - RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - } - } - } - } - - //- rjf: bake location blocks - ProfScope("bake location blocks") - { - for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_LocationCase2 *src = &n->v[n_idx]; - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; - dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 - dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 - dst->location_data_off = rdim_off_from_location(src->location); - } - } - } - - //- rjf: bake global variables - ProfScope("bake global variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->voff = src->offset; - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake thread variables - ProfScope("bake thread variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake inline sites - ProfScope("bake inline sites") - { - for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; - RDIM_InlineSite *src = &n->v[n_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: do final baking tasks - // - ProfScope("do final baking tasks") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") - { - rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") - { - rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); - } - } - lane_sync(); } ////////////////////////////////////////////////////////////// - //- rjf: on group split -> pop sub-lane-ctx, release barriers, join all lanes + //- rjf: bake units, src files, symbols, types, UDTs // - if(rdim2_shared->group_split) { - if(group_0 && lane_idx() == 0) + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) { - barrier_release(rdim2_shared->group_0_barrier); + rdim2_shared->baked_units.units_count = params->units.total_count+1; + rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); } - if(group_1 && lane_idx() == 0) + if(lane_idx() == lane_from_task_idx(1)) { - barrier_release(rdim2_shared->group_1_barrier); + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; + rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_udts.members_count = params->members.total_count+1; + rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + } + if(lane_idx() == lane_from_task_idx(6)) + { + rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; + rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + } + if(lane_idx() == lane_from_task_idx(7)) + { + rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + } + if(lane_idx() == lane_from_task_idx(8)) + { + rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; + rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + } + if(lane_idx() == lane_from_task_idx(9)) + { + rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; + rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); + } + if(lane_idx() == lane_from_task_idx(10)) + { + rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; + rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); + } + if(lane_idx() == lane_from_task_idx(11)) + { + rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + } + if(lane_idx() == lane_from_task_idx(12)) + { + rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + } + if(lane_idx() == lane_from_task_idx(13)) + { + rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + } + if(lane_idx() == lane_from_task_idx(14)) + { + rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + } + if(lane_idx() == lane_from_task_idx(15)) + { + rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; + rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + } + lane_sync(); + + //- rjf: bake units + ProfScope("bake units") + { + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Unit *src = &n->v[n_idx]; + RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; + dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); + dst->language = src->language; + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + + //- rjf: bake type nodes + ProfScope("bake type nodes") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Type *src = &n->v[n_idx]; + RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; + + //- rjf: fill shared type node info + dst->kind = src->kind; + dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 + dst->byte_size = src->byte_size; + + //- rjf: fill built-in-only type node info + if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) + { + dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + } + + //- rjf: fill array sizes + else if(dst->kind == RDI_TypeKind_Array) + { + U64 direct_byte_size = 1; + if(src->direct_type && src->direct_type->byte_size > 0) + { + direct_byte_size = src->direct_type->byte_size; + } + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); + dst->constructed.count = src->byte_size / direct_byte_size; + } + + //- rjf: fill constructed type node info + else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) + { + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->constructed.count = src->count; + if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = src->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); + } + else if(dst->kind == RDI_TypeKind_MemberPtr) + { + // TODO(rjf): member pointers not currently supported. + } + } + + //- rjf: fill user-defined-type info + else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) + { + dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 + dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill bitfield info + else if(dst->kind == RDI_TypeKind_Bitfield) + { + dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->bitfield.off = src->off; + dst->bitfield.size = src->count; + } + } + } + } + + //- rjf: bake UDT members + ProfScope("bake UDT members") + { + for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTMember *src_member = &n->v[n_idx]; + RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + } + } + } + + //- rjf: bake UDT enum vals + ProfScope("bake UDT enum vals") + { + for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDTEnumVal *src_member = &n->v[n_idx]; + RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->val = src_member->val; + } + } + } + + //- rjf: bake UDTs + ProfScope("bake UDTs") + { + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_UDT *src_udt = &n->v[n_idx]; + RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + + //- rjf: fill member info + if(src_udt->member_count != 0) + { + dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); + dst_udt->member_count = src_udt->member_count; + } + + //- rjf: fill enum members + else if(src_udt->enum_val_count != 0) + { + dst_udt->flags |= RDI_UDTFlag_EnumMembers; + dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); + dst_udt->member_count = src_udt->enum_val_count; + } + } + } + } + + //- rjf: bake locations + ProfScope("bake locations") + { + for EachNode(n, RDIM_LocationChunkNode, params->locations.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Location2 *loc = &n->v[n_idx]; + RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + switch((RDI_LocationKindEnum)loc->info.kind) + { + case RDI_LocationKind_NULL:{}break; + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); + RDI_U64 write_off = sizeof(loc->info.kind); + for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) + { + MemoryCopy(dst + write_off, &op_node->op, 1); + write_off += 1; + MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); + write_off += op_node->p_size; + } + dst[write_off] = 0; + }break; + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + case RDI_LocationKind_ValReg: + { + RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + } + } + } + } + + //- rjf: bake location blocks + ProfScope("bake location blocks") + { + for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_LocationCase2 *src = &n->v[n_idx]; + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = rdim_off_from_location(src->location); + } + } + } + + //- rjf: bake global variables + ProfScope("bake global variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->voff = src->offset; + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake thread variables + ProfScope("bake thread variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake inline sites + ProfScope("bake inline sites") + { + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; + RDIM_InlineSite *src = &n->v[n_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: do final baking tasks + // + ProfScope("do final baking tasks") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") + { + rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") + { + rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); } -#if 0 - lane_ctx(lane_ctx_restore); -#endif } lane_sync(); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index f0e2b9bd..aaf07077 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -21,11 +21,6 @@ struct RDIM_UnsortedJoinedLineTable typedef struct RDIM2_Shared RDIM2_Shared; struct RDIM2_Shared { - B32 group_split; - U64 group_0_lane_count; - Barrier group_0_barrier; - Barrier group_1_barrier; - RDI_U64 scope_vmap_count; RDIM_SortKey *scope_vmap_keys; RDIM_SortKey *scope_vmap_keys__swap; From 55b05301a4d589789b546104fd8b3c825d82c406 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 06:07:36 -0700 Subject: [PATCH 074/302] expand scope vmap sorting -> all vmaps; do final vmap bakes; do first pass of scope (1 scope -> many locals, many voffs) layout / baking --- src/base/base_math.c | 17 + src/base/base_math.h | 5 + src/base/base_thread_context.c | 14 - src/base/base_thread_context.h | 3 +- src/mule/mule_main.cpp | 11 + src/raddbg/raddbg_main.c | 2 + src/rdi_make/rdi_make_local_2.c | 531 +++++++++++++++++++++++++++++--- src/rdi_make/rdi_make_local_2.h | 22 +- 8 files changed, 543 insertions(+), 62 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index b21a0a9e..b884937e 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -809,3 +809,20 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list) } return arr; } + +//////////////////////////////// +//~ rjf: N -> M Element Subdivision + +internal Rng1U64 +m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count) +{ + U64 main_idxes_per_lane = m_count/n_count; + U64 leftover_idxes_count = m_count - main_idxes_per_lane*n_count; + U64 leftover_idxes_before_this_lane_count = Min(n_idx, leftover_idxes_count); + U64 lane_base_idx = n_idx*main_idxes_per_lane + leftover_idxes_before_this_lane_count; + U64 lane_base_idx__clamped = Min(lane_base_idx, m_count); + U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((n_idx < leftover_idxes_count) ? 1 : 0); + U64 lane_opl_idx__clamped = Min(lane_opl_idx, m_count); + Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped); + return result; +} diff --git a/src/base/base_math.h b/src/base/base_math.h index e9022690..7ea6e2ec 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -691,4 +691,9 @@ internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); +//////////////////////////////// +//~ rjf: N -> M Element Subdivision + +internal Rng1U64 m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count); + #endif //BASE_MATH_H diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 7fade9d3..c13123fa 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -94,20 +94,6 @@ tctx_lane_barrier_wait(void) ProfEnd(); } -internal Rng1U64 -tctx_lane_idx_range_from_count(U64 count) -{ - U64 main_idxes_per_lane = count/lane_count(); - U64 leftover_idxes_count = count - main_idxes_per_lane*lane_count(); - U64 leftover_idxes_before_this_lane_count = Min(lane_idx(), leftover_idxes_count); - U64 lane_base_idx = lane_idx()*main_idxes_per_lane + leftover_idxes_before_this_lane_count; - U64 lane_base_idx__clamped = Min(lane_base_idx, count); - U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((lane_idx() < leftover_idxes_count) ? 1 : 0); - U64 lane_opl_idx__clamped = Min(lane_opl_idx, count); - Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped); - return result; -} - //- rjf: thread names internal void diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 2394b98b..0f6952aa 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -53,13 +53,12 @@ internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); //- rjf: lane metadata internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx); internal void tctx_lane_barrier_wait(void); -internal Rng1U64 tctx_lane_idx_range_from_count(U64 count); #define lane_idx() (tctx_selected()->lane_ctx.lane_idx) #define lane_count() (tctx_selected()->lane_ctx.lane_count) #define lane_from_task_idx(idx) ((idx)%lane_count()) #define lane_ctx(ctx) tctx_set_lane_ctx((ctx)) #define lane_sync() tctx_lane_barrier_wait() -#define lane_range(count) tctx_lane_idx_range_from_count(count) +#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count)) //- rjf: thread names internal void tctx_set_thread_name(String8 name); diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 203b6036..00a60072 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -345,6 +345,15 @@ enum{ Anonymous_D, }; +typedef uint32_t SizedKind; +enum SizedKindEnum +{ + SizedKind_A, + SizedKind_B, + SizedKind_C, + SizedKind_D, +}; + typedef Kind Alias1; typedef Flag Alias2; typedef Has_Enums Alias3; @@ -635,6 +644,8 @@ type_coverage_eval_tests(void) dynamic_array_vector.push_back(dynamic); dynamic_array_vector.push_back(dynamic); + SizedKind sized_kind = SizedKind_C; + int x = (int)(Anonymous_D); } diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 374427dc..25e8221b 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -10,6 +10,8 @@ // [ ] hardware breakpoints regression (global eval in ctrl) // [ ] native filesystem dialog, resizing raddbg window -> crash! // [ ] stdout/stderr path target setting is now busted >:( +// [ ] target ui entry point should override built-in entry point +// [ ] list of all tabs in palette // //- memory view // [ ] have smaller visible range than entire memory diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index dd448635..79bae023 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -13,34 +13,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); -#if 0 - { - ProfScope("bake all vmaps") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake unit vmap") - { - rdim2_shared->baked_unit_vmap = rdim_bake_unit_vmap(arena, ¶ms->units); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake scope vmap") - { - // rdim2_shared->baked_scope_vmap = rdim_bake_scope_vmap(arena, ¶ms->scopes); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("bake global vmap") - { - rdim2_shared->baked_global_vmap = rdim_bake_global_vmap(arena, ¶ms->global_variables); - } - } - lane_sync(); - } -#endif - ////////////////////////////////////////////////////////////// - //- rjf: bake scope vmap + //- rjf: gather unsorted vmap keys/markers // - ProfScope("bake scope vmap") + ProfScope("gather unsorted vmap keys/markers") { - // rjf: set up - if(lane_idx() == 0) + //- rjf: gather scope vmap keys/markers + if(lane_idx() == lane_from_task_idx(0)) ProfScope("gather scope vmap keys/markers") { rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); @@ -75,22 +54,183 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } + } + + //- rjf: gather unit vmap keys/markers + if(lane_idx() == lane_from_task_idx(1)) ProfScope("gather unit vmap keys/markers") + { + // rjf: count voff ranges + RDI_U64 voff_range_count = 0; + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_Unit *unit = &n->v[idx]; + voff_range_count += unit->voff_ranges.total_count; + } + } + + // rjf: count necessary markers + RDI_U64 marker_count = voff_range_count*2; + + // rjf: build keys/markers arrays + RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + RDI_U32 unit_idx = 1; + for(RDIM_UnitChunkNode *unit_chunk_n = params->units.first; + unit_chunk_n != 0; + unit_chunk_n = unit_chunk_n->next) + { + for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) + { + RDIM_Unit *unit = &unit_chunk_n->v[idx]; + for(RDIM_Rng1U64ChunkNode *n = unit->voff_ranges.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Rng1U64 range = n->v[chunk_idx]; + if(range.min < range.max) + { + key_ptr->key = range.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = range.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + } + unit_idx += 1; + } + } + } + + // rjf: store + rdim2_shared->unit_vmap_count = marker_count; + rdim2_shared->unit_vmap_keys = keys; + rdim2_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim2_shared->unit_vmap_markers = markers; + } + + //- rjf: gather global vmap keys/markers + if(lane_idx() == lane_from_task_idx(2)) ProfScope("gather global vmap keys/markers") + { + //- rjf: allocate keys/markers + RDI_U64 marker_count = params->global_variables.total_count*2 + 2; + RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); + + //- rjf: fill + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + + // rjf: fill actual globals + for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Symbol *global_var = &n->v[chunk_idx]; + RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 + RDI_U64 global_var_size = global_var->type ? global_var->type->byte_size : 1; + + RDI_U64 first = global_var->offset; + RDI_U64 opl = first + global_var_size; + + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + // rjf: fill nil global + { + RDI_U32 global_idx = 0; + RDI_U64 first = 0; + RDI_U64 opl = 0xffffffffffffffffull; + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + //- rjf: store + rdim2_shared->global_vmap_count = marker_count; + rdim2_shared->global_vmap_keys = keys; + rdim2_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim2_shared->global_vmap_markers = markers; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: sort all vmap keys + // + ProfScope("sort all vmap keys") + { + // rjf: set up + if(lane_idx() == 0) + { rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); } lane_sync(); // rjf: sort - ProfScope("sort") + struct { + RDI_U64 vmap_count; + RDIM_SortKey *keys; + RDIM_SortKey *keys__swap; + } + sort_tasks[] = + { + {rdim2_shared->scope_vmap_count, rdim2_shared->scope_vmap_keys, rdim2_shared->scope_vmap_keys__swap}, + {rdim2_shared->unit_vmap_count, rdim2_shared->unit_vmap_keys, rdim2_shared->unit_vmap_keys__swap}, + {rdim2_shared->global_vmap_count, rdim2_shared->global_vmap_keys, rdim2_shared->global_vmap_keys__swap}, + }; + for EachElement(sort_task_idx, sort_tasks) ProfScope("sort %I64u", sort_task_idx) + { + RDI_U64 vmap_count = sort_tasks[sort_task_idx].vmap_count; + RDIM_SortKey *keys = sort_tasks[sort_task_idx].keys; + RDIM_SortKey *keys__swap = sort_tasks[sort_task_idx].keys__swap; U64 bits_per_digit = 8; U64 digits_count = 64 / bits_per_digit; U64 num_possible_values_per_digit = 1 << bits_per_digit; rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - RDIM_SortKey *src = rdim2_shared->scope_vmap_keys; - RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys__swap; - U64 element_count = rdim2_shared->scope_vmap_count; + RDIM_SortKey *src = keys; + RDIM_SortKey *dst = keys__swap; + U64 element_count = vmap_count; for EachIndex(digit_idx, digits_count) { // rjf: count digit value occurrences per-lane @@ -162,21 +302,193 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - lane_sync(); - - // rjf: assert sortedness - { - RDIM_SortKey *dst = rdim2_shared->scope_vmap_keys; - U64 element_count = rdim2_shared->scope_vmap_count; - for EachIndex(idx, element_count) - { - if(idx > 0) - { - AssertAlways(dst[idx-1].key <= dst[idx].key); - } - } - } } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: bake all vmaps + // + ProfScope("bake all vmaps") + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct VMapBakeTask VMapBakeTask; + struct VMapBakeTask + { + VMapBakeTask *next; + String8 name; + RDI_U64 count; + RDIM_SortKey *keys; + RDIM_VMapMarker *markers; + RDIM_BakeVMap *bake_vmap_out; + }; + VMapBakeTask *first_task = 0; + VMapBakeTask *last_task = 0; + if(lane_idx() == lane_from_task_idx(0)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("scopes"); + task->count = rdim2_shared->scope_vmap_count; + task->keys = rdim2_shared->scope_vmap_keys; + task->markers = rdim2_shared->scope_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_scope_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + if(lane_idx() == lane_from_task_idx(1)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("units"); + task->count = rdim2_shared->unit_vmap_count; + task->keys = rdim2_shared->unit_vmap_keys; + task->markers = rdim2_shared->unit_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_unit_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + if(lane_idx() == lane_from_task_idx(2)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("globals"); + task->count = rdim2_shared->global_vmap_count; + task->keys = rdim2_shared->global_vmap_keys; + task->markers = rdim2_shared->global_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_global_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + for(VMapBakeTask *task = first_task; task != 0; task = task->next) ProfScope("vmap bake for %.*s", str8_varg(task->name)) + { + //- rjf: determine if an extra vmap entry for zero is needed + RDI_U32 extra_vmap_entry = 0; + if(task->count > 0 && task->keys[0].key != 0) + { + extra_vmap_entry = 1; + } + + //- rjf: fill output vmap entries + RDI_U32 vmap_count_raw = extra_vmap_entry + task->count; + RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw); + RDI_U32 vmap_entry_count_pass_1 = 0; + ProfScope("fill output vmap entries") + { + typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; + struct RDIM_VMapRangeTracker + { + RDIM_VMapRangeTracker *next; + RDI_U32 idx; + }; + RDI_VMapEntry *vmap_ptr = vmap; + if(extra_vmap_entry) + { + vmap_ptr->voff = 0; + vmap_ptr->idx = 0; + vmap_ptr += 1; + } + RDIM_VMapRangeTracker *tracker_stack = 0; + RDIM_VMapRangeTracker *tracker_free = 0; + RDIM_SortKey *key_ptr = task->keys; + RDIM_SortKey *key_opl = task->keys + task->count; + for(;key_ptr < key_opl;) + { + // rjf: get initial map state from tracker stack + RDI_U32 initial_idx = (RDI_U32)0xffffffff; + if(tracker_stack != 0) + { + initial_idx = tracker_stack->idx; + } + + // rjf: update tracker stack + // + // * we must process _all_ of the changes that apply at this voff before moving on + // + RDI_U64 voff = key_ptr->key; + + for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) + { + RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; + RDI_U32 idx = marker->idx; + + // rjf: range begin -> push to stack + if(marker->begin_range) + { + RDIM_VMapRangeTracker *new_tracker = tracker_free; + if(new_tracker != 0) + { + RDIM_SLLStackPop(tracker_free); + } + else + { + new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); + } + RDIM_SLLStackPush(tracker_stack, new_tracker); + new_tracker->idx = idx; + } + + // rjf: range ending -> pop matching node from stack (not always the top) + else + { + RDIM_VMapRangeTracker **ptr_in = &tracker_stack; + RDIM_VMapRangeTracker *match = 0; + for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) + { + if(node->idx == idx) + { + match = node; + break; + } + ptr_in = &node->next; + node = node->next; + } + if(match != 0) + { + *ptr_in = match->next; + RDIM_SLLStackPush(tracker_free, match); + } + } + } + + // rjf: get final map state from tracker stack + RDI_U32 final_idx = 0; + if(tracker_stack != 0) + { + final_idx = tracker_stack->idx; + } + + // rjf: if final is different from initial - emit new vmap entry + if(final_idx != initial_idx) + { + vmap_ptr->voff = voff; + vmap_ptr->idx = final_idx; + vmap_ptr += 1; + } + } + + vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: combine duplicate neighbors + RDI_U32 vmap_entry_count = 0; + ProfScope("combine duplicate neighbors") + { + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; + RDI_VMapEntry *vmap_out = vmap; + for(;vmap_ptr < vmap_opl;) + { + RDI_VMapEntry *vmap_range_first = vmap_ptr; + RDI_U64 idx = vmap_ptr->idx; + vmap_ptr += 1; + for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; + rdim_memcpy_struct(vmap_out, vmap_range_first); + vmap_out += 1; + } + vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill result + task->bake_vmap_out->vmap = vmap; + task->bake_vmap_out->count = vmap_entry_count; + } + scratch_end(scratch); + } + lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: build interned path tree @@ -984,6 +1296,139 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } + lane_sync(); + RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; + + ////////////////////////////////////////////////////////////// + //- rjf: compute layout for scope sub-lists (locals / voffs) + // + ProfScope("compute layout for scope sub-lists (locals / voffs)") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + } + lane_sync(); + + // rjf: count per-lane-chunk + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 num_locals_in_this_lane_and_node = 0; + U64 num_voffs_in_this_lane_and_node = 0; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + num_locals_in_this_lane_and_node += n->v[n_idx].local_count; + num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count; + } + rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; + rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out each lane's range + if(lane_idx() == 0) + { + U64 local_layout_off = 0; + U64 voff_layout_off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; + rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; + rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; + local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; + voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + lane_sync(); + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: bake scopes + // + ProfScope("bake scopes") + { + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; + rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; + rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; + rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); + } + lane_sync(); + + //- rjf: wide fill + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + Rng1U64 range = lane_range(n->count); + U64 chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; + U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[chunk_lane_slot_idx]; + U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[chunk_lane_slot_idx]; + for EachInRange(n_idx, range) + { + U64 dst_idx = 1 + n->base_idx + n_idx; + RDIM_Scope *src_scope = &n->v[n_idx]; + RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; + + //- rjf: fill voff ranges + U64 voff_idx_first = chunk_voff_off; + for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) + { + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; + chunk_voff_off += 2; + } + U64 voff_idx_opl = chunk_voff_off; + + //- rjf: fill locals + U64 local_idx_first = chunk_local_off; + for EachNode(src_local, RDIM_Local, src_scope->first_local) + { + RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; + chunk_local_off += 1; + } + U64 local_idx_opl = chunk_local_off; + + //- rjf: fill scope + dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 + dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 + dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 + dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 + dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 + dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 + } + chunk_idx += 1; + } + } + } ////////////////////////////////////////////////////////////// //- rjf: bake units, src files, symbols, types, UDTs diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index aaf07077..85649a9a 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -25,9 +25,21 @@ struct RDIM2_Shared RDIM_SortKey *scope_vmap_keys; RDIM_SortKey *scope_vmap_keys__swap; RDIM_VMapMarker *scope_vmap_markers; + RDI_U64 unit_vmap_count; + RDIM_SortKey *unit_vmap_keys; + RDIM_SortKey *unit_vmap_keys__swap; + RDIM_VMapMarker *unit_vmap_markers; + RDI_U64 global_vmap_count; + RDIM_SortKey *global_vmap_keys; + RDIM_SortKey *global_vmap_keys__swap; + RDIM_VMapMarker *global_vmap_markers; U32 **lane_digit_counts; U32 **lane_digit_offsets; + RDIM_ScopeVMapBakeResult baked_scope_vmap; + RDIM_UnitVMapBakeResult baked_unit_vmap; + RDIM_GlobalVMapBakeResult baked_global_vmap; + RDIM_BakePathTree *path_tree; RDI_U64 line_tables_count; @@ -56,6 +68,13 @@ struct RDIM2_Shared RDIM_StringBakeResult baked_strings; RDIM_IndexRunBakeResult baked_idx_runs; + RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] + + RDIM_ScopeBakeResult baked_scopes; + RDIM_UnitBakeResult baked_units; RDIM_SrcFileBakeResult baked_src_files; RDIM_TypeNodeBakeResult baked_type_nodes; @@ -70,9 +89,6 @@ struct RDIM2_Shared RDIM_TopLevelInfoBakeResult baked_top_level_info; RDIM_BinarySectionBakeResult baked_binary_sections; - RDIM_UnitVMapBakeResult baked_unit_vmap; - RDIM_ScopeVMapBakeResult baked_scope_vmap; - RDIM_GlobalVMapBakeResult baked_global_vmap; }; global RDIM2_Shared *rdim2_shared = 0; From 92f24a043d4b5bb171b03a73e723c7ce15d38118 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 07:31:57 -0700 Subject: [PATCH 075/302] idx runs baking --- src/rdi_make/rdi_make_local_2.c | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 79bae023..45883036 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1299,6 +1299,39 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; + ////////////////////////////////////////////////////////////// + //- rjf: bake idx runs + // + ProfScope("bake idx runs") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->total_count; + rdim2_shared->baked_idx_runs.idx_runs = push_array_no_zero(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); + } + lane_sync(); + + // rjf: wide fill + { + Rng1U64 range = lane_range(bake_idx_runs->slots_count); + for EachInRange(slot_idx, range) + { + RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; + for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0])*n->v[n_idx].count); + off += n->v[n_idx].count; + } + } + } + } + } + lane_sync(); + RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; + ////////////////////////////////////////////////////////////// //- rjf: compute layout for scope sub-lists (locals / voffs) // @@ -1858,14 +1891,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) result.thread_variables = rdim2_shared->baked_thread_variables; result.constants = rdim2_shared->baked_constants; result.procedures = rdim2_shared->baked_procedures; - // result.scopes = rdim2_shared->baked_scopes; + result.scopes = rdim2_shared->baked_scopes; result.inline_sites = rdim2_shared->baked_inline_sites; result.scope_vmap = rdim2_shared->baked_scope_vmap; // result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; // result.name_maps = rdim2_shared->baked_name_maps; // result.file_paths = rdim2_shared->baked_file_paths; result.strings = rdim2_shared->baked_strings; - // result.idx_runs = rdim2_shared->baked_idx_runs; + result.idx_runs = rdim2_shared->baked_idx_runs; // result.location_blocks = rdim2_shared->baked_location_blocks; // result.location_data = rdim2_shared->baked_location_data; } From 46ac437e86f3d8afda48eb0e0d325fc3d2e4378c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 09:12:06 -0700 Subject: [PATCH 076/302] name map baking / serialization --- src/rdi_make/rdi_make_local_2.c | 289 +++++++++++++++++++++++++++++++- src/rdi_make/rdi_make_local_2.h | 11 ++ 2 files changed, 293 insertions(+), 7 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 45883036..d6b83b9b 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1332,6 +1332,214 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; + ////////////////////////////////////////////////////////////// + //- rjf: bake name maps + // + ProfScope("bake name maps") + { + // rjf: count unique names in all name maps; lay out baked nodes + ProfScope("count unique names in all name maps; lay out baked nodes") + { + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->lane_name_map_node_counts[k] = push_array(arena, U64, lane_count()); + rdim2_shared->lane_name_map_node_offs[k] = push_array(arena, U64, lane_count()); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 range = lane_range(top->slots_count); + for EachInRange(idx, range) + { + if(map->slots[idx] != 0) + { + U64 total_unique_name_count = 0; + U64 last_hash = 0; + for EachNode(n, RDIM_BakeNameChunkNode, map->slots[idx]->first) + { + for EachIndex(n_idx, n->count) + { + if(n->v[n_idx].hash != last_hash) + { + total_unique_name_count += 1; + last_hash = n->v[n_idx].hash; + } + } + } + rdim2_shared->lane_name_map_node_counts[k] += total_unique_name_count; + } + } + } + lane_sync(); + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDI_U64 node_off = 0; + for EachIndex(l_idx, lane_count()) + { + rdim2_shared->name_map_node_counts[k] += rdim2_shared->lane_name_map_node_counts[k][l_idx]; + rdim2_shared->lane_name_map_node_offs[k][l_idx] = node_off; + node_off += rdim2_shared->lane_name_map_node_counts[k][l_idx]; + } + rdim2_shared->total_name_map_node_count += rdim2_shared->name_map_node_counts[k]; + } + } + } + lane_sync(); + + // rjf: setup + ProfScope("setup") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_top_level_name_maps.name_maps_count = RDI_NameMapKind_COUNT; + rdim2_shared->baked_top_level_name_maps.name_maps = push_array(arena, RDI_NameMap, rdim2_shared->baked_top_level_name_maps.name_maps_count); + RDI_U32 bucket_off = 0; + RDI_U32 node_off = 0; + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; + rdim2_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; + rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim2_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 + rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim2_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 + bucket_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count; + node_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count; + } + rdim2_shared->baked_name_maps.buckets_count = bucket_off; + rdim2_shared->baked_name_maps.buckets = push_array(arena, RDI_NameMapBucket, rdim2_shared->baked_name_maps.buckets_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_name_maps.nodes_count = rdim2_shared->total_name_map_node_count; + rdim2_shared->baked_name_maps.nodes = push_array(arena, RDI_NameMapNode, rdim2_shared->baked_name_maps.nodes_count); + } + } + lane_sync(); + + // rjf: wide fill baked name maps + ProfScope("wide fill baked name maps") + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDI_U64 write_node_off = rdim2_shared->lane_name_map_node_offs[k][lane_idx()]; + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + U64 slots_count = top->slots_count; + RDIM_BakeNameMap2 *src_map = rdim2_shared->bake_name_maps[k]; + RDI_NameMap *dst_map = &rdim2_shared->baked_top_level_name_maps.name_maps[k]; + RDI_NameMapBucket *dst_buckets = rdim2_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; + RDI_NameMapNode *dst_nodes = rdim2_shared->baked_name_maps.nodes + dst_map->node_base_idx; + Rng1U64 slot_range = lane_range(slots_count); + for EachInRange(slot_idx, slot_range) + { + RDIM_BakeNameChunkList *src_slot = src_map->slots[slot_idx]; + if(src_slot == 0) { continue; } + RDI_NameMapBucket *dst_bucket = &dst_buckets[slot_idx]; + dst_bucket->first_node = write_node_off; + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + U64 active_hash = 0; + String8 active_string = {0}; + RDIM_BakeNameChunkNode *n = src_slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + U64 hash = 0; + U64 idx = 0; + String8 string = {0}; + if(n != 0) + { + hash = n->v[n_idx].hash; + idx = n->v[n_idx].idx; + string = n->v[n_idx].string; + } + + // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list + if(hash != active_hash && active_idx_count != 0) + { + // rjf: flatten idxes + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(scratch.arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + + // rjf: serialize node + RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; + dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); + dst_node->match_count = idxs_count; + if(dst_node->match_count == 1) + { + dst_node->match_idx_or_idx_run_first = idxs[0]; + } + else + { + dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, idxs, idxs_count); + } + dst_bucket->node_count += 1; + write_node_off += 1; + + // rjf: start new list + active_hash = hash; + active_string = string; + first_idx_run_node = 0; + last_idx_run_node = 0; + temp_end(scratch); + } + + // rjf: hash matches the active list -> push + if(hash != 0 && hash == active_hash) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); + } + } + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: compute layout for scope sub-lists (locals / voffs) // @@ -1858,17 +2066,84 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: do final baking tasks + //- rjf: bake file paths // - ProfScope("do final baking tasks") + ProfScope("bake file paths") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_file_paths.nodes_count = path_tree->count; + rdim2_shared->baked_file_paths.nodes = push_array(arena, RDI_FilePathNode, rdim2_shared->baked_file_paths.nodes_count); + rdim2_shared->baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, rdim2_shared->baked_file_paths.nodes_count); + { + U64 idx = 0; + for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) + { + rdim2_shared->baked_file_path_src_nodes[idx] = n; + idx += 1; + } + } + } + lane_sync(); + + // rjf: fill + { + Rng1U64 range = lane_range(rdim2_shared->baked_file_paths.nodes_count); + for EachInRange(idx, range) + { + RDIM_BakePathNode *src = rdim2_shared->baked_file_path_src_nodes[idx]; + RDI_FilePathNode *dst = &rdim2_shared->baked_file_paths.nodes[idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->source_file_idx = rdim_idx_from_src_file(src->src_file); + if(src->parent != 0) + { + dst->parent_path_node = src->parent->idx; + } + if(src->first_child != 0) + { + dst->first_child = src->first_child->idx; + } + if(src->next_sibling != 0) + { + dst->next_sibling = src->next_sibling->idx; + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: do small final baking tasks + // + ProfScope("do small final baking tasks") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") { - rdim2_shared->baked_top_level_info = rdim_bake_top_level_info(arena, bake_strings, ¶ms->top_level_info); + rdim2_shared->baked_top_level_info.top_level_info.arch = params->top_level_info.arch; + rdim2_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); + rdim2_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; + rdim2_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; + rdim2_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") { - rdim2_shared->baked_binary_sections = rdim_bake_binary_sections(arena, bake_strings, ¶ms->binary_sections); + RDIM_BinarySectionList *src = ¶ms->binary_sections; + RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src->count+1); + U64 dst_idx = 1; + for(RDIM_BinarySectionNode *src_n = src->first; src_n != 0; src_n = src_n->next, dst_idx += 1) + { + RDIM_BinarySection *src = &src_n->v; + RDI_BinarySection *dst = &dst_base[dst_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->flags = src->flags; + dst->voff_first = src->voff_first; + dst->voff_opl = src->voff_opl; + dst->foff_first = src->foff_first; + dst->foff_opl = src->foff_opl; + } + rdim2_shared->baked_binary_sections.binary_sections = dst_base; + rdim2_shared->baked_binary_sections.binary_sections_count = dst_idx; } } lane_sync(); @@ -1894,9 +2169,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) result.scopes = rdim2_shared->baked_scopes; result.inline_sites = rdim2_shared->baked_inline_sites; result.scope_vmap = rdim2_shared->baked_scope_vmap; - // result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; - // result.name_maps = rdim2_shared->baked_name_maps; - // result.file_paths = rdim2_shared->baked_file_paths; + result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; + result.name_maps = rdim2_shared->baked_name_maps; + result.file_paths = rdim2_shared->baked_file_paths; result.strings = rdim2_shared->baked_strings; result.idx_runs = rdim2_shared->baked_idx_runs; // result.location_blocks = rdim2_shared->baked_location_blocks; diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 85649a9a..c7793baa 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -66,8 +66,16 @@ struct RDIM2_Shared RDIM_BakeIdxRunMap2 bake_idx_runs; RDIM_StringBakeResult baked_strings; + RDIM_IndexRunBakeResult baked_idx_runs; + RDI_U64 *lane_name_map_node_counts[RDI_NameMapKind_COUNT]; + RDI_U64 *lane_name_map_node_offs[RDI_NameMapKind_COUNT]; + RDI_U64 name_map_node_counts[RDI_NameMapKind_COUNT]; + RDI_U64 total_name_map_node_count; + RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; + RDIM_NameMapBakeResult baked_name_maps; + RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] @@ -87,6 +95,9 @@ struct RDIM2_Shared RDIM_ProcedureBakeResult baked_procedures; RDIM_InlineSiteBakeResult baked_inline_sites; + RDIM_BakePathNode **baked_file_path_src_nodes; + RDIM_FilePathBakeResult baked_file_paths; + RDIM_TopLevelInfoBakeResult baked_top_level_info; RDIM_BinarySectionBakeResult baked_binary_sections; }; From 2f9006bb8acaaee6682bdcbe01ca907e72b908de Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 09:33:12 -0700 Subject: [PATCH 077/302] bugfix name map baking --- src/rdi_make/rdi_make_local_2.c | 54 ++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index d6b83b9b..a2ae2f16 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1126,7 +1126,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash && active_idx_count != 0) + if(hash != active_hash) { if(active_idx_count > 1) { @@ -1371,7 +1371,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - rdim2_shared->lane_name_map_node_counts[k] += total_unique_name_count; + rdim2_shared->lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; } } } @@ -1477,35 +1477,39 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash && active_idx_count != 0) + if(hash != active_hash) { - // rjf: flatten idxes - RDI_U64 idxs_count = active_idx_count; - RDI_U32 *idxs = rdim_push_array(scratch.arena, RDI_U32, idxs_count); + // rjf: has active hash -> flatten & serialize + if(active_hash != 0) { - U64 write_idx = 0; - for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + // rjf: flatten idxes + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(scratch.arena, RDI_U32, idxs_count); { - idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 - write_idx += 1; + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } } + + // rjf: serialize node + RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; + dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); + dst_node->match_count = idxs_count; + if(dst_node->match_count == 1) + { + dst_node->match_idx_or_idx_run_first = idxs[0]; + } + else if(dst_node->match_count > 1) + { + dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, idxs, idxs_count); + } + dst_bucket->node_count += 1; + write_node_off += 1; } - // rjf: serialize node - RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; - dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); - dst_node->match_count = idxs_count; - if(dst_node->match_count == 1) - { - dst_node->match_idx_or_idx_run_first = idxs[0]; - } - else - { - dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, idxs, idxs_count); - } - dst_bucket->node_count += 1; - write_node_off += 1; - // rjf: start new list active_hash = hash; active_string = string; From 57125fee1becd40a8110f75474243ff08bfb1d77 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 09:54:23 -0700 Subject: [PATCH 078/302] eliminate helpers from string map baking; no point in extra entry points for partial bakes --- src/rdi_make/rdi_make_local_2.c | 66 ++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index a2ae2f16..62c36cdc 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -708,38 +708,60 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: push small top-level strings if(lane_idx() == 0) ProfScope("push small top-level strings") { - rdim_bake_string_map_loose_push_top_level_info(arena, lane_map_top, lane_map, ¶ms->top_level_info); - rdim_bake_string_map_loose_push_binary_sections(arena, lane_map_top, lane_map, ¶ms->binary_sections); - rdim_bake_string_map_loose_push_path_tree(arena, lane_map_top, lane_map, path_tree); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.exe_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.producer_name); + for(RDIM_BinarySectionNode *n = params->binary_sections.first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->v.name); + } + for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->name); + } } // rjf: push strings from source files ProfScope("src files") { - for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_src_file_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(n_idx, range) + { + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[n_idx].path); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, normalized_path); + } } } // rjf: push strings from units ProfScope("units") { - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + for EachNode(n, RDIM_UnitChunkNode, params->units.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_unit_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(n_idx, range) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].unit_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].compiler_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].source_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].object_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].archive_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].build_path); + } } } // rjf: push strings from types ProfScope("types") { - for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + for EachNode(n, RDIM_TypeChunkNode, params->types.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_type_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(n_idx, range) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + } } } @@ -775,12 +797,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachElement(list_idx, symbol_lists) { - ProfScope("symbols (%I64u)", list_idx) + for EachNode(n, RDIM_SymbolChunkNode, symbol_lists[list_idx]->first) { - for(RDIM_SymbolChunkNode *n = symbol_lists[list_idx]->first; n != 0; n = n->next) + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_symbol_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].link_name); } } } @@ -789,20 +812,29 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: push strings from inline sites ProfScope("inline sites") { - for(RDIM_InlineSiteChunkNode *n = params->inline_sites.first; n != 0; n = n->next) + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_inline_site_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(n_idx, range) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + } } } //- rjf: push strings from scopes ProfScope("scopes") { - for(RDIM_ScopeChunkNode *n = params->scopes.first; n != 0; n = n->next) + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_scope_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(n_idx, range) + { + for EachNode(local, RDIM_Local, n->v[n_idx].first_local) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, local->name); + } + } } } } From e276ce4fb334dd2ecbd41d009cf89e4d6324dfa9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 11:40:36 -0700 Subject: [PATCH 079/302] stub out src file baking --- src/rdi_make/rdi_make_local_2.c | 93 +++++++++++++++++++-------------- src/rdi_make/rdi_make_local_2.h | 3 +- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 62c36cdc..9df723c8 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -14,7 +14,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: gather unsorted vmap keys/markers + //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers // ProfScope("gather unsorted vmap keys/markers") { @@ -193,7 +193,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: sort all vmap keys + //- rjf: @rdim_bake_stage sort all vmap keys // ProfScope("sort all vmap keys") { @@ -306,7 +306,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: bake all vmaps + //- rjf: @rdim_bake_stage bake all vmaps // ProfScope("bake all vmaps") { @@ -491,7 +491,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: build interned path tree + //- rjf: @rdim_bake_stage build interned path tree // if(lane_idx() == 0) ProfScope("build interned path tree") { @@ -501,7 +501,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; ////////////////////////////////////////////////////////////// - //- rjf: gather all unsorted, joined, line table info; & sort + //- rjf: @rdim_bake_stage gather all unsorted, joined, line table info; & sort // ProfScope("gather all unsorted, joined, line table info; & sort") { @@ -678,7 +678,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; ////////////////////////////////////////////////////////////// - //- rjf: build string map + //- rjf: @rdim_bake_stage build string map // ProfScope("build string map") { @@ -916,7 +916,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; ////////////////////////////////////////////////////////////// - //- rjf: build name maps + //- rjf: @rdim_bake_stage build name maps // ProfScope("build name maps") { @@ -1061,7 +1061,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: build index runs + //- rjf: @rdim_bake_stage build index runs // ProfScope("build index runs") { @@ -1281,7 +1281,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_BakeIdxRunMap2 *bake_idx_runs = &rdim2_shared->bake_idx_runs; ////////////////////////////////////////////////////////////// - //- rjf: bake strings + //- rjf: @rdim_bake_stage bake strings // ProfScope("bake strings") { @@ -1332,7 +1332,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; ////////////////////////////////////////////////////////////// - //- rjf: bake idx runs + //- rjf: @rdim_bake_stage bake idx runs // ProfScope("bake idx runs") { @@ -1365,7 +1365,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; ////////////////////////////////////////////////////////////// - //- rjf: bake name maps + //- rjf: @rdim_bake_stage bake name maps // ProfScope("bake name maps") { @@ -1577,7 +1577,32 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: compute layout for scope sub-lists (locals / voffs) + //- rjf: @rdim_bake_stage bake src files + // + ProfScope("bake src files") + { + //- rjf: set up + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + } + lane_sync(); + + //- rjf: bake src files + ProfScope("bake src files") + { + + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) // ProfScope("compute layout for scope sub-lists (locals / voffs)") { @@ -1635,7 +1660,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: bake scopes + //- rjf: @rdim_bake_stage bake scopes // ProfScope("bake scopes") { @@ -1708,7 +1733,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } ////////////////////////////////////////////////////////////// - //- rjf: bake units, src files, symbols, types, UDTs + //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs // { //- rjf: setup outputs @@ -1718,76 +1743,66 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); } if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - } - if(lane_idx() == lane_from_task_idx(3)) { rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); } - if(lane_idx() == lane_from_task_idx(4)) + if(lane_idx() == lane_from_task_idx(2)) { rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); } - if(lane_idx() == lane_from_task_idx(5)) + if(lane_idx() == lane_from_task_idx(3)) { rdim2_shared->baked_udts.members_count = params->members.total_count+1; rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); } - if(lane_idx() == lane_from_task_idx(6)) + if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); } - if(lane_idx() == lane_from_task_idx(7)) + if(lane_idx() == lane_from_task_idx(5)) { rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); } - if(lane_idx() == lane_from_task_idx(8)) + if(lane_idx() == lane_from_task_idx(6)) { rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(7)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(8)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(11)) + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(12)) + if(lane_idx() == lane_from_task_idx(10)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(13)) + if(lane_idx() == lane_from_task_idx(11)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(14)) + if(lane_idx() == lane_from_task_idx(12)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(15)) + if(lane_idx() == lane_from_task_idx(13)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -2102,7 +2117,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: bake file paths + //- rjf: @rdim_bake_stage bake file paths // ProfScope("bake file paths") { @@ -2150,7 +2165,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: do small final baking tasks + //- rjf: @rdim_bake_stage do small final baking tasks // ProfScope("do small final baking tasks") { @@ -2185,7 +2200,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: package results + //- rjf: @rdim_bake_stage package results // RDIM_BakeResults result = {0}; { diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index c7793baa..eb815a92 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -76,6 +76,8 @@ struct RDIM2_Shared RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; RDIM_NameMapBakeResult baked_name_maps; + RDIM_SrcFileBakeResult baked_src_files; + RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] @@ -84,7 +86,6 @@ struct RDIM2_Shared RDIM_ScopeBakeResult baked_scopes; RDIM_UnitBakeResult baked_units; - RDIM_SrcFileBakeResult baked_src_files; RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_UDTBakeResult baked_udts; RDIM_LocationBakeResult baked_locations; From 955f0330434de62c3913472fb2d258c1923e769c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 14:26:29 -0700 Subject: [PATCH 080/302] fix incorrect idx run baking; slots need to be laid out based on *idx counts*, rather than *value counts*! --- src/lib_rdi_make/rdi_make.c | 42 +------ src/lib_rdi_make/rdi_make.h | 14 +-- src/radbin/radbin.c | 9 ++ src/rdi/rdi_local.c | 6 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 2 +- src/rdi_make/rdi_make_local_2.c | 189 +++++++++++++++++++----------- src/rdi_make/rdi_make_local_2.h | 2 + 7 files changed, 143 insertions(+), 121 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 06a087ac..12b3e518 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1709,7 +1709,7 @@ rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM { for(RDIM_BakeIdxRunChunkNode *n = to_push->first; n != 0; n = n->next) { - n->base_idx += dst->total_count; + n->base_idx += dst->total_idx_count; } if(dst->last != 0 && to_push->first != 0) { @@ -1810,6 +1810,7 @@ rdim_bake_idx_run_map_loose_make(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology * { RDIM_BakeIdxRunMapLoose *map = rdim_push_array(arena, RDIM_BakeIdxRunMapLoose, 1); map->slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList *, top->slots_count); + map->slots_idx_counts = rdim_push_array(arena, RDI_U64, top->slots_count); return map; } @@ -1844,48 +1845,13 @@ rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology bir->hash = hash; bir->count = count; bir->idxes = idxes; + map->slots_idx_counts[slot_idx] += count; } } } -RDI_PROC RDIM_BakeIdxRunMapBaseIndices -rdim_bake_idx_run_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map) -{ - RDIM_BakeIdxRunMapBaseIndices indices = {0}; - indices.slots_base_idxs = rdim_push_array(arena, RDI_U64, map_topology->slots_count+1); - RDI_U64 total_count = 0; - for(RDI_U64 idx = 0; idx < map_topology->slots_count; idx += 1) - { - indices.slots_base_idxs[idx] += total_count; - if(map->slots[idx] != 0) - { - total_count += map->slots[idx]->total_count; - } - } - indices.slots_base_idxs[map_topology->slots_count] = total_count; - return indices; -} - //- rjf: finalized / tight map -RDI_PROC RDIM_BakeIdxRunMap2 * -rdim_bake_idx_run_map_from_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapBaseIndices *map_base_indices, RDIM_BakeIdxRunMapLoose *map) -{ - RDIM_BakeIdxRunMap2 *m = rdim_push_array(arena, RDIM_BakeIdxRunMap2, 1); - m->slots_count = map_topology->slots_count; - m->slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, m->slots_count); - m->slots_base_idxs = map_base_indices->slots_base_idxs; - for(RDI_U64 idx = 0; idx < m->slots_count; idx += 1) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&m->slots[idx], map->slots[idx]); - } - } - m->total_count = m->slots_base_idxs[m->slots_count]; - return m; -} - RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count) { @@ -1900,7 +1866,7 @@ rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 c { if(n->v[chunk_idx].hash == hash) { - idx = map->slots_base_idxs[slot_idx] + n->base_idx + chunk_idx + 1; + idx = map->slots_base_idxs[slot_idx] + n->base_idx + n->v[chunk_idx].encoding_idx; break; } } diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index f5a0fe5c..504d74aa 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1183,6 +1183,7 @@ struct RDIM_BakeIdxRun RDI_U64 hash; RDI_U64 count; RDI_U32 *idxes; + RDI_U64 encoding_idx; }; typedef struct RDIM_BakeIdxRunChunkNode RDIM_BakeIdxRunChunkNode; @@ -1202,6 +1203,7 @@ struct RDIM_BakeIdxRunChunkList RDIM_BakeIdxRunChunkNode *last; RDI_U64 chunk_count; RDI_U64 total_count; + RDI_U64 total_idx_count; }; typedef struct RDIM_BakeIdxRunMapTopology RDIM_BakeIdxRunMapTopology; @@ -1210,25 +1212,19 @@ struct RDIM_BakeIdxRunMapTopology RDI_U64 slots_count; }; -typedef struct RDIM_BakeIdxRunMapBaseIndices RDIM_BakeIdxRunMapBaseIndices; -struct RDIM_BakeIdxRunMapBaseIndices -{ - RDI_U64 *slots_base_idxs; -}; - typedef struct RDIM_BakeIdxRunMapLoose RDIM_BakeIdxRunMapLoose; struct RDIM_BakeIdxRunMapLoose { RDIM_BakeIdxRunChunkList **slots; + RDI_U64 *slots_idx_counts; }; typedef struct RDIM_BakeIdxRunMap2 RDIM_BakeIdxRunMap2; struct RDIM_BakeIdxRunMap2 { RDIM_BakeIdxRunChunkList *slots; - RDI_U64 *slots_base_idxs; + RDI_U64 *slots_base_idxs; // NOTE(rjf): [slots_count+1], [slots_count] holds total count RDI_U64 slots_count; - RDI_U64 total_count; }; //- rjf: index runs (OLD) @@ -1836,10 +1832,8 @@ RDI_PROC RDIM_BakeIdxRunChunkList rdim_bake_idx_run_chunk_list_sorted_from_unsor //- rjf: loose map RDI_PROC RDIM_BakeIdxRunMapLoose *rdim_bake_idx_run_map_loose_make(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *top); RDI_PROC void rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map, RDI_U64 chunk_cap, RDI_U32 *idxes, RDI_U32 count); -RDI_PROC RDIM_BakeIdxRunMapBaseIndices rdim_bake_idx_run_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map); //- rjf: finalized / tight map -RDI_PROC RDIM_BakeIdxRunMap2 *rdim_bake_idx_run_map_from_loose(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapBaseIndices *map_base_indices, RDIM_BakeIdxRunMapLoose *map); RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count); //////////////////////////////// diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 5d2e2436..6ab8173c 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -14,6 +14,15 @@ rb_entry_point(CmdLine *cmdline) { Temp scratch = scratch_begin(0, 0); U64 threads_count = os_get_system_info()->logical_processor_count; + String8 threads_count_from_cmdline_string = cmd_line_string(cmdline, str8_lit("thread_count")); + if(threads_count_from_cmdline_string.size != 0) + { + U64 threads_count_from_cmdline = 0; + if(try_u64_from_str8_c_rules(threads_count_from_cmdline_string, &threads_count_from_cmdline)) + { + threads_count = threads_count_from_cmdline; + } + } OS_Handle *threads = push_array(scratch.arena, OS_Handle, threads_count); RB_ThreadParams *threads_params = push_array(scratch.arena, RB_ThreadParams, threads_count); Barrier barrier = barrier_alloc(threads_count); diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index b67ccdca..f11dd5e0 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -798,7 +798,7 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla str8_list_pushf(scratch.arena, ¶m_idx_strings, "%u", param_idx_array[param_idx]); } String8 param_idx_str = str8_list_join(scratch.arena, ¶m_idx_strings, &(StringJoin){.pre = str8_lit("["), .sep = str8_lit(", "), .post = str8_lit("]")}); - dumpf(" constructed__params: %S\n", param_idx_str); + dumpf(" constructed__params: %S // idx_run[%u]\n", param_idx_str, type->constructed.param_idx_run_first); dumpf(" return_type: %u\n", type->constructed.direct_type_idx); } else if(type->kind == RDI_TypeKind_Method) @@ -818,8 +818,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla str8_list_pushf(scratch.arena, ¶m_idx_strings, "%u", param_idx_array[param_idx]); } String8 param_idx_str = str8_list_join(scratch.arena, ¶m_idx_strings, &(StringJoin){.pre = str8_lit("["), .sep = str8_lit(", "), .post = str8_lit("]")}); - dumpf(" constructed__this_type: %S\n", this_type_str); - dumpf(" constructed__params: %S\n", param_idx_str); + dumpf(" constructed__this_type: %S // idx_run[%u]\n", this_type_str, type->constructed.param_idx_run_first); + dumpf(" constructed__params: %S // idx_run[%u]\n", param_idx_str, type->constructed.param_idx_run_first); dumpf(" return_type: %u\n", type->constructed.direct_type_idx); } else if(RDI_TypeKind_FirstConstructed <= type->kind && type->kind <= RDI_TypeKind_LastConstructed) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 063b4bdb..f2287b0f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -1777,7 +1777,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // subsequent passes, to build RDI "UDT" information, which is distinct // from regular type info. // - ProfScope("types pass 3: construct all root/stub types from TPI") if(lane_idx() == 0) + if(lane_idx() == 0) ProfScope("types pass 3: construct all root/stub types from TPI") { #define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 9df723c8..82e14fcf 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1074,6 +1074,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) params->thread_variables.total_count + params->types.total_count); rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); } lane_sync(); @@ -1202,76 +1203,76 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - - //- rjf: join & sort - if(lane_idx() == 0) + } + lane_sync(); + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) { - rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - lane_sync(); - ProfScope("join & sort") - { - //- rjf: join - ProfScope("join") + for EachIndex(src_lane_idx, lane_count()) { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) + RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } - - //- rjf: sort - ProfScope("sort") + } + } + lane_sync(); + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) + *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + lane_sync(); + + //- rjf: tighten idx run table + ProfScope("tighten idx run table") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); + rdim2_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim2_shared->bake_idx_runs.slots_count+1); + RDI_U64 encoding_idx_off = 0; + for(RDI_U64 slot_idx = 0; slot_idx < map_top->slots_count; slot_idx += 1) + { + rdim2_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; + if(map->slots[slot_idx] != 0) { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } + encoding_idx_off += map->slots[slot_idx]->total_idx_count; } } } lane_sync(); - - //- rjf: tighten idx run table - ProfScope("tighten idx run table") + ProfScope("fill tight map") { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; - if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); + for EachInRange(idx, slot_range) { - RDIM_BakeIdxRunMapBaseIndices bake_idx_run_map_base_indices = rdim_bake_idx_run_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; - rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); - rdim2_shared->bake_idx_runs.slots_base_idxs = bake_idx_run_map_base_indices.slots_base_idxs; - rdim2_shared->bake_idx_runs.total_count = rdim2_shared->bake_idx_runs.slots_base_idxs[rdim2_shared->bake_idx_runs.slots_count]; - } - lane_sync(); - ProfScope("fill tight map") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); - for EachInRange(idx, slot_range) + if(map->slots[idx] != 0) { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); - } + rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); } } } @@ -1339,8 +1340,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->total_count; - rdim2_shared->baked_idx_runs.idx_runs = push_array_no_zero(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); + rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; + rdim2_shared->baked_idx_runs.idx_runs = push_array(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); } lane_sync(); @@ -1352,9 +1353,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) { + StaticAssert(sizeof(rdim2_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); for EachIndex(n_idx, n->count) { - rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0])*n->v[n_idx].count); + rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(RDI_U32) * n->v[n_idx].count); off += n->v[n_idx].count; } } @@ -1362,6 +1364,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); + if(lane_idx() == 0) + { + for EachIndex(idx, rdim2_shared->baked_idx_runs.idx_count) + { + printf("%u\n", rdim2_shared->baked_idx_runs.idx_runs[idx]); + } + fflush(stdout); + } RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; ////////////////////////////////////////////////////////////// @@ -1582,24 +1592,65 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) ProfScope("bake src files") { //- rjf: set up - if(lane_idx() == lane_from_task_idx(0)) + ProfScope("set up") { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->lane_src_line_map_counts = push_array(arena, U64, lane_count()); + rdim2_shared->lane_src_line_map_offs = push_array(arena, U64, lane_count()); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + } } lane_sync(); - //- rjf: bake src files - ProfScope("bake src files") + //- rjf: calculate layout of src file line maps + ProfScope("calculate layout of src file line maps") + { + // rjf: count lines seen by each lane + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_SrcFile *src_file = &n->v[n_idx]; + for(RDIM_SrcFileLineMapFragment *f = src_file->first_line_map_fragment; f != 0; f = f->next) + { + rdim2_shared->lane_src_line_map_counts[lane_idx()] += f->seq->line_count; + } + } + } + lane_sync(); + + // rjf: lay out per-lane offset + if(lane_idx() == 0) + { + U64 off = 0; + for EachIndex(l_idx, lane_count()) + { + rdim2_shared->lane_src_line_map_offs[l_idx] = off; + off += rdim2_shared->lane_src_line_map_counts[l_idx]; + } + // rdim2_shared->baked_src_files. + } + } + lane_sync(); + + //- rjf: bake + ProfScope("bake") { } } + lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index eb815a92..9d8ce951 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -76,6 +76,8 @@ struct RDIM2_Shared RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; RDIM_NameMapBakeResult baked_name_maps; + RDI_U64 *lane_src_line_map_counts; + RDI_U64 *lane_src_line_map_offs; RDIM_SrcFileBakeResult baked_src_files; RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] From 6234fb0c4967f85f9b99eeb0e3bec80cc0f44c94 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 14:36:26 -0700 Subject: [PATCH 081/302] fix incorrect scope voff serialization offsets --- src/rdi_make/rdi_make_local_2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 82e14fcf..b6dcac74 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1678,7 +1678,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { num_locals_in_this_lane_and_node += n->v[n_idx].local_count; - num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count; + num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; } rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; @@ -1690,7 +1690,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: lay out each lane's range if(lane_idx() == 0) { - U64 local_layout_off = 0; + U64 local_layout_off = 1; U64 voff_layout_off = 0; U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) @@ -1723,7 +1723,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; + rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count; rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); } if(lane_idx() == lane_from_task_idx(2)) @@ -1782,6 +1782,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } + lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs From f093ba9d35cf92e856fcc47ec652355389cb0141 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 14:54:32 -0700 Subject: [PATCH 082/302] fix src file path gathering determinism - was caused by interleaving each lane's non-inline and inline file paths - with different thread counts, these subdivisions will be different, so the order will change --- src/rdi_from_pdb/rdi_from_pdb_2.c | 100 ++++++++++++++++++++---------- src/rdi_from_pdb/rdi_from_pdb_2.h | 6 +- 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index f2287b0f..dccdbba5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -471,8 +471,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r2_shared->lane_file_paths = push_array(arena, String8Array, lane_count()); - p2r2_shared->lane_file_paths_hashes = push_array(arena, U64Array, lane_count()); + p2r2_shared->lane_inline_file_paths = push_array(arena, String8Array, lane_count()); + p2r2_shared->lane_line_file_paths = push_array(arena, String8Array, lane_count()); + p2r2_shared->lane_inline_file_paths_hashes = push_array(arena, U64Array, lane_count()); + p2r2_shared->lane_line_file_paths_hashes = push_array(arena, U64Array, lane_count()); } lane_sync(); @@ -480,7 +482,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) ProfScope("do wide gather") { Temp scratch = scratch_begin(&arena, 1); - String8List src_file_paths = {0}; + String8List inline_src_file_paths = {0}; + String8List line_src_file_paths = {0}; //- rjf: build local hash table to dedup files within this lane U64 hit_path_slots_count = 4096; @@ -648,7 +651,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_normalized; - str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); + str8_list_push(arena, &inline_src_file_paths, push_str8_copy(arena, file_path_normalized)); } line_count = 0; } @@ -739,7 +742,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_sanitized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); + str8_list_push(scratch.arena, &line_src_file_paths, push_str8_copy(arena, file_path_sanitized)); } } } @@ -748,27 +751,42 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } //- rjf: merge into array for this lane - p2r2_shared->lane_file_paths[lane_idx()] = str8_array_from_list(arena, &src_file_paths); + p2r2_shared->lane_inline_file_paths[lane_idx()] = str8_array_from_list(arena, &inline_src_file_paths); + p2r2_shared->lane_line_file_paths[lane_idx()] = str8_array_from_list(arena, &line_src_file_paths); //- rjf: hash this lane's file paths { - String8Array lane_paths = p2r2_shared->lane_file_paths[lane_idx()]; - U64Array lane_paths_hashes = {0}; - lane_paths_hashes.count = lane_paths.count; - lane_paths_hashes.v = push_array(arena, U64, lane_paths_hashes.count); - for EachIndex(idx, lane_paths.count) + struct { - lane_paths_hashes.v[idx] = rdi_hash(lane_paths.v[idx].str, lane_paths.v[idx].size); + String8Array paths; + U64Array *hashes_out; + } + tasks[] = + { + {p2r2_shared->lane_inline_file_paths[lane_idx()], &p2r2_shared->lane_inline_file_paths_hashes[lane_idx()]}, + {p2r2_shared->lane_line_file_paths[lane_idx()], &p2r2_shared->lane_line_file_paths_hashes[lane_idx()]}, + }; + for EachElement(task_idx, tasks) + { + U64Array hashes = {0}; + hashes.count = tasks[task_idx].paths.count; + hashes.v = push_array(arena, U64, hashes.count); + for EachIndex(idx, tasks[task_idx].paths.count) + { + hashes.v[idx] = rdi_hash(tasks[task_idx].paths.v[idx].str, tasks[task_idx].paths.v[idx].size); + } + tasks[task_idx].hashes_out[0] = hashes; } - p2r2_shared->lane_file_paths_hashes[lane_idx()] = lane_paths_hashes; } scratch_end(scratch); } } lane_sync(); - String8Array *lane_file_paths = p2r2_shared->lane_file_paths; - U64Array *lane_file_paths_hashes = p2r2_shared->lane_file_paths_hashes; + String8Array *lane_inline_file_paths = p2r2_shared->lane_inline_file_paths; + String8Array *lane_line_file_paths = p2r2_shared->lane_line_file_paths; + U64Array *lane_inline_file_paths_hashes = p2r2_shared->lane_inline_file_paths_hashes; + U64Array *lane_line_file_paths_hashes = p2r2_shared->lane_line_file_paths_hashes; ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files @@ -780,7 +798,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) p2r2_shared->total_path_count = 0; for EachIndex(idx, lane_count()) { - p2r2_shared->total_path_count += p2r2_shared->lane_file_paths[idx].count; + p2r2_shared->total_path_count += lane_line_file_paths[idx].count; + p2r2_shared->total_path_count += lane_inline_file_paths[idx].count; } p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); @@ -790,28 +809,43 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: fill table ProfScope("fill table") if(lane_idx() == 0) { - for EachIndex(idx, lane_count()) + struct { - for EachIndex(path_idx, p2r2_shared->lane_file_paths[idx].count) + String8Array *lane_paths; + U64Array *lane_hashes; + } + tasks[] = + { + {lane_inline_file_paths, lane_inline_file_paths_hashes}, + {lane_line_file_paths, lane_line_file_paths_hashes}, + }; + for EachElement(task_idx, tasks) + { + for EachIndex(idx, lane_count()) { - String8 file_path_sanitized = p2r2_shared->lane_file_paths[idx].v[path_idx]; - U64 file_path_sanitized_hash = p2r2_shared->lane_file_paths_hashes[idx].v[path_idx]; - U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + String8Array paths = tasks[task_idx].lane_paths[idx]; + U64Array hashes = tasks[task_idx].lane_hashes[idx]; + for EachIndex(path_idx, paths.count) { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) + String8 file_path_sanitized = paths.v[path_idx]; + U64 file_path_sanitized_hash = hashes.v[path_idx]; + U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) { - src_file_node = n; - break; + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(arena, P2R_SrcFileNode, 1); + SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); + src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); } - } - if(src_file_node == 0) - { - src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); } } } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 02e6495c..a7c7f6a8 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -86,8 +86,10 @@ struct P2R2_Shared P2R2_UnitSubStartPtInfo *lane_unit_sub_start_pt_infos; - String8Array *lane_file_paths; - U64Array *lane_file_paths_hashes; + String8Array *lane_inline_file_paths; + String8Array *lane_line_file_paths; + U64Array *lane_inline_file_paths_hashes; + U64Array *lane_line_file_paths_hashes; U64 total_path_count; From 27d47939000b813abac46d501f334e1de8a9c922 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 14:57:37 -0700 Subject: [PATCH 083/302] fix line table building non-determinism --- src/rdi_from_pdb/rdi_from_pdb_2.c | 26 +++++++++++++++++--------- src/rdi_from_pdb/rdi_from_pdb_2.h | 3 ++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index dccdbba5..3ca96c4f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -941,18 +941,21 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); } - p2r2_shared->lanes_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); + p2r2_shared->lanes_main_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); + p2r2_shared->lanes_inline_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); p2r2_shared->lanes_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, lane_count()); } lane_sync(); RDIM_Unit *units = p2r2_shared->all_units.first->v; U64 units_count = p2r2_shared->all_units.first->count; - RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; + RDIM_LineTableChunkList *lanes_main_line_tables = p2r2_shared->lanes_main_line_tables; + RDIM_LineTableChunkList *lanes_inline_line_tables = p2r2_shared->lanes_inline_line_tables; Assert(units_count == comp_units->count); //- rjf: do per-lane work { - RDIM_LineTableChunkList *dst_line_tables = &lanes_line_tables[lane_idx()]; + RDIM_LineTableChunkList *dst_main_line_tables = &lanes_main_line_tables[lane_idx()]; + RDIM_LineTableChunkList *dst_inline_line_tables = &lanes_inline_line_tables[lane_idx()]; //- rjf: per-unit line table conversion ProfScope("per-unit line table conversion") @@ -1039,9 +1042,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { if(line_table == 0) { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + line_table = rdim_line_table_chunk_list_push(arena, dst_main_line_tables, 256); } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_main_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } } } @@ -1250,13 +1253,13 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { if(line_table == 0) { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + line_table = rdim_line_table_chunk_list_push(arena, dst_inline_line_tables, 256); if(p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] == 0) { p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] = line_table; } } - rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + rdim_line_table_push_sequence(arena, dst_inline_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); } // rjf: clear line chunks for subsequent sequences @@ -1300,7 +1303,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } lane_sync(); RDIM_UnitChunkList all_units = p2r2_shared->all_units; - RDIM_LineTableChunkList *lanes_line_tables = p2r2_shared->lanes_line_tables; + RDIM_LineTableChunkList *lanes_main_line_tables = p2r2_shared->lanes_main_line_tables; + RDIM_LineTableChunkList *lanes_inline_line_tables = p2r2_shared->lanes_inline_line_tables; RDIM_LineTable **lanes_first_inline_site_line_tables = p2r2_shared->lanes_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// @@ -1310,7 +1314,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, lane_count()) { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_line_tables[idx]); + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_main_line_tables[idx]); + } + for EachIndex(idx, lane_count()) + { + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_inline_line_tables[idx]); } } lane_sync(); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index a7c7f6a8..2b7d9b90 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -97,7 +97,8 @@ struct P2R2_Shared P2R_SrcFileMap src_file_map; RDIM_UnitChunkList all_units; - RDIM_LineTableChunkList *lanes_line_tables; + RDIM_LineTableChunkList *lanes_main_line_tables; + RDIM_LineTableChunkList *lanes_inline_line_tables; RDIM_LineTable **lanes_first_inline_site_line_tables; RDIM_LineTableChunkList all_line_tables; From 27f2acd45d34802393e30772608d9aaea2340083 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 18:57:42 -0700 Subject: [PATCH 084/302] further progress/fixes on pdb -> rdi determinism --- project.4coder | 2 +- src/base/base_strings.c | 23 +- src/base/base_strings.h | 2 + src/lib_rdi_make/rdi_make.c | 28 +- src/raddbg/raddbg_main.c | 1 + src/rdi_from_pdb/rdi_from_pdb_2.c | 568 +++++++++++------------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 53 +-- src/rdi_make/rdi_make_local_2.c | 110 ++++-- 8 files changed, 335 insertions(+), 452 deletions(-) diff --git a/project.4coder b/project.4coder index 2d3325c2..1bb5aad9 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 62191bcf..ef927dd0 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -367,10 +367,25 @@ str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMa } internal B32 -str8_ends_with(String8 string, String8 end, StringMatchFlags flags){ - String8 postfix = str8_postfix(string, end.size); - B32 is_match = str8_match(end, postfix, flags); - return is_match; +str8_is_before(String8 a, String8 b) +{ + B32 result = 0; + { + U64 common_size = Min(a.size, b.size); + for(U64 off = 0; off < common_size; off += 1) + { + if(a.str[off] < b.str[off]) + { + result = 1; + break; + } + if(off+1 == common_size) + { + result = (a.size < b.size); + } + } + } + return result; } //////////////////////////////// diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 3ab73314..830f7762 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -205,6 +205,8 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string); internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags); internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags); +internal B32 str8_is_before(String8 a, String8 b); +#define str8_ends_with(string, end, flags) str8_match(str8_postfix((string), (end).size), (end), (flags)) //////////////////////////////// //~ rjf: String Slicing diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 12b3e518..eb16844a 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1482,7 +1482,7 @@ rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_ RSFORCEINLINE int rdim_bake_string_is_before(void *l, void *r) { - return ((RDIM_BakeString *)l)->hash < ((RDIM_BakeString *)r)->hash; + return str8_is_before(((RDIM_BakeString *)l)->string, ((RDIM_BakeString *)r)->string); } RDI_PROC RDIM_BakeStringChunkList @@ -1495,6 +1495,10 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr for(RDI_U64 idx = 0; idx < n->count; idx += 1) { RDIM_BakeString *src_str = &n->v[idx]; + if(str8_match(src_str->string, str8_lit("x2"), 0)) + { + int x = 0; + } RDIM_BakeString *dst_str = rdim_bake_string_chunk_list_push(arena, &dst, src->total_count); rdim_memcpy_struct(dst_str, src_str); } @@ -1728,7 +1732,25 @@ rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM RSFORCEINLINE int rdim_bake_idx_run_is_before(void *l, void *r) { - return ((RDIM_BakeIdxRun *)l)->hash < ((RDIM_BakeIdxRun *)r)->hash; + B32 is_less_than = 0; + { + RDIM_BakeIdxRun *lir = (RDIM_BakeIdxRun *)l; + RDIM_BakeIdxRun *rir = (RDIM_BakeIdxRun *)r; + U64 common_count = Min(lir->count, rir->count); + for(U64 off = 0; off < common_count; off += 1) + { + if(lir->idxes[off] < rir->idxes[off]) + { + is_less_than = 1; + break; + } + if(off+1 == common_count) + { + is_less_than = (lir->count < rir->count); + } + } + } + return is_less_than; } RDI_PROC RDIM_BakeIdxRunChunkList @@ -1923,7 +1945,7 @@ rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_Bake RSFORCEINLINE int rdim_bake_name_is_before(void *l, void *r) { - return ((RDIM_BakeName *)l)->hash < ((RDIM_BakeName *)r)->hash; + return str8_is_before(((RDIM_BakeName *)l)->string, ((RDIM_BakeName *)r)->string); } RDI_PROC RDIM_BakeNameChunkList diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 25e8221b..0a2dd7f3 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -12,6 +12,7 @@ // [ ] stdout/stderr path target setting is now busted >:( // [ ] target ui entry point should override built-in entry point // [ ] list of all tabs in palette +// [ ] u64 + (ptr - ptr) seems to produce unexpected results - double check with C rules? // //- memory view // [ ] have smaller visible range than entire memory diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 3ca96c4f..e9e1afa2 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -412,57 +412,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) lane_sync(); P2R_LinkNameMap link_name_map = p2r2_shared->link_name_map; - ////////////////////////////////////////////////////////////// - //- rjf: organize subsets of unit symbol streams by lane - // - ProfScope("organize subsets of unit symbol streams by lane") - { - //- rjf: set up - ProfScope("set up") if(lane_idx() == 0) - { - p2r2_shared->lane_sym_blocks = push_array(arena, P2R2_SymBlockList, lane_count()); - p2r2_shared->total_sym_record_count = 0; - for EachIndex(sym_idx, p2r2_shared->all_syms_count) - { - p2r2_shared->total_sym_record_count += all_syms[sym_idx]->sym_ranges.count; - } - } - lane_sync(); - - //- rjf: gather - ProfScope("gather") - { - Rng1U64 lane_sym_range = lane_range(p2r2_shared->total_sym_record_count); - { - U64 scan_sym_idx = 0; - for EachIndex(idx, all_syms_count) - { - Rng1U64 stream_sym_range = r1u64(scan_sym_idx, scan_sym_idx + all_syms[idx]->sym_ranges.count); - Rng1U64 sym_range_in_stream = intersect_1u64(stream_sym_range, lane_sym_range); - if(sym_range_in_stream.max > sym_range_in_stream.min) - { - P2R2_SymBlock *block = push_array(arena, P2R2_SymBlock, 1); - SLLQueuePush(p2r2_shared->lane_sym_blocks[lane_idx()].first, p2r2_shared->lane_sym_blocks[lane_idx()].last, block); - if(idx > 0) - { - block->unit = comp_units->units[idx-1]; - } - else - { - block->unit = &pdb_comp_unit_nil; - } - block->sym = all_syms[idx]; - block->c13 = all_c13s[idx]; - block->sym_rec_range = r1u64(sym_range_in_stream.min - scan_sym_idx, sym_range_in_stream.max - scan_sym_idx); - } - scan_sym_idx += all_syms[idx]->sym_ranges.count; - } - } - } - } - lane_sync(); - P2R2_SymBlockList *lane_sym_blocks = p2r2_shared->lane_sym_blocks; - ////////////////////////////////////////////////////////////// //- rjf: gather all file paths // @@ -471,10 +420,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r2_shared->lane_inline_file_paths = push_array(arena, String8Array, lane_count()); - p2r2_shared->lane_line_file_paths = push_array(arena, String8Array, lane_count()); - p2r2_shared->lane_inline_file_paths_hashes = push_array(arena, U64Array, lane_count()); - p2r2_shared->lane_line_file_paths_hashes = push_array(arena, U64Array, lane_count()); + p2r2_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); + p2r2_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); + p2r2_shared->sym_lane_take_counter = 0; } lane_sync(); @@ -482,25 +430,29 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) ProfScope("do wide gather") { Temp scratch = scratch_begin(&arena, 1); - String8List inline_src_file_paths = {0}; - String8List line_src_file_paths = {0}; //- rjf: build local hash table to dedup files within this lane U64 hit_path_slots_count = 4096; String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); - //- rjf: iterate lane blocks & gather inline site file names - ProfScope("gather inline site file names from this lane's symbols") - for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; - lane_block != 0; - lane_block = lane_block->next) + //- rjf: take units across lanes, find all file paths + ProfScope("take units across lanes, find all file paths") + for(;;) { + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) + { + break; + } + U64 unit_idx = unit_num-1; + //- rjf: unpack unit - PDB_CompUnit *unit = lane_block->unit; - CV_SymParsed *sym = lane_block->sym; - CV_C13Parsed *c13 = lane_block->c13; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + lane_block->sym_rec_range.min; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + lane_block->sym_rec_range.max; + PDB_CompUnit *unit = comp_units->units[unit_idx]; + CV_SymParsed *sym = all_syms[unit_idx+1]; + CV_C13Parsed *c13 = all_c13s[unit_idx+1]; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym->sym_ranges.count; //- rjf: produce obj name/path String8 obj_name = unit->obj_name; @@ -514,6 +466,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); //- rjf: find all inline site symbols & gather filenames + String8List src_file_paths = {0}; U64 base_voff = 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; @@ -651,7 +604,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) hit_path_node = push_array(scratch.arena, String8Node, 1); SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); hit_path_node->string = file_path_normalized; - str8_list_push(arena, &inline_src_file_paths, push_str8_copy(arena, file_path_normalized)); + str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); } line_count = 0; } @@ -672,121 +625,78 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }break; } } - } - - //- rjf: do per-unit wide gather from unit line tables - ProfScope("do per-unit wide gather from unit line tables") - { - // rjf: iterate all units for this lane - Rng1U64 range = lane_range(comp_units->count); - for EachInRange(idx, range) + + // rjf: find all files in this unit's (non-inline) line info + ProfScope("find all files in this unit's (non-inline) line info") + for(CV_C13SubSectionNode *node = c13->first_sub_section; + node != 0; + node = node->next) { - PDB_CompUnit *unit = comp_units->units[idx]; - CV_SymParsed *unit_sym = all_syms[idx+1]; - CV_C13Parsed *unit_c13 = all_c13s[idx+1]; - CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; - - // rjf: produce obj name/path - String8 obj_name = unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + if(node->kind == CV_C13SubSectionKind_Lines) { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - // rjf: find all files in this unit's (non-inline) line info - ProfScope("find all files in this unit's (non-inline) line info") - for(CV_C13SubSectionNode *node = unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) + // rjf: file name -> sanitized file path + String8 file_path = lines_n->v.file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); { - // rjf: file name -> sanitized file path - String8 file_path = lines_n->v.file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_sanitized, 0)) { - if(str8_match(n->string, file_path_sanitized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_sanitized; - str8_list_push(scratch.arena, &line_src_file_paths, push_str8_copy(arena, file_path_sanitized)); + hit_path_node = n; + break; } } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_sanitized; + str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); + } } } } - } - - //- rjf: merge into array for this lane - p2r2_shared->lane_inline_file_paths[lane_idx()] = str8_array_from_list(arena, &inline_src_file_paths); - p2r2_shared->lane_line_file_paths[lane_idx()] = str8_array_from_list(arena, &line_src_file_paths); - - //- rjf: hash this lane's file paths - { - struct + + //- rjf: merge into array for this unit + p2r2_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); + + //- rjf: hash this unit's file paths + U64Array hashes = {0}; + hashes.count = p2r2_shared->unit_file_paths[unit_idx].count; + hashes.v = push_array(arena, U64, hashes.count); + for EachIndex(idx, p2r2_shared->unit_file_paths[unit_idx].count) { - String8Array paths; - U64Array *hashes_out; - } - tasks[] = - { - {p2r2_shared->lane_inline_file_paths[lane_idx()], &p2r2_shared->lane_inline_file_paths_hashes[lane_idx()]}, - {p2r2_shared->lane_line_file_paths[lane_idx()], &p2r2_shared->lane_line_file_paths_hashes[lane_idx()]}, - }; - for EachElement(task_idx, tasks) - { - U64Array hashes = {0}; - hashes.count = tasks[task_idx].paths.count; - hashes.v = push_array(arena, U64, hashes.count); - for EachIndex(idx, tasks[task_idx].paths.count) - { - hashes.v[idx] = rdi_hash(tasks[task_idx].paths.v[idx].str, tasks[task_idx].paths.v[idx].size); - } - tasks[task_idx].hashes_out[0] = hashes; + hashes.v[idx] = rdi_hash(p2r2_shared->unit_file_paths[unit_idx].v[idx].str, p2r2_shared->unit_file_paths[unit_idx].v[idx].size); } + p2r2_shared->unit_file_paths_hashes[unit_idx] = hashes; } - scratch_end(scratch); } } lane_sync(); - String8Array *lane_inline_file_paths = p2r2_shared->lane_inline_file_paths; - String8Array *lane_line_file_paths = p2r2_shared->lane_line_file_paths; - U64Array *lane_inline_file_paths_hashes = p2r2_shared->lane_inline_file_paths_hashes; - U64Array *lane_line_file_paths_hashes = p2r2_shared->lane_line_file_paths_hashes; + String8Array *unit_file_paths = p2r2_shared->unit_file_paths; + U64Array *unit_file_paths_hashes = p2r2_shared->unit_file_paths_hashes; ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files @@ -796,10 +706,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) ProfScope("set up table") if(lane_idx() == 0) { p2r2_shared->total_path_count = 0; - for EachIndex(idx, lane_count()) + for EachIndex(idx, comp_units->count) { - p2r2_shared->total_path_count += lane_line_file_paths[idx].count; - p2r2_shared->total_path_count += lane_inline_file_paths[idx].count; + p2r2_shared->total_path_count += unit_file_paths[idx].count; } p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); @@ -809,44 +718,31 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: fill table ProfScope("fill table") if(lane_idx() == 0) { - struct + for EachIndex(idx, comp_units->count) { - String8Array *lane_paths; - U64Array *lane_hashes; - } - tasks[] = - { - {lane_inline_file_paths, lane_inline_file_paths_hashes}, - {lane_line_file_paths, lane_line_file_paths_hashes}, - }; - for EachElement(task_idx, tasks) - { - for EachIndex(idx, lane_count()) + String8Array paths = unit_file_paths[idx]; + U64Array hashes = unit_file_paths_hashes[idx]; + for EachIndex(path_idx, paths.count) { - String8Array paths = tasks[task_idx].lane_paths[idx]; - U64Array hashes = tasks[task_idx].lane_hashes[idx]; - for EachIndex(path_idx, paths.count) + String8 file_path_sanitized = paths.v[path_idx]; + U64 file_path_sanitized_hash = hashes.v[path_idx]; + U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) { - String8 file_path_sanitized = paths.v[path_idx]; - U64 file_path_sanitized_hash = hashes.v[path_idx]; - U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + if(str8_match(n->src_file->path, file_path_sanitized, 0)) { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - if(src_file_node == 0) - { - src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + src_file_node = n; + break; } } + if(src_file_node == 0) + { + src_file_node = push_array(arena, P2R_SrcFileNode, 1); + SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); + src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + } } } } @@ -855,80 +751,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; - ////////////////////////////////////////////////////////////// - //- rjf: for each lane, figure out info for starting a sub-unit range - // - ProfScope("for each lane, figure out info for starting a sub-unit range") - { - // rjf: set up - if(lane_idx() == 0) - { - p2r2_shared->lane_unit_sub_start_pt_infos = push_array(arena, P2R2_UnitSubStartPtInfo, lane_count()); - } - lane_sync(); - - // rjf: fill - { - P2R2_UnitSubStartPtInfo *out_info = &p2r2_shared->lane_unit_sub_start_pt_infos[lane_idx()]; - P2R2_SymBlock *first_block = lane_sym_blocks[lane_idx()].first; - if(first_block != 0 && first_block->sym_rec_range.min > 0) - { - CV_SymParsed *sym = first_block->sym; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + first_block->sym_rec_range.min; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - // rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - // rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - // rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - void *sym_data_opl = sym->data.str + sym_off_opl; - - // rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - // rjf: find range starters - switch(kind) - { - default:{}break; - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - out_info->last_proc_voff = section->voff + proc32->off; - } - }break; - case CV_SymKind_FRAMEPROC: - { - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; - out_info->last_frameproc = *frameproc; - }break; - } - } - } - } - } - lane_sync(); - P2R2_UnitSubStartPtInfo *lane_unit_sub_start_pt_infos = p2r2_shared->lane_unit_sub_start_pt_infos; - ////////////////////////////////////////////////////////////// //- rjf: convert unit info // @@ -944,6 +766,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) p2r2_shared->lanes_main_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); p2r2_shared->lanes_inline_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); p2r2_shared->lanes_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, lane_count()); + p2r2_shared->sym_lane_take_counter = 0; } lane_sync(); RDIM_Unit *units = p2r2_shared->all_units.first->v; @@ -1066,14 +889,21 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: build per-inline-site line tables ProfScope("build per-inline-site line tables") { - for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; - lane_block != 0; - lane_block = lane_block->next) + for(;;) { + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) + { + break; + } + U64 unit_idx = unit_num-1; + + //- rjf: unpack unit Temp scratch = scratch_begin(&arena, 1); - PDB_CompUnit *src_unit = lane_block->unit; - CV_SymParsed *src_unit_sym = lane_block->sym; - CV_C13Parsed *src_unit_c13 = lane_block->c13; + PDB_CompUnit *src_unit = comp_units->units[unit_idx]; + CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; + CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; String8 obj_name = src_unit->obj_name; if(str8_match(obj_name, str8_lit("* Linker *"), 0) || str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) @@ -1081,9 +911,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) MemoryZeroStruct(&obj_name); } String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges + lane_block->sym_rec_range.min; - CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + lane_block->sym_rec_range.max; - U64 base_voff = lane_unit_sub_start_pt_infos[lane_idx()].last_proc_voff; + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; + U64 base_voff = 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; rec_range += 1) @@ -3075,49 +2905,53 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // if(lane_idx() == 0) { - p2r2_shared->lanes_locations = push_array(arena, RDIM_LocationChunkList, lane_count()); - p2r2_shared->lanes_location_cases = push_array(arena, RDIM_LocationCaseChunkList, lane_count()); - p2r2_shared->lanes_procedures = push_array(arena, RDIM_SymbolChunkList, lane_count()); - p2r2_shared->lanes_global_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); - p2r2_shared->lanes_thread_variables = push_array(arena, RDIM_SymbolChunkList, lane_count()); - p2r2_shared->lanes_constants = push_array(arena, RDIM_SymbolChunkList, lane_count()); - p2r2_shared->lanes_scopes = push_array(arena, RDIM_ScopeChunkList, lane_count()); - p2r2_shared->lanes_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, lane_count()); - p2r2_shared->lanes_typedefs = push_array(arena, RDIM_TypeChunkList, lane_count()); + p2r2_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); + p2r2_shared->syms_location_cases = push_array(arena, RDIM_LocationCaseChunkList, all_syms_count); + p2r2_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); + p2r2_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); + p2r2_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); + p2r2_shared->sym_lane_take_counter = 0; } lane_sync(); - //////////////////////////// - //- rjf: set up outputs for this sym stream - // - U64 sym_locations_chunk_cap = 16384; - U64 sym_location_cases_chunk_cap = 16384; - U64 sym_procedures_chunk_cap = 16384; - U64 sym_global_variables_chunk_cap = 16384; - U64 sym_thread_variables_chunk_cap = 16384; - U64 sym_constants_chunk_cap = 16384; - U64 sym_scopes_chunk_cap = 16384; - U64 sym_inline_sites_chunk_cap = 16384; - RDIM_LocationChunkList sym_locations = {0}; - RDIM_LocationCaseChunkList sym_location_cases = {0}; - RDIM_SymbolChunkList sym_procedures = {0}; - RDIM_SymbolChunkList sym_global_variables = {0}; - RDIM_SymbolChunkList sym_thread_variables = {0}; - RDIM_SymbolChunkList sym_constants = {0}; - RDIM_ScopeChunkList sym_scopes = {0}; - RDIM_InlineSiteChunkList sym_inline_sites = {0}; - RDIM_TypeChunkList typedefs = {0}; - //////////////////////////// //- rjf: fill outputs for all unit sym blocks in this lane // - for(P2R2_SymBlock *lane_block = lane_sym_blocks[lane_idx()].first; - lane_block != 0; - lane_block = lane_block->next) + for(;;) { + //- rjf: take next sym + U64 sym_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(sym_num > all_syms_count) + { + break; + } + U64 sym_idx = sym_num-1; + + //- rjf: unpack sym Temp scratch = scratch_begin(&arena, 1); - CV_SymParsed *sym = lane_block->sym; - Rng1U64 sym_rec_range = lane_block->sym_rec_range; + CV_SymParsed *sym = all_syms[sym_idx]; + Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); + U64 sym_locations_chunk_cap = 16384; + U64 sym_location_cases_chunk_cap = 16384; + U64 sym_procedures_chunk_cap = 16384; + U64 sym_global_variables_chunk_cap = 16384; + U64 sym_thread_variables_chunk_cap = 16384; + U64 sym_constants_chunk_cap = 16384; + U64 sym_scopes_chunk_cap = 16384; + U64 sym_inline_sites_chunk_cap = 16384; + RDIM_LocationChunkList *sym_locations = &p2r2_shared->syms_locations[sym_idx]; + RDIM_LocationCaseChunkList *sym_location_cases = &p2r2_shared->syms_location_cases[sym_idx]; + RDIM_SymbolChunkList *sym_procedures = &p2r2_shared->syms_procedures[sym_idx]; + RDIM_SymbolChunkList *sym_global_variables = &p2r2_shared->syms_global_variables[sym_idx]; + RDIM_SymbolChunkList *sym_thread_variables = &p2r2_shared->syms_thread_variables[sym_idx]; + RDIM_SymbolChunkList *sym_constants = &p2r2_shared->syms_constants[sym_idx]; + RDIM_ScopeChunkList *sym_scopes = &p2r2_shared->syms_scopes[sym_idx]; + RDIM_InlineSiteChunkList *sym_inline_sites = &p2r2_shared->syms_inline_sites[sym_idx]; + RDIM_TypeChunkList *typedefs = &p2r2_shared->syms_typedefs[sym_idx]; ////////////////////////// //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) @@ -3253,7 +3087,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; // rjf: build scope, insert into current parent scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); { if(top_scope_node == 0) { @@ -3272,7 +3106,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U64 voff_first = section->voff + block32->off; U64 voff_last = voff_first + block32->len; RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); } } @@ -3331,7 +3165,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build symbol - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, &sym_global_variables, sym_global_variables_chunk_cap); + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); symbol->is_extern = (kind == CV_SymKind_GDATA32); symbol->name = name; symbol->type = type; @@ -3347,7 +3181,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; String8 name = str8_cstring_capped(udt+1, sym_data_opl); - RDIM_Type *type = rdim_type_chunk_list_push(arena, &typedefs, 4096); + RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); type->kind = RDI_TypeKind_Alias; type->name = name; type->direct_type = p2r_type_ptr_from_itype(udt->itype); @@ -3390,7 +3224,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // it here because these scopes refer to the ranges of code that make up a // procedure *not* the namespaces, so a procedure's root scope always has // no parent. - RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); { COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; if(section != 0) @@ -3398,7 +3232,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U64 voff_first = section->voff + proc32->off; U64 voff_last = voff_first + proc32->len; RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, &sym_scopes, procedure_root_scope, voff_range); + rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); procedure_base_voff = voff_first; } } @@ -3422,7 +3256,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build procedure symbol - RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, &sym_procedures, sym_procedures_chunk_cap); + RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); procedure_symbol->name = name; procedure_symbol->link_name = link_name; @@ -3507,7 +3341,11 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build local RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); + if(str8_match(name, str8_lit("example_color_struct"), 0)) + { + int x = 0; + } local->kind = local_kind; local->name = name; local->type = type; @@ -3537,8 +3375,8 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, &sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_LocationCase2 *loc_case = rdim_location_case_chunk_list_push(arena, &sym_location_cases, sym_locations_chunk_cap); + RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_LocationCase2 *loc_case = rdim_location_case_chunk_list_push(arena, sym_location_cases, sym_locations_chunk_cap); loc_case->location = loc2; loc_case->voff_range.min = 0; loc_case->voff_range.max = max_U64; @@ -3550,7 +3388,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: set location case RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, &sym_scopes, &local->locset, voff_range, loc); + rdim_location_set_push_case(arena, sym_scopes, &local->locset, voff_range, loc); } }break; @@ -3582,7 +3420,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build symbol - RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, &sym_thread_variables, sym_thread_variables_chunk_cap); + RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); tvar->name = name; tvar->type = type; tvar->is_extern = (kind == CV_SymKind_GTHREAD32); @@ -3634,7 +3472,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build local RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); local->kind = local_kind; local->name = name; local->type = type; @@ -3668,7 +3506,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL @@ -3712,7 +3550,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel->off; RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, &sym_locations, sym_locations_chunk_cap, &location_info); + RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); // rjf: emit locations over ranges // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); @@ -3747,7 +3585,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE @@ -3788,7 +3626,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: emit location over ranges RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, &sym_scopes, defrange_target, voff_range, location); + rdim_location_set_push_case(arena, sym_scopes, defrange_target, voff_range, location); }break; //- rjf: DEFRANGE_REGISTER_REL @@ -3819,7 +3657,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: FILESTATIC @@ -3872,7 +3710,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &sym_inline_sites, sym_inline_sites_chunk_cap); + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); inline_site->name = name; inline_site->type = type; inline_site->owner = owner; @@ -3899,7 +3737,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); scope->inline_site = inline_site; if(top_scope_node == 0) { @@ -3933,7 +3771,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { // rjf: build new range & add to scope RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; - rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); } if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) @@ -3991,10 +3829,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build constant symbol if(name_qualified.size != 0) { - RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, &sym_constants, sym_constants_chunk_cap); + RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); cnst->name = name_qualified; cnst->type = type; - rdim_symbol_push_value_data(arena, &sym_constants, cnst, val_data); + rdim_symbol_push_value_data(arena, sym_constants, cnst, val_data); } }break; } @@ -4003,20 +3841,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) scratch_end(scratch); } - - //////////////////////////// - //- rjf: output this lane's symbols - // - p2r2_shared->lanes_locations[lane_idx()] = sym_locations; - p2r2_shared->lanes_location_cases[lane_idx()] = sym_location_cases; - p2r2_shared->lanes_procedures[lane_idx()] = sym_procedures; - p2r2_shared->lanes_global_variables[lane_idx()] = sym_global_variables; - p2r2_shared->lanes_thread_variables[lane_idx()] = sym_thread_variables; - p2r2_shared->lanes_constants[lane_idx()] = sym_constants; - p2r2_shared->lanes_scopes[lane_idx()] = sym_scopes; - p2r2_shared->lanes_inline_sites[lane_idx()] = sym_inline_sites; - p2r2_shared->lanes_typedefs[lane_idx()] = typedefs; - #undef p2r_type_ptr_from_itype } lane_sync(); @@ -4027,65 +3851,65 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { if(lane_idx() == lane_from_task_idx(0)) ProfScope("join locations") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->lanes_locations[idx]); + rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->syms_locations[idx]); } } if(lane_idx() == lane_from_task_idx(1)) ProfScope("join location cases") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_location_case_chunk_list_concat_in_place(&p2r2_shared->all_location_cases, &p2r2_shared->lanes_location_cases[idx]); + rdim_location_case_chunk_list_concat_in_place(&p2r2_shared->all_location_cases, &p2r2_shared->syms_location_cases[idx]); } } if(lane_idx() == lane_from_task_idx(2)) ProfScope("join procedures") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->lanes_procedures[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->syms_procedures[idx]); } } if(lane_idx() == lane_from_task_idx(3)) ProfScope("join global variables") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->lanes_global_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->syms_global_variables[idx]); } } if(lane_idx() == lane_from_task_idx(4)) ProfScope("join thread variables") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->lanes_thread_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->syms_thread_variables[idx]); } } if(lane_idx() == lane_from_task_idx(5)) ProfScope("join constants") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->lanes_constants[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->syms_constants[idx]); } } if(lane_idx() == lane_from_task_idx(6)) ProfScope("join scopes") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->lanes_scopes[idx]); + rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->syms_scopes[idx]); } } if(lane_idx() == lane_from_task_idx(7)) ProfScope("join inline sites") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->lanes_inline_sites[idx]); + rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->syms_inline_sites[idx]); } } if(lane_idx() == lane_from_task_idx(8)) ProfScope("join typedefs") { - for EachIndex(idx, lane_count()) + for EachIndex(idx, all_syms_count) { - rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->lanes_typedefs[idx]); + rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->syms_typedefs[idx]); } p2r2_shared->all_types = p2r2_shared->all_types__pre_typedefs; } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 2b7d9b90..8772dc92 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -17,30 +17,6 @@ struct P2R2_ConvertThreadParams RDIM_BakeParams *out_bake_params; }; -typedef struct P2R2_SymBlock P2R2_SymBlock; -struct P2R2_SymBlock -{ - P2R2_SymBlock *next; - PDB_CompUnit *unit; - CV_SymParsed *sym; - CV_C13Parsed *c13; - Rng1U64 sym_rec_range; -}; - -typedef struct P2R2_SymBlockList P2R2_SymBlockList; -struct P2R2_SymBlockList -{ - P2R2_SymBlock *first; - P2R2_SymBlock *last; -}; - -typedef struct P2R2_UnitSubStartPtInfo P2R2_UnitSubStartPtInfo; -struct P2R2_UnitSubStartPtInfo -{ - CV_SymFrameproc last_frameproc; - U64 last_proc_voff; -}; - typedef struct P2R2_Shared P2R2_Shared; struct P2R2_Shared { @@ -81,15 +57,10 @@ struct P2R2_Shared P2R_LinkNameMap link_name_map; - U64 total_sym_record_count; - P2R2_SymBlockList *lane_sym_blocks; + U64 sym_lane_take_counter; - P2R2_UnitSubStartPtInfo *lane_unit_sub_start_pt_infos; - - String8Array *lane_inline_file_paths; - String8Array *lane_line_file_paths; - U64Array *lane_inline_file_paths_hashes; - U64Array *lane_line_file_paths_hashes; + String8Array *unit_file_paths; + U64Array *unit_file_paths_hashes; U64 total_path_count; @@ -121,15 +92,15 @@ struct P2R2_Shared RDIM_UDTMemberChunkList all_members; RDIM_UDTEnumValChunkList all_enum_vals; - RDIM_LocationChunkList *lanes_locations; - RDIM_LocationCaseChunkList *lanes_location_cases; - RDIM_SymbolChunkList *lanes_procedures; - RDIM_SymbolChunkList *lanes_global_variables; - RDIM_SymbolChunkList *lanes_thread_variables; - RDIM_SymbolChunkList *lanes_constants; - RDIM_ScopeChunkList *lanes_scopes; - RDIM_InlineSiteChunkList *lanes_inline_sites; - RDIM_TypeChunkList *lanes_typedefs; + RDIM_LocationChunkList *syms_locations; + RDIM_LocationCaseChunkList *syms_location_cases; + RDIM_SymbolChunkList *syms_procedures; + RDIM_SymbolChunkList *syms_global_variables; + RDIM_SymbolChunkList *syms_thread_variables; + RDIM_SymbolChunkList *syms_constants; + RDIM_ScopeChunkList *syms_scopes; + RDIM_InlineSiteChunkList *syms_inline_sites; + RDIM_TypeChunkList *syms_typedefs; RDIM_LocationChunkList all_locations; RDIM_LocationCaseChunkList all_location_cases; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index b6dcac74..55b6b2ec 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -691,6 +691,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) params->thread_variables.total_count*1 + params->types.total_count/2); rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); } lane_sync(); @@ -838,50 +839,60 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - - //- rjf: join & sort - if(lane_idx() == 0) - { - rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); - } lane_sync(); - ProfScope("join & sort") + + //- rjf: join + ProfScope("join") { - //- rjf: join - ProfScope("join") + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) + for EachIndex(src_lane_idx, lane_count()) { - for EachIndex(src_lane_idx, lane_count()) + RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { - RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } - - //- rjf: sort - ProfScope("sort") + } + lane_sync(); + + // TODO(rjf): debugging: + if(lane_idx() == 0) + { + for EachIndex(slot_idx, rdim2_shared->bake_string_map_topology.slots_count) { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) + if(rdim2_shared->bake_string_map__loose->slots[slot_idx] == 0) { continue; } + for EachNode(n, RDIM_BakeStringChunkNode, rdim2_shared->bake_string_map__loose->slots[slot_idx]->first) { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + for EachIndex(n_idx, n->count) { - *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + // printf("%.*s\n", str8_varg(n->v[n_idx].string)); } } } + fflush(stdout); + } + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } } lane_sync(); @@ -914,6 +925,22 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + // TODO(rjf): debugging: + if(lane_idx() == 0) + { + for EachIndex(slot_idx, bake_strings->slots_count) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + // printf("%.*s\n", str8_varg(n->v[n_idx].string)); + } + } + } + fflush(stdout); + } + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps @@ -1331,6 +1358,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; + // TODO(rjf): debugging: + if(lane_idx() == 0) + { + for EachIndex(string_idx, baked_strings.string_offs_count) + { + String8 string = str8(baked_strings.string_data + baked_strings.string_offs[string_idx], baked_strings.string_offs[string_idx+1]-baked_strings.string_offs[string_idx]); + // printf("%.*s\n", str8_varg(string)); + } + fflush(stdout); + } ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake idx runs @@ -1368,7 +1405,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachIndex(idx, rdim2_shared->baked_idx_runs.idx_count) { - printf("%u\n", rdim2_shared->baked_idx_runs.idx_runs[idx]); + // printf("%u\n", rdim2_shared->baked_idx_runs.idx_runs[idx]); } fflush(stdout); } @@ -2089,6 +2126,17 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: bake global variables ProfScope("bake global variables") { + if(lane_idx() == 0) + { + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + for EachIndex(n_idx, n->count) + { + // printf("%.*s\n", str8_varg(n->v[n_idx].name)); + } + } + fflush(stdout); + } for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) { Rng1U64 range = lane_range(n->count); From 096b631e8acec56d01a99f96c2db2327bf1050b0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 3 Sep 2025 18:58:39 -0700 Subject: [PATCH 085/302] remove debugging code --- src/lib_rdi_make/rdi_make.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index eb16844a..bdc02dc3 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1495,10 +1495,6 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr for(RDI_U64 idx = 0; idx < n->count; idx += 1) { RDIM_BakeString *src_str = &n->v[idx]; - if(str8_match(src_str->string, str8_lit("x2"), 0)) - { - int x = 0; - } RDIM_BakeString *dst_str = rdim_bake_string_chunk_list_push(arena, &dst, src->total_count); rdim_memcpy_struct(dst_str, src_str); } From 4c3bb98c644e8512b65b69377089dd267315ed4f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 10:20:18 -0700 Subject: [PATCH 086/302] more determinism fixes --- src/base/base_strings.c | 9 +- src/lib_rdi_make/rdi_make.c | 7 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 583 ++++++++++++++---------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 5 +- 4 files changed, 291 insertions(+), 313 deletions(-) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index ef927dd0..ce7af60c 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -378,8 +378,13 @@ str8_is_before(String8 a, String8 b) { result = 1; break; - } - if(off+1 == common_size) + } + else if(a.str[off] > b.str[off]) + { + result = 0; + break; + } + else if(off+1 == common_size) { result = (a.size < b.size); } diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index bdc02dc3..5652477c 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1740,7 +1740,12 @@ rdim_bake_idx_run_is_before(void *l, void *r) is_less_than = 1; break; } - if(off+1 == common_count) + else if(lir->idxes[off] > rir->idxes[off]) + { + is_less_than = 0; + break; + } + else if(off+1 == common_count) { is_less_than = (lir->count < rir->count); } diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index e9e1afa2..73e61985 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -763,392 +763,361 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); } - p2r2_shared->lanes_main_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); - p2r2_shared->lanes_inline_line_tables = push_array(arena, RDIM_LineTableChunkList, lane_count()); - p2r2_shared->lanes_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, lane_count()); + p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); + p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); p2r2_shared->sym_lane_take_counter = 0; } lane_sync(); RDIM_Unit *units = p2r2_shared->all_units.first->v; U64 units_count = p2r2_shared->all_units.first->count; - RDIM_LineTableChunkList *lanes_main_line_tables = p2r2_shared->lanes_main_line_tables; - RDIM_LineTableChunkList *lanes_inline_line_tables = p2r2_shared->lanes_inline_line_tables; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; Assert(units_count == comp_units->count); //- rjf: do per-lane work + ProfScope("wide fill") for(;;) { - RDIM_LineTableChunkList *dst_main_line_tables = &lanes_main_line_tables[lane_idx()]; - RDIM_LineTableChunkList *dst_inline_line_tables = &lanes_inline_line_tables[lane_idx()]; - - //- rjf: per-unit line table conversion - ProfScope("per-unit line table conversion") + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) { - Rng1U64 range = lane_range(units_count); - for EachInRange(idx, range) + break; + } + Temp scratch = scratch_begin(&arena, 1); + U64 unit_idx = unit_num-1; + RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; + PDB_CompUnit *src_unit = comp_units->units[unit_idx]; + CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; + CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; + RDIM_Unit *dst_unit = &units[unit_idx]; + + // rjf: extract unit name + String8 unit_name = src_unit->obj_name; + if(unit_name.size != 0) + { + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) { - Temp scratch = scratch_begin(&arena, 1); - PDB_CompUnit *src_unit = comp_units->units[idx]; - CV_SymParsed *src_unit_sym = all_syms[idx+1]; - CV_C13Parsed *src_unit_c13 = all_c13s[idx+1]; - RDIM_Unit *dst_unit = &units[idx]; - - // rjf: produce unit name - String8 unit_name = src_unit->obj_name; - if(unit_name.size != 0) + unit_name = unit_name_past_last_slash; + } + } + + // rjf: produce obj name/path + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: main unit line table conversion + ProfScope("main unit line table conversion") + { + RDIM_LineTable *line_table = 0; + for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) { - unit_name = unit_name_past_last_slash; - } - } - - // rjf: produce obj name/path - String8 obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - // rjf: build this unit's line table, fill out primary line info (inline info added after) - RDIM_LineTable *line_table = 0; - ProfScope("build unit line table") - for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> sanitized file path + String8 file_path = lines->file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + if(lines->line_count != 0) + { + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) { - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + if(str8_match(n->src_file->path, file_path_sanitized, 0)) { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } + src_file_node = n; + break; } } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) + } + + // rjf: push sequence into both line table & source file's line map + if(src_file_node != 0) + { + if(line_table == 0) { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_main_line_tables, 256); - } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_main_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } } } - - // rjf: fill unit - dst_unit->unit_name = unit_name; - dst_unit->compiler_name = src_unit_sym->info.compiler_name; - dst_unit->object_file = obj_name; - dst_unit->archive_file = src_unit->group_name; - dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); - dst_unit->line_table = line_table; - dst_unit->voff_ranges = unit_ranges[idx]; - - scratch_end(scratch); } + + // rjf: fill unit + dst_unit->unit_name = unit_name; + dst_unit->compiler_name = src_unit_sym->info.compiler_name; + dst_unit->object_file = obj_name; + dst_unit->archive_file = src_unit->group_name; + dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); + dst_unit->line_table = line_table; + dst_unit->voff_ranges = unit_ranges[unit_idx]; } //- rjf: build per-inline-site line tables ProfScope("build per-inline-site line tables") { - for(;;) + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) { - //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) - { - break; - } - U64 unit_idx = unit_num-1; + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - //- rjf: unpack unit - Temp scratch = scratch_begin(&arena, 1); - PDB_CompUnit *src_unit = comp_units->units[unit_idx]; - CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; - CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; - String8 obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + //- rjf: skip invalid ranges + if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) { - MemoryZeroStruct(&obj_name); + continue; } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; + void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; - //- rjf: skip invalid ranges - if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; - void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + if(n->v.inlinee == sym->inlinee) { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } + inlinee_lines_parsed = &n->v; + break; } } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) + // rjf: gathered lines + typedef struct LineChunk LineChunk; + struct LineChunk { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - typedef struct LineChunk LineChunk; - struct LineChunk + LineChunk *next; + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + }; + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) { - LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - RDIM_LineTable* line_table = 0; - - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && total_line_chunk_line_count > 0) { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> push line chunks gathered for this file + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && total_line_chunk_line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; + CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); } - // rjf: file updated -> push line chunks gathered for this file - if(last_file_off != max_U32 && last_file_off != curr_file_off) + // rjf: file name -> sanitized file path + String8 file_path = seq_file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) { - CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - - // rjf: gather all lines - RDI_U64 *voffs = 0; - RDI_U32 *line_nums = 0; - RDI_U64 line_count = 0; - if(src_file_node != 0) - { - voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - line_count = total_line_chunk_line_count; - U64 dst_idx = 0; - for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) - { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); - MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); - dst_idx += chunk->count; - } - } - - // rjf: push - if(line_count != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_inline_line_tables, 256); - if(p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] == 0) - { - p2r2_shared->lanes_first_inline_site_line_tables[lane_idx()] = line_table; - } - } - rdim_line_table_push_sequence(arena, dst_inline_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); - } - - // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; - total_line_chunk_line_count = 0; + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); } - // rjf: new line -> emit to chunk - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) + if(str8_match(n->src_file->path, file_path_sanitized, 0)) { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 8; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + src_file_node = n; + break; } - chunk->voffs[chunk->count] = step.line_voff; - chunk->voffs[chunk->count+1] = step.line_voff_end; - chunk->line_nums[chunk->count] = step.ln; - chunk->count += 1; - total_line_chunk_line_count += 1; } - // rjf: no more flags -> done - if(step.flags == 0) + // rjf: gather all lines + RDI_U64 *voffs = 0; + RDI_U32 *line_nums = 0; + RDI_U64 line_count = 0; + if(src_file_node != 0) { - break; + voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + line_count = total_line_chunk_line_count; + U64 dst_idx = 0; + for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) + { + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); + MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); + dst_idx += chunk->count; + } } + + // rjf: push + if(line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(p2r2_shared->units_first_inline_site_line_tables[unit_idx] == 0) + { + p2r2_shared->units_first_inline_site_line_tables[unit_idx] = line_table; + } + } + rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + } + + // rjf: clear line chunks for subsequent sequences + first_line_chunk = last_line_chunk = 0; + total_line_chunk_line_count = 0; + } + + // rjf: new line -> emit to chunk + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 8; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; } } - }break; - } + } + }break; } - scratch_end(scratch); } } + + scratch_end(scratch); } } lane_sync(); RDIM_UnitChunkList all_units = p2r2_shared->all_units; - RDIM_LineTableChunkList *lanes_main_line_tables = p2r2_shared->lanes_main_line_tables; - RDIM_LineTableChunkList *lanes_inline_line_tables = p2r2_shared->lanes_inline_line_tables; - RDIM_LineTable **lanes_first_inline_site_line_tables = p2r2_shared->lanes_first_inline_site_line_tables; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// //- rjf: join all line tables // ProfScope("join all line tables") if(lane_idx() == 0) { - for EachIndex(idx, lane_count()) + for EachIndex(idx, comp_units->count) { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_main_line_tables[idx]); - } - for EachIndex(idx, lane_count()) - { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &p2r2_shared->lanes_inline_line_tables[idx]); + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &units_line_tables[idx]); } } lane_sync(); @@ -3035,7 +3004,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }; P2R_ScopeNode *top_scope_node = 0; P2R_ScopeNode *free_scope_node = 0; - RDIM_LineTable *inline_site_line_table = lanes_first_inline_site_line_tables[lane_idx()]; + RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; rec_range += 1) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 8772dc92..0c0a4fc8 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -68,9 +68,8 @@ struct P2R2_Shared P2R_SrcFileMap src_file_map; RDIM_UnitChunkList all_units; - RDIM_LineTableChunkList *lanes_main_line_tables; - RDIM_LineTableChunkList *lanes_inline_line_tables; - RDIM_LineTable **lanes_first_inline_site_line_tables; + RDIM_LineTableChunkList *units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables; RDIM_LineTableChunkList all_line_tables; From 8b83e5ef48a587012f1d968f9569c70cbf77fac4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 11:47:09 -0700 Subject: [PATCH 087/302] more non-determinism & bug fixes in name map & idx run map building --- src/lib_rdi_make/rdi_make.c | 44 +++++++++++----- src/lib_rdi_make/rdi_make.h | 3 -- src/rdi/rdi_local.c | 5 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 4 -- src/rdi_make/rdi_make_local_2.c | 87 +++++++++---------------------- 5 files changed, 61 insertions(+), 82 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 5652477c..715211a7 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1707,10 +1707,6 @@ rdim_bake_idx_run_chunk_list_push(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *l RDI_PROC void rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM_BakeIdxRunChunkList *to_push) { - for(RDIM_BakeIdxRunChunkNode *n = to_push->first; n != 0; n = n->next) - { - n->base_idx += dst->total_idx_count; - } if(dst->last != 0 && to_push->first != 0) { dst->last->next = to_push->first; @@ -1782,7 +1778,10 @@ rdim_bake_idx_run_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeId RDI_U64 last_idx = 0; for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) { - if(dst.first->v[last_idx].hash == dst.first->v[idx].hash) + if(dst.first->v[last_idx].count == dst.first->v[idx].count && + MemoryMatch(dst.first->v[last_idx].idxes, + dst.first->v[idx].idxes, + sizeof(dst.first->v[idx].idxes[0]) * dst.first->v[idx].count)) { rdim_memzero_struct(&dst.first->v[idx]); num_duplicates += 1; @@ -1854,7 +1853,9 @@ rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology { for(RDI_U64 idx = 0; idx < n->count; idx += 1) { - if(n->v[idx].hash == hash) + if(n->v[idx].hash == hash && + n->v[idx].count == count && + MemoryMatch(n->v[idx].idxes, idxes, sizeof(idxes[0])*count)) { is_duplicate = 1; goto break_all; @@ -1883,17 +1884,22 @@ rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 c { RDI_U64 hash = rdim_hash_from_idx_run(idxes, count); RDI_U64 slot_idx = hash%map->slots_count; + RDI_U64 off = 0; for(RDIM_BakeIdxRunChunkNode *n = map->slots[slot_idx].first; n != 0; n = n->next) { for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) { - if(n->v[chunk_idx].hash == hash) + if(n->v[chunk_idx].hash == hash && + n->v[chunk_idx].count == count && + MemoryMatch(n->v[chunk_idx].idxes, idxes, sizeof(idxes[0])*count)) { - idx = map->slots_base_idxs[slot_idx] + n->base_idx + n->v[chunk_idx].encoding_idx; - break; + idx = (RDI_U32)(map->slots_base_idxs[slot_idx] + off); // TODO(rjf): @u64_to_u32 + goto end_lookup; } + off += n->v[chunk_idx].count; } } + end_lookup:; } return idx; } @@ -1946,7 +1952,19 @@ rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_Bake RSFORCEINLINE int rdim_bake_name_is_before(void *l, void *r) { - return str8_is_before(((RDIM_BakeName *)l)->string, ((RDIM_BakeName *)r)->string); + RDIM_BakeName *lhs = (RDIM_BakeName *)l; + RDIM_BakeName *rhs = (RDIM_BakeName *)r; + B32 lhs_name_lt = str8_is_before(lhs->string, rhs->string); + B32 is_before = lhs_name_lt; + if(!lhs_name_lt) + { + B32 rhs_name_lt = str8_is_before(rhs->string, lhs->string); + if(!rhs_name_lt) + { + is_before = (lhs->idx > rhs->idx); + } + } + return is_before; } RDI_PROC RDIM_BakeNameChunkList @@ -1977,7 +1995,8 @@ rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameC RDI_U64 last_idx = 0; for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1) { - if(rdim_str8_match(dst.first->v[last_idx].string, dst.first->v[idx].string, 0)) + if(rdim_str8_match(dst.first->v[last_idx].string, dst.first->v[idx].string, 0) && + dst.first->v[last_idx].idx == dst.first->v[idx].idx) { rdim_memzero_struct(&dst.first->v[idx]); num_duplicates += 1; @@ -2050,7 +2069,8 @@ rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_top { for(RDI_U64 idx = 0; idx < n->count; idx += 1) { - if(rdim_str8_match(n->v[idx].string, string, 0)) + if(rdim_str8_match(n->v[idx].string, string, 0) && + n->v[idx].idx == idx) { is_duplicate = 1; goto break_all; diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 504d74aa..a81271cb 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1183,7 +1183,6 @@ struct RDIM_BakeIdxRun RDI_U64 hash; RDI_U64 count; RDI_U32 *idxes; - RDI_U64 encoding_idx; }; typedef struct RDIM_BakeIdxRunChunkNode RDIM_BakeIdxRunChunkNode; @@ -1193,7 +1192,6 @@ struct RDIM_BakeIdxRunChunkNode RDIM_BakeIdxRun *v; RDI_U64 count; RDI_U64 cap; - RDI_U64 base_idx; }; typedef struct RDIM_BakeIdxRunChunkList RDIM_BakeIdxRunChunkList; @@ -1203,7 +1201,6 @@ struct RDIM_BakeIdxRunChunkList RDIM_BakeIdxRunChunkNode *last; RDI_U64 chunk_count; RDI_U64 total_count; - RDI_U64 total_idx_count; }; typedef struct RDIM_BakeIdxRunMapTopology RDIM_BakeIdxRunMapTopology; diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index f11dd5e0..6f43ca4b 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -1201,9 +1201,10 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla for(U32 idx_i = 0; idx_i < idx_count; idx_i += 1) { U32 idx = idx_array[idx_i]; - str8_list_pushf(temp.arena, &idx_strings, "%u"); + str8_list_pushf(temp.arena, &idx_strings, "%u", idx); } - indices = str8_list_join(scratch.arena, &idx_strings, &(StringJoin){.sep = str8_lit(", ")}); + String8 extra = push_str8f(temp.arena, " // idx_run[%u]", node_ptr->match_idx_or_idx_run_first); + indices = str8_list_join(scratch.arena, &idx_strings, &(StringJoin){.sep = str8_lit(", "), .post = extra}); } dumpf(" \"%S\": %S\n", str, indices); temp_end(temp); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 73e61985..2a6f50e7 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -3311,10 +3311,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build local RDIM_Scope *scope = top_scope_node->scope; RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); - if(str8_match(name, str8_lit("example_color_struct"), 0)) - { - int x = 0; - } local->kind = local_kind; local->name = name; local->type = type; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 55b6b2ec..b1453e6c 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -864,23 +864,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); - // TODO(rjf): debugging: - if(lane_idx() == 0) - { - for EachIndex(slot_idx, rdim2_shared->bake_string_map_topology.slots_count) - { - if(rdim2_shared->bake_string_map__loose->slots[slot_idx] == 0) { continue; } - for EachNode(n, RDIM_BakeStringChunkNode, rdim2_shared->bake_string_map__loose->slots[slot_idx]->first) - { - for EachIndex(n_idx, n->count) - { - // printf("%.*s\n", str8_varg(n->v[n_idx].string)); - } - } - } - fflush(stdout); - } - //- rjf: sort ProfScope("sort") { @@ -925,22 +908,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; - // TODO(rjf): debugging: - if(lane_idx() == 0) - { - for EachIndex(slot_idx, bake_strings->slots_count) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) - { - for EachIndex(n_idx, n->count) - { - // printf("%.*s\n", str8_varg(n->v[n_idx].string)); - } - } - } - fflush(stdout); - } - ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps @@ -1164,7 +1131,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) IdxRunNode *first_idx_run_node = 0; IdxRunNode *last_idx_run_node = 0; U64 active_idx_count = 0; - U64 active_hash = 0; + String8 active_string = {0}; RDIM_BakeNameChunkNode *n = slot->first; U64 n_idx = 0; for(;;) @@ -1177,16 +1144,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: grab next element - U64 hash = 0; + String8 string = {0}; U64 idx = 0; if(n != 0) { - hash = n->v[n_idx].hash; + string = n->v[n_idx].string; idx = n->v[n_idx].idx; } // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash) + if(!str8_match(string, active_string, 0)) { if(active_idx_count > 1) { @@ -1202,14 +1169,15 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); } - active_hash = hash; + active_string = string; first_idx_run_node = 0; last_idx_run_node = 0; + active_idx_count = 0; temp_end(scratch); } - // rjf: hash matches the active list -> push - if(hash != 0 && hash == active_hash) + // rjf: new element matches the active list -> push + if(active_string.size != 0 && str8_match(string, active_string, 0)) { IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); idx_run_n->idx = idx; @@ -1243,6 +1211,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; @@ -1266,6 +1235,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) { *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + map->slots_idx_counts[slot_idx] = 0; + for EachNode(n, RDIM_BakeIdxRunChunkNode, map->slots[slot_idx]->first) + { + for EachIndex(idx, n->count) + { + map->slots_idx_counts[slot_idx] += n->v[idx].count; + } + } } } } @@ -1287,9 +1264,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; if(map->slots[slot_idx] != 0) { - encoding_idx_off += map->slots[slot_idx]->total_idx_count; + encoding_idx_off += map->slots_idx_counts[slot_idx]; } } + rdim2_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; } lane_sync(); ProfScope("fill tight map") @@ -1358,16 +1336,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; - // TODO(rjf): debugging: - if(lane_idx() == 0) - { - for EachIndex(string_idx, baked_strings.string_offs_count) - { - String8 string = str8(baked_strings.string_data + baked_strings.string_offs[string_idx], baked_strings.string_offs[string_idx+1]-baked_strings.string_offs[string_idx]); - // printf("%.*s\n", str8_varg(string)); - } - fflush(stdout); - } ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake idx runs @@ -1393,7 +1361,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) StaticAssert(sizeof(rdim2_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); for EachIndex(n_idx, n->count) { - rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(RDI_U32) * n->v[n_idx].count); + rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); off += n->v[n_idx].count; } } @@ -1531,7 +1499,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) IdxRunNode *first_idx_run_node = 0; IdxRunNode *last_idx_run_node = 0; U64 active_idx_count = 0; - U64 active_hash = 0; String8 active_string = {0}; RDIM_BakeNameChunkNode *n = src_slot->first; U64 n_idx = 0; @@ -1545,21 +1512,19 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: grab next element - U64 hash = 0; U64 idx = 0; String8 string = {0}; if(n != 0) { - hash = n->v[n_idx].hash; idx = n->v[n_idx].idx; string = n->v[n_idx].string; } - // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(hash != active_hash) + // rjf: next element doesn't match the active list? -> push index run, clear active list, start new list + if(!str8_match(active_string, string, 0)) { - // rjf: has active hash -> flatten & serialize - if(active_hash != 0) + // rjf: has active run -> flatten & serialize + if(active_string.size != 0) { // rjf: flatten idxes RDI_U64 idxs_count = active_idx_count; @@ -1590,15 +1555,15 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: start new list - active_hash = hash; active_string = string; first_idx_run_node = 0; last_idx_run_node = 0; + active_idx_count = 0; temp_end(scratch); } // rjf: hash matches the active list -> push - if(hash != 0 && hash == active_hash) + if(active_string.size != 0 && str8_match(active_string, string, 0)) { IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); idx_run_n->idx = idx; From a84142ed771f89659ba67be58a987a8acf6cb424 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 11:58:36 -0700 Subject: [PATCH 088/302] re-nest enum vals & members into udts; we want to keep the building API flexible with order of member building, and we can assume ~statistically-uniform distribution across all udts, so it makes more sense to just parallelize on udts, and pay the small cost of an upfront per-lane layout. --- src/lib_rdi_make/rdi_make.c | 44 ------------------------- src/lib_rdi_make/rdi_make.h | 54 ------------------------------- src/rdi_from_pdb/rdi_from_pdb_2.c | 40 ++++++++--------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 4 --- src/rdi_make/rdi_make_local_2.c | 38 +++++++++++++--------- 5 files changed, 35 insertions(+), 145 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 715211a7..ce468cc9 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -837,50 +837,6 @@ rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList RDIM_IdxedChunkListConcatInPlace(RDIM_TypeChunkNode, dst, to_push); } -//- rjf: UDT members - -RDI_PROC RDIM_UDTMember * -rdim_udt_member_chunk_list_push(RDIM_Arena *arena, RDIM_UDTMemberChunkList *list, RDI_U64 cap) -{ - RDIM_IdxedChunkListPush(arena, list, RDIM_UDTMemberChunkNode, RDIM_UDTMember, cap, result); - return result; -} - -RDI_PROC RDI_U64 -rdim_idx_from_udt_member(RDIM_UDTMember *member) -{ - RDIM_IdxedChunkListElementGetIdx(member, idx); - return idx; -} - -RDI_PROC void -rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UDTMemberChunkList *to_push) -{ - RDIM_IdxedChunkListConcatInPlace(RDIM_UDTMemberChunkNode, dst, to_push); -} - -//- rjf: UDT enum values - -RDI_PROC RDIM_UDTEnumVal * -rdim_udt_enum_val_chunk_list_push(RDIM_Arena *arena, RDIM_UDTEnumValChunkList *list, RDI_U64 cap) -{ - RDIM_IdxedChunkListPush(arena, list, RDIM_UDTEnumValChunkNode, RDIM_UDTEnumVal, cap, result); - return result; -} - -RDI_PROC RDI_U64 -rdim_idx_from_udt_enum_val(RDIM_UDTEnumVal *enum_val) -{ - RDIM_IdxedChunkListElementGetIdx(enum_val, idx); - return idx; -} - -RDI_PROC void -rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM_UDTEnumValChunkList *to_push) -{ - RDIM_IdxedChunkListConcatInPlace(RDIM_UDTEnumValChunkNode, dst, to_push); -} - //- rjf: UDTs RDI_PROC RDIM_UDT * diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index a81271cb..db7aea55 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -723,7 +723,6 @@ struct RDIM_TypeChunkList typedef struct RDIM_UDTMember RDIM_UDTMember; struct RDIM_UDTMember { - struct RDIM_UDTMemberChunkNode *chunk; RDIM_UDTMember *next; RDI_MemberKind kind; RDIM_String8 name; @@ -731,55 +730,16 @@ struct RDIM_UDTMember RDI_U32 off; }; -typedef struct RDIM_UDTMemberChunkNode RDIM_UDTMemberChunkNode; -struct RDIM_UDTMemberChunkNode -{ - RDIM_UDTMemberChunkNode *next; - RDIM_UDTMember *v; - RDI_U64 count; - RDI_U64 cap; - RDI_U64 base_idx; -}; - -typedef struct RDIM_UDTMemberChunkList RDIM_UDTMemberChunkList; -struct RDIM_UDTMemberChunkList -{ - RDIM_UDTMemberChunkNode *first; - RDIM_UDTMemberChunkNode *last; - RDI_U64 chunk_count; - RDI_U64 total_count; -}; - //- rjf: UDT enum values typedef struct RDIM_UDTEnumVal RDIM_UDTEnumVal; struct RDIM_UDTEnumVal { - struct RDIM_UDTEnumValChunkNode *chunk; RDIM_UDTEnumVal *next; RDIM_String8 name; RDI_U64 val; }; -typedef struct RDIM_UDTEnumValChunkNode RDIM_UDTEnumValChunkNode; -struct RDIM_UDTEnumValChunkNode -{ - RDIM_UDTEnumValChunkNode *next; - RDIM_UDTEnumVal *v; - RDI_U64 count; - RDI_U64 cap; - RDI_U64 base_idx; -}; - -typedef struct RDIM_UDTEnumValChunkList RDIM_UDTEnumValChunkList; -struct RDIM_UDTEnumValChunkList -{ - RDIM_UDTEnumValChunkNode *first; - RDIM_UDTEnumValChunkNode *last; - RDI_U64 chunk_count; - RDI_U64 total_count; -}; - //- rjf: UDTs typedef struct RDIM_UDT RDIM_UDT; @@ -1078,8 +1038,6 @@ struct RDIM_BakeParams RDIM_UnitChunkList units; RDIM_TypeChunkList types; RDIM_UDTChunkList udts; - RDIM_UDTMemberChunkList members; - RDIM_UDTEnumValChunkList enum_vals; RDIM_SrcFileChunkList src_files; RDIM_LineTableChunkList line_tables; RDIM_LocationChunkList locations; @@ -1718,22 +1676,10 @@ RDI_PROC RDIM_Type *rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkL RDI_PROC RDI_U64 rdim_idx_from_type(RDIM_Type *type); RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push); -//- rjf: UDT members -RDI_PROC RDIM_UDTMember *rdim_udt_member_chunk_list_push(RDIM_Arena *arena, RDIM_UDTMemberChunkList *list, RDI_U64 cap); -RDI_PROC RDI_U64 rdim_idx_from_udt_member(RDIM_UDTMember *member); -RDI_PROC void rdim_udt_member_chunk_list_concat_in_place(RDIM_UDTMemberChunkList *dst, RDIM_UDTMemberChunkList *to_push); - -//- rjf: UDT enum values -RDI_PROC RDIM_UDTEnumVal *rdim_udt_enum_val_chunk_list_push(RDIM_Arena *arena, RDIM_UDTEnumValChunkList *list, RDI_U64 cap); -RDI_PROC RDI_U64 rdim_idx_from_udt_enum_val(RDIM_UDTEnumVal *enum_val); -RDI_PROC void rdim_udt_enum_val_chunk_list_concat_in_place(RDIM_UDTEnumValChunkList *dst, RDIM_UDTEnumValChunkList *to_push); - //- rjf: UDTs RDI_PROC RDIM_UDT *rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap); RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt); RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push); - -//- TODO(rjf): to be removed: RDI_PROC RDIM_UDTMember *rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); RDI_PROC RDIM_UDTEnumVal *rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 2a6f50e7..3ece1c98 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2171,19 +2171,13 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) if(lane_idx() == 0) { p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); - p2r2_shared->lanes_members = push_array(arena, RDIM_UDTMemberChunkList, lane_count()); - p2r2_shared->lanes_enum_vals = push_array(arena, RDIM_UDTEnumValChunkList, lane_count()); } lane_sync(); //- rjf: do wide fill { U64 udts_chunk_cap = 4096; - U64 members_chunk_cap = 4096; - U64 enum_vals_chunk_cap = 4096; RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; - RDIM_UDTMemberChunkList *members = &p2r2_shared->lanes_members[lane_idx()]; - RDIM_UDTEnumValChunkList *enum_vals = &p2r2_shared->lanes_enum_vals[lane_idx()]; Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { @@ -2371,7 +2365,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_DataField; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); @@ -2393,7 +2387,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_StaticData; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); @@ -2471,7 +2465,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { default: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; @@ -2479,7 +2473,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }break; case CV_MethodProp_Static: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; @@ -2490,7 +2484,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) case CV_MethodProp_Intro: case CV_MethodProp_PureIntro: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; @@ -2529,7 +2523,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { default: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; @@ -2537,7 +2531,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }break; case CV_MethodProp_Static: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; @@ -2548,7 +2542,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) case CV_MethodProp_Intro: case CV_MethodProp_PureIntro: { - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; @@ -2569,7 +2563,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); @@ -2590,7 +2584,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); @@ -2612,7 +2606,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = offset_ptr+offset.encoded_size; // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_Base; mem->type = p2r_type_ptr_from_itype(lf->itype); mem->off = (U32)offset64; @@ -2638,7 +2632,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = (U8 *)(lf+1); // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_member_chunk_list_push(arena, members, members_chunk_cap); + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_VirtualBase; mem->type = p2r_type_ptr_from_itype(lf->itype); new_member = mem; @@ -2810,7 +2804,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) next_read_ptr = name.str+name.size+1; // rjf: emit member - RDIM_UDTEnumVal *enum_val = rdim_udt_enum_val_chunk_list_push(arena, enum_vals, enum_vals_chunk_cap); + RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); enum_val->name = name; enum_val->val = val64; new_enum_val = enum_val; @@ -2842,8 +2836,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } lane_sync(); RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; - RDIM_UDTMemberChunkList *lanes_members = p2r2_shared->lanes_members; - RDIM_UDTEnumValChunkList *lanes_enum_vals = p2r2_shared->lanes_enum_vals; ////////////////////////////////////////////////////////////// //- rjf: join all UDTs @@ -2853,14 +2845,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) for EachIndex(idx, lane_count()) { rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); - rdim_udt_member_chunk_list_concat_in_place(&p2r2_shared->all_members, &lanes_members[idx]); - rdim_udt_enum_val_chunk_list_concat_in_place(&p2r2_shared->all_enum_vals, &lanes_enum_vals[idx]); } } lane_sync(); RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; - RDIM_UDTMemberChunkList all_members = p2r2_shared->all_members; - RDIM_UDTEnumValChunkList all_enum_vals = p2r2_shared->all_enum_vals; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams @@ -3934,8 +3922,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) result.units = all_units; result.types = all_types; result.udts = all_udts; - result.members = all_members; - result.enum_vals = all_enum_vals; result.src_files = all_src_files; result.line_tables = all_line_tables; result.locations = all_locations; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 0c0a4fc8..47b0cd06 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -84,12 +84,8 @@ struct P2R2_Shared RDIM_TypeChunkList all_types__pre_typedefs; RDIM_UDTChunkList *lanes_udts; - RDIM_UDTMemberChunkList *lanes_members; - RDIM_UDTEnumValChunkList *lanes_enum_vals; RDIM_UDTChunkList all_udts; - RDIM_UDTMemberChunkList all_members; - RDIM_UDTEnumValChunkList all_enum_vals; RDIM_LocationChunkList *syms_locations; RDIM_LocationCaseChunkList *syms_location_cases; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index b1453e6c..f2e43fc4 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -766,23 +766,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - // rjf: push strings from udt members - ProfScope("udt members") + // rjf: push strings from udts + ProfScope("udts") { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) { Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_member_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); - } - } - - // rjf: push strings from udt enum values - ProfScope("udt enum values") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - rdim_bake_string_map_loose_push_udt_enum_val_slice(arena, lane_map_top, lane_map, n->v + range.min, dim_1u64(range)); + for EachInRange(idx, range) + { + for EachNode(mem, RDIM_UDTMember, n->v[idx].first_member) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, mem->name); + } + for EachNode(enum_val, RDIM_UDTEnumVal, n->v[idx].first_enum_val) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, enum_val->name); + } + } } } @@ -1808,12 +1808,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(3)) { - rdim2_shared->baked_udts.members_count = params->members.total_count+1; + rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); } if(lane_idx() == lane_from_task_idx(4)) { - rdim2_shared->baked_udts.enum_members_count = params->enum_vals.total_count+1; + rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); } if(lane_idx() == lane_from_task_idx(5)) @@ -1960,6 +1960,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } //- rjf: bake UDT members +#if 0 ProfScope("bake UDT members") { for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) @@ -1992,6 +1993,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } +#endif //- rjf: bake UDTs ProfScope("bake UDTs") @@ -2011,19 +2013,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) dst_udt->col = src_udt->col; //- rjf: fill member info +#if 0 if(src_udt->member_count != 0) { dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); dst_udt->member_count = src_udt->member_count; } +#endif //- rjf: fill enum members +#if 0 else if(src_udt->enum_val_count != 0) { dst_udt->flags |= RDI_UDTFlag_EnumMembers; dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); dst_udt->member_count = src_udt->enum_val_count; } +#endif } } } From fa05bbf2a5261d44f7296f6cf567972c8fca1a63 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 14:45:40 -0700 Subject: [PATCH 089/302] udt member/enum-val layout & nested baking; use rio to pre-fault all commits --- project.4coder | 2 +- src/os/core/win32/os_core_win32.c | 14 ++ src/os/core/win32/os_core_win32.h | 3 + src/rdi_from_pdb/rdi_from_pdb_2.c | 35 ---- src/rdi_make/rdi_make_local_2.c | 267 +++++++++++++++++------------- src/rdi_make/rdi_make_local_2.h | 7 +- 6 files changed, 174 insertions(+), 154 deletions(-) diff --git a/project.4coder b/project.4coder index 1bb5aad9..2d3325c2 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 0abd840e..d90d68ff 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -8,6 +8,7 @@ typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription); global W32_SetThreadDescription_Type *w32_SetThreadDescription_func = 0; +global RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {0}; //////////////////////////////// //~ rjf: File Info Conversion Helpers @@ -207,6 +208,7 @@ internal B32 os_commit(void *ptr, U64 size) { B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); + w32_rio_functions.RIODeregisterBuffer(w32_rio_functions.RIORegisterBuffer(ptr, size)); return result; } @@ -1716,6 +1718,18 @@ w32_entry_point_caller(int argc, WCHAR **wargv) } } + //- rjf: get RIO extension function table + { + // NOTE(mmozeiko): need to get function pointers to RIO functions, and that requires dummy socket + WSADATA WinSockData; + WSAStartup(MAKEWORD(2, 2), &WinSockData); + GUID guid = WSAID_MULTIPLE_RIO; + DWORD rio_byte = 0; + SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), (void**)&w32_rio_functions, sizeof(w32_rio_functions), &rio_byte, 0, 0); + closesocket(Sock); + } + //- rjf: get system info SYSTEM_INFO sysinfo = {0}; GetSystemInfo(&sysinfo); diff --git a/src/os/core/win32/os_core_win32.h b/src/os/core/win32/os_core_win32.h index 4938a828..8a7f65e8 100644 --- a/src/os/core/win32/os_core_win32.h +++ b/src/os/core/win32/os_core_win32.h @@ -7,6 +7,8 @@ //////////////////////////////// //~ rjf: Includes / Libraries +#include +#include #include #include #include @@ -20,6 +22,7 @@ #pragma comment(lib, "rpcrt4") #pragma comment(lib, "shlwapi") #pragma comment(lib, "comctl32") +#pragma comment(lib, "ws2_32") #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // this is required for loading correct comctl32 dll file //////////////////////////////// diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 3ece1c98..6d359824 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2309,7 +2309,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: process field - RDIM_UDTMember *new_member = 0; switch(field_kind) { //- rjf: unhandled/invalid cases @@ -2370,7 +2369,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); mem->off = (U32)offset64; - new_member = mem; }break; //- rjf: STMEMBER @@ -2391,7 +2389,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_StaticData; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); - new_member = mem; }break; //- rjf: METHOD @@ -2469,7 +2466,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; - new_member = mem; }break; case CV_MethodProp_Static: { @@ -2477,7 +2473,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; - new_member = mem; }break; case CV_MethodProp_Virtual: case CV_MethodProp_PureVirtual: @@ -2488,7 +2483,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; - new_member = mem; }break; } } @@ -2527,7 +2521,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_Method; mem->name = name; mem->type = method_type; - new_member = mem; }break; case CV_MethodProp_Static: { @@ -2535,7 +2528,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_StaticMethod; mem->name = name; mem->type = method_type; - new_member = mem; }break; case CV_MethodProp_Virtual: case CV_MethodProp_PureVirtual: @@ -2546,7 +2538,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_VirtualMethod; mem->name = name; mem->type = method_type; - new_member = mem; }break; } }break; @@ -2567,7 +2558,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); - new_member = mem; }break; //- rjf: NESTTYPEEX @@ -2588,7 +2578,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_NestedType; mem->name = name; mem->type = p2r_type_ptr_from_itype(lf->itype); - new_member = mem; }break; //- rjf: BCLASS @@ -2610,7 +2599,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) mem->kind = RDI_MemberKind_Base; mem->type = p2r_type_ptr_from_itype(lf->itype); mem->off = (U32)offset64; - new_member = mem; }break; //- rjf: VBCLASS/IVBCLASS @@ -2635,7 +2623,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); mem->kind = RDI_MemberKind_VirtualBase; mem->type = p2r_type_ptr_from_itype(lf->itype); - new_member = mem; }break; //- rjf: VFUNCTAB @@ -2651,16 +2638,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) }break; } - // rjf: add member to UDT - if(new_member != 0) - { - if(dst_udt->first_member == 0) - { - dst_udt->first_member = new_member; - } - dst_udt->member_count += 1; - } - // rjf: align-up next field next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); } @@ -2751,7 +2728,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: process field - RDIM_UDTEnumVal *new_enum_val = 0; switch(field_kind) { //- rjf: unhandled/invalid cases @@ -2807,20 +2783,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); enum_val->name = name; enum_val->val = val64; - new_enum_val = enum_val; }break; } - // rjf: push new enum val to udt - if(new_enum_val != 0) - { - if(dst_udt->first_enum_val == 0) - { - dst_udt->first_enum_val = new_enum_val; - } - dst_udt->enum_val_count += 1; - } - // rjf: align-up next field next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); } diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index f2e43fc4..1f13a457 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1369,14 +1369,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); - if(lane_idx() == 0) - { - for EachIndex(idx, rdim2_shared->baked_idx_runs.idx_count) - { - // printf("%u\n", rdim2_shared->baked_idx_runs.idx_runs[idx]); - } - fflush(stdout); - } RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; ////////////////////////////////////////////////////////////// @@ -1786,6 +1778,148 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts + // + ProfScope("compute lane UDT member/enum-val layouts") + { + // rjf: allocate + if(lane_idx() == 0) + { + rdim2_shared->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + } + lane_sync(); + + // rjf: count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + U64 slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; + rdim2_shared->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; + rdim2_shared->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 member_layout_off = 1; + U64 enum_val_layout_off = 1; + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->udts.chunk_count + chunk_idx; + rdim2_shared->member_chunk_lane_offs[slot_idx] = member_layout_off; + rdim2_shared->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; + member_layout_off += rdim2_shared->member_chunk_lane_counts[slot_idx]; + enum_val_layout_off += rdim2_shared->enum_val_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake UDTs + // + ProfScope("bake UDTs") + { + //- rjf: set up + ProfScope("set up") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; + rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; + rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + } + } + lane_sync(); + + //- rjf: bake UDTs + ProfScope("bake UDTs") + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + U64 layout_slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; + U64 member_layout_off = rdim2_shared->member_chunk_lane_offs[layout_slot_idx]; + U64 enum_val_layout_off = rdim2_shared->enum_val_chunk_lane_offs[layout_slot_idx]; + for EachInRange(n_idx, range) + { + RDIM_UDT *src_udt = &n->v[n_idx]; + RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + + //- rjf: fill member info + if(src_udt->first_member != 0) + { + U64 member_off_first = member_layout_off; + for EachNode(src_member, RDIM_UDTMember, src_udt->first_member) + { + RDI_Member *dst_member = &rdim2_shared->baked_udts.members[member_layout_off]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + member_layout_off += 1; + } + U64 member_off_opl = member_layout_off; + dst_udt->member_first = (RDI_U32)member_off_first; // TODO(rjf): @u64_to_u32 + dst_udt->member_count = (RDI_U32)(member_off_opl - member_off_first); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill enum val info + else if(src_udt->first_enum_val != 0) + { + U64 enum_val_off_first = enum_val_layout_off; + for EachNode(src_enum_val, RDIM_UDTEnumVal, src_udt->first_enum_val) + { + RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[enum_val_layout_off]; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_enum_val->name); + dst_member->val = src_enum_val->val; + enum_val_layout_off += 1; + } + U64 enum_val_off_opl = enum_val_layout_off; + dst_udt->flags |= RDI_UDTFlag_EnumMembers; + dst_udt->member_first = (RDI_U32)enum_val_off_first; // TODO(rjf): @u64_to_u32 + dst_udt->member_count = (RDI_U32)(enum_val_off_opl - enum_val_off_first); // TODO(rjf): @u64_to_u32 + } + } + chunk_idx += 1; + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs // @@ -1802,61 +1936,46 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); } if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; - rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); - } - if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; - rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); - } - if(lane_idx() == lane_from_task_idx(4)) - { - rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; - rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); - } - if(lane_idx() == lane_from_task_idx(5)) { rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); } - if(lane_idx() == lane_from_task_idx(6)) + if(lane_idx() == lane_from_task_idx(3)) { rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); } - if(lane_idx() == lane_from_task_idx(7)) + if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(8)) + if(lane_idx() == lane_from_task_idx(5)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(6)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(7)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(11)) + if(lane_idx() == lane_from_task_idx(8)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(12)) + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(13)) + if(lane_idx() == lane_from_task_idx(10)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -1959,81 +2078,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: bake UDT members -#if 0 - ProfScope("bake UDT members") - { - for EachNode(n, RDIM_UDTMemberChunkNode, params->members.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTMember *src_member = &n->v[n_idx]; - RDI_Member *dst_member = &rdim2_shared->baked_udts.members[n->base_idx + n_idx + 1]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - } - } - } - - //- rjf: bake UDT enum vals - ProfScope("bake UDT enum vals") - { - for EachNode(n, RDIM_UDTEnumValChunkNode, params->enum_vals.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDTEnumVal *src_member = &n->v[n_idx]; - RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[n->base_idx + n_idx + 1]; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->val = src_member->val; - } - } - } -#endif - - //- rjf: bake UDTs - ProfScope("bake UDTs") - { - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_UDT *src_udt = &n->v[n_idx]; - RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; - - //- rjf: fill basics - dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 - dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 - dst_udt->line = src_udt->line; - dst_udt->col = src_udt->col; - - //- rjf: fill member info -#if 0 - if(src_udt->member_count != 0) - { - dst_udt->member_first = rdim_idx_from_udt_member(src_udt->first_member); - dst_udt->member_count = src_udt->member_count; - } -#endif - - //- rjf: fill enum members -#if 0 - else if(src_udt->enum_val_count != 0) - { - dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = rdim_idx_from_udt_enum_val(src_udt->first_enum_val); - dst_udt->member_count = src_udt->enum_val_count; - } -#endif - } - } - } - //- rjf: bake locations ProfScope("bake locations") { @@ -2097,17 +2141,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: bake global variables ProfScope("bake global variables") { - if(lane_idx() == 0) - { - for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) - { - for EachIndex(n_idx, n->count) - { - // printf("%.*s\n", str8_varg(n->v[n_idx].name)); - } - } - fflush(stdout); - } for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) { Rng1U64 range = lane_range(n->count); diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 9d8ce951..27a34836 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -87,9 +87,14 @@ struct RDIM2_Shared RDIM_ScopeBakeResult baked_scopes; + RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] + RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] + RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] + RDI_U64 *enum_val_chunk_lane_offs; // [lane_count * udt_chunk_count] + RDIM_UDTBakeResult baked_udts; + RDIM_UnitBakeResult baked_units; RDIM_TypeNodeBakeResult baked_type_nodes; - RDIM_UDTBakeResult baked_udts; RDIM_LocationBakeResult baked_locations; RDIM_LocationBlockBakeResult baked_location_blocks; RDIM_GlobalVariableBakeResult baked_global_variables; From cc9f45299a923e18bbfe33af64a06bd487bf2276 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 15:08:17 -0700 Subject: [PATCH 090/302] eliminate separate chunk list for location cases --- project.4coder | 2 +- src/lib_rdi_make/rdi_make.c | 28 ++++------------------ src/lib_rdi_make/rdi_make.h | 28 ++-------------------- src/rdi_from_pdb/rdi_from_pdb_2.c | 30 ++++++++---------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 2 -- src/rdi_make/rdi_make_local_2.c | 39 +++++++++---------------------- 6 files changed, 28 insertions(+), 101 deletions(-) diff --git a/project.4coder b/project.4coder index 2d3325c2..1bb5aad9 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index ce468cc9..45d2c074 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1007,26 +1007,6 @@ rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_Locat RDIM_IdxedChunkListConcatInPlace(RDIM_LocationChunkNode, dst, to_push, dst->total_encoded_size += to_push->total_encoded_size); } -RDI_PROC RDIM_LocationCase2 * -rdim_location_case_chunk_list_push(RDIM_Arena *arena, RDIM_LocationCaseChunkList *list, RDI_U64 cap) -{ - RDIM_IdxedChunkListPush(arena, list, RDIM_LocationCaseChunkNode, RDIM_LocationCase2, cap, result); - return result; -} - -RDI_PROC RDI_U64 -rdim_idx_from_location_case(RDIM_LocationCase2 *location_case) -{ - RDIM_IdxedChunkListElementGetIdx(location_case, idx); - return idx; -} - -RDI_PROC void -rdim_location_case_chunk_list_concat_in_place(RDIM_LocationCaseChunkList *dst, RDIM_LocationCaseChunkList *to_push) -{ - RDIM_IdxedChunkListConcatInPlace(RDIM_LocationCaseChunkNode, dst, to_push); -} - //////////////////////////////// //~ rjf: [Building] Scope Info Building @@ -1050,9 +1030,9 @@ RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push) { RDIM_IdxedChunkListConcatInPlace(RDIM_ScopeChunkNode, dst, to_push, - dst->scope_voff_count += to_push->scope_voff_count, - dst->local_count += to_push->local_count, - dst->location_count += to_push->location_count); + dst->scope_voff_count += to_push->scope_voff_count, + dst->local_count += to_push->local_count, + dst->location_case_count += to_push->location_case_count); } RDI_PROC void @@ -1214,7 +1194,7 @@ rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM locset->location_case_count += 1; location_case->voff_range = voff_range; location_case->location = location; - scopes->location_count +=1; + scopes->location_case_count +=1; } //- rjf:location block chunk list diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index db7aea55..7066f103 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -848,30 +848,11 @@ struct RDIM_LocationChunkList typedef struct RDIM_LocationCase2 RDIM_LocationCase2; struct RDIM_LocationCase2 { - struct RDIM_LocationCaseChunkNode *chunk; + RDIM_LocationCase2 *next; RDIM_Location2 *location; RDIM_Rng1U64 voff_range; }; -typedef struct RDIM_LocationCaseChunkNode RDIM_LocationCaseChunkNode; -struct RDIM_LocationCaseChunkNode -{ - RDIM_LocationCaseChunkNode *next; - RDIM_LocationCase2 *v; - RDI_U64 count; - RDI_U64 cap; - RDI_U64 base_idx; -}; - -typedef struct RDIM_LocationCaseChunkList RDIM_LocationCaseChunkList; -struct RDIM_LocationCaseChunkList -{ - RDIM_LocationCaseChunkNode *first; - RDIM_LocationCaseChunkNode *last; - RDI_U64 chunk_count; - RDI_U64 total_count; -}; - //- rjf: locations (OLD) typedef struct RDIM_Location RDIM_Location; @@ -1022,7 +1003,7 @@ struct RDIM_ScopeChunkList RDI_U64 total_count; RDI_U64 scope_voff_count; RDI_U64 local_count; - RDI_U64 location_count; + RDI_U64 location_case_count; }; //////////////////////////////// @@ -1041,7 +1022,6 @@ struct RDIM_BakeParams RDIM_SrcFileChunkList src_files; RDIM_LineTableChunkList line_tables; RDIM_LocationChunkList locations; - RDIM_LocationCaseChunkList location_cases; RDIM_SymbolChunkList global_variables; RDIM_SymbolChunkList thread_variables; RDIM_SymbolChunkList constants; @@ -1707,10 +1687,6 @@ RDI_PROC RDI_U64 rdim_idx_from_location(RDIM_Location2 *location); RDI_PROC RDI_U64 rdim_off_from_location(RDIM_Location2 *location); RDI_PROC void rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push); -RDI_PROC RDIM_LocationCase2 *rdim_location_case_chunk_list_push(RDIM_Arena *arena, RDIM_LocationCaseChunkList *list, RDI_U64 cap); -RDI_PROC RDI_U64 rdim_idx_from_location_case(RDIM_LocationCase2 *location_case); -RDI_PROC void rdim_location_case_chunk_list_concat_in_place(RDIM_LocationCaseChunkList *dst, RDIM_LocationCaseChunkList *to_push); - //////////////////////////////// //~ rjf: [Building] Scope Info Building diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 6d359824..6bacf123 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -330,7 +330,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - RDI_Arch arch = RDI_Arch_NULL; + RDI_Arch arch = p2r2_shared->arch; U64 arch_addr_size = rdi_addr_size_from_arch(arch); ////////////////////////////////////////////////////////////// @@ -2828,7 +2828,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) if(lane_idx() == 0) { p2r2_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); - p2r2_shared->syms_location_cases = push_array(arena, RDIM_LocationCaseChunkList, all_syms_count); p2r2_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); p2r2_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); p2r2_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); @@ -2858,7 +2857,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) CV_SymParsed *sym = all_syms[sym_idx]; Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); U64 sym_locations_chunk_cap = 16384; - U64 sym_location_cases_chunk_cap = 16384; U64 sym_procedures_chunk_cap = 16384; U64 sym_global_variables_chunk_cap = 16384; U64 sym_thread_variables_chunk_cap = 16384; @@ -2866,7 +2864,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U64 sym_scopes_chunk_cap = 16384; U64 sym_inline_sites_chunk_cap = 16384; RDIM_LocationChunkList *sym_locations = &p2r2_shared->syms_locations[sym_idx]; - RDIM_LocationCaseChunkList *sym_location_cases = &p2r2_shared->syms_location_cases[sym_idx]; RDIM_SymbolChunkList *sym_procedures = &p2r2_shared->syms_procedures[sym_idx]; RDIM_SymbolChunkList *sym_global_variables = &p2r2_shared->syms_global_variables[sym_idx]; RDIM_SymbolChunkList *sym_thread_variables = &p2r2_shared->syms_thread_variables[sym_idx]; @@ -3294,6 +3291,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); +#if 0 RDIM_LocationCase2 *loc_case = rdim_location_case_chunk_list_push(arena, sym_location_cases, sym_locations_chunk_cap); loc_case->location = loc2; loc_case->voff_range.min = 0; @@ -3302,6 +3300,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: equip location case to local local->first_location_case = loc_case; local->location_case_count = 1; +#endif // rjf: set location case RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); @@ -3774,56 +3773,49 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->syms_locations[idx]); } } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("join location cases") - { - for EachIndex(idx, all_syms_count) - { - rdim_location_case_chunk_list_concat_in_place(&p2r2_shared->all_location_cases, &p2r2_shared->syms_location_cases[idx]); - } - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("join procedures") + if(lane_idx() == lane_from_task_idx(1)) ProfScope("join procedures") { for EachIndex(idx, all_syms_count) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->syms_procedures[idx]); } } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("join global variables") + if(lane_idx() == lane_from_task_idx(2)) ProfScope("join global variables") { for EachIndex(idx, all_syms_count) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->syms_global_variables[idx]); } } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("join thread variables") + if(lane_idx() == lane_from_task_idx(3)) ProfScope("join thread variables") { for EachIndex(idx, all_syms_count) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->syms_thread_variables[idx]); } } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("join constants") + if(lane_idx() == lane_from_task_idx(4)) ProfScope("join constants") { for EachIndex(idx, all_syms_count) { rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->syms_constants[idx]); } } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("join scopes") + if(lane_idx() == lane_from_task_idx(5)) ProfScope("join scopes") { for EachIndex(idx, all_syms_count) { rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->syms_scopes[idx]); } } - if(lane_idx() == lane_from_task_idx(7)) ProfScope("join inline sites") + if(lane_idx() == lane_from_task_idx(6)) ProfScope("join inline sites") { for EachIndex(idx, all_syms_count) { rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->syms_inline_sites[idx]); } } - if(lane_idx() == lane_from_task_idx(8)) ProfScope("join typedefs") + if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") { for EachIndex(idx, all_syms_count) { @@ -3834,7 +3826,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } lane_sync(); RDIM_LocationChunkList all_locations = p2r2_shared->all_locations; - RDIM_LocationCaseChunkList all_location_cases = p2r2_shared->all_location_cases; RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; @@ -3890,7 +3881,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) result.src_files = all_src_files; result.line_tables = all_line_tables; result.locations = all_locations; - result.location_cases = all_location_cases; result.global_variables = all_global_variables; result.thread_variables = all_thread_variables; result.constants = all_constants; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 47b0cd06..86270d8d 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -88,7 +88,6 @@ struct P2R2_Shared RDIM_UDTChunkList all_udts; RDIM_LocationChunkList *syms_locations; - RDIM_LocationCaseChunkList *syms_location_cases; RDIM_SymbolChunkList *syms_procedures; RDIM_SymbolChunkList *syms_global_variables; RDIM_SymbolChunkList *syms_thread_variables; @@ -98,7 +97,6 @@ struct P2R2_Shared RDIM_TypeChunkList *syms_typedefs; RDIM_LocationChunkList all_locations; - RDIM_LocationCaseChunkList all_location_cases; RDIM_SymbolChunkList all_procedures; RDIM_SymbolChunkList all_global_variables; RDIM_SymbolChunkList all_thread_variables; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 1f13a457..73d61ca9 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1757,6 +1757,11 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachNode(src_local, RDIM_Local, src_scope->first_local) { RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; + dst_local->kind = src_local->kind; + dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); + dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 + // dst_local->location_first = location_block_idx_first; + // dst_local->location_opl = location_block_idx_opl; chunk_local_off += 1; } U64 local_idx_opl = chunk_local_off; @@ -1941,41 +1946,36 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); } if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_location_blocks.location_blocks_count = params->location_cases.total_count+1; - rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); - } - if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(5)) + if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(6)) + if(lane_idx() == lane_from_task_idx(5)) { rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); } - if(lane_idx() == lane_from_task_idx(7)) + if(lane_idx() == lane_from_task_idx(6)) { rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); } - if(lane_idx() == lane_from_task_idx(8)) + if(lane_idx() == lane_from_task_idx(7)) { rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(8)) { rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); } - if(lane_idx() == lane_from_task_idx(10)) + if(lane_idx() == lane_from_task_idx(9)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -2121,23 +2121,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: bake location blocks - ProfScope("bake location blocks") - { - for EachNode(n, RDIM_LocationCaseChunkNode, params->location_cases.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_LocationCase2 *src = &n->v[n_idx]; - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[n->base_idx + n_idx + 1]; - dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 - dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 - dst->location_data_off = rdim_off_from_location(src->location); - } - } - } - //- rjf: bake global variables ProfScope("bake global variables") { From 6f9b22b2588cd13899c81c09a9e2ce9905053b56 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 15:23:49 -0700 Subject: [PATCH 091/302] plug in new location building code to pdb conversion --- src/lib_rdi_make/rdi_make.c | 174 ++++++++++++++++-------------- src/lib_rdi_make/rdi_make.h | 25 +++-- src/rdi_from_pdb/rdi_from_pdb_2.c | 40 +++++-- 3 files changed, 141 insertions(+), 98 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 45d2c074..2cc36a6f 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -937,6 +937,91 @@ rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_ //////////////////////////////// //~ rjf: [Building] Location Info Building +//- rjf: bytecode + +RDI_PROC void +rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p) +{ + RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; + RDI_U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + + RDIM_EvalBytecodeOp *node = rdim_push_array(arena, RDIM_EvalBytecodeOp, 1); + node->op = op; + node->p_size = p_size; + node->p = p; + + RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node); + bytecode->op_count += 1; + bytecode->encoded_size += 1 + p_size; +} + +RDI_PROC void +rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x) +{ + if(x <= 0xFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, x); + } + else if(x <= 0xFFFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, x); + } + else if(x <= 0xFFFFFFFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, x); + } + else + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, x); + } +} + +RDI_PROC void +rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x) +{ + if(-0x80 <= x && x <= 0x7F) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 8); + } + else if(-0x8000 <= x && x <= 0x7FFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 16); + } + else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 32); + } + else + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, (RDI_U64)x); + } +} + +RDI_PROC void +rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed) +{ + if(right_destroyed->first_op != 0) + { + if(left_dst->first_op == 0) + { + rdim_memcpy_struct(left_dst, right_destroyed); + } + else + { + left_dst->last_op->next = right_destroyed->first_op; + left_dst->last_op = right_destroyed->last_op; + left_dst->op_count += right_destroyed->op_count; + left_dst->encoded_size += right_destroyed->encoded_size; + } + rdim_memzero_struct(right_destroyed); + } +} + +//- rjf: locations + RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info) { @@ -1052,87 +1137,16 @@ rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope return local; } -//- rjf: bytecode - -RDI_PROC void -rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p) +RDI_PROC RDIM_LocationCase2 * +rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *location, RDIM_Rng1U64 voff_range) { - RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; - RDI_U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); - - RDIM_EvalBytecodeOp *node = rdim_push_array(arena, RDIM_EvalBytecodeOp, 1); - node->op = op; - node->p_size = p_size; - node->p = p; - - RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node); - bytecode->op_count += 1; - bytecode->encoded_size += 1 + p_size; -} - -RDI_PROC void -rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x) -{ - if(x <= 0xFF) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, x); - } - else if(x <= 0xFFFF) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, x); - } - else if(x <= 0xFFFFFFFF) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, x); - } - else - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, x); - } -} - -RDI_PROC void -rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x) -{ - if(-0x80 <= x && x <= 0x7F) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, (RDI_U64)x); - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 8); - } - else if(-0x8000 <= x && x <= 0x7FFF) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, (RDI_U64)x); - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 16); - } - else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll) - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, (RDI_U64)x); - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 32); - } - else - { - rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, (RDI_U64)x); - } -} - -RDI_PROC void -rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed) -{ - if(right_destroyed->first_op != 0) - { - if(left_dst->first_op == 0) - { - rdim_memcpy_struct(left_dst, right_destroyed); - } - else - { - left_dst->last_op->next = right_destroyed->first_op; - left_dst->last_op = right_destroyed->last_op; - left_dst->op_count += right_destroyed->op_count; - left_dst->encoded_size += right_destroyed->encoded_size; - } - rdim_memzero_struct(right_destroyed); - } + RDIM_LocationCase2 *loc_case = rdim_push_array(arena, RDIM_LocationCase2, 1); + RDIM_SLLQueuePush(local->location_cases.first, local->location_cases.last, loc_case); + local->location_cases.count += 1; + loc_case->location = location; + loc_case->voff_range = voff_range; + scopes->location_case_count += 1; + return loc_case; } //- rjf: individual locations diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 7066f103..4311659d 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -853,6 +853,14 @@ struct RDIM_LocationCase2 RDIM_Rng1U64 voff_range; }; +typedef struct RDIM_LocationCaseList RDIM_LocationCaseList; +struct RDIM_LocationCaseList +{ + RDIM_LocationCase2 *first; + RDIM_LocationCase2 *last; + RDI_U64 count; +}; + //- rjf: locations (OLD) typedef struct RDIM_Location RDIM_Location; @@ -964,8 +972,7 @@ struct RDIM_Local RDIM_String8 name; RDIM_Type *type; RDIM_LocationSet locset; - RDIM_LocationCase2 *first_location_case; - RDI_U64 location_case_count; + RDIM_LocationCaseList location_cases; }; typedef struct RDIM_Scope RDIM_Scope; @@ -1681,6 +1688,13 @@ RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkLi //////////////////////////////// //~ rjf: [Building] Location Info Building +//- rjf: bytecode +RDI_PROC void rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); +RDI_PROC void rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x); +RDI_PROC void rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x); +RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed); + +//- rjf: locations RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info); RDI_PROC RDIM_Location2 *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info); RDI_PROC RDI_U64 rdim_idx_from_location(RDIM_Location2 *location); @@ -1696,12 +1710,7 @@ RDI_PROC RDI_U64 rdim_idx_from_scope(RDIM_Scope *scope); RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push); RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDIM_Scope *scope, RDIM_Rng1U64 range); RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope); - -//- rjf: bytecode -RDI_PROC void rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); -RDI_PROC void rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x); -RDI_PROC void rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x); -RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed); +RDI_PROC RDIM_LocationCase2 *rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *location, RDIM_Rng1U64 voff_range); //- rjf: individual locations RDI_PROC RDIM_Location *rdim_push_location_addr_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode); diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 6bacf123..e90fd41f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -2941,6 +2941,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") { RDIM_LocationSet *defrange_target = 0; + RDIM_Local *defrange_target2 = 0; B32 defrange_target_is_param = 0; U64 procedure_num = 0; U64 procedure_base_voff = 0; @@ -2996,6 +2997,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) SLLStackPush(free_scope_node, n); } defrange_target = 0; + defrange_target2 = 0; defrange_target_is_param = 0; }break; @@ -3291,16 +3293,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); -#if 0 - RDIM_LocationCase2 *loc_case = rdim_location_case_chunk_list_push(arena, sym_location_cases, sym_locations_chunk_cap); - loc_case->location = loc2; - loc_case->voff_range.min = 0; - loc_case->voff_range.max = max_U64; - - // rjf: equip location case to local - local->first_location_case = loc_case; - local->location_case_count = 1; -#endif + rdim_local_push_location_case(arena, sym_scopes, local, loc2, (RDIM_Rng1U64){0, max_U64}); // rjf: set location case RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); @@ -3374,6 +3367,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { // TODO(rjf): add global modification symbols defrange_target = 0; + defrange_target2 = 0; defrange_target_is_param = 0; } @@ -3396,6 +3390,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: save defrange target, for subsequent defrange symbols defrange_target = &local->locset; + defrange_target2 = local; defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); } }break; @@ -3409,6 +3404,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } + if(defrange_target2 == 0) + { + break; + } // rjf: unpack sym CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; @@ -3435,6 +3434,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } + if(defrange_target2 == 0) + { + break; + } // rjf: find current procedure's frameproc CV_SymFrameproc *frameproc = 0; @@ -3482,6 +3485,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } + if(defrange_target2 == 0) + { + break; + } // rjf: unpack sym CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; @@ -3514,6 +3521,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } + if(defrange_target2 == 0) + { + break; + } // rjf: find current procedure's frameproc CV_SymFrameproc *frameproc = 0; @@ -3540,10 +3551,13 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel_full_scope->off; RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit location over ranges RDIM_Rng1U64 voff_range = {0, max_U64}; rdim_location_set_push_case(arena, sym_scopes, defrange_target, voff_range, location); + rdim_local_push_location_case(arena, sym_scopes, defrange_target2, loc, voff_range); }break; //- rjf: DEFRANGE_REGISTER_REL @@ -3555,6 +3569,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } + if(defrange_target2 == 0) + { + break; + } // rjf: unpack sym CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; @@ -3585,6 +3603,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); // TODO(rjf): emit a global modifier symbol defrange_target = 0; + defrange_target2 = 0; defrange_target_is_param = 0; }break; @@ -3717,6 +3736,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) SLLStackPush(free_scope_node, n); } defrange_target = 0; + defrange_target2 = 0; defrange_target_is_param = 0; }break; From cd77ddb1b70498051eed7b03661a963f9a15d5e9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 15:34:19 -0700 Subject: [PATCH 092/302] pdb converter - new location info building for all cases --- src/rdi_from_pdb/rdi_from_pdb_2.c | 41 ++++++++++++++++++++++++++++++- src/rdi_from_pdb/rdi_from_pdb_2.h | 2 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index e90fd41f..1e4cc181 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -39,9 +39,38 @@ p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode re } internal void -p2r2_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) { + //- rjf: extract range info + U64 voff_first = 0; + U64 voff_opl = 0; + if(section != 0) + { + voff_first = section->voff + range->off; + voff_opl = voff_first + range->len; + } + //- rjf: emit location for ranges not coverd by gaps + CV_LvarAddrGap *gap_ptr = gaps; + U64 voff_cursor = voff_first; + for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) + { + U64 voff_gap_first = voff_first + gap_ptr->off; + U64 voff_gap_opl = voff_gap_first + gap_ptr->len; + if(voff_cursor < voff_gap_first) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; + rdim_local_push_location_case(arena, scopes, local, loc, voff_range); + } + voff_cursor = voff_gap_opl; + } + + //- rjf: emit remaining range + if(voff_cursor < voff_opl) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; + rdim_local_push_location_case(arena, scopes, local, loc, voff_range); + } } internal RDIM_BakeParams @@ -3419,9 +3448,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; @@ -3473,6 +3505,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, location, range, range_section, gaps, gap_count); // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; @@ -3506,9 +3539,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; @@ -3589,9 +3625,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; B32 extra_indirection_to_value = 0; S64 var_off = defrange_register_rel->reg_off; + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index 86270d8d..e818c615 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -109,7 +109,7 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); -internal void p2r2_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); +internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); From ee8dc2742855eed00bc8c3e8acbcc2b6c35f9098 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 4 Sep 2025 16:09:02 -0700 Subject: [PATCH 093/302] location data / location block baking --- src/lib_rdi_make/rdi_make.h | 3 + src/rdi_make/rdi_make_local_2.c | 144 +++++++++++++++++++++++++++++++- src/rdi_make/rdi_make_local_2.h | 8 +- 3 files changed, 152 insertions(+), 3 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 4311659d..4acd5eab 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -906,6 +906,7 @@ struct RDIM_Symbol RDIM_Type *container_type; struct RDIM_Scope *root_scope; RDIM_LocationSet frame_base; + RDIM_LocationCaseList location_cases; RDIM_String8 value_data; }; @@ -1537,6 +1538,8 @@ struct RDIM_BakeResults RDIM_FilePathBakeResult file_paths; RDIM_StringBakeResult strings; RDIM_IndexRunBakeResult idx_runs; + RDIM_LocationBakeResult locations; + RDIM_LocationBlockBakeResult location_blocks2; RDIM_String8 location_blocks; RDIM_String8 location_data; }; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 73d61ca9..3a669576 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1925,6 +1925,146 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute lane location block layout + // + U64 total_location_case_chunk_count = (params->procedures.chunk_count + params->scopes.chunk_count); + ProfScope("compute lane location block layout") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->location_case_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + rdim2_shared->location_case_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + } + lane_sync(); + + // rjf: per-chunk-lane count of location cases + { + // rjf: count location cases in scopes + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(local, RDIM_Local, n->v[idx].first_local) + { + rdim2_shared->location_case_chunk_lane_counts[slot_idx] += local->location_cases.count; + } + } + chunk_idx += 1; + } + + // rjf: count location cases in procedures + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + rdim2_shared->location_case_chunk_lane_counts[slot_idx] += n->v[idx].location_cases.count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out location case offsets + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 location_case_layout_off = 1; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; + rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; + rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + rdim2_shared->total_location_case_count = location_case_layout_off; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake location blocks + // + ProfScope("bake location blocks") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_location_blocks.location_blocks_count = rdim2_shared->total_location_case_count; + rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + } + lane_sync(); + + // rjf: wide fill from scopes + U64 chunk_idx = 0; + ProfScope("wide fill from scopes") + { + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(local, RDIM_Local, n->v[idx].first_local) + { + for EachNode(src, RDIM_LocationCase2, local->location_cases.first) + { + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 + layout_off += 1; + } + } + } + chunk_idx += 1; + } + } + + // rjf: wide fill from procedures + ProfScope("wide fill from procedures") + { + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(src, RDIM_LocationCase2, n->v[idx].location_cases.first) + { + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 + layout_off += 1; + } + } + chunk_idx += 1; + } + } + } + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs // @@ -2312,8 +2452,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) result.file_paths = rdim2_shared->baked_file_paths; result.strings = rdim2_shared->baked_strings; result.idx_runs = rdim2_shared->baked_idx_runs; - // result.location_blocks = rdim2_shared->baked_location_blocks; - // result.location_data = rdim2_shared->baked_location_data; + result.locations = rdim2_shared->baked_locations; + result.location_blocks2 = rdim2_shared->baked_location_blocks; } return result; diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 27a34836..6d6ea1c0 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -91,12 +91,18 @@ struct RDIM2_Shared RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_offs; // [lane_count * udt_chunk_count] + RDIM_UDTBakeResult baked_udts; + RDI_U64 *location_case_chunk_lane_counts; // [lane_count * (scope_chunk_count + procedure_chunk_count) + RDI_U64 *location_case_chunk_lane_offs; // [lane_count * (scope_chunk_count + procedure_chunk_count) + RDI_U64 total_location_case_count; + + RDIM_LocationBlockBakeResult baked_location_blocks; + RDIM_UnitBakeResult baked_units; RDIM_TypeNodeBakeResult baked_type_nodes; RDIM_LocationBakeResult baked_locations; - RDIM_LocationBlockBakeResult baked_location_blocks; RDIM_GlobalVariableBakeResult baked_global_variables; RDIM_ThreadVariableBakeResult baked_thread_variables; RDIM_ConstantsBakeResult baked_constants; From 15e9cda7d2fdce66efcbe78aadd908b90607da11 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 13:20:51 -0700 Subject: [PATCH 094/302] new location info baking, new constants baking --- project.4coder | 2 +- src/lib_rdi_make/rdi_make.c | 5 + src/rdi/rdi_local.c | 17 +- src/rdi_make/rdi_make_local_2.c | 554 ++++++++++++++++++++------------ src/rdi_make/rdi_make_local_2.h | 26 +- 5 files changed, 378 insertions(+), 226 deletions(-) diff --git a/project.4coder b/project.4coder index 1bb5aad9..2d3325c2 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 2cc36a6f..64f0bd58 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -4315,6 +4315,11 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) bundle.sections[RDI_SectionKind_Locals] = rdim_serialized_section_make_unpacked_array(results->scopes.locals, results->scopes.locals_count); bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.str, results->location_blocks.size); bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->location_data.str, results->location_data.size); + if(results->location_blocks.size == 0) + { + bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks2.location_blocks, results->location_blocks2.location_blocks_count); + bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size); + } bundle.sections[RDI_SectionKind_ConstantValueData] = rdim_serialized_section_make_unpacked_array(results->constants.constant_value_data, results->constants.constant_value_data_size); bundle.sections[RDI_SectionKind_ConstantValueTable] = rdim_serialized_section_make_unpacked_array(results->constants.constant_values, results->constants.constant_values_count); bundle.sections[RDI_SectionKind_NameMaps] = rdim_serialized_section_make_unpacked_array(results->top_level_name_maps.name_maps, results->top_level_name_maps.name_maps_count); diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index 6f43ca4b..cb1be2cc 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -530,7 +530,7 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla RDI_SectionKind kind = (RDI_SectionKind)idx; RDI_Section *section = &rdi->sections[idx]; String8 kind_str = rdi_string_from_data_section_kind(scratch.arena, kind); - dumpf(" {%#08llx %7u %7u %*s} // data_section[%I64u]\n", section->off, section->encoded_size, section->unpacked_size, 24, kind_str.str, idx); + dumpf(" {%#010llx %10u %10u %*s} // data_section[%I64u]\n", section->off, section->encoded_size, section->unpacked_size, 24, kind_str.str, idx); scratch_end(scratch); } } @@ -987,20 +987,23 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { RDI_Procedure *proc = &v[idx]; Temp scratch = scratch_begin(&arena, 1); - String8List frame_base_location_strings = rdi_strings_from_locations(scratch.arena, rdi, tli->arch, r1u64(proc->frame_base_location_first, proc->frame_base_location_opl)); dumpf("\n '%S': // procedure[%I64u]\n {\n", str8_from_rdi_string_idx(rdi, proc->name_string_idx), idx); dumpf(" link_name: '%S'\n", str8_from_rdi_string_idx(rdi, proc->link_name_string_idx)); dumpf(" link_flags: `%S`\n", rdi_string_from_link_flags(scratch.arena, proc->link_flags)); dumpf(" type_idx: %u\n", proc->type_idx); dumpf(" root_scope_idx: %u\n", proc->root_scope_idx); dumpf(" container_idx: %u\n", proc->container_idx); - dumpf(" frame_base: // (first: %u, opl: %u)\n", proc->frame_base_location_first, proc->frame_base_location_opl); - dumpf(" {\n"); - for(String8Node *n = frame_base_location_strings.first; n != 0; n = n->next) + if(proc->frame_base_location_first != 0) { - dumpf(" %S\n", n->string); + String8List frame_base_location_strings = rdi_strings_from_locations(scratch.arena, rdi, tli->arch, r1u64(proc->frame_base_location_first, proc->frame_base_location_opl)); + dumpf(" frame_base: // (first: %u, opl: %u)\n", proc->frame_base_location_first, proc->frame_base_location_opl); + dumpf(" {\n"); + for(String8Node *n = frame_base_location_strings.first; n != 0; n = n->next) + { + dumpf(" %S\n", n->string); + } + dumpf(" }\n"); } - dumpf(" }\n"); dumpf(" }\n"); scratch_end(scratch); } diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 3a669576..25c5ea66 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1646,143 +1646,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) - // - ProfScope("compute layout for scope sub-lists (locals / voffs)") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - } - lane_sync(); - - // rjf: count per-lane-chunk - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - U64 num_locals_in_this_lane_and_node = 0; - U64 num_voffs_in_this_lane_and_node = 0; - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - num_locals_in_this_lane_and_node += n->v[n_idx].local_count; - num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; - } - rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; - rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: lay out each lane's range - if(lane_idx() == 0) - { - U64 local_layout_off = 1; - U64 voff_layout_off = 0; - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; - rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; - rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; - local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; - voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - } - lane_sync(); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake scopes - // - ProfScope("bake scopes") - { - //- rjf: setup outputs - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; - rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count; - rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; - rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); - } - lane_sync(); - - //- rjf: wide fill - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - Rng1U64 range = lane_range(n->count); - U64 chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; - U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[chunk_lane_slot_idx]; - U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[chunk_lane_slot_idx]; - for EachInRange(n_idx, range) - { - U64 dst_idx = 1 + n->base_idx + n_idx; - RDIM_Scope *src_scope = &n->v[n_idx]; - RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; - - //- rjf: fill voff ranges - U64 voff_idx_first = chunk_voff_off; - for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) - { - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; - chunk_voff_off += 2; - } - U64 voff_idx_opl = chunk_voff_off; - - //- rjf: fill locals - U64 local_idx_first = chunk_local_off; - for EachNode(src_local, RDIM_Local, src_scope->first_local) - { - RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; - dst_local->kind = src_local->kind; - dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); - dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 - // dst_local->location_first = location_block_idx_first; - // dst_local->location_opl = location_block_idx_opl; - chunk_local_off += 1; - } - U64 local_idx_opl = chunk_local_off; - - //- rjf: fill scope - dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 - dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 - dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 - dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 - dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 - dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 - } - chunk_idx += 1; - } - } - } - lane_sync(); - ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts // @@ -1928,7 +1791,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute lane location block layout // - U64 total_location_case_chunk_count = (params->procedures.chunk_count + params->scopes.chunk_count); + U64 total_location_case_chunk_count = (params->scopes.chunk_count + params->procedures.chunk_count); ProfScope("compute lane location block layout") { // rjf: set up @@ -2065,6 +1928,349 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake locations + // + ProfScope("bake locations") + { + if(lane_idx() == 0) + { + rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + } + lane_sync(); + for EachNode(n, RDIM_LocationChunkNode, params->locations.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Location2 *loc = &n->v[n_idx]; + RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + switch((RDI_LocationKindEnum)loc->info.kind) + { + case RDI_LocationKind_NULL:{}break; + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); + RDI_U64 write_off = sizeof(loc->info.kind); + for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) + { + MemoryCopy(dst + write_off, &op_node->op, 1); + write_off += 1; + MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); + write_off += op_node->p_size; + } + dst[write_off] = 0; + }break; + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + case RDI_LocationKind_ValReg: + { + RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + } + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) + // + ProfScope("compute layout for scope sub-lists (locals / voffs)") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + } + lane_sync(); + + // rjf: count per-lane-chunk + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 num_locals_in_this_lane_and_node = 0; + U64 num_voffs_in_this_lane_and_node = 0; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + num_locals_in_this_lane_and_node += n->v[n_idx].local_count; + num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; + } + rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; + rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out each lane's range + if(lane_idx() == 0) + { + U64 local_layout_off = 1; + U64 voff_layout_off = 0; + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; + rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; + rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; + local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; + voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + lane_sync(); + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake scopes + // + ProfScope("bake scopes") + { + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; + rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count; + rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; + rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); + } + lane_sync(); + + //- rjf: wide fill + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + Rng1U64 range = lane_range(n->count); + U64 scope_chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; + U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 location_block_chunk_lane_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 chunk_location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_chunk_lane_slot_idx]; + for EachInRange(n_idx, range) + { + U64 dst_idx = 1 + n->base_idx + n_idx; + RDIM_Scope *src_scope = &n->v[n_idx]; + RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; + + //- rjf: fill voff ranges + U64 voff_idx_first = chunk_voff_off; + for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) + { + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; + chunk_voff_off += 2; + } + U64 voff_idx_opl = chunk_voff_off; + + //- rjf: fill locals + U64 local_idx_first = chunk_local_off; + for EachNode(src_local, RDIM_Local, src_scope->first_local) + { + RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; + dst_local->kind = src_local->kind; + dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); + dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 + if(src_local->location_cases.count != 0) + { + dst_local->location_first = chunk_location_block_off; + dst_local->location_opl = chunk_location_block_off + src_local->location_cases.count; + chunk_location_block_off += src_local->location_cases.count; + } + chunk_local_off += 1; + } + U64 local_idx_opl = chunk_local_off; + + //- rjf: fill scope + dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 + dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 + dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 + dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 + dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 + dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake procedures + // + ProfScope("bake procedures") + { + if(lane_idx() == 0) + { + rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + } + lane_sync(); + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 location_block_layout_slot_idx = lane_idx()*total_location_case_chunk_count + params->scopes.chunk_count + chunk_idx; + U64 location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_Procedure *dst = &rdim2_shared->baked_procedures.procedures[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 + if(src->location_cases.count != 0) + { + dst->frame_base_location_first = location_block_off; + dst->frame_base_location_opl = location_block_off + src->location_cases.count; + location_block_off += src->location_cases.count; + } + } + chunk_idx += 1; + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute layout for constant data + // + ProfScope("compute layout for constant data") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); + } + lane_sync(); + + // rjf: count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + rdim2_shared->constant_data_chunk_lane_counts[slot_idx] += n->v[idx].value_data.size; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 layout_off = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->constants.chunk_count + chunk_idx; + rdim2_shared->constant_data_chunk_lane_offs[slot_idx] = layout_off; + layout_off += rdim2_shared->constant_data_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake constants + // + ProfScope("bake constants") + { + // rjf: set up + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + } + lane_sync(); + + // rjf: wide bake + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; + U64 value_data_off = rdim2_shared->constant_data_chunk_lane_offs[slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_Constant *dst = &rdim2_shared->baked_constants.constants[1 + n->base_idx + n_idx]; + RDI_U32 *dst_value_off = &rdim2_shared->baked_constants.constant_values[1 + n->base_idx + n_idx]; + RDI_U8 *dst_value_data = rdim2_shared->baked_constants.constant_value_data + value_data_off; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->constant_value_idx = 1 + n->base_idx + n_idx; + dst_value_off[0] = (RDI_U32)value_data_off; // TODO(rjf): @u64_to_u32 + rdim_memcpy(dst_value_data, src->value_data.str, src->value_data.size); + value_data_off += src->value_data.size; + } + chunk_idx += 1; + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs // @@ -2081,41 +2287,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); } if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; - rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); - } - if(lane_idx() == lane_from_task_idx(3)) { rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); } - if(lane_idx() == lane_from_task_idx(4)) + if(lane_idx() == lane_from_task_idx(3)) { rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); } - if(lane_idx() == lane_from_task_idx(5)) - { - rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); - } - if(lane_idx() == lane_from_task_idx(6)) - { - rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); - } - if(lane_idx() == lane_from_task_idx(7)) - { - rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; - rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); - } - if(lane_idx() == lane_from_task_idx(8)) - { - rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; - rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); - } - if(lane_idx() == lane_from_task_idx(9)) + if(lane_idx() == lane_from_task_idx(4)) { rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); @@ -2218,49 +2399,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - //- rjf: bake locations - ProfScope("bake locations") - { - for EachNode(n, RDIM_LocationChunkNode, params->locations.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Location2 *loc = &n->v[n_idx]; - RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; - switch((RDI_LocationKindEnum)loc->info.kind) - { - case RDI_LocationKind_NULL:{}break; - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); - RDI_U64 write_off = sizeof(loc->info.kind); - for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) - { - MemoryCopy(dst + write_off, &op_node->op, 1); - write_off += 1; - MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); - write_off += op_node->p_size; - } - dst[write_off] = 0; - }break; - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - case RDI_LocationKind_ValReg: - { - RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - } - } - } - } - //- rjf: bake global variables ProfScope("bake global variables") { diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 6d6ea1c0..3f162a20 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -80,13 +80,6 @@ struct RDIM2_Shared RDI_U64 *lane_src_line_map_offs; RDIM_SrcFileBakeResult baked_src_files; - RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] - RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] - RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] - RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] - - RDIM_ScopeBakeResult baked_scopes; - RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] @@ -100,13 +93,26 @@ struct RDIM2_Shared RDIM_LocationBlockBakeResult baked_location_blocks; + RDIM_LocationBakeResult baked_locations; + + RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] + + RDIM_ScopeBakeResult baked_scopes; + + RDIM_ProcedureBakeResult baked_procedures; + + RDI_U64 *constant_data_chunk_lane_counts; // [lane_count * constant_chunk_count] + RDI_U64 *constant_data_chunk_lane_offs; // [lane_count * constant_chunk_count] + + RDIM_ConstantsBakeResult baked_constants; + RDIM_UnitBakeResult baked_units; RDIM_TypeNodeBakeResult baked_type_nodes; - RDIM_LocationBakeResult baked_locations; RDIM_GlobalVariableBakeResult baked_global_variables; RDIM_ThreadVariableBakeResult baked_thread_variables; - RDIM_ConstantsBakeResult baked_constants; - RDIM_ProcedureBakeResult baked_procedures; RDIM_InlineSiteBakeResult baked_inline_sites; RDIM_BakePathNode **baked_file_path_src_nodes; From d2e6e5de5a670af3bcbd7ec8e0961f64d26f3784 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 13:25:12 -0700 Subject: [PATCH 095/302] oops - fix non-allocation in previous part --- src/rdi_make/rdi_make_local_2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 25c5ea66..39b659f0 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -2183,6 +2183,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { rdim2_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); + rdim2_shared->constant_data_chunk_lane_offs = push_array(arena, U64, lane_count() * params->constants.chunk_count); } lane_sync(); From efb24fb0fa753658bbf3eeec1f1a77ba9b68e356 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 14:18:55 -0700 Subject: [PATCH 096/302] checkpoint on src file / src line map baking --- src/lib_rdi_make/rdi_make.c | 1 + src/lib_rdi_make/rdi_make.h | 1 + src/rdi_make/rdi_make_local_2.c | 157 +++++++++++++++++++++----------- src/rdi_make/rdi_make_local_2.h | 7 +- 4 files changed, 113 insertions(+), 53 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 64f0bd58..fd8cf483 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -719,6 +719,7 @@ rdim_src_file_push_line_sequence(RDIM_Arena *arena, RDIM_SrcFileChunkList *src_f RDIM_SrcFileLineMapFragment *fragment = rdim_push_array(arena, RDIM_SrcFileLineMapFragment, 1); fragment->seq = seq; RDIM_SLLQueuePush(src_file->first_line_map_fragment, src_file->last_line_map_fragment, fragment); + src_file->total_line_count += seq->line_count; src_files->total_line_count += seq->line_count; } diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 4acd5eab..958d2623 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -538,6 +538,7 @@ struct RDIM_SrcFile RDIM_String8 path; RDIM_SrcFileLineMapFragment *first_line_map_fragment; RDIM_SrcFileLineMapFragment *last_line_map_fragment; + RDI_U64 total_line_count; }; typedef struct RDIM_SrcFileChunkNode RDIM_SrcFileChunkNode; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 39b659f0..6152a20b 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1580,71 +1580,126 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute src file / src file line map layout + // + ProfScope("compute src file / src file line map layout") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + } + lane_sync(); + + // rjf: wide count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + for EachInRange(idx, range) + { + U64 line_count = n->v[idx].total_line_count; + rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += line_count; + rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!line_count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 num_layout_off = 0; + U64 map_layout_off = 1; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; + rdim2_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; + rdim2_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; + num_layout_off += rdim2_shared->lane_chunk_src_file_num_counts[slot_idx]; + map_layout_off += rdim2_shared->lane_chunk_src_file_map_counts[slot_idx]; + } + chunk_idx += 1; + } + } + } + lane_sync(); + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake src files // ProfScope("bake src files") { //- rjf: set up - ProfScope("set up") + if(lane_idx() == 0) { - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->lane_src_line_map_counts = push_array(arena, U64, lane_count()); - rdim2_shared->lane_src_line_map_offs = push_array(arena, U64, lane_count()); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - } - } - lane_sync(); - - //- rjf: calculate layout of src file line maps - ProfScope("calculate layout of src file line maps") - { - // rjf: count lines seen by each lane - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_SrcFile *src_file = &n->v[n_idx]; - for(RDIM_SrcFileLineMapFragment *f = src_file->first_line_map_fragment; f != 0; f = f->next) - { - rdim2_shared->lane_src_line_map_counts[lane_idx()] += f->seq->line_count; - } - } - } - lane_sync(); - - // rjf: lay out per-lane offset - if(lane_idx() == 0) - { - U64 off = 0; - for EachIndex(l_idx, lane_count()) - { - rdim2_shared->lane_src_line_map_offs[l_idx] = off; - off += rdim2_shared->lane_src_line_map_counts[l_idx]; - } - // rdim2_shared->baked_src_files. - } + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + rdim2_shared->baked_src_files.source_line_map_nums_count = params->src_files.total_line_count; + rdim2_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_nums_count); + rdim2_shared->baked_src_files.source_line_map_rngs_count = params->src_files.total_line_count + rdim2_shared->baked_src_files.source_line_maps_count; + rdim2_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_rngs_count); + rdim2_shared->baked_src_files.source_line_map_voffs_count = params->src_files.total_line_count; + rdim2_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_src_files.source_line_map_voffs_count); } lane_sync(); //- rjf: bake - ProfScope("bake") + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { - + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + U64 dst_num_off = rdim2_shared->lane_chunk_src_file_num_offs[slot_idx]; + U64 dst_map_off = rdim2_shared->lane_chunk_src_file_map_offs[slot_idx]; + U64 dst_rng_off = dst_num_off + dst_map_off; + U64 dst_voff_off = dst_num_off; + for EachInRange(idx, range) + { + RDIM_SrcFile *src = &n->v[idx]; + RDI_SourceFile *dst = &rdim2_shared->baked_src_files.source_files[n->base_idx + idx + 1]; + RDI_SourceLineMap *dst_map = &rdim2_shared->baked_src_files.source_line_maps[dst_map_off]; + RDI_U32 *dst_nums = &rdim2_shared->baked_src_files.source_line_map_nums[dst_num_off]; + RDI_U32 *dst_rngs = &rdim2_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; + RDI_U64 *dst_voffs = &rdim2_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; + + //- rjf: fill nums/ranges/voffs info + if(src->total_line_count != 0) + { + + } + + //- rjf: fill map info + if(src->total_line_count != 0) + { + // dst_map->line_count = (RDI_U32)src->total_line_count; // TODO(rjf): @u64_to_u32 + // dst_map->voff_count = (RDI_U32)src->total_line_count+1; // TODO(rjf): @u64_to_u32 + dst_map_off += 1; + } + + //- rjf: fill file info + Temp scratch = scratch_begin(&arena, 1); + String8 normalized_path = rdim_lower_from_str8(scratch.arena, src->path); + dst->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src->path); + dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); + dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; + scratch_end(scratch); + } + chunk_idx += 1; } } - lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 3f162a20..94d373ed 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -76,8 +76,11 @@ struct RDIM2_Shared RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; RDIM_NameMapBakeResult baked_name_maps; - RDI_U64 *lane_src_line_map_counts; - RDI_U64 *lane_src_line_map_offs; + RDI_U64 *lane_chunk_src_file_num_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_map_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] + RDIM_SrcFileBakeResult baked_src_files; RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] From 4eca7f7feae9602215a9ec556e9daf63113556d5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 15:12:08 -0700 Subject: [PATCH 097/302] source file / source line map baking --- src/lib_rdi_make/rdi_make.h | 26 +++++ src/rdi_make/rdi_make_local_2.c | 184 ++++++++++++++++++++++++++++---- src/rdi_make/rdi_make_local_2.h | 9 ++ 3 files changed, 197 insertions(+), 22 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 958d2623..4e7ff0d4 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -1315,6 +1315,32 @@ struct RDIM_VMapMarker RDI_U32 begin_range; }; +//- rjf: source line maps + +typedef struct RDIM_BakeSrcLineMapNode RDIM_BakeSrcLineMapNode; +struct RDIM_BakeSrcLineMapNode +{ + RDIM_BakeSrcLineMapNode *next; + RDI_U32 line_num; + RDIM_Rng1U64List voff_ranges; +}; + +typedef struct RDIM_BakeSrcLineMapSlot RDIM_BakeSrcLineMapSlot; +struct RDIM_BakeSrcLineMapSlot +{ + RDIM_BakeSrcLineMapNode *first; + RDIM_BakeSrcLineMapNode *last; +}; + +typedef struct RDIM_BakeSrcLineMap RDIM_BakeSrcLineMap; +struct RDIM_BakeSrcLineMap +{ + RDIM_BakeSrcLineMapSlot *slots; + RDI_U64 slots_count; + RDI_U64 line_count; + RDI_U64 voff_range_count; +}; + //- rjf: line table records typedef struct RDIM_LineRec RDIM_LineRec; diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index 6152a20b..e8efd781 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -1580,6 +1580,118 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } lane_sync(); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage gather line-bucketed src line map data + // + ProfScope("gather line-bucketed src line map data") + { + if(lane_idx() == 0) + { + rdim2_shared->bake_src_line_maps = push_array(arena, RDIM_BakeSrcLineMap, params->src_files.total_count); + } + lane_sync(); + { + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + U64 file_idx = n->base_idx + n_idx; + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[file_idx]; + + // rjf: set up map + map->slots_count = n->v[n_idx].total_line_count; + map->slots = push_array(arena, RDIM_BakeSrcLineMapSlot, map->slots_count); + + // rjf: gather line-bucketed info + for EachNode(frag, RDIM_SrcFileLineMapFragment, n->v[n_idx].first_line_map_fragment) + { + RDIM_LineSequence *seq = frag->seq; + for EachIndex(idx, seq->line_count) + { + RDI_U32 line_num = seq->line_nums[idx]; + RDI_U64 voff_first = seq->voffs[idx]; + RDI_U64 voff_opl = seq->voffs[idx+1]; + RDI_U64 slot_idx = line_num%map->slots_count; + + // rjf: find existing line node + RDIM_BakeSrcLineMapNode *line_node = 0; + { + for EachNode(line_n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) + { + if(line_n->line_num == line_num) + { + line_node = line_n; + break; + } + } + } + + // rjf: construct new node if unseen + if(line_node == 0) + { + line_node = push_array(arena, RDIM_BakeSrcLineMapNode, 1); + SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, line_node); + line_node->line_num = line_num; + map->line_count += 1; + } + + // rjf: push this voff range + RDIM_Rng1U64 voff_range = {voff_first, voff_opl}; + rdim_rng1u64_list_push(arena, &line_node->voff_ranges, voff_range); + map->voff_range_count += 1; + } + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage sort line-bucketed src line map data + // + ProfScope("sort line-bucketed src line map data") + { + U64 map_count = params->src_files.total_count; + if(lane_idx() == 0) + { + rdim2_shared->bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); + } + lane_sync(); + for(;;) + { + U64 map_num = ins_atomic_u64_inc_eval(&rdim2_shared->bake_src_line_map_take_counter); + if(map_num < 1 || map_count < map_num) + { + break; + } + U64 map_idx = map_num-1; + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[map_idx]; + + // rjf: gather keys + rdim2_shared->bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); + RDIM_SortKey *keys = rdim2_shared->bake_src_line_map_keys[map_idx]; + { + U64 key_idx = 0; + for EachIndex(slot_idx, map->slots_count) + { + for EachNode(n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) + { + keys[key_idx].key = n->line_num; + keys[key_idx].val = n; + key_idx += 1; + } + } + } + + // rjf: sort keys + { + radsort(keys, map->line_count, rdim_sort_key_is_before); + } + } + } + ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute src file / src file line map layout // @@ -1589,8 +1701,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { rdim2_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); rdim2_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); rdim2_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); rdim2_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); } lane_sync(); @@ -1604,9 +1718,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; for EachInRange(idx, range) { - U64 line_count = n->v[idx].total_line_count; - rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += line_count; - rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!line_count; + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; + rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; + rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; + rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; } chunk_idx += 1; } @@ -1618,6 +1733,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { U64 chunk_idx = 0; U64 num_layout_off = 0; + U64 voff_layout_off = 0; U64 map_layout_off = 1; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { @@ -1625,12 +1741,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; rdim2_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; + rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; rdim2_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; num_layout_off += rdim2_shared->lane_chunk_src_file_num_counts[slot_idx]; + voff_layout_off += rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx]; map_layout_off += rdim2_shared->lane_chunk_src_file_map_counts[slot_idx]; } chunk_idx += 1; } + rdim2_shared->total_src_map_line_count = num_layout_off; + rdim2_shared->total_src_map_voff_count = voff_layout_off; } } lane_sync(); @@ -1645,13 +1765,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count; + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - rdim2_shared->baked_src_files.source_line_map_nums_count = params->src_files.total_line_count; + rdim2_shared->baked_src_files.source_line_map_nums_count = rdim2_shared->total_src_map_line_count; rdim2_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_nums_count); - rdim2_shared->baked_src_files.source_line_map_rngs_count = params->src_files.total_line_count + rdim2_shared->baked_src_files.source_line_maps_count; + rdim2_shared->baked_src_files.source_line_map_rngs_count = rdim2_shared->total_src_map_line_count + rdim2_shared->baked_src_files.source_line_maps_count; rdim2_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_rngs_count); - rdim2_shared->baked_src_files.source_line_map_voffs_count = params->src_files.total_line_count; + rdim2_shared->baked_src_files.source_line_map_voffs_count = rdim2_shared->total_src_map_voff_count; rdim2_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_src_files.source_line_map_voffs_count); } lane_sync(); @@ -1664,10 +1784,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; U64 dst_num_off = rdim2_shared->lane_chunk_src_file_num_offs[slot_idx]; U64 dst_map_off = rdim2_shared->lane_chunk_src_file_map_offs[slot_idx]; + U64 dst_voff_off = rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx]; U64 dst_rng_off = dst_num_off + dst_map_off; - U64 dst_voff_off = dst_num_off; for EachInRange(idx, range) { + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; + RDIM_SortKey *sorted_map_keys = rdim2_shared->bake_src_line_map_keys[n->base_idx + idx]; RDIM_SrcFile *src = &n->v[idx]; RDI_SourceFile *dst = &rdim2_shared->baked_src_files.source_files[n->base_idx + idx + 1]; RDI_SourceLineMap *dst_map = &rdim2_shared->baked_src_files.source_line_maps[dst_map_off]; @@ -1675,20 +1797,6 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDI_U32 *dst_rngs = &rdim2_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; RDI_U64 *dst_voffs = &rdim2_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; - //- rjf: fill nums/ranges/voffs info - if(src->total_line_count != 0) - { - - } - - //- rjf: fill map info - if(src->total_line_count != 0) - { - // dst_map->line_count = (RDI_U32)src->total_line_count; // TODO(rjf): @u64_to_u32 - // dst_map->voff_count = (RDI_U32)src->total_line_count+1; // TODO(rjf): @u64_to_u32 - dst_map_off += 1; - } - //- rjf: fill file info Temp scratch = scratch_begin(&arena, 1); String8 normalized_path = rdim_lower_from_str8(scratch.arena, src->path); @@ -1696,6 +1804,38 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; scratch_end(scratch); + + //- rjf: fill map info + if(src->total_line_count != 0) + { + dst_map->line_count = (RDI_U32)map->line_count; // TODO(rjf): @u64_to_u32 + dst_map->voff_count = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 + dst_map->line_map_nums_base_idx = (RDI_U32)dst_num_off; // TODO(rjf): @u64_to_u32 + dst_map->line_map_range_base_idx = (RDI_U32)dst_rng_off; // TODO(rjf): @u64_to_u32 + dst_map->line_map_voff_base_idx = (RDI_U32)dst_voff_off; // TODO(rjf): @u64_to_u32 + dst_map_off += 1; + } + + //- rjf: fill nums/ranges/voffs info + if(src->total_line_count != 0) + { + U64 *dst_voff_ptr = dst_voffs; + for EachIndex(line_num_idx, map->line_count) + { + dst_nums[line_num_idx] = (RDI_U32)sorted_map_keys[line_num_idx].key; // TODO(rjf): @u64_to_u32 + dst_rngs[line_num_idx] = (RDI_U32)(dst_voff_ptr - dst_voffs); // TODO(rjf): @u64_to_u32 + RDIM_BakeSrcLineMapNode *node = (RDIM_BakeSrcLineMapNode *)sorted_map_keys[line_num_idx].val; + for EachNode(rng_n, RDIM_Rng1U64Node, node->voff_ranges.first) + { + dst_voff_ptr[0] = rng_n->v.min; + dst_voff_ptr += 1; + } + } + dst_rngs[map->line_count] = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 + dst_num_off += map->line_count; + dst_rng_off += map->line_count+1; + dst_voff_off += map->voff_range_count; + } } chunk_idx += 1; } diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h index 94d373ed..7b43b9be 100644 --- a/src/rdi_make/rdi_make_local_2.h +++ b/src/rdi_make/rdi_make_local_2.h @@ -76,10 +76,19 @@ struct RDIM2_Shared RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; RDIM_NameMapBakeResult baked_name_maps; + RDIM_BakeSrcLineMap *bake_src_line_maps; + + RDI_U64 bake_src_line_map_take_counter; + RDIM_SortKey **bake_src_line_map_keys; + RDI_U64 *lane_chunk_src_file_num_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_voff_counts; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_map_counts; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_voff_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] + RDI_U64 total_src_map_line_count; + RDI_U64 total_src_map_voff_count; RDIM_SrcFileBakeResult baked_src_files; From 0ceadff5252b4df678249908e7967de6a804a8f2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 19 Aug 2025 14:08:34 -0700 Subject: [PATCH 098/302] maintain input order of objs in PDB --- src/linker/lnk_debug_info.c | 68 ++++++++++++++++++------------------- src/linker/lnk_debug_info.h | 18 +++++----- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 4905bae5..0c163f4e 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -140,7 +140,7 @@ THREAD_POOL_TASK_FUNC(lnk_parse_cv_symbols_task) } internal LNK_PchInfo * -lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols) +lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols) { Temp scratch = scratch_begin(&arena, 1); @@ -155,16 +155,16 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_ if (debug_t->count && debug_p->count) { lnk_error_obj(LNK_Warning_MultipleDebugTAndDebugP, - &obj_arr[obj_idx], + obj_arr[obj_idx], "multiple sections with debug types detected, obj must have either .debug$T or .debug$P (using .debug$T for type server)"); continue; } if (debug_p->count) { - String8 obj_path = obj_arr[obj_idx].path; + String8 obj_path = obj_arr[obj_idx]->path; obj_path = path_absolute_dst_from_relative_dst_src(scratch.arena, obj_path, work_dir); if (hash_table_search_path(debug_p_ht, obj_path)) { - lnk_error_obj(LNK_Warning_DuplicateObjPath, &obj_arr[obj_idx], "duplicate obj path %S", obj_path); + lnk_error_obj(LNK_Warning_DuplicateObjPath, obj_arr[obj_idx], "duplicate obj path %S", obj_path); } else { hash_table_push_path_u64(scratch.arena, debug_p_ht, obj_path, obj_idx); } @@ -183,7 +183,7 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_ // map obj name in LF_PRECOMP to obj index U64 debug_p_obj_idx; if (!hash_table_search_path_u64(debug_p_ht, obj_path, &debug_p_obj_idx)) { - lnk_error_obj(LNK_Error_PrecompObjNotFound, &obj_arr[obj_idx], "LF_PRECOMP references non-existent obj %S", obj_path); + lnk_error_obj(LNK_Error_PrecompObjNotFound, obj_arr[obj_idx], "LF_PRECOMP references non-existent obj %S", obj_path); lnk_exit(LNK_Error_PrecompObjNotFound); } @@ -194,34 +194,34 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_ // error check LF_PRECOMP if (precomp.start_index > CV_MinComplexTypeIndex) { - lnk_error_obj(LNK_Warning_AtypicalStartIndex, &obj_arr[obj_idx], "atypical start index 0x%X in LF_PRECOMP", precomp.start_index); + lnk_error_obj(LNK_Warning_AtypicalStartIndex, obj_arr[obj_idx], "atypical start index 0x%X in LF_PRECOMP", precomp.start_index); } if (precomp.start_index < CV_MinComplexTypeIndex) { - lnk_error_obj(LNK_Error_InvalidStartIndex, &obj_arr[obj_idx], "invalid start index 0x%X in LF_PRECOMP; must be >= 0x%X", precomp.start_index, CV_MinComplexTypeIndex); + lnk_error_obj(LNK_Error_InvalidStartIndex, obj_arr[obj_idx], "invalid start index 0x%X in LF_PRECOMP; must be >= 0x%X", precomp.start_index, CV_MinComplexTypeIndex); } if (precomp.leaf_count > debug_p.count) { - lnk_error_obj(LNK_Error_InvalidPrecompLeafCount, &obj_arr[obj_idx], "leaf count %u LF_PRECOMP exceeds leaf count %u in .debug$P in %S", precomp.leaf_count, debug_p.count, obj_arr[debug_p_obj_idx].path); + lnk_error_obj(LNK_Error_InvalidPrecompLeafCount, obj_arr[obj_idx], "leaf count %u LF_PRECOMP exceeds leaf count %u in .debug$P in %S", precomp.leaf_count, debug_p.count, obj_arr[debug_p_obj_idx]->path); } // error check LF_ENDPRECOMP if (endprecomp_leaf.kind != CV_LeafKind_ENDPRECOMP) { - lnk_error_obj(LNK_Error_EndprecompNotFound, &obj_arr[obj_idx], "unable to find LF_ENDPRECOMP @ 0x%X in %S", precomp.leaf_count, obj_arr[debug_p_obj_idx].path); + lnk_error_obj(LNK_Error_EndprecompNotFound, obj_arr[obj_idx], "unable to find LF_ENDPRECOMP @ 0x%X in %S", precomp.leaf_count, obj_arr[debug_p_obj_idx]->path); } if (endprecomp_leaf.data.size != sizeof(CV_LeafEndPreComp)) { - lnk_error_obj(LNK_Error_IllData, &obj_arr[obj_idx], "invalid size 0x%X for LF_ENDPRECOMP", endprecomp_leaf.data.size); + lnk_error_obj(LNK_Error_IllData, obj_arr[obj_idx], "invalid size 0x%X for LF_ENDPRECOMP", endprecomp_leaf.data.size); } if (endprecomp->sig != precomp.sig) { - lnk_error_obj(LNK_Error_PrecompSigMismatch, &obj_arr[obj_idx], "signature mismatch between LF_PRECOMP(0x%X) and LF_ENDPRECOMP(0x%X); precomp obj %S", precomp.sig, endprecomp->sig, obj_arr[debug_p_obj_idx].path); + lnk_error_obj(LNK_Error_PrecompSigMismatch, obj_arr[obj_idx], "signature mismatch between LF_PRECOMP(0x%X) and LF_ENDPRECOMP(0x%X); precomp obj %S", precomp.sig, endprecomp->sig, obj_arr[debug_p_obj_idx]->path); } { // check against S_OBJNAME sig in precompiled obj $$SYMBOLS CV_SymbolList symbol_list = parsed_symbols[debug_p_obj_idx].v[0]; if (symbol_list.count) { CV_ObjInfo obj_info = cv_obj_info_from_symbol(symbol_list.first->data); if (obj_info.sig != 0 && obj_info.sig != precomp.sig) { - lnk_error_obj(LNK_Error_PrecompSigMismatch, &obj_arr[obj_idx], "signature mismatch between LF_PRECOMP(0x%X) and S_OBJNAME(0x%X) in %S", precomp.sig, obj_info.sig, &obj_arr[debug_p_obj_idx].path); + lnk_error_obj(LNK_Error_PrecompSigMismatch, obj_arr[obj_idx], "signature mismatch between LF_PRECOMP(0x%X) and S_OBJNAME(0x%X) in %S", precomp.sig, obj_info.sig, obj_arr[debug_p_obj_idx]->path); } } else { - lnk_error_obj(LNK_Warning_PrecompObjSymbolsNotFound, &obj_arr[obj_idx], "symbols not found, unable to chceck LF_PRECOMP signature against S_OBJ"); + lnk_error_obj(LNK_Warning_PrecompObjSymbolsNotFound, obj_arr[obj_idx], "symbols not found, unable to chceck LF_PRECOMP signature against S_OBJ"); } } @@ -406,7 +406,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla ProfBegin("Sort Type Servers"); U64 external_count = 0, internal_count = 0; - LNK_Obj *sorted_obj_arr = push_array_no_zero(tp_arena->v[0], LNK_Obj, obj_count); + LNK_Obj **sorted_obj_arr = push_array_no_zero(tp_arena->v[0], LNK_Obj *, obj_count); CV_DebugS *sorted_debug_s_arr = push_array_no_zero(tp_arena->v[0], CV_DebugS, obj_count); CV_DebugT *sorted_debug_t_arr = push_array_no_zero(tp_arena->v[0], CV_DebugT, obj_count); CV_DebugT *sorted_debug_p_arr = push_array_no_zero(tp_arena->v[0], CV_DebugT, obj_count); @@ -420,7 +420,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla // TODO: report error: somehow obj was compiled with /Zi and /Yc Assert(debug_p_arr[obj_idx].count == 0); - sorted_obj_arr[slot_idx] = *obj_arr[obj_idx]; + sorted_obj_arr[slot_idx] = obj_arr[obj_idx]; sorted_debug_s_arr[slot_idx] = debug_s_arr[obj_idx]; sorted_debug_t_arr[slot_idx] = debug_t_arr[obj_idx]; MemoryZeroStruct(&sorted_debug_p_arr[slot_idx]); @@ -429,7 +429,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla U64 slot_idx = internal_count; ++internal_count; - sorted_obj_arr[slot_idx] = *obj_arr[obj_idx]; + sorted_obj_arr[slot_idx] = obj_arr[obj_idx]; sorted_debug_s_arr[slot_idx] = debug_s_arr[obj_idx]; sorted_debug_t_arr[slot_idx] = debug_t_arr[obj_idx]; sorted_debug_p_arr[slot_idx] = debug_p_arr[obj_idx]; @@ -439,8 +439,8 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla ProfEnd(); // setup pointers to arrays - LNK_Obj *internal_obj_arr = sorted_obj_arr; - LNK_Obj *external_obj_arr = sorted_obj_arr + internal_count; + LNK_Obj **internal_obj_arr = sorted_obj_arr; + LNK_Obj **external_obj_arr = sorted_obj_arr + internal_count; CV_DebugS *internal_debug_s_arr = sorted_debug_s_arr; CV_DebugS *external_debug_s_arr = sorted_debug_s_arr + internal_count; CV_DebugT *internal_debug_t_arr = sorted_debug_t_arr; @@ -726,7 +726,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla str8_list_pushf(scratch.arena, &unopen_type_server_list, "\t%S\n", ts_path_arr.v[ts_idx]); str8_list_pushf(scratch.arena, &unopen_type_server_list, "\t\tDependent obj(s):\n"); for (U64Node *obj_idx_node = obj_idx_list.first; obj_idx_node != 0; obj_idx_node = obj_idx_node->next) { - String8 obj_path = external_obj_arr[obj_idx_node->data].path; + String8 obj_path = external_obj_arr[obj_idx_node->data]->path; str8_list_pushf(scratch.arena, &unopen_type_server_list, "\t\t\t%S\n", obj_path); } } @@ -754,7 +754,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla cv.type_server_count = ts_path_arr.count; cv.type_server_path_arr = ts_path_arr.v; cv.ts_to_obj_arr = ts_to_obj_arr; - cv.obj_arr = sorted_obj_arr; + cv.obj_arr = obj_arr; cv.pch_arr = pch_arr; cv.debug_s_arr = sorted_debug_s_arr; cv.debug_p_arr = sorted_debug_p_arr; @@ -1209,7 +1209,7 @@ lnk_hash_cv_leaf(Arena *arena, String8 leaf_kind_str = cv_string_from_leaf_kind(leaf.kind); String8 leaf_info = push_str8f(scratch.arena, "LF_%S(type_index: 0x%x) forward refs member type index 0x%x (leaf struct offset: 0x%llx)", leaf_kind_str, curr_ti, sub_ti, ti_n->offset); if (loc_type == LNK_LeafLocType_Internal) { - lnk_error_obj(LNK_Error_InvalidTypeIndex, input->internal_obj_arr+loc_idx, "%S", leaf_info); + lnk_error_obj(LNK_Error_InvalidTypeIndex, input->internal_obj_arr[loc_idx], "%S", leaf_info); } else if (loc_type == LNK_LeafLocType_External) { lnk_error(LNK_Error_InvalidTypeIndex, "%S: %S", input->type_server_path_arr[loc_idx], leaf_info); } else { @@ -2944,7 +2944,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) U64 obj_idx = task_id; LNK_PushDbiSecContribTaskData *task = raw_task; PDB_DbiModule *mod = task->mod_arr[obj_idx]; - LNK_Obj *obj = &task->obj_arr[obj_idx]; + LNK_Obj *obj = task->obj_arr[obj_idx]; COFF_SectionHeader *obj_section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; PDB_DbiSectionContribNode *sc_arr = push_array_no_zero(arena, PDB_DbiSectionContribNode, obj->header.section_count_no_null); @@ -3094,7 +3094,7 @@ lnk_build_pdb(TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, - LNK_Obj *obj_arr, + LNK_Obj **obj_arr, CV_DebugS *debug_s_arr, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, @@ -3132,7 +3132,7 @@ lnk_build_pdb(TP_Context *tp, ProfBegin("Reserve DBI Modules"); PDB_DbiModule **mod_arr = push_array(tp_arena->v[0], PDB_DbiModule *, obj_count); for (U64 obj_idx = 0; obj_idx < obj_count; ++obj_idx) { - LNK_Obj *obj = obj_arr + obj_idx; + LNK_Obj *obj = obj_arr[obj_idx]; mod_arr[obj_idx] = dbi_push_module(pdb->dbi, obj->path, lnk_obj_get_lib_path(obj)); // we don't support symbol append @@ -4306,10 +4306,10 @@ THREAD_POOL_TASK_FUNC(lnk_insert_src_files_task) String8List raw_strtab_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable); if (raw_strtab_list.node_count > 1) { - lnk_error_obj(LNK_Warning_IllData, &task->obj_arr[obj_idx], "Multiple string table sub-sections, picking first one."); + lnk_error_obj(LNK_Warning_IllData, task->obj_arr[obj_idx], "Multiple string table sub-sections, picking first one."); } if (raw_chksms_list.node_count > 1) { - lnk_error_obj(LNK_Warning_IllData, &task->obj_arr[obj_idx], "Multiple file checksum sub-sections, picking first one."); + lnk_error_obj(LNK_Warning_IllData, task->obj_arr[obj_idx], "Multiple file checksum sub-sections, picking first one."); } String8 string_table = cv_string_table_from_debug_s(debug_s); @@ -4490,7 +4490,7 @@ THREAD_POOL_TASK_FUNC(lnk_find_obj_compiler_info_task) } exit:; - LNK_Obj *obj = &task->obj_arr[task_id]; + LNK_Obj *obj = task->obj_arr[task_id]; // fill out unit info U64 unit_chunk_idx = task_id / task->unit_chunk_cap; @@ -4517,7 +4517,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_line_tables_to_rdi_task) U64 unit_idx = task_id; LNK_ConvertUnitToRDITask *task = raw_task; - LNK_Obj *obj = &task->obj_arr[unit_idx]; + LNK_Obj *obj = task->obj_arr[unit_idx]; CV_DebugS debug_s = task->debug_s_arr[unit_idx]; U64 unit_chunk_idx = unit_idx / task->unit_chunk_cap; @@ -4614,7 +4614,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) LNK_ConvertUnitToRDITask *task = raw_task; LNK_CodeViewSymbolsInput symbols_input = task->symbol_inputs[task_id]; - LNK_Obj *obj = &task->obj_arr[symbols_input.obj_idx]; + LNK_Obj *obj = task->obj_arr[symbols_input.obj_idx]; LNK_CodeViewCompilerInfo comp_info = task->comp_info_arr[symbols_input.obj_idx]; CV_InlineeLinesAccel *inlinee_lines_accel = task->inlinee_lines_accel_arr[symbols_input.obj_idx]; @@ -5243,8 +5243,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_inline_site_line_tables_task) // prase checksum header CV_C13Checksum *checksum_header = (CV_C13Checksum *) (raw_file_chksms.str + lines.file_off); if (lines.file_off + sizeof(CV_C13Checksum) + checksum_header->len > raw_file_chksms.size) { - LNK_Obj *obj = task->obj_arr + obj_idx; - lnk_error_obj(LNK_Warning_IllData, obj, "Not enough bytes to read file checksum @ 0x%llx.", lines.file_off); + lnk_error_obj(LNK_Warning_IllData, task->obj_arr[obj_idx], "Not enough bytes to read file checksum @ 0x%llx.", lines.file_off); continue; } String8 file_path = str8_cstring_capped(raw_string_table.str + checksum_header->name_off, raw_string_table.str + raw_string_table.size); @@ -5255,8 +5254,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_inline_site_line_tables_task) U64 src_file_hash = lnk_src_file_hash_cv(normal_path, checksum_header->kind, checksum_bytes); LNK_SourceFileBucket *src_file_bucket = lnk_src_file_hash_table_lookup_slot(task->src_file_buckets, task->src_file_buckets_cap, src_file_hash, normal_path, checksum_header->kind, checksum_bytes); if (src_file_bucket == 0) { - LNK_Obj *obj = task->obj_arr + obj_idx; - lnk_error_obj(LNK_Error_UnexpectedCodePath, obj, "Unable to find source file in the hash table: \"%S\".", file_path); + lnk_error_obj(LNK_Error_UnexpectedCodePath, task->obj_arr[obj_idx], "Unable to find source file in the hash table: \"%S\".", file_path); continue; } RDIB_SourceFile *src_file = src_file_bucket->src_file; @@ -5290,7 +5288,7 @@ THREAD_POOL_TASK_FUNC(lnk_collect_obj_virtual_ranges_task) LNK_ConvertUnitToRDITask *task = raw_task; U64 unit_idx = task_id; - LNK_Obj *obj = &task->obj_arr[unit_idx]; + LNK_Obj *obj = task->obj_arr[unit_idx]; U64 unit_chunk_idx = unit_idx / task->unit_chunk_cap; U64 local_unit_idx = unit_idx - unit_chunk_idx * task->unit_chunk_cap; @@ -5329,7 +5327,7 @@ lnk_build_rad_debug_info(TP_Context *tp, String8 image_name, String8 image_data, U64 obj_count, - LNK_Obj *obj_arr, + LNK_Obj **obj_arr, CV_DebugS *debug_s_arr, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index 36ff5923..663edf44 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -28,7 +28,7 @@ typedef struct LNK_CodeViewInput String8 *type_server_path_arr; // [type_server_count] String8 *type_server_data_arr; // [type_server_count] U64List *ts_to_obj_arr; // [type_server_count] - LNK_Obj *obj_arr; // [count] + LNK_Obj **obj_arr; // [count] LNK_PchInfo *pch_arr; // [count] CV_DebugS *debug_s_arr; // [count] CV_DebugT *debug_p_arr; // [count] @@ -39,7 +39,7 @@ typedef struct LNK_CodeViewInput LNK_CodeViewSymbolsInput *symbol_inputs; // [total_symbol_input_count] CV_SymbolListArray *parsed_symbols; // [count] - LNK_Obj *internal_obj_arr; // [internal_count] + LNK_Obj **internal_obj_arr; // [internal_count] CV_DebugS *internal_debug_s_arr; // [internal_count] CV_DebugT *internal_debug_t_arr; // [internal_count] CV_DebugT *internal_debug_p_arr; // [internal_count] @@ -47,7 +47,7 @@ typedef struct LNK_CodeViewInput LNK_CodeViewSymbolsInput *internal_symbol_inputs; // [internal_total_symbol_input_count] CV_SymbolListArray *internal_parsed_symbols; // [internal_count] - LNK_Obj *external_obj_arr; // [external_count] + LNK_Obj **external_obj_arr; // [external_count] CV_DebugS *external_debug_s_arr; // [external_count] CV_DebugT *external_debug_t_arr; // [external_count] CV_DebugT *external_debug_p_arr; // [external_count] @@ -312,7 +312,7 @@ typedef struct typedef struct { - LNK_Obj *obj_arr; + LNK_Obj **obj_arr; PDB_DbiModule **mod_arr; PDB_DbiSectionContribList *sc_list; String8 image_data; @@ -436,7 +436,7 @@ typedef struct typedef struct { - LNK_Obj *obj_arr; + LNK_Obj **obj_arr; CV_DebugS *debug_s_arr; U64 total_src_file_count; LNK_SourceFileBucket **src_file_buckets; @@ -453,7 +453,7 @@ typedef struct typedef struct { COFF_SectionHeaderArray image_sects; - LNK_Obj *obj_arr; + LNK_Obj **obj_arr; CV_DebugS *debug_s_arr; CV_DebugT ipi; LNK_CodeViewSymbolsInput *symbol_inputs; @@ -496,7 +496,7 @@ typedef struct internal CV_DebugS * lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *sect_list_arr); internal CV_DebugT * lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *debug_t_list_arr); internal CV_SymbolList * lnk_cv_symbol_list_arr_from_debug_s_arr(TP_Context *tp, TP_Arena *arena, U64 obj_count, CV_DebugS *debug_s_arr); -internal LNK_PchInfo * lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj *obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols); +internal LNK_PchInfo * lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols); internal LNK_CodeViewInput lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, U64 objs_count, LNK_Obj **objs); @@ -553,7 +553,7 @@ internal String8List lnk_build_rad_debug_info(TP_Context *tp, String8 image_name, String8 image_data, U64 obj_count, - LNK_Obj *obj_arr, + LNK_Obj **obj_arr, CV_DebugS *debug_s_arr, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, @@ -575,7 +575,7 @@ internal String8List lnk_build_pdb(TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, - LNK_Obj *obj_arr, + LNK_Obj **obj_arr, CV_DebugS *debug_s_arr, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, From 89d496c855778616537fad9ee045f0e1c24210d0 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 Aug 2025 14:13:29 -0700 Subject: [PATCH 099/302] fix replacement rule for weak search library vs undefined --- src/linker/lnk.c | 5 +---- src/linker/lnk_symbol_table.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7bf2fae5..f1b77591 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1537,9 +1537,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (symbol_ht) { COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { - // clear slot for the weak alternate name that replaces an undefined symbol - symbol_ht->symbol = 0; - // make obj with alternamte name symbol String8 alt_name_obj; { @@ -1556,7 +1553,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->path = alt_name_n->data.obj ? alt_name_n->data.obj->path : str8_lit("RADLINK"); input->exclude_from_debug_info = 1; - input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAME FOR %S=%S *", alt_name_n->data.from, alt_name_n->data.to, obj_list.count); + input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAME FOR %S=%S %u *", alt_name_n->data.from, alt_name_n->data.to, obj_list.count); input->data = alt_name_obj; input->lib = alt_name_n->data.obj ? alt_name_n->data.obj->lib : 0; } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 4e7a6a98..a9e95d60 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -159,7 +159,7 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = dst_interp == COFF_SymbolValueInterp_Weak; + can_replace = lnk_symbol_defined_is_before(dst, src); } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { From f1b22dbe2771c4ecbd412d68ab02530face822c7 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 Aug 2025 15:17:11 -0700 Subject: [PATCH 100/302] change library to use compressed member offsets --- src/linker/hash_table.c | 20 +++++++++ src/linker/hash_table.h | 2 + src/linker/lnk_lib.c | 91 +++++++++++++++++++++++++++-------------- src/linker/lnk_lib.h | 5 ++- 4 files changed, 85 insertions(+), 33 deletions(-) diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index e6adec79..e8c3a3c0 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -276,6 +276,13 @@ hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out) return 0; } +internal BucketNode * +hash_table_push_u32_u32(Arena *arena, HashTable *ht, U32 key, U32 value) +{ + U64 hash = hash_table_hasher(str8_struct(&key)); + return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u32 = key, .value_u32 = value }); +} + internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) { @@ -289,6 +296,19 @@ hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) return 0; } +internal B32 +hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out) +{ + KeyValuePair *result = hash_table_search_u32(ht, key); + if (result) { + if (value_out) { + *value_out = result->value_u32; + } + return 1; + } + return 0; +} + //////////////////////////////// internal int diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 2bda690a..0eb3bf67 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -64,6 +64,7 @@ internal BucketNode * hash_table_push_u64_raw (Arena *arena, HashTable *ht, internal BucketNode * hash_table_push_path_raw (Arena *arena, HashTable *ht, String8 path, void *value); internal BucketNode * hash_table_push_path_u64 (Arena *arena, HashTable *ht, String8 path, U64 value); internal BucketNode * hash_table_push_u64_u64 (Arena *arena, HashTable *ht, U64 key, U64 value); +internal BucketNode * hash_table_push_u32_u32 (Arena *arena, HashTable *ht, U32 key, U32 value); //- search @@ -77,6 +78,7 @@ internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_o internal B32 hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out); internal B32 hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out); internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out); +internal B32 hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out); //- key-value helpers diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 14d69774..9cb00e91 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -69,9 +69,10 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) return 0; } - U64 symbol_count; - String8 string_table; - U32 *member_off_arr; + U64 symbol_count = 0; + String8 string_table = {0}; + U16 *symbol_indices = 0; + U32 *member_offsets = 0; // try to init library from optional second member if (parse.second_member.member_count) { @@ -81,51 +82,78 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) symbol_count = second_member.symbol_count; string_table = second_member.string_table; - member_off_arr = push_array_no_zero(arena, U32, symbol_count); - - // decompress member offsets - for (U64 symbol_idx = 0; symbol_idx < symbol_count; symbol_idx += 1) { - U16 off_number = second_member.symbol_indices[symbol_idx]; - if (0 < off_number && off_number <= second_member.member_count) { - member_off_arr[symbol_idx] = second_member.member_offsets[off_number - 1]; - } else { - // TODO: log bad offset - member_off_arr[symbol_idx] = max_U32; - } - } + member_offsets = second_member.member_offsets; + symbol_indices = second_member.symbol_indices; } // first member is deprecated however tools emit it for compatibility reasons // and lld-link with /DLL emits only first member else if (parse.first_member.symbol_count) { + Temp scratch = scratch_begin(&arena, 1); + COFF_ArchiveFirstMember first_member = parse.first_member; Assert(first_member.symbol_count == first_member.member_offset_count); symbol_count = first_member.symbol_count; string_table = first_member.string_table; - member_off_arr = first_member.member_offsets; // convert big endian offsets for (U32 offset_idx = 0; offset_idx < symbol_count; offset_idx += 1) { - member_off_arr[offset_idx] = from_be_u32(member_off_arr[offset_idx]); + first_member.member_offsets[offset_idx] = from_be_u32(first_member.member_offsets[offset_idx]); } - } else { - symbol_count = 0; - string_table = str8_zero(); - member_off_arr = 0; + + // compress member offsets to match those from the second header + { + HashTable *member_off_ht = hash_table_init(scratch.arena, (U64)((F64)first_member.symbol_count * 1.3)); + for EachIndex(symbol_idx, symbol_count) { + if (!hash_table_search_u32_u32(member_off_ht, first_member.member_offsets[symbol_idx], 0)) { + hash_table_push_u32_u32(scratch.arena, member_off_ht, first_member.member_offsets[symbol_idx], member_off_ht->count); + } + } + + symbol_indices = push_array(arena, U16, first_member.symbol_count); + for EachIndex(symbol_idx, first_member.symbol_count) { + U32 member_off = first_member.member_offsets[symbol_idx]; + U32 member_off_idx = 0; + if (!hash_table_search_u32_u32(member_off_ht, member_off, &member_off_idx)) { + InvalidPath; + } + symbol_indices[symbol_idx] = member_off_idx+1; + } + + member_offsets = push_array_no_zero(arena, U32, member_off_ht->count); + for EachIndex(bucket_idx, member_off_ht->cap) { + BucketList *bucket = &member_off_ht->buckets[bucket_idx]; + for (BucketNode *n = bucket->first; n != 0; n = n->next) { + U32 member_off = n->v.key_u32; + U32 member_off_idx = n->v.value_u32; + member_offsets[member_off_idx] = member_off; + } + } + } + + scratch_end(scratch); } // parse string table - String8List symbol_name_list = str8_split_by_string_chars(arena, string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); - Assert(symbol_name_list.node_count >= symbol_count); - symbol_count = Min(symbol_count, symbol_name_list.node_count); + String8Array symbol_names; + { + Temp scratch = scratch_begin(&arena, 1); + String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); + Assert(symbol_name_list.node_count >= symbol_count); + symbol_names = str8_array_from_list(arena, &symbol_name_list); + scratch_end(scratch); + } + + symbol_count = Min(symbol_count, symbol_names.count); // init lib lib_out->path = push_str8_copy(arena, path); lib_out->data = data; lib_out->type = type; lib_out->symbol_count = symbol_count; - lib_out->member_off_arr = member_off_arr; - lib_out->symbol_name_list = symbol_name_list; + lib_out->member_offsets = member_offsets; + lib_out->symbol_indices = symbol_indices; + lib_out->symbol_names = symbol_names; lib_out->long_names = parse.long_names; ProfEnd(); @@ -195,11 +223,12 @@ THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task) LNK_SymbolPusher *task = raw_task; LNK_SymbolTable *symtab = task->symtab; LNK_Lib *lib = &task->u.libs.v[task_id].data; - - String8Node *name_node = lib->symbol_name_list.first; - for (U64 symbol_idx = 0; symbol_idx < lib->symbol_count; ++symbol_idx, name_node = name_node->next) { - LNK_Symbol *symbol = lnk_make_lib_symbol(arena, name_node->string, lib, lib->member_off_arr[symbol_idx]); - lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol); + for EachIndex(symbol_idx, lib->symbol_count) { + U32 member_offset_number = lib->symbol_indices[symbol_idx]; + if (member_offset_number > 0) { + LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, lib->member_offsets[member_offset_number-1]); + lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol); + } } } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 7b5f1c27..8a7cb2b5 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -9,8 +9,9 @@ typedef struct LNK_Lib String8 data; COFF_ArchiveType type; U32 symbol_count; - U32 *member_off_arr; - String8List symbol_name_list; + U32 *member_offsets; + U16 *symbol_indices; + String8Array symbol_names; String8 long_names; U64 input_idx; } LNK_Lib; From 330c8ead38e659f89205fe34d34c6e640f44cf79 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 Aug 2025 15:29:32 -0700 Subject: [PATCH 101/302] move member queue-attempt flag from symbol to lib struct --- src/base/base_core.h | 1 + src/linker/lnk.c | 17 ++++++----------- src/linker/lnk_lib.c | 24 ++++++++++++++---------- src/linker/lnk_lib.h | 1 + src/linker/lnk_symbol_table.c | 17 +++++------------ src/linker/lnk_symbol_table.h | 6 ++---- 6 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index b72a46f3..45518081 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -194,6 +194,7 @@ #if COMPILER_MSVC # include # if ARCH_X64 +# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((volatile CHAR *)(x), (c)) # define ins_atomic_u64_eval(x) *((volatile U64 *)(x)) # define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) # define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f1b77591..5bf7bb5b 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -982,10 +982,12 @@ lnk_queue_lib_member_for_input(Arena *arena, } } - B32 was_live = lnk_mark_symbol_live(best_match); - if (!was_live) { - LNK_Lib *lib = best_match->u.member.v.lib; - U64 member_offset = best_match->u.member.v.member_offset; + LNK_Lib *lib = best_match->u.member.v.lib; + U32 member_idx = best_match->u.member.v.member_idx; + + B32 was_member_queued = ins_atomic_u8_eval_assign(&lib->was_member_queued[member_idx], 1); + if (!was_member_queued) { + U64 member_offset = lib->member_offsets[member_idx]; // compose input index so that members are laid out in the image // in the order of undefined symbols appearing in objs, @@ -1163,13 +1165,6 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); LNK_Obj *ref_obj = ref_symbol.obj; - // mark referenced symbol live - if (ref_parsed.storage_class == COFF_SymStorageClass_External || - ref_parsed.storage_class == COFF_SymStorageClass_WeakExternal) { - LNK_Symbol *ref_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - lnk_mark_symbol_live(ref_symbol); - } - if (ref_interp == COFF_SymbolValueInterp_Regular) { // make section number list (reloc section + associates) U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 9cb00e91..3437c68b 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -69,6 +69,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) return 0; } + U32 member_count = 0; U64 symbol_count = 0; String8 string_table = {0}; U16 *symbol_indices = 0; @@ -80,6 +81,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) Assert(second_member.symbol_count == second_member.symbol_index_count); Assert(second_member.member_count == second_member.member_offset_count); + member_count = second_member.member_count; symbol_count = second_member.symbol_count; string_table = second_member.string_table; member_offsets = second_member.member_offsets; @@ -120,7 +122,8 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) symbol_indices[symbol_idx] = member_off_idx+1; } - member_offsets = push_array_no_zero(arena, U32, member_off_ht->count); + member_count = member_off_ht->count; + member_offsets = push_array_no_zero(arena, U32, member_count); for EachIndex(bucket_idx, member_off_ht->cap) { BucketList *bucket = &member_off_ht->buckets[bucket_idx]; for (BucketNode *n = bucket->first; n != 0; n = n->next) { @@ -147,14 +150,15 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) symbol_count = Min(symbol_count, symbol_names.count); // init lib - lib_out->path = push_str8_copy(arena, path); - lib_out->data = data; - lib_out->type = type; - lib_out->symbol_count = symbol_count; - lib_out->member_offsets = member_offsets; - lib_out->symbol_indices = symbol_indices; - lib_out->symbol_names = symbol_names; - lib_out->long_names = parse.long_names; + lib_out->path = push_str8_copy(arena, path); + lib_out->data = data; + lib_out->type = type; + lib_out->symbol_count = symbol_count; + lib_out->member_offsets = member_offsets; + lib_out->symbol_indices = symbol_indices; + lib_out->was_member_queued = push_array(arena, B8, member_count); + lib_out->symbol_names = symbol_names; + lib_out->long_names = parse.long_names; ProfEnd(); return 1; @@ -226,7 +230,7 @@ THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task) for EachIndex(symbol_idx, lib->symbol_count) { U32 member_offset_number = lib->symbol_indices[symbol_idx]; if (member_offset_number > 0) { - LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, lib->member_offsets[member_offset_number-1]); + LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, member_offset_number-1); lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol); } } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 8a7cb2b5..04c3ef54 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -11,6 +11,7 @@ typedef struct LNK_Lib U32 symbol_count; U32 *member_offsets; U16 *symbol_indices; + B8 *was_member_queued; String8Array symbol_names; String8 long_names; U64 input_idx; diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index a9e95d60..41cecd19 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -12,12 +12,12 @@ lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 sym } internal LNK_Symbol * -lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset) +lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx) { - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->u.member.v.lib = lib; - symbol->u.member.v.member_offset = member_offset; + LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); + symbol->name = name; + symbol->u.member.v.lib = lib; + symbol->u.member.v.member_idx = member_idx; return symbol; } @@ -536,13 +536,6 @@ lnk_interp_from_symbol(LNK_Symbol *symbol) return coff_interp_from_parsed_symbol(symbol_parsed); } -internal B32 -lnk_mark_symbol_live(LNK_Symbol *symbol) -{ - B32 was_live = ins_atomic_u32_eval_assign(&symbol->is_live, 1); - return was_live; -} - internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) { diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 2af086fd..5a90bcf2 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -21,13 +21,12 @@ typedef struct LNK_SymbolDefined typedef struct LNK_SymbolLib { struct LNK_Lib *lib; - U64 member_offset; + U32 member_idx; } LNK_SymbolLib; typedef struct LNK_Symbol { String8 name; - B32 is_live; union { LNK_SymbolDefined defined; struct { @@ -100,7 +99,7 @@ typedef struct LNK_SymbolTable // --- Symbol Make ------------------------------------------------------------- internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); -internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset); +internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx); // --- Symbol Containers ------------------------------------------------------ @@ -123,7 +122,6 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); internal COFF_SymbolValueInterpType lnk_interp_from_symbol(LNK_Symbol *symbol); -internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol); internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol); // --- Symbol Table ------------------------------------------------------------ From 67e66dc26ebf6c880338b35e375c9c4363fa20ce Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 Aug 2025 16:45:01 -0700 Subject: [PATCH 102/302] WIP switching to serial library search-style, removed lib scope from the symbol table --- src/linker/lnk.c | 341 +++++++++++---------- src/linker/lnk.h | 11 +- src/linker/lnk_debug_info.c | 6 +- src/linker/lnk_lib.c | 29 +- src/linker/lnk_obj.c | 12 +- src/linker/lnk_symbol_table.c | 544 ++++++++++++++++------------------ src/linker/lnk_symbol_table.h | 36 +-- 7 files changed, 462 insertions(+), 517 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 5bf7bb5b..f23c5eac 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -969,22 +969,11 @@ internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, - LNK_Symbol *member_symbol, + LNK_Lib *lib, + U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { - // lookup member in the lib where pull-in reference is declared - LNK_Symbol *best_match = member_symbol; - for (LNK_Symbol *s = member_symbol; s != 0; s = s->u.member.next) { - if (s->u.member.v.lib == pull_in_ref->u.defined.obj->lib) { - best_match = s; - break; - } - } - - LNK_Lib *lib = best_match->u.member.v.lib; - U32 member_idx = best_match->u.member.v.member_idx; - B32 was_member_queued = ins_atomic_u8_eval_assign(&lib->was_member_queued[member_idx], 1); if (!was_member_queued) { U64 member_offset = lib->member_offsets[member_idx]; @@ -992,7 +981,7 @@ lnk_queue_lib_member_for_input(Arena *arena, // compose input index so that members are laid out in the image // in the order of undefined symbols appearing in objs, // mimicking serial discovery - U64 input_idx = Compose64Bit(pull_in_ref->u.defined.obj->input_idx, pull_in_ref->u.defined.symbol_idx); + U64 input_idx = Compose64Bit(pull_in_ref->defined.obj->input_idx, pull_in_ref->defined.symbol_idx); // parse member COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); @@ -1067,20 +1056,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj String8List roots = str8_list_copy(scratch.arena, &config->include_symbol_list); // tls - LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); + LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME); if (tls_symbol) { str8_list_pushf(scratch.arena, &roots, MSCRT_TLS_SYMBOL_NAME); } // push tasks for each root symbol for (String8Node *root_n = roots.first; root_n != 0; root_n = root_n->next) { - LNK_Symbol *root = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, root_n->string); + LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->string); struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root->u.defined.obj; + t->obj = root->defined.obj; t->relocs.count = 1; t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root->u.defined.symbol_idx; + t->relocs.v[0].isymbol = root->defined.symbol_idx; SLLStackPush(task_stack, t); } @@ -1133,20 +1122,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { - ref_symbol = symlink->u.defined; + ref_symbol = symlink->defined; } break; } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - next_ref = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = defn->defined; } else { MemoryZeroStruct(&ref_symbol); break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - next_ref = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = defn->defined; } else { break; } @@ -1247,12 +1236,12 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->u.defined); + LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->u.defined.obj->header.is_big_obj); - if (symbol->u.defined.obj->header.is_big_obj) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); + if (symbol->defined.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; symbol32->section_number = COFF_Symbol_UndefinedSection; symbol32->value = 0; @@ -1264,7 +1253,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) symbol16->storage_class = COFF_SymStorageClass_External; } } else { - symbol->u.defined = resolve; + symbol->defined = resolve; } } } @@ -1391,11 +1380,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) hash_table_push_string_raw(ht_arena, import_stub_ht, import_header.func_name, 0); // create import stubs (later replaced with acutal imports generated by linker) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); - LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); - lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, thunk_symbol); - lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, imp_symbol); + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->defined.obj, import_stub->defined.symbol_idx); + LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->defined.obj, import_stub->defined.symbol_idx); + lnk_symbol_table_push(symtab, thunk_symbol); + lnk_symbol_table_push(symtab, imp_symbol); // pick imports hash table HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? delayed_imports : static_imports; @@ -1410,6 +1399,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // push symbol str8_list_push(scratch.arena, import_symbols, input->data.coff_import); } + + search_flags = SearchFlag_All; // reset input MemoryZeroStruct(&input_import_list); @@ -1528,7 +1519,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // replace undefined symbols that have an alternate name with a weak symbol for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { - LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, LNK_SymbolScope_Defined, alt_name_n->data.from); + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->data.from); if (symbol_ht) { COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { @@ -1631,8 +1622,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfBegin("Lib Init"); LNK_LibNodeArray libs = lnk_lib_list_push_parallel(tp, tp_arena, &lib_index[input_source], datas, paths); ProfEnd(); - - lnk_input_lib_symbols(tp, symtab, libs); if (lnk_get_log_status(LNK_Log_InputLib)) { if (libs.count > 0) { @@ -1669,70 +1658,95 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } break; case State_SearchUndefined: { ProfBegin("Search Undefined"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); - } - } - } - } - } - ProfEnd(); - } break; - case State_SearchWeak: { - ProfBegin("Search Weak"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); - } - } - } - } - } - } - ProfEnd(); - } break; - case State_SearchWeakAntiDep: { - ProfBegin("Search Weak AntiDep"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->u.defined); - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol_parsed.name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); } } } } } + if (input_import_list.count || input_obj_list.count) { + goto end_search_undefined; + } } } + end_search_undefined:; + ProfEnd(); + } break; + case State_SearchWeak: { + ProfBegin("Search Weak"); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + } + } + } + } + } + } + if (input_import_list.count || input_obj_list.count) { + goto end_search_weak; + } + } + } + end_search_weak:; + ProfEnd(); + } break; + case State_SearchWeakAntiDep: { + ProfBegin("Search Weak AntiDep"); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->defined); + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + } + } + } + } + } + } + } + + if (input_import_list.count || input_obj_list.count) { + goto end_search_antidep; + } + } + } + end_search_antidep:; ProfEnd(); } break; case State_SearchEntryPoint: { @@ -1748,23 +1762,28 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); + entry_point_symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); if (entry_point_symbol) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->entry_point_name = name_arr.v[entry_idx]; goto dbl_break; } } } // search for potential entry points in libs - if (!entry_point_symbol) { + if (config->entry_point_name.size) { for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); - if (entry_point_symbol) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; - goto dbl_break; + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { + config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->entry_point_name = name_arr.v[entry_idx]; + goto dbl_break; + } + } } } } @@ -1776,42 +1795,44 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // and see which is in the symbol table String8Array name_arr = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); if (symbol) { - if (entry_point_symbol) { + if (config->entry_point_name.size) { lnk_error(LNK_Error_EntryPoint, "multiple entry point symbols found: %S(%S) and %S(%S)", - entry_point_symbol->name, entry_point_symbol->u.defined.obj->path, - symbol->name, symbol->u.defined.obj->path); + entry_point_symbol->name, entry_point_symbol->defined.obj->path, + symbol->name, symbol->defined.obj->path); } else { - entry_point_symbol = symbol; + config->entry_point_name = name_arr.v[entry_idx]; } } } // search for entry point in libs - if (!entry_point_symbol) { + if (!config->entry_point_name.size) { for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); - if (entry_point_symbol) { - break; + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { + config->entry_point_name = name_arr.v[entry_idx]; + goto dbl_break2; + } + } } } + dbl_break2:; } } // redirect user entry to appropriate CRT entry - if (entry_point_symbol) { - config->entry_point_name = entry_point_symbol->name; - if (str8_match_lit("wmain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wmainCRTStartup"); - } else if (str8_match_lit("main", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("mainCRTStartup"); - } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("WinMainCRTStartup"); - } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wWinMainCRTStartup"); - } + if (str8_match_lit("wmain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("wmainCRTStartup"); + } else if (str8_match_lit("main", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("mainCRTStartup"); + } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("WinMainCRTStartup"); + } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("wWinMainCRTStartup"); } } @@ -1822,7 +1843,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) str8_list_push(scratch.arena, &value_strings, config->entry_point_name); lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); } - // no entry point, error and exit + // no entry point, print out error and exit else { lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); } @@ -1968,7 +1989,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (!exp->is_forwarder) { // filter out unresolved exports - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, exp_n->data.name); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, exp_n->data.name); if (symbol == 0) { lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "unresolved export symbol %S\n", exp->name); continue; @@ -2170,7 +2191,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); { @@ -2220,7 +2241,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(i, count) { LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->u.defined.obj, "unresolved symbol %S", symbol->name); + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); } // TODO: /FORCE @@ -2289,34 +2310,34 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_Symbol switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); - *symbol_out = symlink ? symlink->u.defined : symbol; + *symbol_out = symlink ? symlink->defined : symbol; } break; case COFF_SymbolValueInterp_Weak: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->defined.symbol_idx); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Undefined) { - *symbol_out = defn->u.defined; + *symbol_out = defn->defined; } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Undefined: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); if (defn) { - *symbol_out = defn->u.defined; + *symbol_out = defn->defined; } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Common: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - *symbol_out = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + *symbol_out = defn->defined; } break; case COFF_SymbolValueInterp_Abs: { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - *symbol_out = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + *symbol_out = defn->defined; } else { *symbol_out = symbol; } @@ -2442,7 +2463,7 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) if (symlink == 0) { continue; } COFF_ParsedSymbol symlink_parsed = lnk_parsed_symbol_from_defined(symlink); - task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->u.defined.obj->input_idx][symlink_parsed.section_number - 1]; + task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->defined.obj->input_idx][symlink_parsed.section_number - 1]; } ProfEnd(); } @@ -2485,12 +2506,12 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number); - if (symlink && symlink->u.defined.obj != obj) { + if (symlink && symlink->defined.obj != obj) { U32 section_number; U32 value; if (symbol.storage_class == COFF_SymStorageClass_External) { // COMDAT leader may be at a different offset, so update this symbol with leader's offset - COFF_ParsedSymbol parsed_symlink = lnk_parsed_symbol_from_coff_symbol_idx(symlink->u.defined.obj, symlink->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symlink = lnk_parsed_symbol_from_coff_symbol_idx(symlink->defined.obj, symlink->defined.symbol_idx); section_number = symbol.section_number; value = parsed_symlink.value; } else { @@ -2548,10 +2569,10 @@ lnk_common_block_contrib_is_before(void *raw_a, void *raw_b) if (a->u.size == b->u.size) { LNK_Symbol *a_symbol = a->symbol; LNK_Symbol *b_symbol = b->symbol; - if (a_symbol->u.defined.obj->input_idx == b_symbol->u.defined.obj->input_idx) { - is_before = a_symbol->u.defined.symbol_idx < b_symbol->u.defined.symbol_idx; + if (a_symbol->defined.obj->input_idx == b_symbol->defined.obj->input_idx) { + is_before = a_symbol->defined.symbol_idx < b_symbol->defined.symbol_idx; } else { - is_before = a_symbol->u.defined.obj->input_idx < b_symbol->u.defined.obj->input_idx; + is_before = a_symbol->defined.obj->input_idx < b_symbol->defined.obj->input_idx; } } else { is_before = a->u.size > b->u.size; @@ -2571,8 +2592,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx]; LNK_Symbol *symbol = contrib->symbol; - LNK_Obj *obj = symbol->u.defined.obj; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->u.defined.symbol_idx); + LNK_Obj *obj = symbol->defined.obj; + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->defined.symbol_idx); U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1; if (obj->header.is_big_obj) { @@ -2585,7 +2606,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) symbol16->section_number = safe_cast_u16(section_number); } - task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->u.defined.symbol_idx] = 1; + task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->defined.symbol_idx] = 1; } ProfEnd(); @@ -2605,8 +2626,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Common) { - LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); + LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->defined.symbol_idx); Assert(coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class) == COFF_SymbolValueInterp_Regular); if (defn) { if (obj->header.is_big_obj) { @@ -2880,10 +2901,10 @@ THREAD_POOL_TASK_FUNC(lnk_count_common_block_contribs_task) LNK_BuildImageTask *task = raw_task; LNK_SymbolTable *symtab = task->symtab; - for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { + for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { task->u.common_block.counts[task_id] += 1; @@ -2899,10 +2920,10 @@ THREAD_POOL_TASK_FUNC(lnk_fill_out_common_block_contribs_task) LNK_SymbolTable *symtab = task->symtab; U64 cursor = task->u.common_block.offsets[task_id]; - for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { + for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { LNK_CommonBlockContrib *contrib = &task->u.common_block.contribs[cursor++]; @@ -3833,7 +3854,7 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config COFF_SectionHeader **section_table = push_array(arena, COFF_SectionHeader *, coff_section_table_count + 1); for (U64 i = 1; i <= coff_section_table_count; i += 1) { section_table[i] = &coff_section_table[i-1]; } - LNK_Symbol *entry_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, config->entry_point_name); + LNK_Symbol *entry_symbol = lnk_symbol_table_search(symtab, config->entry_point_name); if (entry_symbol) { *entry_point_va = safe_cast_u32(lnk_virt_off_from_symbol(section_table, entry_symbol)); } @@ -4272,7 +4293,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch load config { - LNK_Symbol *load_config_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); + LNK_Symbol *load_config_symbol = lnk_symbol_table_search(symtab, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); if (load_config_symbol) { U64 load_config_foff = lnk_file_off_from_symbol(image_section_table, load_config_symbol); String8 load_config_data = str8_skip(image_data, load_config_foff); @@ -4326,16 +4347,16 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch import and import addr { LNK_Section *idata_sect = lnk_section_table_search(sectab, str8_lit(".idata"), PE_IDATA_SECTION_FLAGS); - LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "__NULL_IMPORT_DESCRIPTOR"); - LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); + LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, "__NULL_IMPORT_DESCRIPTOR"); + LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); if (idata_sect && null_import_desc && null_thunk_data) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT); import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off; import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; - COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_thunk_data->u.defined.obj, null_thunk_data->u.defined.symbol_idx); + COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_thunk_data->defined.obj, null_thunk_data->defined.symbol_idx); U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value; U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off; PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); @@ -4348,10 +4369,10 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch delay imports { LNK_Section *didat_sect = lnk_section_table_search(sectab, str8_lit(".didat"), PE_IDATA_SECTION_FLAGS); - LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); - LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); + LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); + LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab,"\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); if (didat_sect && null_import_desc && last_null_thunk) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DELAY_IMPORT); import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect); @@ -4361,7 +4382,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch TLS { - LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); + LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME); if (tls_used_symbol) { ProfBegin("Patch TLS"); @@ -4441,8 +4462,8 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // compute image guid, and patch PDB and RDI guids { - LNK_Symbol *guid_pdb_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINK_PE_DEBUG_GUID_PDB")); - LNK_Symbol *guid_rdi_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINK_PE_DEBUG_GUID_RDI")); + LNK_Symbol *guid_pdb_symbol = lnk_symbol_table_search(symtab, str8_lit("RAD_LINK_PE_DEBUG_GUID_PDB")); + LNK_Symbol *guid_rdi_symbol = lnk_symbol_table_search(symtab, str8_lit("RAD_LINK_PE_DEBUG_GUID_RDI")); if (guid_pdb_symbol || guid_rdi_symbol) { switch (config->guid_type) { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 20fc27be..07491fe0 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -175,15 +175,6 @@ typedef struct U128 *hashes; } LNK_Blake3Hasher; -typedef struct -{ - LNK_SymbolTable *symtab; - union { - LNK_ObjNodeArray objs; - LNK_LibNodeArray libs; - } u; -} LNK_SymbolPusher; - // --- Config ----------------------------------------------------------------- internal LNK_Config * lnk_config_from_argcv(Arena *arena, int argc, char **argv); @@ -221,7 +212,7 @@ internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config); -internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Symbol *member_symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 0c163f4e..e940de6b 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3023,7 +3023,7 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) LNK_Symbol *symbol = chunk->v[i].symbol; COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->u.defined.obj)) { continue; } + if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->defined.obj)) { continue; } COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp != COFF_SymbolValueInterp_Regular) { continue; } @@ -3072,8 +3072,8 @@ lnk_build_pdb_public_symbols(TP_Context *tp, ProfBegin("Defined"); LNK_BuildPublicSymbolsTask task = {0}; - task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count); - task.chunk_lists = symtab->chunk_lists[LNK_SymbolScope_Defined]; + task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count); + task.chunk_lists = symtab->chunks; tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task); ProfEnd(); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 3437c68b..c8270380 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -221,29 +221,18 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S return result; } -internal -THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task) +internal B32 +lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out) { - LNK_SymbolPusher *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_Lib *lib = &task->u.libs.v[task_id].data; + // TODO: symbol names are already sorted, replace with binary search for EachIndex(symbol_idx, lib->symbol_count) { - U32 member_offset_number = lib->symbol_indices[symbol_idx]; - if (member_offset_number > 0) { - LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, member_offset_number-1); - lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol); + if (str8_match(lib->symbol_names.v[symbol_idx], symbol_name, 0)) { + if (member_idx_out) { + *member_idx_out = lib->symbol_indices[symbol_idx] - 1; + } + return 1; } } -} - -internal void -lnk_input_lib_symbols(TP_Context *tp, LNK_SymbolTable *symtab, LNK_LibNodeArray libs) -{ - ProfBeginFunction(); - LNK_SymbolPusher task = {0}; - task.symtab = symtab; - task.u.libs = libs; - tp_for_parallel(tp, symtab->arena, libs.count, lnk_push_lib_symbols_task, &task); - ProfEnd(); + return 0; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 8b990655..bb15bcc2 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -345,27 +345,27 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) break; } LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Undefined: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Debug: { @@ -388,7 +388,7 @@ lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj) COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { if (symlinks[symbol.section_number] == 0 || symbol.value == 0) { - symlinks[symbol.section_number] = lnk_symbol_table_search_(symtab, LNK_SymbolScope_Defined, symbol.name); + symlinks[symbol.section_number] = lnk_symbol_table_search_(symtab, symbol.name); } } } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 41cecd19..cfa7276e 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -6,18 +6,8 @@ lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 sym { LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); symbol->name = name; - symbol->u.defined.obj = obj; - symbol->u.defined.symbol_idx = symbol_idx; - return symbol; -} - -internal LNK_Symbol * -lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx) -{ - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->u.member.v.lib = lib; - symbol->u.member.v.member_idx = member_idx; + symbol->defined.obj = obj; + symbol->defined.symbol_idx = symbol_idx; return symbol; } @@ -25,7 +15,7 @@ internal B32 lnk_symbol_defined_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx; + return a->defined.obj->input_idx < b->defined.obj->input_idx; } internal B32 @@ -34,13 +24,6 @@ lnk_symbol_defined_ptr_is_before(void *raw_a, void *raw_b) return lnk_symbol_defined_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); } -internal B32 -lnk_symbol_lib_is_before(void *raw_a, void *raw_b) -{ - LNK_Symbol *a = raw_a, *b = raw_b; - return a->u.member.v.lib->input_idx < b->u.member.v.lib->input_idx; -} - internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node) { @@ -125,281 +108,265 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx); + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->defined.symbol_idx, src->defined.obj->path, src->defined.symbol_idx); } internal B32 -lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) +lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { B32 can_replace = 0; - switch (scope) { - case LNK_SymbolScope_Defined: { - LNK_Obj *dst_obj = dst->u.defined.obj; - LNK_Obj *src_obj = src->u.defined.obj; - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); - COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); - COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); - // undefined vs regular - if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { - can_replace = 1; - } - // (weak vs undefined) or (undefined vs weak) - else if ((dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Undefined) || (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak)) { - LNK_Symbol *weak, *undef; - COFF_ParsedSymbol weak_parsed; - if (dst_interp == COFF_SymbolValueInterp_Weak) { - weak = dst, undef = src; - weak_parsed = dst_parsed; - } else { - weak = src, undef = dst; - weak_parsed = src_parsed; - } + LNK_Obj *dst_obj = dst->defined.obj; + LNK_Obj *src_obj = src->defined.obj; + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->defined.symbol_idx); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->defined.symbol_idx); + COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); + COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = lnk_symbol_defined_is_before(dst, src); - } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { - can_replace = dst_interp == COFF_SymbolValueInterp_Weak; - } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { - can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; - } else { - can_replace = lnk_symbol_defined_is_before(src, dst); - } + // undefined vs regular + if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { + can_replace = 1; + } + // (weak vs undefined) or (undefined vs weak) + else if ((dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Undefined) || (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak)) { + LNK_Symbol *weak, *undef; + COFF_ParsedSymbol weak_parsed; + if (dst_interp == COFF_SymbolValueInterp_Weak) { + weak = dst, undef = src; + weak_parsed = dst_parsed; + } else { + weak = src, undef = dst; + weak_parsed = src_parsed; } - // undefined vs undefined - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + can_replace = lnk_symbol_defined_is_before(dst, src); + } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; + } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { + can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; + } else { can_replace = lnk_symbol_defined_is_before(src, dst); } - // undefined vs common - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { + } + // undefined vs undefined + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = lnk_symbol_defined_is_before(src, dst); + } + // undefined vs common + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { + can_replace = 1; + } + // undefined vs abs + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) { + can_replace = 1; + } + // undefined vs debug + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { + can_replace = 1; + } + // regular/common/abs/debug vs undefined + else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = 0; + } + // regular vs abs + else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { + lnk_error_multiply_defined_symbol(dst, src); + } + // abs vs regular + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) { + lnk_error_multiply_defined_symbol(dst, src); + } + // abs vs common + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) { + if (lnk_symbol_defined_is_before(dst, src)) { can_replace = 1; - } - // undefined vs abs - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) { - can_replace = 1; - } - // undefined vs debug - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { - can_replace = 1; - } - // regular/common/abs/debug vs undefined - else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { - can_replace = 0; - } - // regular vs abs - else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { + } else { lnk_error_multiply_defined_symbol(dst, src); } - // abs vs regular - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) { + } + // common vs abs + else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) { + if (lnk_symbol_defined_is_before(dst, src)) { lnk_error_multiply_defined_symbol(dst, src); } - // abs vs common - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) { - if (lnk_symbol_defined_is_before(dst, src)) { - can_replace = 1; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } - // common vs abs - else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) { - if (lnk_symbol_defined_is_before(dst, src)) { - lnk_error_multiply_defined_symbol(dst, src); - } - } - // abs vs abs - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Abs) { - lnk_error_multiply_defined_symbol(dst, src); - } - // weak vs weak - else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->u.defined.obj->header.is_big_obj); - COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->u.defined.obj->header.is_big_obj); - if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { - if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 0; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 1; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - lnk_error_multiply_defined_symbol(dst, src); - } else { - can_replace = lnk_symbol_defined_is_before(src, dst); - } - } - // weak vs regular/abs/common - else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) { - can_replace = 1; - } - // regular/abs/common vs weak - else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Abs || dst_interp == COFF_SymbolValueInterp_Common) && src_interp == COFF_SymbolValueInterp_Weak) { - can_replace = 0; - } - // regular/common vs regular/common - else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { - // parse dst symbol properties - B32 dst_is_comdat = 0; - COFF_ComdatSelectType dst_select; - U32 dst_section_length; - U32 dst_check_sum; - if (dst_interp == COFF_SymbolValueInterp_Regular) { - dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->u.defined.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); - } else if (dst_interp == COFF_SymbolValueInterp_Common) { - dst_select = COFF_ComdatSelect_Largest; - dst_section_length = dst_parsed.value; - dst_check_sum = 0; - dst_is_comdat = 1; - } - - // parse src symbol properties - B32 src_is_comdat = 0; - COFF_ComdatSelectType src_select; - U32 src_section_length, src_checks; - U32 src_check_sum; - if (src_interp == COFF_SymbolValueInterp_Regular) { - src_is_comdat = lnk_try_comdat_props_from_section_number(src->u.defined.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); - } else if (src_interp == COFF_SymbolValueInterp_Common) { - src_select = COFF_ComdatSelect_Largest; - src_section_length = src_parsed.value; - src_check_sum = 0; - src_is_comdat = 1; - } - - // regular non-comdat vs communal - if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat && src_interp == COFF_SymbolValueInterp_Common) { + } + // abs vs abs + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Abs) { + lnk_error_multiply_defined_symbol(dst, src); + } + // weak vs weak + else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->defined.obj->header.is_big_obj); + if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { + if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { can_replace = 0; - } - // communal vs regular non-comdat - else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) { - can_replace = 1; - } - // handle COMDATs - else if (dst_is_comdat && src_is_comdat) { - if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest)) { - src_select = COFF_ComdatSelect_Largest; - } - if (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any) { - dst_select = COFF_ComdatSelect_Largest; - } - - if (src_select == dst_select) { - switch (src_select) { - case COFF_ComdatSelect_Null: - case COFF_ComdatSelect_Any: { - if (src_section_length == dst_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - // both COMDATs are valid but to get smaller exe pick smallest - can_replace = src_section_length < dst_section_length; - } - } break; - case COFF_ComdatSelect_NoDuplicates: { - lnk_error_multiply_defined_symbol(dst, src); - } break; - case COFF_ComdatSelect_SameSize: { - if (dst_section_length == src_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } break; - case COFF_ComdatSelect_ExactMatch: { - COFF_SectionHeader *dst_sect_header = lnk_coff_section_header_from_section_number(dst_obj, dst_parsed.section_number); - COFF_SectionHeader *src_sect_header = lnk_coff_section_header_from_section_number(src_obj, src_parsed.section_number); - String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize)); - String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize)); - B32 is_exact_match = 0; - if (dst_check_sum != 0 && src_check_sum != 0) { - is_exact_match = dst_check_sum == src_check_sum && str8_match(dst_data, src_data, 0); - } else { - is_exact_match = str8_match(dst_data, src_data, 0); - } - - if (is_exact_match) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } break; - case COFF_ComdatSelect_Largest: { - if (dst_section_length == src_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - can_replace = dst_section_length < src_section_length; - } - } break; - case COFF_ComdatSelect_Associative: { /* ignore */ } break; - default: { InvalidPath; } break; - } - } else { - lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj, - "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", - src->name, coff_string_from_comdat_select_type(src_select), coff_string_from_comdat_select_type(dst_select), dst_obj); - } } else { lnk_error_multiply_defined_symbol(dst, src); } + } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 1; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + lnk_error_multiply_defined_symbol(dst, src); + } else { + can_replace = lnk_symbol_defined_is_before(src, dst); + } + } + // weak vs regular/abs/common + else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) { + can_replace = 1; + } + // regular/abs/common vs weak + else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Abs || dst_interp == COFF_SymbolValueInterp_Common) && src_interp == COFF_SymbolValueInterp_Weak) { + can_replace = 0; + } + // regular/common vs regular/common + else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { + // parse dst symbol properties + B32 dst_is_comdat = 0; + COFF_ComdatSelectType dst_select; + U32 dst_section_length; + U32 dst_check_sum; + if (dst_interp == COFF_SymbolValueInterp_Regular) { + dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->defined.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); + } else if (dst_interp == COFF_SymbolValueInterp_Common) { + dst_select = COFF_ComdatSelect_Largest; + dst_section_length = dst_parsed.value; + dst_check_sum = 0; + dst_is_comdat = 1; + } + + // parse src symbol properties + B32 src_is_comdat = 0; + COFF_ComdatSelectType src_select; + U32 src_section_length, src_checks; + U32 src_check_sum; + if (src_interp == COFF_SymbolValueInterp_Regular) { + src_is_comdat = lnk_try_comdat_props_from_section_number(src->defined.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); + } else if (src_interp == COFF_SymbolValueInterp_Common) { + src_select = COFF_ComdatSelect_Largest; + src_section_length = src_parsed.value; + src_check_sum = 0; + src_is_comdat = 1; + } + + // regular non-comdat vs communal + if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat && src_interp == COFF_SymbolValueInterp_Common) { + can_replace = 0; + } + // communal vs regular non-comdat + else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) { + can_replace = 1; + } + // handle COMDATs + else if (dst_is_comdat && src_is_comdat) { + if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest)) { + src_select = COFF_ComdatSelect_Largest; + } + if (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any) { + dst_select = COFF_ComdatSelect_Largest; + } + + if (src_select == dst_select) { + switch (src_select) { + case COFF_ComdatSelect_Null: + case COFF_ComdatSelect_Any: { + if (src_section_length == dst_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + // both COMDATs are valid but to get smaller exe pick smallest + can_replace = src_section_length < dst_section_length; + } + } break; + case COFF_ComdatSelect_NoDuplicates: { + lnk_error_multiply_defined_symbol(dst, src); + } break; + case COFF_ComdatSelect_SameSize: { + if (dst_section_length == src_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } break; + case COFF_ComdatSelect_ExactMatch: { + COFF_SectionHeader *dst_sect_header = lnk_coff_section_header_from_section_number(dst_obj, dst_parsed.section_number); + COFF_SectionHeader *src_sect_header = lnk_coff_section_header_from_section_number(src_obj, src_parsed.section_number); + String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize)); + String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize)); + B32 is_exact_match = 0; + if (dst_check_sum != 0 && src_check_sum != 0) { + is_exact_match = dst_check_sum == src_check_sum && str8_match(dst_data, src_data, 0); + } else { + is_exact_match = str8_match(dst_data, src_data, 0); + } + + if (is_exact_match) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } break; + case COFF_ComdatSelect_Largest: { + if (dst_section_length == src_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + can_replace = dst_section_length < src_section_length; + } + } break; + case COFF_ComdatSelect_Associative: { /* ignore */ } break; + default: { InvalidPath; } break; + } + } else { + lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj, + "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", + src->name, coff_string_from_comdat_select_type(src_select), coff_string_from_comdat_select_type(dst_select), dst_obj); + } } else { - lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); + lnk_error_multiply_defined_symbol(dst, src); } - } break; - case LNK_SymbolScope_Lib: { - can_replace = lnk_symbol_lib_is_before(src, dst); - } break; - default: { InvalidPath; } + } else { + lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); } + return can_replace; } internal void -lnk_on_symbol_replace(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) +lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - switch (scope) { - case LNK_SymbolScope_Defined: { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx); - COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); - if (dst_interp == COFF_SymbolValueInterp_Regular) { - // remove replaced section from the output - COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->u.defined.obj, dst_parsed.section_number); - dst_sect->flags |= COFF_SectionFlag_LnkRemove; + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->defined.symbol_idx); + COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); + if (dst_interp == COFF_SymbolValueInterp_Regular) { + // remove replaced section from the output + COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->defined.obj, dst_parsed.section_number); + dst_sect->flags |= COFF_SectionFlag_LnkRemove; - // remove associated sections from the output - for (U32Node *associated_section = dst->u.defined.obj->associated_sections[dst_parsed.section_number]; - associated_section != 0; - associated_section = associated_section->next) { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->u.defined.obj, associated_section->data); - section_header->flags |= COFF_SectionFlag_LnkRemove; - } + // remove associated sections from the output + for (U32Node *associated_section = dst->defined.obj->associated_sections[dst_parsed.section_number]; + associated_section != 0; + associated_section = associated_section->next) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->defined.obj, associated_section->data); + section_header->flags |= COFF_SectionFlag_LnkRemove; } - - // assert leader section is live -#if BUILD_DEBUG - { - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); - COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); - if (src_interp == COFF_SymbolValueInterp_Regular) { - COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->u.defined.obj, src_parsed.section_number); - AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); - } - } -#endif - } break; - case LNK_SymbolScope_Lib: { - LNK_Symbol *last; - for (last = src; last->u.member.next != 0; last = last->u.member.next); - last->u.member.next = dst; - } break; - default: { InvalidPath; } } + + // assert leader section is live +#if BUILD_DEBUG + { + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->defined.symbol_idx); + COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); + if (src_interp == COFF_SymbolValueInterp_Regular) { + COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->defined.obj, src_parsed.section_number); + AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); + } + } +#endif } internal void @@ -407,7 +374,6 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, - LNK_SymbolScope scope, LNK_Symbol *symbol) { LNK_SymbolHashTrie **curr_trie_ptr = trie; @@ -447,13 +413,13 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, // apply replacement if (leader) { - if (lnk_can_replace_symbol(scope, leader, src)) { + if (lnk_can_replace_symbol(leader, src)) { // discard leader - lnk_on_symbol_replace(scope, leader, src); + lnk_on_symbol_replace(leader, src); leader = src; } else { // discard source - lnk_on_symbol_replace(scope, src, leader); + lnk_on_symbol_replace(src, leader); src = leader; } } else { @@ -526,7 +492,7 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) { - return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + return lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); } internal COFF_SymbolValueInterpType @@ -576,11 +542,11 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) SLLQueuePush(sf, sl, s); // does weak symbol have a definition? - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx); + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->defined.obj, defn_symbol->defined.symbol_idx); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Weak) { - current_symbol = defn_symbol->u.defined; + current_symbol = defn_symbol->defined; break; } @@ -593,20 +559,20 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, tag_parsed.name); + LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); tag_interp = lnk_interp_from_symbol(dep_symbol); } if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); // unresolved undefined symbol if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } // follow symbol definition - current_symbol = defn_symbol->u.defined; + current_symbol = defn_symbol->defined; } else { break; } } @@ -630,41 +596,39 @@ lnk_symbol_table_init(TP_Arena *arena) { LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); symtab->arena = arena; - for (U64 i = 0; i < LNK_SymbolScope_Count; ++i) { - symtab->chunk_lists[i] = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); - } + symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); return symtab; } internal void -lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_SymbolScope scope, LNK_Symbol *symbol) +lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) { U64 hash = lnk_symbol_hash(symbol->name); - lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunk_lists[scope][worker_id], &symtab->scopes[scope], hash, scope, symbol); + lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunks[worker_id], &symtab->root, hash, symbol); } internal void -lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol *symbol) +lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol) { - lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, scope, symbol); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, symbol); } internal LNK_SymbolHashTrie * -lnk_symbol_table_search_(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) +lnk_symbol_table_search_(LNK_SymbolTable *symtab, String8 name) { U64 hash = lnk_symbol_hash(name); - return lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name); + return lnk_symbol_hash_trie_search(symtab->root, hash, name); } internal LNK_Symbol * -lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) +lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name) { - LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, scope, name); + LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, name); return trie ? trie->symbol : 0; } internal LNK_Symbol * -lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...) +lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...) { Temp scratch = scratch_begin(0, 0); @@ -672,7 +636,7 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f String8 name = push_str8fv(scratch.arena, fmt, args); va_end(args); - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, scope, name); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name); scratch_end(scratch); return symbol; @@ -681,7 +645,7 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); ISectOff sc = {0}; sc.isect = parsed_symbol.section_number; diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 5a90bcf2..b87fa44b 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -5,35 +5,16 @@ // --- Symbol ------------------------------------------------------------------ -typedef enum -{ - LNK_SymbolScope_Defined, - LNK_SymbolScope_Lib, - LNK_SymbolScope_Count -} LNK_SymbolScope; - typedef struct LNK_SymbolDefined { struct LNK_Obj *obj; U32 symbol_idx; } LNK_SymbolDefined; -typedef struct LNK_SymbolLib -{ - struct LNK_Lib *lib; - U32 member_idx; -} LNK_SymbolLib; - typedef struct LNK_Symbol { - String8 name; - union { - LNK_SymbolDefined defined; - struct { - struct LNK_Symbol *next; - LNK_SymbolLib v; - } member; - } u; + String8 name; + LNK_SymbolDefined defined; } LNK_Symbol; // --- Symbol Containers ------------------------------------------------------- @@ -92,14 +73,13 @@ typedef struct LNK_SymbolHashTrieChunkList typedef struct LNK_SymbolTable { TP_Arena *arena; - LNK_SymbolHashTrie *scopes[LNK_SymbolScope_Count]; - LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScope_Count]; + LNK_SymbolHashTrie *root; + LNK_SymbolHashTrieChunkList *chunks; } LNK_SymbolTable; // --- Symbol Make ------------------------------------------------------------- internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); -internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx); // --- Symbol Containers ------------------------------------------------------ @@ -113,7 +93,7 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol // --- Symbol Hash Trie -------------------------------------------------------- -internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol); +internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *symbol); internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name); internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie); internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out); @@ -129,9 +109,9 @@ internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *sym internal U64 lnk_symbol_hash(String8 string); internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena); -internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol *symbol); -internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name); -internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...); +internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); +internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name); +internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...); // --- Symbol Contrib Helpers -------------------------------------------------- From b64e1dca9a1628c35dfd5e66cea716edd8a321c7 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 20 Aug 2025 17:26:46 -0700 Subject: [PATCH 103/302] WIP fix lib push order and sort new inputs --- src/linker/linker.natvis | 2 + src/linker/lnk.c | 63 ++++++++++++++--- src/linker/lnk_input.c | 13 ++-- src/linker/lnk_input.h | 8 +-- src/linker/lnk_lib.c | 90 ++++++++---------------- src/linker/lnk_lib.h | 38 ++++++---- src/linker/scripts/obj_paths_from_pdb.py | 4 +- 7 files changed, 118 insertions(+), 100 deletions(-) diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index d1031fa1..8414241e 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -16,6 +16,7 @@ + {{count={count} first={first} last={last} }} @@ -33,6 +34,7 @@ + {{count={count} first={first} }} diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f23c5eac..31dcb462 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1626,7 +1626,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (lnk_get_log_status(LNK_Log_InputLib)) { if (libs.count > 0) { U64 input_size = 0; - for EachIndex(i, libs.count) { input_size += libs.v[i].data.data.size; } + for EachIndex(i, libs.count) { input_size += libs.v[i]->data.data.size; } lnk_log(LNK_Log_InputObj, "[ Lib Input Size %M ]", input_size); } } @@ -1658,6 +1658,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } break; case State_SearchUndefined: { ProfBegin("Search Undefined"); + LNK_InputImportList new_imports = {0}; + LNK_InputObjList new_objs = {0}; for EachIndex(i, ArrayCount(lib_index)) { for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { for EachIndex(worker_id, symtab->arena->count) { @@ -1669,22 +1671,38 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (symbol_interp == COFF_SymbolValueInterp_Undefined) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); } } } } } - if (input_import_list.count || input_obj_list.count) { + if (new_imports.count || new_objs.count) { goto end_search_undefined; } } } end_search_undefined:; + + { + LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); + radsort(import_nodes, new_imports.count, lnk_input_import_is_before); + new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); + + LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); + radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); + new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); + + lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); + lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); + } + ProfEnd(); } break; case State_SearchWeak: { ProfBegin("Search Weak"); + LNK_InputImportList new_imports = {0}; + LNK_InputObjList new_objs = {0}; for EachIndex(i, ArrayCount(lib_index)) { for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { for EachIndex(worker_id, symtab->arena->count) { @@ -1698,23 +1716,39 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); } } } } } } - if (input_import_list.count || input_obj_list.count) { + if (new_imports.count || new_objs.count) { goto end_search_weak; } } } end_search_weak:; + + { + LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); + radsort(import_nodes, new_imports.count, lnk_input_import_is_before); + new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); + + LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); + radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); + new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); + + lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); + lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); + } + ProfEnd(); } break; case State_SearchWeakAntiDep: { ProfBegin("Search Weak AntiDep"); + LNK_InputImportList new_imports = {0}; + LNK_InputObjList new_objs = {0}; for EachIndex(i, ArrayCount(lib_index)) { for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { for EachIndex(worker_id, symtab->arena->count) { @@ -1732,7 +1766,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (dep_interp == COFF_SymbolValueInterp_Weak) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); } } } @@ -1740,13 +1774,26 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } } } - - if (input_import_list.count || input_obj_list.count) { + if (new_imports.count || new_objs.count) { goto end_search_antidep; } } } end_search_antidep:; + + { + LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); + radsort(import_nodes, new_imports.count, lnk_input_import_is_before); + new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); + + LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); + radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); + new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); + + lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); + lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); + } + ProfEnd(); } break; case State_SearchEntryPoint: { diff --git a/src/linker/lnk_input.c b/src/linker/lnk_input.c index a7f543bf..16f8deef 100644 --- a/src/linker/lnk_input.c +++ b/src/linker/lnk_input.c @@ -84,20 +84,15 @@ lnk_path_array_from_input_obj_array(Arena *arena, LNK_InputObj **arr, U64 count) internal int lnk_input_obj_compar(const void *raw_a, const void *raw_b) { - const LNK_InputObj **a = (const LNK_InputObj **) raw_a; - const LNK_InputObj **b = (const LNK_InputObj **) raw_b; - int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path); - return cmp; + LNK_InputObj * const *a = raw_a, * const *b = raw_b; + return u64_compar(&(*a)->input_idx, &(*b)->input_idx); } internal int lnk_input_obj_compar_is_before(void *raw_a, void *raw_b) { - LNK_InputObj **a = raw_a; - LNK_InputObj **b = raw_b; - int cmp = str8_compar_case_sensitive(&(*a)->path, &(*b)->path); - int is_before = cmp < 0; - return is_before; + LNK_InputObj **a = raw_a, **b = raw_b; + return lnk_input_obj_compar(a, b) < 0; } internal LNK_InputObjList diff --git a/src/linker/lnk_input.h b/src/linker/lnk_input.h index 63eb305f..a8869d37 100644 --- a/src/linker/lnk_input.h +++ b/src/linker/lnk_input.h @@ -36,15 +36,15 @@ typedef struct LNK_InputImportList typedef struct LNK_InputObj { - struct LNK_InputObj *next; + String8 path; + String8 dedup_id; + String8 data; B8 is_thin; B8 exclude_from_debug_info; B8 has_disk_read_failed; - String8 dedup_id; - String8 path; - String8 data; struct LNK_Lib *lib; U64 input_idx; + struct LNK_InputObj *next; } LNK_InputObj; typedef struct LNK_InputObjList diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index c8270380..d620f2cb 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -1,56 +1,17 @@ // Copyright (c) 2025 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal LNK_LibNode * -lnk_lib_list_pop_node_atomic(LNK_LibList *list) +internal int +lnk_lib_node_is_before(void *a, void *b) { - for (;;) { - LNK_LibNode *expected = list->first; - LNK_LibNode *current = ins_atomic_ptr_eval_cond_assign(&list->first, expected->next, expected); - if (expected == current) { - ins_atomic_u64_dec_eval(&list->count); - return expected; - } - } + return ((LNK_LibNode*)a)->data.input_idx < ((LNK_LibNode*)b)->data.input_idx; } -internal void -lnk_lib_list_push_node_atomic(LNK_LibList *list, LNK_LibNode *node) +internal int +lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b) { - for (;;) { - LNK_LibNode *expected = list->first; - LNK_LibNode *current = ins_atomic_ptr_eval_cond_assign(&list->first, node, expected); - if (current == expected) { - node->next = expected; - ins_atomic_u64_inc_eval(&list->count); - return; - } - } -} - -internal void -lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node) -{ - SLLStackPush(list->first, node); - list->count += 1; -} - -internal LNK_LibList -lnk_lib_list_reserve(Arena *arena, U64 count) -{ - LNK_LibList result = {0}; - LNK_LibNode *nodes = push_array(arena, LNK_LibNode, count); - for (U64 i = 0; i < count; i += 1) { lnk_lib_list_push_node(&result, &nodes[i]); } - return result; -} - -internal LNK_LibNodeArray -lnk_array_from_lib_list(Arena *arena, LNK_LibList list) -{ - LNK_LibNodeArray result = {0}; - result.v = push_array(arena, LNK_LibNode, list.count); - for (LNK_LibNode *n = list.first; n != 0; n = n->next) { result.v[result.count++] = *n; } - return result; + LNK_LibNode **a = raw_a, **b = raw_b; + return lnk_lib_node_is_before(*a, *b); } internal B32 @@ -169,21 +130,25 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer) { LNK_LibIniter *task = raw_task; - LNK_LibNode *lib_node = lnk_lib_list_pop_node_atomic(&task->free_libs); + U64 lib_node_idx = ins_atomic_u64_inc_eval(&task->next_free_lib_idx)-1; + LNK_LibNode *lib_node = &task->free_libs[lib_node_idx]; lib_node->data.input_idx = task_id; B32 is_valid_lib = lnk_lib_from_data(arena, task->data_arr[task_id], task->path_arr[task_id], &lib_node->data); if (is_valid_lib) { - lnk_lib_list_push_node_atomic(&task->valid_libs, lib_node); + U64 valid_lib_idx = ins_atomic_u64_inc_eval(&task->valid_libs_count)-1; + task->valid_libs[valid_lib_idx] = lib_node; } else { - lnk_lib_list_push_node_atomic(&task->invalid_libs, lib_node); + U64 invalid_lib_idx = ins_atomic_u64_inc_eval(&task->invalid_libs_count); + task->invalid_libs[invalid_lib_idx] = lib_node; } } -internal int -lnk_lib_node_is_before(void *a, void *b) +internal void +lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node) { - return ((LNK_LibNode*)a)->data.input_idx < ((LNK_LibNode*)b)->data.input_idx; + SLLQueuePush(list->first, list->last, node); + list->count += 1; } internal LNK_LibNodeArray @@ -196,27 +161,28 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S // parse libs in parallel LNK_LibIniter task = {0}; - task.free_libs = lnk_lib_list_reserve(scratch.arena, lib_count); + task.free_libs = push_array(arena->v[0], LNK_LibNode, lib_count); + task.valid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count); + task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count); task.data_arr = data_arr.v; task.path_arr = path_arr.v; tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task); // report invalid libs - LNK_LibNodeArray invalid_libs = lnk_array_from_lib_list(scratch.arena, task.invalid_libs); - radsort(invalid_libs.v, invalid_libs.count, lnk_lib_node_is_before); - for (U64 i = 0; i < task.invalid_libs.count; i += 1) { - U64 input_idx = invalid_libs.v[i].data.input_idx; + radsort(task.invalid_libs, task.invalid_libs_count, lnk_lib_node_ptr_is_before); + for EachIndex(i, task.invalid_libs_count) { + U64 input_idx = task.invalid_libs[i]->data.input_idx; lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", path_arr.v[input_idx]); } // push parsed libs - LNK_LibNodeArray result = lnk_array_from_lib_list(arena->v[0], task.valid_libs); - radsort(result.v, result.count, lnk_lib_node_is_before); - for (U64 i = result.count; i > 0; i -= 1) { - result.v[i-1].data.input_idx = list->count; - lnk_lib_list_push_node(list, &result.v[i-1]); + radsort(task.valid_libs, task.valid_libs_count, lnk_lib_node_ptr_is_before); + for EachIndex(i, task.valid_libs_count) { + lnk_lib_list_push_node(list, task.valid_libs[i]); } + LNK_LibNodeArray result = { .count = task.valid_libs_count, task.valid_libs }; + scratch_end(scratch); return result; } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 04c3ef54..b585d302 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -16,7 +16,7 @@ typedef struct LNK_Lib String8 long_names; U64 input_idx; } LNK_Lib; - + typedef struct LNK_LibNode { LNK_Lib data; @@ -25,31 +25,39 @@ typedef struct LNK_LibNode typedef struct LNK_LibNodeArray { - U64 count; - LNK_LibNode *v; + U64 count; + LNK_LibNode **v; } LNK_LibNodeArray; typedef struct LNK_LibList { - U64 count; - struct LNK_LibNode *first; + U64 count; + LNK_LibNode *first; + LNK_LibNode *last; } LNK_LibList; + +// --- Workers Contexts -------------------------------------------------------- typedef struct { - String8 *data_arr; - String8 *path_arr; - LNK_LibList free_libs; - LNK_LibList valid_libs; - LNK_LibList invalid_libs; + String8 *data_arr; + String8 *path_arr; + U64 next_free_lib_idx; + U64 valid_libs_count; + U64 invalid_libs_count; + LNK_LibNode *free_libs; + LNK_LibNode **valid_libs; + LNK_LibNode **invalid_libs; } LNK_LibIniter; -internal LNK_LibNode * lnk_lib_list_pop_node_atomic(LNK_LibList *list); -internal void lnk_lib_list_push_node_atomic(LNK_LibList *list, LNK_LibNode *node); -internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node); -internal LNK_LibList lnk_lib_list_reserve(Arena *arena, U64 count); -internal LNK_LibNodeArray lnk_array_from_lib_list(Arena *arena, LNK_LibList list); +// ----------------------------------------------------------------------------- + +internal int lnk_lib_node_is_before(void *a, void *b); +internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b); internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out); +internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node); internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr); +internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out); + diff --git a/src/linker/scripts/obj_paths_from_pdb.py b/src/linker/scripts/obj_paths_from_pdb.py index a4d3de02..2bd11b50 100644 --- a/src/linker/scripts/obj_paths_from_pdb.py +++ b/src/linker/scripts/obj_paths_from_pdb.py @@ -8,8 +8,8 @@ def get_sorted_objs(pdb_path): filtered_lines = [line for line in lines if line.lstrip().startswith("Mod ")] # sort by the obj_path portion (line format: "Mod ") def extract_path(line): return line.split(maxsplit=2)[2].lower() - sorted_lines = sorted(filtered_lines, key=extract_path) - return sorted_lines + #sorted_lines = sorted(filtered_lines, key=extract_path) + return filtered_lines if __name__ == "__main__": sorted_objs = get_sorted_objs(sys.argv[1]) From 41fe8a7410ce53a605a1bd0114f33b6541aad802 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 11:32:20 -0700 Subject: [PATCH 104/302] merge undefined and weak search passes --- src/linker/lnk.c | 71 +++++++++--------------------------------------- 1 file changed, 13 insertions(+), 58 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 31dcb462..9697ca98 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1271,8 +1271,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) State_InputLibs, State_InputDelayLoadDlls, State_InputLinkerObjs, - State_SearchUndefined, - State_SearchWeak, + State_SearchUndefinedAndWeak, State_SearchWeakAntiDep, State_SearchEntryPoint, }; @@ -1286,10 +1285,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } while (0) #define state_list_pop(l) (l).first->state; SLLQueuePop((l).first, (l).last); (l).count -= 1 typedef enum { - SearchFlag_Undefined = (1 << 0), - SearchFlag_Weak = (1 << 1), - SearchFlag_WeakAntiDep = (1 << 2), - SearchFlag_All = (SearchFlag_Undefined|SearchFlag_Weak|SearchFlag_WeakAntiDep) + SearchFlag_UndefinedAndWeak = (1 << 0), + SearchFlag_WeakAntiDep = (1 << 1), + SearchFlag_All = (SearchFlag_UndefinedAndWeak|SearchFlag_WeakAntiDep) } SearchFlags; ProfBeginFunction(); @@ -1656,8 +1654,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfEnd(); } break; - case State_SearchUndefined: { - ProfBegin("Search Undefined"); + case State_SearchUndefinedAndWeak: { + ProfBegin("Search Undefined And Weak"); LNK_InputImportList new_imports = {0}; LNK_InputObjList new_objs = {0}; for EachIndex(i, ArrayCount(lib_index)) { @@ -1673,45 +1671,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); } - } - } - } - } - if (new_imports.count || new_objs.count) { - goto end_search_undefined; - } - } - } - end_search_undefined:; - - { - LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); - radsort(import_nodes, new_imports.count, lnk_input_import_is_before); - new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); - - LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); - radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); - new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); - - lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); - lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); - } - - ProfEnd(); - } break; - case State_SearchWeak: { - ProfBegin("Search Weak"); - LNK_InputImportList new_imports = {0}; - LNK_InputObjList new_objs = {0}; - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { + } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { U32 member_idx; @@ -1724,12 +1684,12 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } } if (new_imports.count || new_objs.count) { - goto end_search_weak; + goto end_search_undefined; } } } - end_search_weak:; - + end_search_undefined:; + { LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); radsort(import_nodes, new_imports.count, lnk_input_import_is_before); @@ -2207,14 +2167,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) state_list_push(scratch.arena, state_list, State_InputDelayLoadDlls); continue; } - if (search_flags & SearchFlag_Undefined) { - search_flags &= ~SearchFlag_Undefined; - state_list_push(scratch.arena, state_list, State_SearchUndefined); - continue; - } - if (search_flags & SearchFlag_Weak) { - search_flags &= ~SearchFlag_Weak; - state_list_push(scratch.arena, state_list, State_SearchWeak); + if (search_flags & SearchFlag_UndefinedAndWeak) { + search_flags &= ~SearchFlag_UndefinedAndWeak; + state_list_push(scratch.arena, state_list, State_SearchUndefinedAndWeak); continue; } if (search_flags & SearchFlag_WeakAntiDep) { From 3bd8f0e1d5e31e55b3b9051599314818e4183549 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 14:16:49 -0700 Subject: [PATCH 105/302] fix argument expansion in github actions and build.bat --- .github/workflows/builds.yml | 2 +- build.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index a1a3dd9a..f9263756 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -31,7 +31,7 @@ jobs: shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 - call build %${{ matrix.target }}% %${{ matrix.compiler }}% %${{ matrix.mode }}% || exit /b 1 + call build "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1 run-torture: runs-on: windows-2022 diff --git a/build.bat b/build.bat index aab7c76e..426caafa 100644 --- a/build.bat +++ b/build.bat @@ -27,7 +27,7 @@ cd /D "%~dp0" :: - `spall`: enable spall profiling support :: --- Unpack Arguments ------------------------------------------------------- -for %%a in (%*) do set "%%a=1" +for %%a in (%*) do set "%%~a=1" if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1 if not "%release%"=="1" set debug=1 if "%debug%"=="1" set release=0 && echo [debug mode] From e0c409e3f460846970744d2c6bbdfa29535ea3b1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 14:30:48 -0700 Subject: [PATCH 106/302] move prototype decl to base_core.h to fix implicit function usage --- src/base/base_core.c | 4 ---- src/base/base_core.h | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/base/base_core.c b/src/base/base_core.c index 9121d923..1e58d1f1 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -627,12 +627,8 @@ index_of_zero_u64(U64 *ptr, U64 count) //////////////////////////////// //~ rjf: Third Party Includes -#define STB_SPRINTF_DECORATE(name) raddbg_##name -#include "third_party/stb/stb_sprintf.h" - #if !BUILD_SUPPLEMENTARY_UNIT # define STB_SPRINTF_IMPLEMENTATION -# define STB_SPRINTF_STATIC # include "third_party/stb/stb_sprintf.h" #endif diff --git a/src/base/base_core.h b/src/base/base_core.h index 45518081..02fb8d6d 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -13,6 +13,13 @@ #include #include +//////////////////////////////// +//~ rjf: Third Party Includes + +#define STB_SPRINTF_DECORATE(name) raddbg_##name +#define STB_SPRINTF_STATIC +#include "third_party/stb/stb_sprintf.h" + //////////////////////////////// //~ rjf: Codebase Keywords From 1a9e17ee37a1da20d32a399f0f4c208e311d5a60 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:10:04 -0700 Subject: [PATCH 107/302] remove invalid normalize helpers for integer vectors (they always produce zero) --- src/base/base_math.c | 5 ----- src/base/base_math.h | 5 ----- 2 files changed, 10 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index b884937e..16e3ad28 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -42,7 +42,6 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v. internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;} internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;} internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;} -internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;} internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;} @@ -54,7 +53,6 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v. internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;} internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;} internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;} -internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;} internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;} @@ -66,7 +64,6 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;} internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;} internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;} -internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;} internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;} internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;} @@ -99,7 +96,6 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v. internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;} internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;} internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;} -internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;} internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;} internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;} @@ -124,7 +120,6 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v. internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;} internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;} internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;} -internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;} internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;} //////////////////////////////// diff --git a/src/base/base_math.h b/src/base/base_math.h index 7ea6e2ec..416dfeeb 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -443,7 +443,6 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s); internal S64 dot_2s64(Vec2S64 a, Vec2S64 b); internal S64 length_squared_2s64(Vec2S64 v); internal S64 length_2s64(Vec2S64 v); -internal Vec2S64 normalize_2s64(Vec2S64 v); internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t); #define v2s32(x, y) vec_2s32((x), (y)) @@ -456,7 +455,6 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s); internal S32 dot_2s32(Vec2S32 a, Vec2S32 b); internal S32 length_squared_2s32(Vec2S32 v); internal S32 length_2s32(Vec2S32 v); -internal Vec2S32 normalize_2s32(Vec2S32 v); internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t); #define v2s16(x, y) vec_2s16((x), (y)) @@ -469,7 +467,6 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s); internal S16 dot_2s16(Vec2S16 a, Vec2S16 b); internal S16 length_squared_2s16(Vec2S16 v); internal S16 length_2s16(Vec2S16 v); -internal Vec2S16 normalize_2s16(Vec2S16 v); internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t); #define v3f32(x, y, z) vec_3f32((x), (y), (z)) @@ -497,7 +494,6 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s); internal S32 dot_3s32(Vec3S32 a, Vec3S32 b); internal S32 length_squared_3s32(Vec3S32 v); internal S32 length_3s32(Vec3S32 v); -internal Vec3S32 normalize_3s32(Vec3S32 v); internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t); internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b); @@ -524,7 +520,6 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s); internal S32 dot_4s32(Vec4S32 a, Vec4S32 b); internal S32 length_squared_4s32(Vec4S32 v); internal S32 length_4s32(Vec4S32 v); -internal Vec4S32 normalize_4s32(Vec4S32 v); internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t); //////////////////////////////// From 971f1b9a2f5e98c14d5e973529a424799729d235 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:15:19 -0700 Subject: [PATCH 108/302] ignore sign conversions in blake3 --- src/linker/base_ext/base_blake3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/linker/base_ext/base_blake3.c b/src/linker/base_ext/base_blake3.c index ca29e21a..ce380e6b 100644 --- a/src/linker/base_ext/base_blake3.c +++ b/src/linker/base_ext/base_blake3.c @@ -4,6 +4,7 @@ #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmacro-redefined" +#pragma clang diagnostic ignored "-Wsign-conversion" #elif defined(_MSC_VER) #pragma warning (push, 0) #endif From daf69ff1c78418e23d76056ffa966a32983a7d08 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:16:32 -0700 Subject: [PATCH 109/302] fix sign conversion in radsort.h --- src/third_party/radsort/radsort.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/third_party/radsort/radsort.h b/src/third_party/radsort/radsort.h index 9b735a41..9850a6ff 100644 --- a/src/third_party/radsort/radsort.h +++ b/src/third_party/radsort/radsort.h @@ -558,7 +558,7 @@ RSFORCEINLINE void radsortinternal( void * start, size_t len, size_t element_siz piv = scan; while( scan <= rend ) { - size_t adv = is_before( scan, tmp ); + int adv = is_before( scan, tmp ); swapper( piv, scan, element_size ); if ( adv ) piv = rsadd_ptr( piv, element_size ); // needs to be a cmov scan = rsadd_ptr( scan, element_size ); From fc4e26921103edac7db588bbf00bc7556a7dba24 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:16:52 -0700 Subject: [PATCH 110/302] ignore sign conversions in stb_sprintf.h --- src/base/base_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/base/base_core.c b/src/base/base_core.c index 1e58d1f1..2711b9e7 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -628,10 +628,24 @@ index_of_zero_u64(U64 *ptr, U64 count) //~ rjf: Third Party Includes #if !BUILD_SUPPLEMENTARY_UNIT +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#elif defined(_MSC_VER) +#pragma warning (push, 0) +#endif + # define STB_SPRINTF_IMPLEMENTATION +# define STB_SPRINTF_STATIC # include "third_party/stb/stb_sprintf.h" #endif +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(_MSC_VER) +#pragma warning (pop, 0) +#endif + //////////////////////////////// //~ rjf: String <-> Integer Tables From 0dac1a91db8800118eb4e9210c8d3a73005a0797 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:21:18 -0700 Subject: [PATCH 111/302] fix u128 make --- src/base/base_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/base_core.c b/src/base/base_core.c index 2711b9e7..97515ce6 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -41,7 +41,7 @@ u128_zero(void) internal U128 u128_make(U64 v0, U64 v1) { - U128 v = {v0, v1}; + U128 v = { .u64 = { v0, v1 }}; return v; } From 843de72f64100d8754b98c2dbcfda415e048bf0b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:25:51 -0700 Subject: [PATCH 112/302] add U8 atomic exchange for clang and gcc --- src/base/base_core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/base/base_core.h b/src/base/base_core.h index 02fb8d6d..34a0cb64 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -217,6 +217,7 @@ # error Atomic intrinsics not defined for this compiler / architecture combination. # endif #elif COMPILER_CLANG || COMPILER_GCC +# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST) # define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) # define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1) # define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1) From c397b1dfb17633c7b796dc6fb8facde80826071a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:26:25 -0700 Subject: [PATCH 113/302] handle common section case --- src/coff/coff_obj_writer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 4bf384a4..2a8a91af 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -93,6 +93,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break; case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break; case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break; + case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break; } d->type = s->type; d->storage_class = s->storage_class; From d7cdaa98b5d862820b4222cee572471487c1e58a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:26:40 -0700 Subject: [PATCH 114/302] oops forgot to set enum type --- src/linker/lnk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 9697ca98..8c4858db 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1262,7 +1262,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { - enum { + enum State { State_Null, State_InputDisallowLibs, State_InputImports, From e1b716860517d4993de6652de6be19ad1cd69f9d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 21 Aug 2025 15:57:25 -0700 Subject: [PATCH 115/302] update weak vs undefined replacement rule --- src/linker/lnk.c | 3 +++ src/linker/lnk_symbol_table.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 8c4858db..1ddc0c99 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1521,6 +1521,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (symbol_ht) { COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { + // clear out slot so weak symbol can replace undefined symbol + symbol_ht->symbol = 0; + // make obj with alternamte name symbol String8 alt_name_obj; { diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index cfa7276e..fd1fd461 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -141,7 +141,11 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->defined.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = lnk_symbol_defined_is_before(dst, src); + // NOTE: MSVC does not let a weak symbol to replace an undefined one, + // but LLD links without errors or warnings, meaning undefined symbols + // are resolved to the weak, which can potentially change behaviour of + // the linked image + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { From b0db2b19f87ea59695a640a4587f3131851d72db Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 27 Aug 2025 13:17:42 -0700 Subject: [PATCH 116/302] move entry point name redirection helper to MSCRT layer --- src/msvc_crt/msvc_crt.c | 16 ++++++++++++++++ src/msvc_crt/msvc_crt.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/msvc_crt/msvc_crt.c b/src/msvc_crt/msvc_crt.c index c251a7b7..aa2c54bc 100644 --- a/src/msvc_crt/msvc_crt.c +++ b/src/msvc_crt/msvc_crt.c @@ -1,6 +1,22 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal String8 +msvcrt_ctr_entry_from_user_entry(String8 user_entry) +{ + String8 crt_entry = {0}; + if (str8_match_lit("wmain", user_entry, 0)) { + crt_entry = str8_lit("wmainCRTStartup"); + } else if (str8_match_lit("main", user_entry, 0)) { + crt_entry = str8_lit("mainCRTStartup"); + } else if (str8_match_lit("WinMain", user_entry, 0)) { + crt_entry = str8_lit("WinMainCRTStartup"); + } else if (str8_match_lit("wWinMain", user_entry, 0)) { + crt_entry = str8_lit("wWinMainCRTStartup"); + } + return crt_entry; +} + internal String8 mscrt_delay_load_helper_name_from_machine(COFF_MachineType machine) { diff --git a/src/msvc_crt/msvc_crt.h b/src/msvc_crt/msvc_crt.h index 11000af2..4ad6354c 100644 --- a/src/msvc_crt/msvc_crt.h +++ b/src/msvc_crt/msvc_crt.h @@ -343,6 +343,10 @@ typedef struct MSCRT_ParsedFuncInfoV4 MSCRT_IP2State32V4 ip2state_map; } MSCRT_ParsedFuncInfoV4; +//- Entry Point + +internal String8 msvcrt_ctr_entry_from_user_entry(String8 user_entry_point); + //- Delay Load Helper internal String8 mscrt_delay_load_helper_name_from_machine(COFF_MachineType machine); From d9eb26a8309a43eb9e545e9084ae18982c1e85dd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 27 Aug 2025 13:18:09 -0700 Subject: [PATCH 117/302] infer subsystem when only entry point is specified --- src/linker/lnk.c | 277 +++++++++++++++++++++-------------------------- src/linker/lnk.h | 5 +- 2 files changed, 126 insertions(+), 156 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1ddc0c99..75dfd025 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -875,6 +875,49 @@ lnk_make_linker_coff_obj(Arena *arena, return obj; } +internal String8 +lnk_make_linker_obj(Arena *arena, LNK_Config *config) +{ + ProfBeginFunction(); + + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, config->machine); + + // Emit __ImageBase symbol. + // + // This symbol is used with REL32 to compute delta from current IP + // to the image base. CRT uses this trick to get to HINSTANCE * without + // passing it around as a function argument. + // + // 100h: lea rax, [rip + ffffff00h] ; -100h + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("__ImageBase"), 0, COFF_SymStorageClass_External); + + { // load config symbols + if (config->machine == COFF_MachineType_X86) { + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), 0, COFF_SymStorageClass_External); + } + + // TODO: investigate IMAGE_ENCLAVE_CONFIG 32/64 + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_ENCLAVE_CONFIG_SYMBOL_NAME), 0, COFF_SymStorageClass_External); + + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FLAGS_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FIDS_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FIDS_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_IAT_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_IAT_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_LONGJMP_TABLE_SYMBOL_NAME), 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_LONGJMP_COUNT_SYMBOL_NAME), 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_EHCONT_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_EHCONT_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); + } + + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + coff_obj_writer_release(&obj_writer); + + ProfEnd(); + return obj; +} + internal String8 lnk_get_lib_name(String8 path) { @@ -922,49 +965,6 @@ lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path) } } -internal String8 -lnk_make_linker_obj(Arena *arena, LNK_Config *config) -{ - ProfBeginFunction(); - - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, config->machine); - - // Emit __ImageBase symbol. - // - // This symbol is used with REL32 to compute delta from current IP - // to the image base. CRT uses this trick to get to HINSTANCE * without - // passing it around as a function argument. - // - // 100h: lea rax, [rip + ffffff00h] ; -100h - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("__ImageBase"), 0, COFF_SymStorageClass_External); - - { // load config symbols - if (config->machine == COFF_MachineType_X86) { - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), 0, COFF_SymStorageClass_External); - } - - // TODO: investigate IMAGE_ENCLAVE_CONFIG 32/64 - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_ENCLAVE_CONFIG_SYMBOL_NAME), 0, COFF_SymStorageClass_External); - - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FLAGS_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FIDS_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_FIDS_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_IAT_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_IAT_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_LONGJMP_TABLE_SYMBOL_NAME), 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_LONGJMP_COUNT_SYMBOL_NAME), 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_EHCONT_TABLE_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(MSCRT_GUARD_EHCONT_COUNT_SYMBOL_NAME) , 0, COFF_SymStorageClass_External); - } - - String8 obj = coff_obj_writer_serialize(arena, obj_writer); - coff_obj_writer_release(&obj_writer); - - ProfEnd(); - return obj; -} - internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, @@ -1761,129 +1761,95 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } break; case State_SearchEntryPoint: { ProfBegin("Search Entry Point"); - LNK_Symbol *entry_point_symbol = 0; - B32 is_entry_point_unspecified = config->entry_point_name.size == 0; - if (is_entry_point_unspecified) { - if (config->subsystem == PE_WindowsSubsystem_UNKNOWN) { - // we don't have a subsystem and entry point name, - // so we loop over every subsystem and search potential entry - // points in the symbol table - for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { - String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); - if (entry_point_symbol) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; - config->entry_point_name = name_arr.v[entry_idx]; - goto dbl_break; - } - } - } - - // search for potential entry points in libs - if (config->entry_point_name.size) { - for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { - String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for EachIndex(entry_idx, name_arr.count) { - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; - config->entry_point_name = name_arr.v[entry_idx]; - goto dbl_break; - } - } - } - } - } - } - - dbl_break:; - } else { - // we have subsystem but no entry point name, get potential entry point names - // and see which is in the symbol table - String8Array name_arr = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); - for EachIndex(entry_idx, name_arr.count) { - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); + // loop over all possible subsystems and entry point names and pick + // subsystem that has a defined entry point symbol + if (config->entry_point_name.size == 0) { + PE_WindowsSubsystem subsys_first = config->subsystem; + PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1; + LNK_Symbol *entry_point_symbol = 0; + for (U64 subsys_idx = subsys_first; subsys_idx < subsys_last; subsys_idx += 1) { + String8Array entry_points = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, entry_points.v[i]); if (symbol) { - if (config->entry_point_name.size) { - lnk_error(LNK_Error_EntryPoint, - "multiple entry point symbols found: %S(%S) and %S(%S)", - entry_point_symbol->name, entry_point_symbol->defined.obj->path, - symbol->name, symbol->defined.obj->path); - } else { - config->entry_point_name = name_arr.v[entry_idx]; - } + config->subsystem = subsys_idx; + config->entry_point_name = entry_points.v[i]; + goto found_entry_and_subsystem; } } - - // search for entry point in libs - if (!config->entry_point_name.size) { - for EachIndex(entry_idx, name_arr.count) { - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { - config->entry_point_name = name_arr.v[entry_idx]; - goto dbl_break2; - } - } - } - } - dbl_break2:; - } - } - - // redirect user entry to appropriate CRT entry - if (str8_match_lit("wmain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wmainCRTStartup"); - } else if (str8_match_lit("main", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("mainCRTStartup"); - } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("WinMainCRTStartup"); - } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wWinMainCRTStartup"); } + found_entry_and_subsystem:; } - - // generate undefined symbol so in case obj is in lib it will be linked + + // search for entry point in libs + if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); + for EachIndex(entry_idx, entry_points.count) { + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, entry_points.v[entry_idx], 0)) { + config->entry_point_name = entry_points.v[entry_idx]; + goto found_entry_in_libs; + } + } + } + } + found_entry_in_libs:; + } + + // infer subsystem from entry point name + if (config->entry_point_name.size != 0 && config->subsystem == PE_WindowsSubsystem_UNKNOWN) { + for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { + String8Array entry_points = pe_get_entry_point_names(config->machine, subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + if (str8_match(entry_points.v[i], config->entry_point_name, 0)) { + config->subsystem = subsys_idx; + goto subsystem_inferred_from_entry; + } + } + } + subsystem_inferred_from_entry:; + } + + // do we have an entry point name? if (config->entry_point_name.size) { + // redirect user entry to appropriate CRT entry + String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); + config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; + + // generate undefined symbol for entry point + // // TODO: config_refactor String8List value_strings = {0}; str8_list_push(scratch.arena, &value_strings, config->entry_point_name); lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - } - // no entry point, print out error and exit - else { - lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); - } - - // by default terminal server is enabled for windows and console applications - if (~config->flags & LNK_ConfigFlag_NoTsAware && - ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { - if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { - config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; + + // do we have a subsystem? + if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + // if subsystem version not specified set default values + if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { + config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); + } + + // check subsystem version against allowed min version + Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); + if (version_compar(config->subsystem_ver, min_subsystem_ver) < 0) { + lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", + config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); + } + + // by default terminal server is enabled for windows and console applications + if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { + if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { + config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; + } + } + } else { + lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); } } - - // do we have a subsystem? - if (config->subsystem == PE_WindowsSubsystem_UNKNOWN) { - lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); - } - - if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { - // subsystem version not specified, set default values - config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); - } - - // check subsystem version against allowed min version - Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); - int ver_cmp = version_compar(config->subsystem_ver, min_subsystem_ver); - if (ver_cmp < 0) { - lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", - config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); - } - + ProfEnd(); } break; case State_InputLinkerObjs: { @@ -2215,6 +2181,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } ProfEnd(); + + if (config->entry_point_name.size == 0) { + lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); + } + ProfBegin("Report Unresolved Symbols"); { U64 count = 0; diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 07491fe0..e15252a0 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -201,7 +201,7 @@ internal String8 lnk_manifest_from_inputs(Arena *arena, LNK_IO_Flags io_flags, S internal String8 lnk_make_null_obj(Arena *arena); internal String8 lnk_make_res_obj(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); -internal String8 lnk_make_linker_coff_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 cwd_path, String8 exe_path, String8 pdb_path, String8 cmd_line, String8 obj_name); +internal String8 lnk_make_linker_obj(Arena *arena, LNK_Config *config); // --- Link Context ------------------------------------------------------------ @@ -211,8 +211,7 @@ internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path); internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path); internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); -internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config); -internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); From 240935f0cc05d0ad7302a25f58ec2beed667f814 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 1 Sep 2025 14:32:49 -0700 Subject: [PATCH 118/302] WIP: use MSVC rule for COMDAT symbol replacement --- src/linker/lnk_symbol_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index fd1fd461..47e709c4 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -285,7 +285,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) can_replace = lnk_obj_is_before(src_obj, dst_obj); } else { // both COMDATs are valid but to get smaller exe pick smallest - can_replace = src_section_length < dst_section_length; + can_replace = 0; } } break; case COFF_ComdatSelect_NoDuplicates: { From 1aac27095e74d2f0ed07f2c1704a2f52beaa9313 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 1 Sep 2025 14:39:19 -0700 Subject: [PATCH 119/302] WIP: reorder input and library search order to match MSVC behavior --- src/linker/hash_table.c | 63 +- src/linker/hash_table.h | 1 + src/linker/linker.natvis | 34 + src/linker/lnk.c | 2352 ++++++++++++++++----------------- src/linker/lnk.h | 152 ++- src/linker/lnk_config.c | 152 ++- src/linker/lnk_config.h | 42 +- src/linker/lnk_input.c | 175 --- src/linker/lnk_input.h | 77 -- src/linker/lnk_lib.c | 49 +- src/linker/lnk_lib.h | 22 +- src/linker/lnk_obj.c | 91 +- src/linker/lnk_obj.h | 45 +- src/linker/lnk_symbol_table.c | 13 +- src/linker/lnk_symbol_table.h | 1 + 15 files changed, 1652 insertions(+), 1617 deletions(-) delete mode 100644 src/linker/lnk_input.c delete mode 100644 src/linker/lnk_input.h diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index e8c3a3c0..4a4c462f 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -211,11 +211,18 @@ hash_table_search_u64(HashTable *ht, U64 key_u64) return 0; } -internal void * -hash_table_search_u64_raw(HashTable *ht, U64 key_u64) +internal KeyValuePair * +hash_table_search_raw(HashTable *ht, void *key) { - KeyValuePair *kv = hash_table_search_u64(ht, key_u64); - return kv ? kv->value_raw : 0; + U64 hash = hash_table_hasher(str8_struct(&key)); + U64 ibucket = hash % ht->cap; + BucketList *bucket = ht->buckets + ibucket; + for (BucketNode *n = bucket->first; n != 0; n = n->next) { + if (n->v.key_raw == key) { + return &n->v; + } + } + return 0; } internal KeyValuePair * @@ -230,13 +237,6 @@ hash_table_search_path(HashTable *ht, String8 path) return result; } -internal void * -hash_table_search_path_raw(HashTable *ht, String8 path) -{ - KeyValuePair *kv = hash_table_search_path(ht, path); - return kv ? kv->value_raw : 0; -} - internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) { @@ -250,6 +250,27 @@ hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) return 0; } +internal void * +hash_table_search_u64_raw(HashTable *ht, U64 key_u64) +{ + KeyValuePair *kv = hash_table_search_u64(ht, key_u64); + return kv ? kv->value_raw : 0; +} + +internal void * +hash_table_search_path_raw(HashTable *ht, String8 path) +{ + KeyValuePair *kv = hash_table_search_path(ht, path); + return kv ? kv->value_raw : 0; +} + +internal void * +hash_table_search_raw_raw(HashTable *ht, void *key) +{ + KeyValuePair *kv = hash_table_search_raw(ht, key); + return kv ? kv->value_raw : 0; +} + internal B32 hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) { @@ -283,6 +304,13 @@ hash_table_push_u32_u32(Arena *arena, HashTable *ht, U32 key, U32 value) return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u32 = key, .value_u32 = value }); } +internal BucketNode * +hash_table_push_raw_raw(Arena *arena, HashTable *ht, void *key, void *value) +{ + U64 hash = hash_table_hasher(str8_struct(&key)); + return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_raw = key, .value_raw = value }); +} + internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) { @@ -381,6 +409,19 @@ key_value_pairs_from_hash_table(Arena *arena, HashTable *ht) return pairs; } +internal void * +keys_from_hash_table_raw(Arena *arena, HashTable *ht) +{ + void **result = push_array(arena, void *, ht->count); + for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) { + for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) { + Assert(cursor < ht->count); + result[cursor++] = n->v.key_raw; + } + } + return result; +} + internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht) { diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 0eb3bf67..d7458adc 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -87,6 +87,7 @@ internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable internal String8 keys_from_hash_table_str8 (Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); +internal void * keys_from_hash_table_raw(Arena *arena, HashTable *ht); internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht); internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index 8414241e..9c69c117 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -17,6 +17,8 @@ + + {{count={count} first={first} last={last} }} @@ -92,6 +94,38 @@ + + + count + + + + + + idx = 0 + + + node->v[idx] + idx += 1 + + node = node->next + + + + + + + {count,cap,v} + + count + cap + + count + v + + + + diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 75dfd025..3f9ce0e0 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -99,7 +99,6 @@ #include "lnk_timer.h" #include "lnk_io.h" #include "lnk_cmd_line.h" -#include "lnk_input.h" #include "lnk_config.h" #include "lnk_symbol_table.h" #include "lnk_section_table.h" @@ -114,7 +113,6 @@ #include "lnk_timer.c" #include "lnk_io.c" #include "lnk_cmd_line.c" -#include "lnk_input.c" #include "lnk_config.c" #include "lnk_symbol_table.c" #include "lnk_section_table.c" @@ -212,7 +210,7 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) } // init config - LNK_Config *config = lnk_config_from_cmd_line(arena, raw_cmd_line, cmd_line); + LNK_Config *config = lnk_config_from_cmd_line(raw_cmd_line, cmd_line); #if PROFILE_TELEMETRY { @@ -375,7 +373,7 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest for (String8Node *man_node = manifest_path_list.first; man_node != 0; man_node = man_node->next) { - // resolve relativ path inputs + // resolve relative inputs String8 full_path = path_absolute_dst_from_relative_dst_src(scratch.arena, man_node->string, work_dir); // normalize slashes @@ -467,7 +465,7 @@ lnk_make_null_obj(Arena *arena) // push import stub { - COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("RAD_IMPORT_STUB_NULL"), 0, COFF_SymStorageClass_Static); + COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_IMPORT_STUB), 0, COFF_SymStorageClass_Static); coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_AntiDependency, tag); } @@ -919,114 +917,1148 @@ lnk_make_linker_obj(Arena *arena, LNK_Config *config) } internal String8 -lnk_get_lib_name(String8 path) +lnk_make_obj_with_undefined_symbols(Arena *arena, String8List symbol_names) { - static String8 LIB_EXT = str8_lit_comp(".LIB"); - - // strip path - String8 name = str8_skip_last_slash(path); - - // strip extension - String8 name_ext = str8_postfix(name, LIB_EXT.size); - if (str8_match(name_ext, LIB_EXT, StringMatchFlag_CaseInsensitive)) { - name = str8_chop(name, LIB_EXT.size); + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); + for (String8Node *name_n = symbol_names.first; name_n != 0; name_n = name_n->next) { + coff_obj_writer_push_symbol_undef(obj_writer, name_n->string); } - - return name; -} - -internal B32 -lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path) -{ - String8 lib_name = lnk_get_lib_name(path); - return hash_table_search_path(disallow_lib_ht, lib_name) != 0; -} - -internal B32 -lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 path) -{ - KeyValuePair *is_loaded = hash_table_search_path(loaded_lib_ht, path); - return is_loaded != 0; + String8 obj = coff_obj_writer_serialize(arena, obj_writer); + coff_obj_writer_release(&obj_writer); + return obj; } internal void -lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path) +lnk_input_list_push_node(LNK_InputList *list, LNK_Input *node) { - String8 lib_name = lnk_get_lib_name(path); - hash_table_push_path_u64(arena, disallow_lib_ht, lib_name, 0); + SLLQueuePush(list->first, list->last, node); + list->count += 1; } internal void -lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path) +lnk_input_list_concat_in_place(LNK_InputList *list, LNK_InputList *to_concat) { - if (!hash_table_search_path(loaded_lib_ht, path)) { - String8 path_copy = push_str8_copy(arena, path); - hash_table_push_path_u64(arena, loaded_lib_ht, path_copy, 0); + SLLConcatInPlace(list, to_concat); +} + +internal LNK_InputPtrArray +lnk_array_from_input_list(Arena *arena, LNK_InputList list) +{ + LNK_InputPtrArray result = {0}; + result.v = push_array(arena, LNK_Input *, list.count); + for (LNK_Input *node = list.first; node != 0; node = node->next, result.count += 1) { + result.v[result.count] = node; } + return result; } -internal void -lnk_queue_lib_member_for_input(Arena *arena, - LNK_Config *config, - LNK_Symbol *pull_in_ref, - LNK_Lib *lib, - U32 member_idx, - LNK_InputImportList *input_import_list, - LNK_InputObjList *input_obj_list) +internal LNK_Inputer * +lnk_inputer_init(void) { - B32 was_member_queued = ins_atomic_u8_eval_assign(&lib->was_member_queued[member_idx], 1); - if (!was_member_queued) { - U64 member_offset = lib->member_offsets[member_idx]; + Arena *arena = arena_alloc(); + LNK_Inputer *inputer = push_array(arena, LNK_Inputer, 1); + inputer->arena = arena; + inputer->objs_ht = hash_table_init(arena, 0x20000); + inputer->libs_ht = hash_table_init(arena, 0x1000); + inputer->missing_lib_ht = hash_table_init(arena, 0x100); + return inputer; +} - // compose input index so that members are laid out in the image - // in the order of undefined symbols appearing in objs, - // mimicking serial discovery - U64 input_idx = Compose64Bit(pull_in_ref->defined.obj->input_idx, pull_in_ref->defined.symbol_idx); +internal LNK_Input * +lnk_input_push(Arena *arena, LNK_InputList *list, String8 path, String8 data) +{ + LNK_Input *node = push_array(arena, LNK_Input, 1); + node->path = path; + node->data = data; + lnk_input_list_push_node(list, node); + return node; +} - // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); - COFF_DataType member_type = coff_data_type_from_data(member_info.data); +internal LNK_Input * +lnk_inputer_push_linkgen(Arena *arena, LNK_InputList *list, String8 data, String8 path) +{ + LNK_Input *input = lnk_input_push(arena, list, data, path); + input->exclude_from_debug_info = 1; + return input; +} - switch (member_type) { - case COFF_DataType_Null: break; - case COFF_DataType_Import: { - LNK_InputImportNode *input = lnk_input_import_list_push(arena, input_import_list); - input->data.coff_import = member_info.data; - input->data.input_idx = input_idx; - } break; - case COFF_DataType_BigObj: - case COFF_DataType_Obj: { - String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); +internal LNK_Input * +lnk_inputer_push_thin(Arena *arena, LNK_InputList *list, HashTable *ht, String8 full_path) +{ + Temp scratch = scratch_begin(&arena, 1); + LNK_Input *input = hash_table_search_path_raw(ht, full_path); + if (input == 0) { + input = lnk_input_push(arena, list, full_path, str8_zero()); + input->path = push_str8_copy(arena, full_path); + input->is_thin = 1; - // obj path in thin archive has slash appended which screws up - // file lookup on disk; it couble be there to enable paths to symbols - // but we don't use this feature - String8 slash = str8_lit("/"); - if (str8_ends_with(obj_path, slash, 0)) { - obj_path = str8_chop(obj_path, slash.size); - } + hash_table_push_path_raw(arena, ht, full_path, input); + } + scratch_end(scratch); + return input; +} - // obj path in thin archive is relative to directory with archive - B32 is_thin = lib->type == COFF_Archive_Thin; - if (is_thin) { - Temp scratch = scratch_begin(&arena, 1); - String8List obj_path_list = {0}; - str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); - str8_list_push(scratch.arena, &obj_path_list, obj_path); - obj_path = str8_path_list_join_by_style(arena, &obj_path_list, config->path_style); - scratch_end(scratch); - } +internal LNK_Input * +lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data) +{ + lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); + LNK_Input *input = lnk_input_push(inputer->arena, &inputer->new_objs, path, data); + input->trigger = trigger; + return input; +} - LNK_InputObj *input = lnk_input_obj_list_push(arena, input_obj_list); - input->is_thin = is_thin; - input->dedup_id = push_str8f(arena, "%S/%S", lib->path, obj_path); - input->path = obj_path; - input->data = member_info.data; - input->lib = lib; - input->input_idx = input_idx; - } break; +internal LNK_Input * +lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data) +{ + lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); + LNK_Input *input = lnk_inputer_push_linkgen(inputer->arena, &inputer->new_objs, path, data); + input->trigger = trigger; + return input; +} + +internal LNK_Input * +lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path) +{ + lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); + Temp scratch = scratch_begin(0,0); + String8 full_path = os_full_path_from_path(scratch.arena, path); + LNK_Input *input = lnk_inputer_push_thin(inputer->arena, &inputer->new_objs, inputer->objs_ht, full_path); + input->trigger = trigger; + scratch_end(scratch); + return input; +} + +internal LNK_Input * +lnk_inputer_push_lib(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data) +{ + lnk_log(LNK_Log_InputLib, "Input Lib: %S", path); + return lnk_input_push(inputer->arena, &inputer->new_libs[input_source], path, data); +} + +internal LNK_Input * +lnk_inputer_push_lib_linkgen(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data) +{ + lnk_log(LNK_Log_InputLib, "Input Lib: %S", path); + return lnk_input_push(inputer->arena, &inputer->new_libs[input_source], path, data); +} + +internal LNK_Input * +lnk_input_from_path(HashTable *load_ht, String8 path) +{ + LNK_Input *input = hash_table_search_path_raw(load_ht, path); + if (input == 0) { + Temp scratch = scratch_begin(0, 0); + String8 full_path = os_full_path_from_path(scratch.arena, path); + input = hash_table_search_path_raw(load_ht, full_path); + scratch_end(scratch); + } + return input; +} + +internal LNK_Input * +lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSourceType input_source, String8 path) +{ + Temp scratch = scratch_begin(0,0); + + LNK_Input *input = 0; + + // default libraries may omit extension + if (input_source == LNK_InputSource_Default || input_source == LNK_InputSource_Obj) { + if (!str8_ends_with(path, str8_lit(".lib"), StringMatchFlag_CaseInsensitive)) { + path = push_str8f(scratch.arena, "%S.lib", path); + } + if (lnk_is_lib_disallowed(config, path)) { + goto exit; } } + + // was library already loaded? + input = hash_table_search_path_raw(inputer->libs_ht, path); + if (input) { + goto exit; + } + + // search disk for library + String8List matches = lnk_file_search(scratch.arena, config->lib_dir_list, path); + + // warn about missing library + if (matches.node_count == 0) { + KeyValuePair *was_reported = hash_table_search_path(inputer->missing_lib_ht, path); + if (was_reported == 0) { + hash_table_push_path_u64(inputer->arena, inputer->missing_lib_ht, path, 0); + lnk_error(LNK_Warning_FileNotFound, "unable to find library `%S`", path); + } + goto exit; + } + + String8 first_match = matches.first->string; + input = hash_table_search_path_raw(inputer->libs_ht, first_match); + if (input) { + goto exit; + } + + // warn about multiple matches + if (matches.node_count > 1) { + lnk_error(LNK_Warning_MultipleLibMatch, "multiple libraries match `%S` (picking first match)", path); + lnk_supplement_error_list(matches); + } + + lnk_log(LNK_Log_InputLib, "Input Lib: %S", first_match); + input = lnk_inputer_push_thin(inputer->arena, &inputer->new_libs[input_source], inputer->libs_ht, first_match); + + exit:; + scratch_end(scratch); + return input; +} + +internal B32 +lnk_inputer_has_items(LNK_Inputer *inputer) +{ + if (inputer->new_objs.count > 0) { + return 1; + } + + for EachIndex(i, ArrayCount(inputer->new_libs)) { + if (inputer->new_libs[i].count > 0) { + return 1; + } + } + + return 0; +} + +internal LNK_InputPtrArray +lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs) +{ + Temp scratch = scratch_begin(&arena, 1); + + ProfBegin("Gather Thin Inputs"); + U64 thin_inputs_count = 0; + for (LNK_Input *node = new_inputs->first; node != 0; node = node->next) { + if (node->is_thin) { + thin_inputs_count += 1; + } + } + LNK_Input **thin_inputs = push_array(scratch.arena, LNK_Input *, thin_inputs_count); + U64 thin_idx = 0; + for (LNK_Input *node = new_inputs->first; node != 0; node = node->next) { + if (node->is_thin) { + thin_inputs[thin_idx++] = node; + } + } + String8Array thin_input_paths = {0}; + thin_input_paths.count = thin_inputs_count; + thin_input_paths.v = push_array(scratch.arena, String8, thin_inputs_count); + for EachIndex(i, thin_inputs_count) { + thin_input_paths.v[i] = thin_inputs[i]->path; + } + ProfEnd(); + + ProfBegin("Load Inputs From Disk"); + String8Array thin_input_datas = lnk_read_data_from_file_path_parallel(tp, inputer->arena, io_flags, thin_input_paths); + for EachIndex(thin_input_idx, thin_inputs_count) { + thin_inputs[thin_input_idx]->has_disk_read_failed = thin_input_datas.v[thin_input_idx].size == 0; + thin_inputs[thin_input_idx]->data = thin_input_datas.v[thin_input_idx]; + } + ProfEnd(); + + ProfBegin("Disk Read Check"); + for EachIndex(i, thin_inputs_count) { + if (thin_inputs[i]->has_disk_read_failed) { + lnk_error(LNK_Error_InvalidPath, "unable to find file \"%S\"", thin_inputs[i]->path); + } + } + ProfEnd(); + + LNK_InputPtrArray result = lnk_array_from_input_list(arena, *new_inputs); + + lnk_input_list_concat_in_place(all_inputs, new_inputs); + + scratch_end(scratch); + return result; +} + +internal void +lnk_lib_member_ref_list_push_node(LNK_LibMemberRefList *list, LNK_LibMemberRef *node) +{ + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal int +lnk_lib_member_ref_is_before(void *raw_a, void *raw_b) +{ + LNK_LibMemberRef **a = raw_a, **b = raw_b; + LNK_Symbol *a_pull_in_ref = (*a)->lib->was_member_linked[(*a)->member_idx]; + LNK_Symbol *b_pull_in_ref = (*b)->lib->was_member_linked[(*b)->member_idx]; + return lnk_symbol_defined_is_before(a_pull_in_ref, b_pull_in_ref); +} + +internal LNK_LibMemberRef ** +lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list) +{ + LNK_LibMemberRef **result = push_array(arena, LNK_LibMemberRef *, list.count); + U64 idx = 0; + for (LNK_LibMemberRef *node = list.first; node != 0; node = node->next, idx += 1) { + result[idx] = node; + } + return result; +} + +internal LNK_ObjNode * +lnk_load_objs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out) +{ + ProfBegin("Input Objs [Count %llu]", inputer->new_objs.count); + Temp scratch = scratch_begin(arena->v, arena->count); + + // load obj inputer from disk + LNK_InputPtrArray new_input_objs = lnk_inputer_flush(arena->v[0], tp, inputer, config->io_flags, &inputer->objs, &inputer->new_objs); + + if (lnk_get_log_status(LNK_Log_InputObj) && new_input_objs.count) { + U64 input_size = 0; + for EachIndex(i, new_input_objs.count) { input_size += new_input_objs.v[i]->data.size; } + lnk_log(LNK_Log_InputObj, "[ Obj Input Size %M ]", input_size); + } + + LNK_ObjNode *new_objs = lnk_obj_from_input_many(tp, arena, config->machine, new_input_objs.count, new_input_objs.v); + + // if machine type was unspecified on the command line, derive it from obj file + if (config->machine == COFF_MachineType_Unknown) { + for EachIndex(obj_idx, new_input_objs.count) { + if (new_objs[obj_idx].data.header.machine != COFF_MachineType_Unknown) { + config->machine = new_objs[obj_idx].data.header.machine; + break; + } + } + } + + ProfBegin("Apply Directives"); + for EachIndex(obj_idx, new_input_objs.count) { + LNK_Obj *obj = &new_objs[obj_idx].data; + String8List raw_directives = lnk_raw_directives_from_obj(scratch.arena, obj); + LNK_DirectiveInfo directive_info = lnk_directive_info_from_raw_directives(scratch.arena, obj, raw_directives); + for EachIndex(i, ArrayCount(directive_info.v)) { + for (LNK_Directive *dir = directive_info.v[i].first; dir != 0; dir = dir->next) { + lnk_apply_cmd_option_to_config(config, dir->id, dir->value_list, obj); + } + } + } + ProfEnd(); + + if (objs_count_out) { + *objs_count_out = new_input_objs.count; + } + + scratch_end(scratch); + ProfEnd(); + return new_objs; +} + +internal void +lnk_load_libs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link) +{ + for EachIndex(input_source, LNK_InputSource_Count) { + ProfBegin("Input Libs [Count %llu]", inputer->new_libs[i].count); + + LNK_InputPtrArray new_input_libs = lnk_inputer_flush(arena->v[0], tp, inputer, config->io_flags, &inputer->libs, &inputer->new_libs[input_source]); + + if (lnk_get_log_status(LNK_Log_InputLib) && new_input_libs.count) { + U64 input_size = 0; + for EachIndex(i, new_input_libs.count) { input_size += new_input_libs.v[i]->data.size; } + lnk_log(LNK_Log_InputObj, "[ Lib Input Size %M ]", input_size); + } + + lnk_lib_list_push_parallel(tp, arena, &link->libs, new_input_libs.count, new_input_libs.v); + + ProfEnd(); + } +} + +internal void +lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link) +{ + Temp scratch = scratch_begin(arena->v, arena->count); + + U64 obj_id_base = link->objs.count; + + U64 objs_count = 0; + LNK_ObjNode *objs = lnk_load_objs(tp, arena, config, inputer, symtab, link, &objs_count); + lnk_obj_list_push_node_many(&link->objs, objs_count, objs); + + // handle /INCLUDE + { + // group include symbols by obj + HashTable *ht = hash_table_init(scratch.arena, 64); + for (LNK_IncludeSymbolNode *node = config->include_symbol_list.first; node != 0; node = node->next) { + LNK_IncludeSymbol *include_symbol = &node->v; + + // skip, include symbol is already in the global symbol table + if (lnk_symbol_table_search(symtab, include_symbol->name)) { + continue; + } + + // was obj already seen? + String8List *include_name_list = hash_table_search_raw_raw(ht, include_symbol->obj); + + if (include_name_list == 0) { + // push entry for new obj + include_name_list = push_array(scratch.arena, String8List, 1); + hash_table_push_raw_raw(scratch.arena, ht, include_symbol->obj, include_name_list); + } + + // append include symbol to obj's name list + str8_list_push(scratch.arena, include_name_list, include_symbol->name); + } + + LNK_Obj **objs_with_includes = keys_from_hash_table_raw(scratch.arena, ht); + String8List **include_names = values_from_hash_table_raw(scratch.arena, ht); + for EachIndex(i, ht->count) { + LNK_Obj *obj_with_includes = objs_with_includes[i]; + String8 include_obj_path = obj_with_includes ? obj_with_includes->path : str8_lit("RADLINK"); + String8 include_obj_data = lnk_make_obj_with_undefined_symbols(arena->v[0], *include_names[i]); + lnk_inputer_push_obj_linkgen(inputer, obj_with_includes ? obj_with_includes->trigger_symbol : 0, include_obj_path, include_obj_data); + + U64 include_obj_count = 0; + LNK_ObjNode *include_obj = lnk_load_objs(tp, arena, config, inputer, symtab, link, &include_obj_count); + AssertAlways(include_obj_count == 1); + + if (obj_with_includes) { + DLLInsert(link->objs.first, link->objs.last, obj_with_includes->node, include_obj); + link->objs.count += 1; + } else { + lnk_obj_list_push_node(&link->objs, include_obj); + } + } + } + + // assign input indices to objs + { + U64 node_idx = 0; + for (LNK_ObjNode *node = objs; node != 0; node = node->next, node_idx += 1) { + node->data.input_idx = obj_id_base + node_idx; + } + } + + // input indices on objs are finalized, push external symbols to the global symbol table + { + U64 new_objs_count = 0; + for (LNK_ObjNode *node = objs; node != 0; node = node->next) { new_objs_count += 1; } + + LNK_Obj **new_objs = push_array(scratch.arena, LNK_Obj *, new_objs_count); + { + U64 node_idx = 0; + for (LNK_ObjNode *node = objs; node != 0; node = node->next) { + new_objs[node_idx++] = &node->data; + } + } + + lnk_push_obj_symbols(tp, arena, symtab, new_objs_count, new_objs); + } + + // input default libraries + for (; *link->last_default_lib; link->last_default_lib = &(*link->last_default_lib)->next) { + lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Default, (*link->last_default_lib)->string); + } + + // input libraries referenced in objs + for (; *link->last_obj_lib; link->last_obj_lib = &(*link->last_obj_lib)->next) { + lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, (*link->last_obj_lib)->string); + } + + // load new libs + lnk_load_libs(tp, arena, config, inputer, link); + + scratch_end(scratch); +} + +internal void +lnk_resolve_entry_point(LNK_Config *config, LNK_SymbolTable *symtab, LNK_Link *link) +{ + // loop over all possible subsystems and entry point names and pick + // subsystem that has a defined entry point symbol + if (config->entry_point_name.size == 0) { + PE_WindowsSubsystem subsys_first = config->subsystem; + PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1; + LNK_Symbol *entry_point_symbol = 0; + for (U64 subsys_idx = subsys_first; subsys_idx < subsys_last; subsys_idx += 1) { + String8Array entry_points = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, entry_points.v[i]); + if (symbol) { + config->subsystem = subsys_idx; + config->entry_point_name = entry_points.v[i]; + goto found_entry_and_subsystem; + } + } + } +found_entry_and_subsystem:; + } + + // search for entry point in libs + if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); + for EachIndex(entry_idx, entry_points.count) { + for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, entry_points.v[entry_idx], 0)) { + config->entry_point_name = entry_points.v[entry_idx]; + goto found_entry_in_libs; + } + } + } +found_entry_in_libs:; + } + + // infer subsystem from entry point name + if (config->entry_point_name.size != 0 && config->subsystem == PE_WindowsSubsystem_UNKNOWN) { + for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { + String8Array entry_points = pe_get_entry_point_names(config->machine, subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + if (str8_match(entry_points.v[i], config->entry_point_name, 0)) { + config->subsystem = subsys_idx; + goto subsystem_inferred_from_entry; + } + } + } +subsystem_inferred_from_entry:; + } + + // do we have an entry point name? + if (config->entry_point_name.size) { + // redirect user entry to appropriate CRT entry + String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); + config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; + + // generate undefined symbol for entry point + lnk_include_symbol(config, config->entry_point_name, 0); + + // do we have a subsystem? + if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + // if subsystem version not specified set default values + if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { + config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); + } + + // check subsystem version against allowed min version + Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); + if (version_compar(config->subsystem_ver, min_subsystem_ver) < 0) { + lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", + config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); + } + + // by default terminal server is enabled for windows and console applications + if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { + if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { + config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; + } + } + + // entry point found! + link->try_to_resolve_entry_point = 0; + } else { + lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); + } + } +} + +internal void +lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *trigger_symbol, LNK_Lib *lib, U32 member_idx) +{ + if (lnk_flag_member_as_queued(lib, member_idx, trigger_symbol)) { + LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1); + member_ref->lib = lib; + member_ref->member_idx = member_idx; + + lnk_lib_member_ref_list_push_node(queued_members, member_ref); + + trigger_symbol->is_lib_member_linked = 1; + } +} + +internal void +lnk_link_inputs_(TP_Context *tp, + TP_Arena *arena, + LNK_Config *config, + LNK_Inputer *inputer, + LNK_SymbolTable *symtab, + LNK_Link *link, + LNK_ImportTables *imps, + B32 search_anti_deps) +{ + Temp scratch = scratch_begin(arena->v, arena->count); + + lnk_load_inputs(tp, arena, config, inputer, symtab, link); + + for (U64 resolved_members_count = 0; ; resolved_members_count = 0) { + if (link->try_to_resolve_entry_point) { + lnk_resolve_entry_point(config, symtab, link); + } + + for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { + do { + LNK_LibMemberRefList queued_members = {0}; + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + if (symbol->is_lib_member_linked) { continue; } + + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); + } + } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); + } + } else if (search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->defined); + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member(scratch.arena, &queued_members, symbol, &lib_n->data, member_idx); + } + } + } + } + } + } + } + + LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members); + radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before); + + // load lib member refs + for EachIndex(i, queued_members.count) { + LNK_LibMemberRef *member_ref = member_refs[i]; + LNK_Lib *lib = member_ref->lib; + U32 member_offset = lib->member_offsets[member_ref->member_idx]; + + // parse member + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); + COFF_DataType member_type = coff_data_type_from_data(member_info.data); + + switch (member_type) { + case COFF_DataType_Import: { + COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(member_info.data); + + // import machine compat check + if (import_header.machine != config->machine) { + lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)", + import_header.func_name, + coff_string_from_machine_type(import_header.machine), + coff_string_from_machine_type(config->machine)); + break; + } + + if (str8_match(import_header.func_name, str8_lit("LoadLibraryA"), 0)) { + int x = 0; + } + + // skip duplicate import inputer + if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name, 0)) { break; } + hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); + + // create import stubs (later replaced with acutal imports generated by linker) + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->defined.obj, import_stub->defined.symbol_idx); + LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(symtab->arena->v[0], "__imp_%S", import_header.func_name), import_stub->defined.obj, import_stub->defined.symbol_idx); + lnk_symbol_table_push(symtab, thunk_symbol); + lnk_symbol_table_push(symtab, imp_symbol); + + // search DLL symbol list + HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? imps->delayed_imports : imps->static_imports; + String8List *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + if (import_symbols == 0) { + import_symbols = push_array(imps->arena, String8List, 1); + hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols); + } + + // push symbol + str8_list_push(imps->arena, import_symbols, member_info.data); + } break; + case COFF_DataType_BigObj: + case COFF_DataType_Obj: { + String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); + + // obj path in thin archive has slash appended which screws up + // file lookup on disk; it couble be there to enable paths to symbols + // but we don't use this feature + String8 slash = str8_lit("/"); + if (str8_ends_with(obj_path, slash, 0)) { + obj_path = str8_chop(obj_path, slash.size); + } + + B32 is_thin = lib->type == COFF_Archive_Thin; + if (is_thin) { + + // obj path in thin archive is relative to directory with archive + String8List obj_path_list = {0}; + str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); + str8_list_push(scratch.arena, &obj_path_list, obj_path); + obj_path = str8_path_list_join_by_style(inputer->arena, &obj_path_list, config->path_style); + + lnk_inputer_push_obj_thin(inputer, member_ref, obj_path); + } else { + lnk_inputer_push_obj(inputer, member_ref, obj_path, member_info.data); + } + } break; + case COFF_DataType_Null: break; + default: { InvalidPath; } break; + } + } + + lnk_load_inputs(tp, arena, config, inputer, symtab, link); + + resolved_members_count += queued_members.count; + } while (lnk_inputer_has_items(inputer)); + } + + if (resolved_members_count == 0) { break; } + } + + scratch_end(scratch); +} + +internal void +lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, LNK_ImportTables *imps) +{ + lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 0); + + // input /ALTERNATENAME + { + // replace undefined symbols that have an alternate name with a weak symbol + for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->data.from); + if (symbol_ht) { + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); + if (interp == COFF_SymbolValueInterp_Undefined) { + // clear out slot so weak symbol can replace undefined symbol (general rule is + // weak symbol is not allowed to replace undefined) + symbol_ht->symbol = 0; + + // make obj with alternamte name symbol + String8 alt_name_obj_data; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); + COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.from, COFF_WeakExt_SearchLibrary, 0); + COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.to, COFF_WeakExt_AntiDependency, from_symbol); + coff_obj_writer_set_default_symbol(from_symbol, to_symbol); + alt_name_obj_data = coff_obj_writer_serialize(arena->v[0], obj_writer); + coff_obj_writer_release(&obj_writer); + } + + // input alt name obj + LNK_Obj *obj_with_alt_name = alt_name_n->data.obj; + String8 alt_name_obj_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); + lnk_inputer_push_obj_linkgen(inputer, 0, alt_name_obj_path, alt_name_obj_data); + } + } + } + } + + // + // include delay load helper + // + if (config->machine != COFF_MachineType_Unknown && config->delay_load_helper_name.size == 0 && config->delay_load_dll_list.node_count) { + config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); + if (config->delay_load_helper_name.size) { + lnk_include_symbol(config, config->delay_load_helper_name, 0); + } + } + + lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 1); +} + +internal +THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) +{ + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); + COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); + COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); + if (resolve_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); + if (symbol->defined.obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; + symbol32->section_number = COFF_Symbol_UndefinedSection; + symbol32->value = 0; + symbol32->storage_class = COFF_SymStorageClass_External; + } else { + COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; + symbol16->section_number = COFF_Symbol_UndefinedSection; + symbol16->value = 0; + symbol16->storage_class = COFF_SymStorageClass_External; + } + } else { + symbol->defined = resolve; + } + } + } +} + +internal LNK_Link * +lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab) +{ + Temp scratch = scratch_begin(arena->v, arena->count); + + // + // init link context + // + LNK_Link *link = push_array(arena->v[0], LNK_Link, 1); + link->last_include = &config->include_symbol_list.first; + link->last_default_lib = &config->input_default_lib_list.first; + link->last_obj_lib = &config->input_obj_lib_list.first; + link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first; + link->try_to_resolve_entry_point = 1; + + // + // init import hash tables + // + LNK_ImportTables *imps = 0; + { + Arena *imps_arena = arena_alloc(); + imps = push_array(imps_arena, LNK_ImportTables, 1); + imps->arena = imps_arena; + imps->static_imports = hash_table_init(imps->arena, 0x1000); + imps->delayed_imports = hash_table_init(imps->arena, 0x1000); + imps->import_stub_ht = hash_table_init(imps->arena, 0x10000); + } + + // input :null_obj + String8 null_obj = lnk_make_null_obj(inputer->arena); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null *"), null_obj); + + // input objs on command line + for (String8Node *obj_path = config->input_list[LNK_Input_Obj].first; obj_path != 0; obj_path = obj_path->next) { + lnk_inputer_push_obj_thin(inputer, 0, obj_path->string); + } + + // input libs from command line + for (; *link->last_cmd_lib; link->last_cmd_lib = &(*link->last_cmd_lib)->next) { + lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_CmdLine, (*link->last_cmd_lib)->string); + } + + // link inputer + lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); + + // TODO: need to know under which condition to include load config + //lnk_include_symbol(config, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME), 0); + + { + ProfBegin("Push Linker Symbols"); + String8 linker_symbols_obj = lnk_make_linker_obj(arena->v[0], config); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Linker Symbols *"), linker_symbols_obj); + ProfEnd(); + } + + // make and input delayed imports + { + HashTable *delayed_imports = imps->delayed_imports; + if (delayed_imports->count) { + ProfBegin("Build Delay Import Table"); + + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; + B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; + String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); + + for EachIndex(dll_idx, delayed_imports->count) { + String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); + String8 import_obj = pe_make_import_dll_obj_delayed(arena->v[0], time_stamp, config->machine, dll_names[dll_idx], config->delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); + lnk_inputer_push_obj(inputer, 0, dll_names[dll_idx], import_obj); + } + + String8 linker_debug_symbols = lnk_make_linker_debug_symbols(arena->v[0], config->machine); + String8 null_desc_obj = pe_make_null_import_descriptor_delayed(arena->v[0], time_stamp, config->machine, linker_debug_symbols); + String8 null_thunk_obj = pe_make_null_thunk_data_obj_delayed(arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + lnk_inputer_push_obj(inputer, 0, str8_lit("* Delayed Null Import Descriptor *"), null_desc_obj); + lnk_inputer_push_obj(inputer, 0, str8_lit("* Delayed Null Thunk Data *"), null_thunk_obj); + + ProfEnd(); + } + } + + // make and input static imports + { + HashTable *static_imports = imps->static_imports; + if (static_imports->count) { + ProfBegin("Build Static Import Table"); + + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); + for EachIndex(dll_idx, static_imports->count) { + String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); + String8 import_obj = pe_make_import_dll_obj_static(arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); + lnk_inputer_push_obj(inputer, 0, dll_names[dll_idx], import_obj); + } + + String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); + String8 null_desc_obj = pe_make_null_import_descriptor_obj(arena->v[0], time_stamp, config->machine, linker_debug_symbols); + String8 null_thunk_obj = pe_make_null_thunk_data_obj(arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null Import Descriptor *"), null_desc_obj); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null Thunk Data *"), null_thunk_obj); + + ProfEnd(); + } + } + + if (config->export_symbol_list.count) { + ProfBegin("Build Export Table"); + + PE_ExportParseList resolved_exports = {0}; + for (PE_ExportParseNode *exp_n = config->export_symbol_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) { + exp_n_next = exp_n->next; + PE_ExportParse *exp = &exp_n->data; + + if (str8_match(exp->name, config->entry_point_name, 0)) { + lnk_error_with_loc(LNK_Warning_TryingToExportEntryPoint, exp->obj_path, exp->lib_path, "exported entry point \"%S\"", exp->name); + } + if (str8_match(exp->alias, config->entry_point_name, 0)) { + lnk_error_with_loc(LNK_Warning_TryingToExportEntryPoint, exp->obj_path, exp->lib_path, "alias exports entry point \"%S=%S\"", exp->name, exp->alias); + continue; + } + + if (!exp->is_forwarder) { + // filter out unresolved exports + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, exp_n->data.name); + if (symbol == 0) { + lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "unresolved export symbol %S\n", exp->name); + continue; + } + } + + // push resolved export + pe_export_parse_list_push_node(&resolved_exports, exp_n); + } + + PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports); + String8 edata_obj = pe_make_edata_obj(arena->v[0], str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Exports *"), edata_obj); + + ProfEnd(); + } + + { + String8List res_data_list = {0}; + String8List res_path_list = {0}; + + // do we have manifest deps passed through pragma alone? + LNK_ManifestOpt manifest_opt = config->manifest_opt; + if (config->manifest_dependency_list.node_count > 0 && manifest_opt == LNK_ManifestOpt_Null) { + manifest_opt = LNK_ManifestOpt_Embed; + } + + switch (manifest_opt) { + case LNK_ManifestOpt_Embed: { + ProfBegin("Embed Manifest"); + // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest + // resource to the tree directly + String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, config->input_list[LNK_Input_Manifest], config->manifest_dependency_list); + String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data); + str8_list_push(scratch.arena, &res_data_list, manifest_res); + str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); + ProfEnd(); + } break; + case LNK_ManifestOpt_WriteToFile: { + ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); + Temp temp = temp_begin(scratch.arena); + String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, config->input_list[LNK_Input_Manifest], config->manifest_dependency_list); + lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data); + temp_end(temp); + ProfEnd(); + } break; + case LNK_ManifestOpt_Null: { + Assert(config->input_list[LNK_Input_Manifest].node_count == 0); + Assert(config->manifest_dependency_list.node_count == 0); + } break; + case LNK_ManifestOpt_No: { + // omit manifest generation + } break; + } + + ProfBegin("Load .res files from disk"); + for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { + String8 res_data = lnk_read_data_from_file_path(scratch.arena, config->io_flags, node->string); + if (res_data.size > 0) { + if (pe_is_res(res_data)) { + str8_list_push(scratch.arena, &res_data_list, res_data); + String8 stable_res_path = lnk_make_full_path(scratch.arena, config->path_style, config->work_dir, node->string); + str8_list_push(scratch.arena, &res_path_list, stable_res_path); + } else { + lnk_error(LNK_Error_LoadRes, "file is not of RES format: %S", node->string); + } + } else { + lnk_error(LNK_Error_LoadRes, "unable to open res file: %S", node->string); + } + } + ProfEnd(); + + if (res_data_list.node_count > 0) { + ProfBegin("Build * Resources *"); + String8 obj_name = str8_lit("* Resources *"); + String8 obj_data = lnk_make_res_obj(arena->v[0], res_data_list, res_path_list, config->machine, config->time_stamp, config->work_dir, config->path_style, obj_name); + lnk_inputer_push_obj_linkgen(inputer, 0, obj_name, obj_data); + ProfEnd(); + } + } + + if (lnk_do_debug_info(config)) { + { + ProfBegin("Build * Linker * Obj"); + String8 obj_name = str8_lit("* Linker *"); + String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }); + String8 obj_data = lnk_make_linker_coff_obj(arena->v[0], config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name); + lnk_inputer_push_obj_linkgen(inputer, 0, obj_name, obj_data); + ProfEnd(); + } + + ProfBegin("Build * Debug Directories *"); + if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { + String8 pdb_dir_obj = pe_make_debug_directory_pdb_obj(arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Debug Directory PDB *"), pdb_dir_obj); + } + if (config->rad_debug == LNK_SwitchState_Yes) { + String8 rdi_dir_obj = pe_make_debug_directory_rdi_obj(arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Debug Directory RDI *"), rdi_dir_obj); + } + ProfEnd(); + } + + // + // link linker made objs + // + lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); + + // + // warn about unused delayloads + // + if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) { + for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { + if (!hash_table_search_path_raw(imps->delayed_imports, dll_name_n->string)) { + lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string); + } + } + } + + // + // report undefined symbols + // + { + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); + + ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); + { + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); +#if BUILD_DEBUG + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); + } + } +#endif + } + ProfEnd(); + + + if (config->entry_point_name.size == 0) { + lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); + } + + ProfBegin("Report Unresolved Symbols"); + { + U64 count = 0; + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + count += 1; + } + } + } + + U64 cursor = 0; + LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + unresolved[cursor++] = chunk->v[i].symbol; + } + } + } + + radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); + + for EachIndex(i, count) { + LNK_Symbol *symbol = unresolved[i]; + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); + } + + // TODO: /FORCE + if (count) { + lnk_exit(LNK_Error_UnresolvedSymbol); + } + } + ProfEnd(); + } + + // + // discard COMDAT sections that are not referenced + // + if (config->opt_ref == LNK_SwitchState_Yes) { + lnk_opt_ref(tp, symtab, config, link->objs); + } + + // + // infer minimal padding size for functions from the target machine + // + if (config->machine != COFF_MachineType_Unknown && config->infer_function_pad_min) { + config->function_pad_min = lnk_get_default_function_pad_min(config->machine); + config->infer_function_pad_min = 0; + } + + // + // log + // + if (lnk_get_log_status(LNK_Log_InputObj)) { + U64 total_input_size = 0; + for (LNK_ObjNode *obj_n = link->objs.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; } + lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size); + } + if (lnk_get_log_status(LNK_Log_InputLib)) { + U64 total_input_size = 0; + for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; } + lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); + } + + scratch_end(scratch); + return link; } internal void @@ -1053,17 +2085,15 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj // define roots // { - String8List roots = str8_list_copy(scratch.arena, &config->include_symbol_list); - // tls LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME); if (tls_symbol) { - str8_list_pushf(scratch.arena, &roots, MSCRT_TLS_SYMBOL_NAME); + lnk_include_symbol(config, str8_lit(MSCRT_TLS_SYMBOL_NAME), 0); } // push tasks for each root symbol - for (String8Node *root_n = roots.first; root_n != 0; root_n = root_n->next) { - LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->string); + for (LNK_IncludeSymbolNode *root_n = config->include_symbol_list.first; root_n != 0; root_n = root_n->next) { + LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); struct Task *t = push_array(scratch.arena, struct Task, 1); t->obj = root->defined.obj; @@ -1193,10 +2223,12 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj ProfBegin("Remove Unreachable Sections"); for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { LNK_Obj *obj = &obj_n->data; + for EachIndex(sect_idx, obj->header.section_count_no_null) { U32 section_number = sect_idx+1; COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } // remove unreferenced sections @@ -1225,1058 +2257,6 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj ProfEnd(); } -internal -THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) -{ - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); - COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); - COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); - if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); - if (symbol->defined.obj->header.is_big_obj) { - COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; - symbol32->section_number = COFF_Symbol_UndefinedSection; - symbol32->value = 0; - symbol32->storage_class = COFF_SymStorageClass_External; - } else { - COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; - symbol16->section_number = COFF_Symbol_UndefinedSection; - symbol16->value = 0; - symbol16->storage_class = COFF_SymStorageClass_External; - } - } else { - symbol->defined = resolve; - } - } - } -} - -internal LNK_LinkContext -lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) -{ - enum State { - State_Null, - State_InputDisallowLibs, - State_InputImports, - State_InputInclude, - State_InputObjs, - State_InputLibs, - State_InputDelayLoadDlls, - State_InputLinkerObjs, - State_SearchUndefinedAndWeak, - State_SearchWeakAntiDep, - State_SearchEntryPoint, - }; - struct StateNode { struct StateNode *next; enum State state; }; - struct StateList { U64 count; struct StateNode *first; struct StateNode *last; }; -#define state_list_push(a, l, s) do { \ - struct StateNode *node = push_array(a, struct StateNode, 1); \ - node->state = s; \ - SLLQueuePush(l.first, l.last, node); \ - l.count += 1; \ -} while (0) -#define state_list_pop(l) (l).first->state; SLLQueuePop((l).first, (l).last); (l).count -= 1 - typedef enum { - SearchFlag_UndefinedAndWeak = (1 << 0), - SearchFlag_WeakAntiDep = (1 << 1), - SearchFlag_All = (SearchFlag_UndefinedAndWeak|SearchFlag_WeakAntiDep) - } SearchFlags; - - ProfBeginFunction(); - Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); - - // - // state - // - LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); - String8Node **last_include_symbol = &config->include_symbol_list.first; - String8Node **last_disallow_lib = &config->disallow_lib_list.first; - String8Node **last_delay_load_dll = &config->delay_load_dll_list.first; - LNK_InputObjList input_obj_list = {0}; - LNK_InputImportList input_import_list = {0}; - LNK_InputLib **input_libs[LNK_InputSource_Count] = { &config->input_list[LNK_Input_Lib].first, &config->input_default_lib_list.first, &config->input_obj_lib_list.first }; - LNK_ObjList obj_list = {0}; - LNK_LibList lib_index[LNK_InputSource_Count] = {0}; - U64 entry_point_search_attempts = 0; - SearchFlags search_flags = SearchFlag_All; - B32 input_linker_objs = 1; - HashTable *static_imports = hash_table_init(scratch.arena, 512); - HashTable *delayed_imports = hash_table_init(scratch.arena, 512); - HashTable *import_stub_ht = hash_table_init(scratch.arena, 0x1000); - // TODO: move disallow_lib, loaded_lib, missing_lib, and loaded_obj to config - Arena *ht_arena = arena_alloc(); - HashTable *disallow_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *loaded_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *missing_lib_ht = hash_table_init(scratch.arena, 0x100); - HashTable *loaded_obj_ht = hash_table_init(scratch.arena, 0x4000); - - // TODO: this should happen in the config before state machine setup - { - // input :null_obj - LNK_InputObj *null_obj_input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - null_obj_input->exclude_from_debug_info = 1; - null_obj_input->path = str8_lit("* Null Obj *"); - null_obj_input->dedup_id = null_obj_input->path; - null_obj_input->data = lnk_make_null_obj(tp_arena->v[0]); - - // input command line objs - LNK_InputObjList cmd_line_obj_inputs = lnk_input_obj_list_from_string_list(scratch.arena, config->input_list[LNK_Input_Obj]); - lnk_input_obj_list_concat_in_place(&input_obj_list, &cmd_line_obj_inputs); - } - - // TODO: MSVC does not need this flag to include load config - if (config->guard_flags != LNK_Guard_None) { - // TODO: config_refactor - String8List value_strings = {0}; - str8_list_push(scratch.arena, &value_strings, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - } - - // - // run states - // - struct StateList state_list = {0}; - for (;;) { - for (; state_list.count > 0; ) { - enum State state = state_list_pop(state_list); - switch (state) { - case State_Null: break; - - case State_InputDisallowLibs: { - ProfBegin("Input /disallowlib"); - for (; *last_disallow_lib; last_disallow_lib = &(*last_disallow_lib)->next) { - if ( ! lnk_is_lib_disallowed(disallow_lib_ht, (*last_disallow_lib)->string)) { - lnk_push_disallow_lib(scratch.arena, disallow_lib_ht, (*last_disallow_lib)->string); - } - } - ProfEnd(); - } break; - case State_InputImports: { - ProfBegin("Input Imports"); - for (LNK_InputImportNode *input = input_import_list.first; input != 0; input = input->next) { - COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(input->data.coff_import); - - // import machine compat check - if (import_header.machine != config->machine) { - lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)", - import_header.func_name, - coff_string_from_machine_type(import_header.machine), - coff_string_from_machine_type(config->machine)); - continue; - } - - // skip duplicate import inputs - if (hash_table_search_string_raw(import_stub_ht, import_header.func_name, 0)) { continue; } - hash_table_push_string_raw(ht_arena, import_stub_ht, import_header.func_name, 0); - - // create import stubs (later replaced with acutal imports generated by linker) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->defined.obj, import_stub->defined.symbol_idx); - LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->defined.obj, import_stub->defined.symbol_idx); - lnk_symbol_table_push(symtab, thunk_symbol); - lnk_symbol_table_push(symtab, imp_symbol); - - // pick imports hash table - HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? delayed_imports : static_imports; - - // search DLL symbol list - String8List *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); - if (import_symbols == 0) { - import_symbols = push_array(scratch.arena, String8List, 1); - hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols); - } - - // push symbol - str8_list_push(scratch.arena, import_symbols, input->data.coff_import); - } - - search_flags = SearchFlag_All; - - // reset input - MemoryZeroStruct(&input_import_list); - - ProfEnd(); - } break; - case State_InputInclude: { - ProfBegin("Input Include"); - - // push a relocation which references an undefined include symbol - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".radinc$"), 0, str8_zero()); - for (; *last_include_symbol; last_include_symbol = &(*last_include_symbol)->next) { - COFF_ObjSymbol *include_symbol = coff_obj_writer_push_symbol_undef(obj_writer, (*last_include_symbol)->string); - coff_obj_writer_section_push_reloc(obj_writer, sect, 0, include_symbol, 0); - } - - // input obj with includes - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->exclude_from_debug_info = 1; - input->path = str8_lit("* INCLUDE SYMBOLS *"); - input->dedup_id = push_str8f(scratch.arena, "%S %llu", input->path, obj_list.count); - input->data = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); - - coff_obj_writer_release(&obj_writer); - - ProfEnd(); - } break; - case State_InputObjs: { - ProfBegin("Input Objs [Count %llu]", input_obj_list.count); - - ProfBegin("Collect Obj Paths"); - LNK_InputObjList unique_obj_input_list = {0}; - for (LNK_InputObj *input = input_obj_list.first, *next; input != 0; input = next) { - next = input->next; - - B32 was_obj_loaded = hash_table_search_path_u64(loaded_obj_ht, input->dedup_id, 0); - if (was_obj_loaded) { continue; } - - if (input->is_thin) { - String8 full_path = input->dedup_id.size ? os_full_path_from_path(scratch.arena, input->dedup_id) : str8_zero(); - B32 was_full_path_used = hash_table_search_path_u64(loaded_obj_ht, full_path, 0); - if (was_full_path_used) { continue; } - if (!str8_match(input->dedup_id, full_path, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive)) { - hash_table_push_path_u64(scratch.arena, loaded_obj_ht, full_path, 0); - } - } - - hash_table_push_path_u64(scratch.arena, loaded_obj_ht, input->dedup_id, 0); - - lnk_input_obj_list_push_node(&unique_obj_input_list, input); - - lnk_log(LNK_Log_InputObj, "Input Obj: %S", input->path); - } - ProfEnd(); - - ProfBegin("Load Objs From Disk"); - U64 thin_inputs_count = 0; - LNK_InputObj **thin_inputs = lnk_thin_array_from_input_obj_list(scratch.arena, unique_obj_input_list, &thin_inputs_count); - String8Array thin_input_paths = lnk_path_array_from_input_obj_array(scratch.arena, thin_inputs, thin_inputs_count); - String8Array thin_input_datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], config->io_flags, thin_input_paths); - for EachIndex(thin_input_idx, thin_inputs_count) { - thin_inputs[thin_input_idx]->has_disk_read_failed = thin_input_datas.v[thin_input_idx].size == 0; - thin_inputs[thin_input_idx]->data = thin_input_datas.v[thin_input_idx]; - } - ProfEnd(); - - ProfBegin("Disk Read Check"); - LNK_InputObj **input_obj_arr = lnk_array_from_input_obj_list(scratch.arena, unique_obj_input_list); - for EachIndex(input_idx, unique_obj_input_list.count) { - if (input_obj_arr[input_idx]->has_disk_read_failed) { - lnk_error(LNK_Error_InvalidPath, "unable to find obj \"%S\"", input_obj_arr[input_idx]->path); - } - } - ProfEnd(); - - if (lnk_get_log_status(LNK_Log_InputObj)) { - U64 input_size = 0; - for EachIndex(i, unique_obj_input_list.count) { input_size += input_obj_arr[i]->data.size; } - lnk_log(LNK_Log_InputObj, "[ Obj Input Size %M ]", input_size); - } - - LNK_ObjNodeArray obj_node_arr = lnk_obj_list_push_parallel(tp, tp_arena, &obj_list, config->machine, unique_obj_input_list.count, input_obj_arr); - - // if the machine was omitted on the command line, derive machine from obj - if (config->machine == COFF_MachineType_Unknown) { - for EachIndex(obj_idx, obj_node_arr.count) { - if (obj_node_arr.v[obj_idx].data.header.machine != COFF_MachineType_Unknown) { - config->machine = obj_node_arr.v[obj_idx].data.header.machine; - break; - } - } - } - - ProfBegin("Apply Directives"); - for EachIndex(obj_idx, obj_node_arr.count) { - LNK_Obj *obj = &obj_node_arr.v[obj_idx].data; - String8List raw_directives = lnk_raw_directives_from_obj(scratch.arena, obj); - LNK_DirectiveInfo directive_info = lnk_directive_info_from_raw_directives(scratch.arena, obj, raw_directives); - for EachIndex(i, ArrayCount(directive_info.v)) { - for (LNK_Directive *dir = directive_info.v[i].first; dir != 0; dir = dir->next) { - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, dir->id, dir->value_list, obj); - } - } - } - ProfEnd(); - - // input extern symbols from each obj to the symbol table - lnk_input_obj_symbols(tp, tp_arena, symtab, obj_node_arr); - - // schedule symbol input - search_flags = SearchFlag_All; - - // reset input objs - MemoryZeroStruct(&input_obj_list); - - // replace undefined symbols that have an alternate name with a weak symbol - for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { - LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->data.from); - if (symbol_ht) { - COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); - if (interp == COFF_SymbolValueInterp_Undefined) { - // clear out slot so weak symbol can replace undefined symbol - symbol_ht->symbol = 0; - - // make obj with alternamte name symbol - String8 alt_name_obj; - { - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.from, COFF_WeakExt_SearchLibrary, 0); - COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.to, COFF_WeakExt_AntiDependency, from_symbol); - coff_obj_writer_set_default_symbol(from_symbol, to_symbol); - alt_name_obj = coff_obj_writer_serialize(tp_arena->v[0], obj_writer); - coff_obj_writer_release(&obj_writer); - } - - // input alt name obj - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = alt_name_n->data.obj ? alt_name_n->data.obj->path : str8_lit("RADLINK"); - input->exclude_from_debug_info = 1; - input->dedup_id = push_str8f(scratch.arena, "* ALTERNATE NAME FOR %S=%S %u *", alt_name_n->data.from, alt_name_n->data.to, obj_list.count); - input->data = alt_name_obj; - input->lib = alt_name_n->data.obj ? alt_name_n->data.obj->lib : 0; - } - } - } - } - - ProfEnd(); - } break; - case State_InputLibs: { - ProfBegin("Input Libs"); - - // input libs from command line only - U64 input_source_opl = config->no_default_libs ? LNK_InputSource_Default: LNK_InputSource_Count; - for EachIndex(input_source, input_source_opl) { - ProfBeginV("Input Source %S", lnk_string_from_input_source(input_source)); - - Temp temp = temp_begin(scratch.arena); - LNK_InputLibList unique_input_lib_list = {0}; - - ProfBegin("Collect unique input libs"); - for (; *input_libs[input_source] != 0; input_libs[input_source] = &(*input_libs[input_source])->next) { - String8 path = (*input_libs[input_source])->string; - - if (input_source == LNK_InputSource_Default || input_source == LNK_InputSource_Obj) { - if (!str8_ends_with(path, str8_lit(".lib"), StringMatchFlag_CaseInsensitive)) { - path = push_str8f(temp.arena, "%S.lib", path); - } - if (lnk_is_lib_disallowed(disallow_lib_ht, path)) { - continue; - } - } - - if (lnk_is_lib_loaded(loaded_lib_ht, path)) { - continue; - } - - // search disk for library - String8List match_list = lnk_file_search(temp.arena, config->lib_dir_list, path); - - // warn about missing lib - if (match_list.node_count == 0) { - KeyValuePair *was_reported = hash_table_search_path(missing_lib_ht, path); - if (was_reported == 0) { - hash_table_push_path_u64(ht_arena, missing_lib_ht, path, 0); - lnk_error(LNK_Warning_FileNotFound, "unable to find library `%S`", path); - } - continue; - } - - // pick first match - String8 full_path = str8_list_first(&match_list); - - if (lnk_is_lib_loaded(loaded_lib_ht, full_path)) { - continue; - } - - // warn about multiple matches - if (match_list.node_count > 1) { - lnk_error(LNK_Warning_MultipleLibMatch, "multiple libs match `%S` (picking first match)", path); - lnk_supplement_error_list(match_list); - } - - // push library for loading - str8_list_push(temp.arena, &unique_input_lib_list, full_path); - - // save paths for future checks - lnk_push_loaded_lib(ht_arena, loaded_lib_ht, path); - lnk_push_loaded_lib(ht_arena, loaded_lib_ht, full_path); - - lnk_log(LNK_Log_InputLib, "Input Lib: %S", full_path); - } - ProfEnd(); - - ProfBegin("Disk Read Libs"); - String8Array paths = str8_array_from_list(temp.arena, &unique_input_lib_list); - String8Array datas = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], config->io_flags, paths); - ProfEnd(); - - ProfBegin("Lib Init"); - LNK_LibNodeArray libs = lnk_lib_list_push_parallel(tp, tp_arena, &lib_index[input_source], datas, paths); - ProfEnd(); - - if (lnk_get_log_status(LNK_Log_InputLib)) { - if (libs.count > 0) { - U64 input_size = 0; - for EachIndex(i, libs.count) { input_size += libs.v[i]->data.data.size; } - lnk_log(LNK_Log_InputObj, "[ Lib Input Size %M ]", input_size); - } - } - - temp_end(temp); - ProfEnd(); - } - - // schedule symbol input - search_flags = SearchFlag_All; - - ProfEnd(); - } break; - case State_InputDelayLoadDlls: { - ProfBegin("Input Delay Load Dlls"); - - // skip input delay load dlls - for (; *last_delay_load_dll; last_delay_load_dll = &(*last_delay_load_dll)->next); - - // establish delay load helper name - config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); - - // TODO: config_refactor - String8List value_strings = {0}; - str8_list_push(scratch.arena, &value_strings, config->delay_load_helper_name); - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - - ProfEnd(); - } break; - case State_SearchUndefinedAndWeak: { - ProfBegin("Search Undefined And Weak"); - LNK_InputImportList new_imports = {0}; - LNK_InputObjList new_objs = {0}; - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); - } - } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); - } - } - } - } - } - } - if (new_imports.count || new_objs.count) { - goto end_search_undefined; - } - } - } - end_search_undefined:; - - { - LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); - radsort(import_nodes, new_imports.count, lnk_input_import_is_before); - new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); - - LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); - radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); - new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); - - lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); - lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); - } - - ProfEnd(); - } break; - case State_SearchWeakAntiDep: { - ProfBegin("Search Weak AntiDep"); - LNK_InputImportList new_imports = {0}; - LNK_InputObjList new_objs = {0}; - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->defined); - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &new_imports, &new_objs); - } - } - } - } - } - } - } - if (new_imports.count || new_objs.count) { - goto end_search_antidep; - } - } - } - end_search_antidep:; - - { - LNK_InputImportNode **import_nodes = lnk_input_import_arr_from_list(scratch.arena, new_imports); - radsort(import_nodes, new_imports.count, lnk_input_import_is_before); - new_imports = lnk_list_from_input_import_arr(import_nodes, new_imports.count); - - LNK_InputObj **obj_nodes = lnk_array_from_input_obj_list(scratch.arena, new_objs); - radsort(obj_nodes, new_objs.count, lnk_input_obj_compar_is_before); - new_objs = lnk_list_from_input_obj_arr(obj_nodes, new_objs.count); - - lnk_input_import_list_concat_in_place(&input_import_list, &new_imports); - lnk_input_obj_list_concat_in_place(&input_obj_list, &new_objs); - } - - ProfEnd(); - } break; - case State_SearchEntryPoint: { - ProfBegin("Search Entry Point"); - - // loop over all possible subsystems and entry point names and pick - // subsystem that has a defined entry point symbol - if (config->entry_point_name.size == 0) { - PE_WindowsSubsystem subsys_first = config->subsystem; - PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1; - LNK_Symbol *entry_point_symbol = 0; - for (U64 subsys_idx = subsys_first; subsys_idx < subsys_last; subsys_idx += 1) { - String8Array entry_points = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for EachIndex(i, entry_points.count) { - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, entry_points.v[i]); - if (symbol) { - config->subsystem = subsys_idx; - config->entry_point_name = entry_points.v[i]; - goto found_entry_and_subsystem; - } - } - } - found_entry_and_subsystem:; - } - - // search for entry point in libs - if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) { - String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); - for EachIndex(entry_idx, entry_points.count) { - for EachIndex(i, ArrayCount(lib_index)) { - for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { - if (lnk_search_lib(&lib_n->data, entry_points.v[entry_idx], 0)) { - config->entry_point_name = entry_points.v[entry_idx]; - goto found_entry_in_libs; - } - } - } - } - found_entry_in_libs:; - } - - // infer subsystem from entry point name - if (config->entry_point_name.size != 0 && config->subsystem == PE_WindowsSubsystem_UNKNOWN) { - for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { - String8Array entry_points = pe_get_entry_point_names(config->machine, subsys_idx, config->file_characteristics); - for EachIndex(i, entry_points.count) { - if (str8_match(entry_points.v[i], config->entry_point_name, 0)) { - config->subsystem = subsys_idx; - goto subsystem_inferred_from_entry; - } - } - } - subsystem_inferred_from_entry:; - } - - // do we have an entry point name? - if (config->entry_point_name.size) { - // redirect user entry to appropriate CRT entry - String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); - config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; - - // generate undefined symbol for entry point - // - // TODO: config_refactor - String8List value_strings = {0}; - str8_list_push(scratch.arena, &value_strings, config->entry_point_name); - lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); - - // do we have a subsystem? - if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { - // if subsystem version not specified set default values - if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { - config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); - } - - // check subsystem version against allowed min version - Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); - if (version_compar(config->subsystem_ver, min_subsystem_ver) < 0) { - lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", - config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); - } - - // by default terminal server is enabled for windows and console applications - if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { - if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { - config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; - } - } - } else { - lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); - } - } - - ProfEnd(); - } break; - case State_InputLinkerObjs: { - { - ProfBegin("Push Linker Symbols"); - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Linker Symbols *"); - input->exclude_from_debug_info = 1; - input->dedup_id = input->path; - input->data = lnk_make_linker_obj(tp_arena->v[0], config); - ProfEnd(); - } - - // warn about unused delayloads - if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) { - for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { - if (!hash_table_search_path_raw(delayed_imports, dll_name_n->string)) { - lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string); - } - } - } - - // make and input delayed imports - if (delayed_imports->count) { - ProfBegin("Build Delay Import Table"); - - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; - B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); - - for EachIndex(dll_idx, delayed_imports->count) { - String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_import_dll_obj_delayed(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], config->delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); - input->path = dll_names[dll_idx]; - input->dedup_id = input->path; - } - String8 linker_debug_symbols = lnk_make_linker_debug_symbols(tp_arena->v[0], config->machine); - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->exclude_from_debug_info = 1; - input->data = pe_make_null_import_descriptor_delayed(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Import Descriptor *"); - input->dedup_id = input->path; - } - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->exclude_from_debug_info = 1; - input->data = pe_make_null_thunk_data_obj_delayed(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Null Thunk Data *"); - input->dedup_id = input->path; - } - - ProfEnd(); - } - - // make and input static imports - if (static_imports->count) { - ProfBegin("Build Static Import Table"); - - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); - for EachIndex(dll_idx, static_imports->count) { - String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->data = pe_make_import_dll_obj_static(tp_arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); - input->path = dll_names[dll_idx]; - input->dedup_id = dll_names[dll_idx]; - } - String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->exclude_from_debug_info = 1; - input->data = pe_make_null_import_descriptor_obj(tp_arena->v[0], time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Import Descriptor *"); - input->dedup_id = input->path; - } - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = obj_list.count; - input->exclude_from_debug_info = 1; - input->data = pe_make_null_thunk_data_obj(tp_arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Null Thunk Data *"); - input->dedup_id = input->path; - } - - ProfEnd(); - } - - if (config->export_symbol_list.count) { - ProfBegin("Build Export Table"); - - PE_ExportParseList resolved_exports = {0}; - for (PE_ExportParseNode *exp_n = config->export_symbol_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) { - exp_n_next = exp_n->next; - PE_ExportParse *exp = &exp_n->data; - - if (str8_match(exp->name, config->entry_point_name, 0)) { - lnk_error_with_loc(LNK_Warning_TryingToExportEntryPoint, exp->obj_path, exp->lib_path, "exported entry point \"%S\"", exp->name); - } - if (str8_match(exp->alias, config->entry_point_name, 0)) { - lnk_error_with_loc(LNK_Warning_TryingToExportEntryPoint, exp->obj_path, exp->lib_path, "alias exports entry point \"%S=%S\"", exp->name, exp->alias); - continue; - } - - if (!exp->is_forwarder) { - // filter out unresolved exports - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, exp_n->data.name); - if (symbol == 0) { - lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "unresolved export symbol %S\n", exp->name); - continue; - } - } - - // push resolved export - pe_export_parse_list_push_node(&resolved_exports, exp_n); - } - - PE_FinalizedExports finalized_exports = pe_finalize_export_list(scratch.arena, resolved_exports); - String8 edata_obj = pe_make_edata_obj(tp_arena->v[0], str8_skip_last_slash(config->image_name), COFF_TimeStamp_Max, config->machine, finalized_exports); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Exports *"); - input->dedup_id = input->path; - input->data = edata_obj; - - ProfEnd(); - } - - { - String8List res_data_list = {0}; - String8List res_path_list = {0}; - - // do we have manifest deps passed through pragma alone? - LNK_ManifestOpt manifest_opt = config->manifest_opt; - if (config->manifest_dependency_list.node_count > 0 && manifest_opt == LNK_ManifestOpt_Null) { - manifest_opt = LNK_ManifestOpt_Embed; - } - - switch (manifest_opt) { - case LNK_ManifestOpt_Embed: { - ProfBegin("Embed Manifest"); - // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest - // resource to the tree directly - String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, config->input_list[LNK_Input_Manifest], config->manifest_dependency_list); - String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data); - str8_list_push(scratch.arena, &res_data_list, manifest_res); - str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); - ProfEnd(); - } break; - case LNK_ManifestOpt_WriteToFile: { - ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); - Temp temp = temp_begin(scratch.arena); - String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->io_flags, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, config->input_list[LNK_Input_Manifest], config->manifest_dependency_list); - lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data); - temp_end(temp); - ProfEnd(); - } break; - case LNK_ManifestOpt_Null: { - Assert(config->input_list[LNK_Input_Manifest].node_count == 0); - Assert(config->manifest_dependency_list.node_count == 0); - } break; - case LNK_ManifestOpt_No: { - // omit manifest generation - } break; - } - - ProfBegin("Load .res files from disk"); - for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { - String8 res_data = lnk_read_data_from_file_path(scratch.arena, config->io_flags, node->string); - if (res_data.size > 0) { - if (pe_is_res(res_data)) { - str8_list_push(scratch.arena, &res_data_list, res_data); - String8 stable_res_path = lnk_make_full_path(scratch.arena, config->path_style, config->work_dir, node->string); - str8_list_push(scratch.arena, &res_path_list, stable_res_path); - } else { - lnk_error(LNK_Error_LoadRes, "file is not of RES format: %S", node->string); - } - } else { - lnk_error(LNK_Error_LoadRes, "unable to open res file: %S", node->string); - } - } - ProfEnd(); - - if (res_data_list.node_count > 0) { - ProfBegin("Build * Resources *"); - - String8 obj_name = str8_lit("* Resources *"); - String8 obj_data = lnk_make_res_obj(tp_arena->v[0], - res_data_list, - res_path_list, - config->machine, - config->time_stamp, - config->work_dir, - config->path_style, - obj_name); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->dedup_id = obj_name; - input->path = obj_name; - input->data = obj_data; - - ProfEnd(); - } - } - - if (lnk_do_debug_info(config)) { - { - ProfBegin("Build * Linker * Obj"); - - String8 obj_name = str8_lit("* Linker *"); - String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }); - String8 obj_data = lnk_make_linker_coff_obj(tp_arena->v[0], config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->dedup_id = obj_name; - input->path = obj_name; - input->data = obj_data; - - ProfEnd(); - } - - { - ProfBegin("Build * Debug Directories *"); - if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->exclude_from_debug_info = 1; - input->path = str8_lit("* Debug Directory PDB *"); - input->dedup_id = input->path; - input->data = pe_make_debug_directory_pdb_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->pdb_alt_path); - } - if (config->rad_debug == LNK_SwitchState_Yes) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->exclude_from_debug_info = 1; - input->path = str8_lit("* Debug Directory RDI *"); - input->dedup_id = input->path; - input->data = pe_make_debug_directory_rdi_obj(tp_arena->v[0], config->machine, config->guid, config->age, config->time_stamp, config->rad_debug_alt_path); - } - ProfEnd(); - } - } - } break; - } - } - - if (*last_disallow_lib) { - state_list_push(scratch.arena, state_list, State_InputDisallowLibs); - continue; - } - if (input_import_list.count) { - state_list_push(scratch.arena, state_list, State_InputImports); - continue; - } - if (*last_include_symbol) { - state_list_push(scratch.arena, state_list, State_InputInclude); - continue; - } - { - B32 have_pending_lib_inputs = 0; - for EachIndex(i, ArrayCount(input_libs)) { - if (*input_libs[i] != 0) { - have_pending_lib_inputs = 1; - break; - } - } - if (have_pending_lib_inputs) { - state_list_push(scratch.arena, state_list, State_InputLibs); - continue; - } - } - if (input_obj_list.count) { - state_list_push(scratch.arena, state_list, State_InputObjs); - continue; - } - if (*last_delay_load_dll) { - state_list_push(scratch.arena, state_list, State_InputDelayLoadDlls); - continue; - } - if (search_flags & SearchFlag_UndefinedAndWeak) { - search_flags &= ~SearchFlag_UndefinedAndWeak; - state_list_push(scratch.arena, state_list, State_SearchUndefinedAndWeak); - continue; - } - if (search_flags & SearchFlag_WeakAntiDep) { - search_flags &= ~SearchFlag_WeakAntiDep; - state_list_push(scratch.arena, state_list, State_SearchWeakAntiDep); - continue; - } - if (entry_point_search_attempts == 0) { - state_list_push(scratch.arena, state_list, State_SearchEntryPoint); - entry_point_search_attempts += 1; - continue; - } - if (input_linker_objs) { - input_linker_objs = 0; - state_list_push(scratch.arena, state_list, State_InputLinkerObjs); - continue; - } - - break; - } - - { - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); - - ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); - { - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); -#if BUILD_DEBUG - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); - } - } -#endif - } - ProfEnd(); - - - if (config->entry_point_name.size == 0) { - lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); - } - - ProfBegin("Report Unresolved Symbols"); - { - U64 count = 0; - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - count += 1; - } - } - } - - U64 cursor = 0; - LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - unresolved[cursor++] = chunk->v[i].symbol; - } - } - } - - radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); - - for EachIndex(i, count) { - LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); - } - - // TODO: /FORCE - if (count) { - lnk_exit(LNK_Error_UnresolvedSymbol); - } - } - ProfEnd(); - } - - // - // discard COMDAT sections that are not referenced - // - if (config->opt_ref == LNK_SwitchState_Yes) { - lnk_opt_ref(tp, symtab, config, obj_list); - } - - // - // infer minimal padding size for functions from the target machine - // - if (config->machine != COFF_MachineType_Unknown && config->infer_function_pad_min) { - config->function_pad_min = lnk_get_default_function_pad_min(config->machine); - config->infer_function_pad_min = 0; - } - - // - // log - // - if (lnk_get_log_status(LNK_Log_InputObj)) { - U64 total_input_size = 0; - for (LNK_ObjNode *obj_n = obj_list.first; obj_n != 0; obj_n = obj_n->next) { total_input_size += obj_n->data.data.size; } - lnk_log(LNK_Log_InputObj, "[Total Obj Input Size %M]", total_input_size); - } - if (lnk_get_log_status(LNK_Log_InputLib)) { - U64 total_input_size = 0; - for EachIndex(i, ArrayCount(lib_index)) { - LNK_LibList list = lib_index[i]; - for (LNK_LibNode *lib_n = list.first; lib_n != 0; lib_n = lib_n->next) { total_input_size += lib_n->data.data.size; } - } - lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %M]", total_input_size); - } - - // - // fill out link context - // - LNK_LinkContext link_ctx = {0}; - link_ctx.symtab = symtab; - link_ctx.objs_count = obj_list.count; - link_ctx.objs = lnk_array_from_obj_list(tp_arena->v[0], obj_list); - MemoryCopyTyped(&link_ctx.lib_index[0], &lib_index[0], ArrayCount(lib_index)); - - ProfEnd(); - scratch_end(scratch); - return link_ctx; - -#undef state_list_push -#undef state_list_pop -} - internal B32 lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_SymbolDefined *symbol_out) { @@ -2769,6 +2749,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) String8 symbol_table = str8_substr(obj->data, obj_header.symbol_table_range); String8 string_table = str8_substr(obj->data, obj_header.string_table_range); + U32 closest_sect = 0; + U32 closest_reloc = 0; + U32 closest_foff = max_U32; + for EachIndex(sect_idx, obj_header.section_count_no_null) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; @@ -2917,15 +2901,17 @@ THREAD_POOL_TASK_FUNC(lnk_flag_hotpatch_contribs_task) U64 obj_idx = task_id; LNK_Obj *obj = task->objs[obj_idx]; - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular && COFF_SymbolType_IsFunc(symbol.type)) { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); - LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; - if (sc != task->null_sc) { - sc->hotpatch = !!(section_header->flags & COFF_SectionFlag_CntCode); + if (obj->hotpatch) { + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_Regular && COFF_SymbolType_IsFunc(symbol.type)) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; + if (sc != task->null_sc) { + sc->hotpatch = !!(section_header->flags & COFF_SectionFlag_CntCode); + } } } } @@ -3859,6 +3845,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT lnk_section_table_push(sectab, str8_lit(".rdata"), PE_RDATA_SECTION_FLAGS); lnk_section_table_push(sectab, str8_lit(".data" ), PE_DATA_SECTION_FLAGS ); lnk_section_table_push(sectab, str8_lit(".bss" ), PE_BSS_SECTION_FLAGS ); + lnk_section_table_push(sectab, str8_lit(".pdata"), PE_PDATA_SECTION_FLAGS); LNK_Section *common_block_sect = lnk_section_table_search(sectab, str8_lit(".bss"), PE_BSS_SECTION_FLAGS); LNK_BuildImageTask task = { @@ -4577,7 +4564,7 @@ lnk_pair_u32_nearest_section(PairU32 *arr, U64 count, LNK_Obj **objs, U32 voff) } internal String8List -lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs_count, LNK_Obj **objs, LNK_LibList lib_index[LNK_InputSource_Count], LNK_SectionTable *sectab) +lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs_count, LNK_Obj **objs, U64 libs_count, LNK_Lib **libs, LNK_SectionTable *sectab) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -4687,12 +4674,10 @@ lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs str8_list_pushf(arena, &map, "\n"); ProfBegin("LIBS"); - for (U64 input_source = 0; input_source < LNK_InputSource_Count; ++input_source) { - if (lib_index[input_source].count) { - str8_list_pushf(arena, &map, "# LIBS (%S)\n", lnk_string_from_input_source(input_source)); - for (LNK_LibNode *lib_n = lib_index[input_source].first; lib_n != 0; lib_n = lib_n->next) { - str8_list_pushf(arena, &map, "%S\n", lib_n->data.path); - } + if (libs_count) { + str8_list_pushf(arena, &map, "# LIBS\n"); + for EachIndex(i, libs_count) { + str8_list_pushf(arena, &map, "%S\n", libs[i]->path); } } ProfEnd(); @@ -4752,14 +4737,29 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) Temp scratch = scratch_begin(arena->v, arena->count); // - // Link Inputs + // Input Context // - LNK_LinkContext link_ctx = lnk_build_link_context(tp, arena, config); + LNK_Inputer *inputer = lnk_inputer_init(); // - // Image + // Symbol Table // - LNK_ImageContext image_ctx = lnk_build_image(arena, tp, config, link_ctx.symtab, link_ctx.objs_count, link_ctx.objs); + LNK_SymbolTable *symtab = lnk_symbol_table_init(arena); + + // + // Link Image + // + LNK_Link *link = lnk_link_image(tp, arena, config, inputer, symtab); + + U64 objs_count = link->objs.count; + U64 libs_count = link->libs.count; + LNK_Obj **objs = lnk_array_from_obj_list(scratch.arena, link->objs); + LNK_Lib **libs = lnk_array_from_lib_list(scratch.arena, link->libs); + + // + // Layout Image + // + LNK_ImageContext image_ctx = lnk_build_image(arena, tp, config, symtab, objs_count, objs); // Write image in the background LNK_WriteThreadContext *image_write_ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1); @@ -4772,7 +4772,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) // RAD Map // if (config->rad_chunk_map == LNK_SwitchState_Yes) { - String8List rad_map = lnk_build_rad_map(scratch.arena, image_ctx.image_data, config, link_ctx.objs_count, link_ctx.objs, link_ctx.lib_index, image_ctx.sectab); + String8List rad_map = lnk_build_rad_map(scratch.arena, image_ctx.image_data, config, objs_count, objs, libs_count, libs, image_ctx.sectab); lnk_write_data_list_to_file_path(config->rad_chunk_map_name, config->temp_rad_chunk_map_name, rad_map); } @@ -4796,18 +4796,18 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) ProfBegin("Debug Info"); lnk_timer_begin(LNK_Timer_Debug); - U64 objs_count = 0; - LNK_Obj **objs = push_array(scratch.arena, LNK_Obj *, link_ctx.objs_count); - for EachIndex(obj_idx, link_ctx.objs_count) { - LNK_Obj *obj = link_ctx.objs[obj_idx]; + U64 debug_info_objs_count = 0; + LNK_Obj **debug_info_objs = push_array(scratch.arena, LNK_Obj *, objs_count); + for EachIndex(obj_idx, objs_count) { + LNK_Obj *obj = objs[obj_idx]; if (obj->exclude_from_debug_info) { continue; } - objs[objs_count++] = obj; + debug_info_objs[debug_info_objs_count++] = obj; } // // CodeView // - LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, objs_count, objs); + LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, debug_info_objs_count, debug_info_objs); CV_DebugT *types = lnk_import_types(tp, arena, &input); // @@ -4851,7 +4851,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) arena, image_ctx.image_data, config, - link_ctx.symtab, + symtab, input.count, input.obj_arr, input.debug_s_arr, diff --git a/src/linker/lnk.h b/src/linker/lnk.h index e15252a0..f26c5f24 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -3,21 +3,99 @@ #pragma once -// --- Link -------------------------------------------------------------------- +// --- Input ------------------------------------------------------------------- + +typedef struct LNK_LibMemberRef +{ + LNK_Lib *lib; + U32 member_idx; + + struct LNK_LibMemberRef *next; +} LNK_LibMemberRef; + +typedef struct LNK_LibMemberRefList +{ + U64 count; + LNK_LibMemberRef *first; + LNK_LibMemberRef *last; +} LNK_LibMemberRefList; + +typedef enum +{ + LNK_InputSource_CmdLine, // specified on command line + LNK_InputSource_Default, // specified through defaultlib switch + LNK_InputSource_Obj, // refrenced from objects + LNK_InputSource_Count +} LNK_InputSourceType; + +typedef struct LNK_Input +{ + String8 path; + String8 data; + B32 disallow; + B32 is_thin; + B32 has_disk_read_failed; + B32 exclude_from_debug_info; + LNK_LibMemberRef *trigger; + void *loaded_input; + + struct LNK_Input *next; +} LNK_Input; + +typedef struct LNK_InputList +{ + U64 count; + LNK_Input *first; + LNK_Input *last; +} LNK_InputList; + +typedef struct LNK_InputPtrArray +{ + U64 count; + LNK_Input **v; +} LNK_InputPtrArray; + +typedef struct LNK_Inputer +{ + Arena *arena; + + LNK_InputList objs; + HashTable *objs_ht; + LNK_InputList new_objs; + + HashTable *libs_ht; + HashTable *missing_lib_ht; + LNK_InputList libs; + LNK_InputList new_libs[LNK_InputSource_Count]; +} LNK_Inputer; + +// --- Image Link ------------------------------------------------------------- #define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" #define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***" + #define LNK_SECTION_FLAG_IS_LIVE (1 << 0) -typedef struct LNK_LinkContext +typedef struct LNK_ImportTables { - LNK_SymbolTable *symtab; - U64 objs_count; - LNK_Obj **objs; - LNK_LibList lib_index[LNK_InputSource_Count]; -} LNK_LinkContext; + Arena *arena; + HashTable *static_imports; + HashTable *delayed_imports; + HashTable *import_stub_ht; +} LNK_ImportTables; -// -- Image -------------------------------------------------------------------- +typedef struct LNK_Link +{ + LNK_ObjList objs; + LNK_LibList libs; + LNK_IncludeSymbolNode **last_include; + String8Node **last_cmd_lib; + String8Node **last_default_lib; + String8Node **last_obj_lib; + B32 try_to_resolve_entry_point; +} LNK_Link; + +// -- Image Layout ------------------------------------------------------------ #define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3 #define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3 @@ -135,24 +213,6 @@ typedef struct B32 is_large_addr_aware; } LNK_ObjBaseRelocTask; -typedef struct -{ - LNK_InputObjList input_obj_list; - U64 input_imports_count; - LNK_InputImport *input_imports; - LNK_InputImportList input_import_list; - LNK_SymbolList unresolved_symbol_list; -} LNK_SymbolFinderResult; - -typedef struct -{ - PathStyle path_style; - LNK_SymbolTable *symtab; - LNK_SymbolNodeArray lookup_node_arr; - LNK_SymbolFinderResult *result_arr; - Rng1U64 *range_arr; -} LNK_SymbolFinder; - typedef struct { String8 image_data; @@ -203,17 +263,43 @@ internal String8 lnk_make_null_obj(Arena *arena); internal String8 lnk_make_res_obj(Arena *arena, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); internal String8 lnk_make_linker_obj(Arena *arena, LNK_Config *config); +// --- Inputer ----------------------------------------------------------------- + +internal void lnk_input_list_push_node(LNK_InputList *list, LNK_Input *node); +internal void lnk_input_list_concat_in_place(LNK_InputList *list, LNK_InputList *to_concat); +internal LNK_InputPtrArray lnk_array_from_input_list(Arena *arena, LNK_InputList list); + +internal LNK_Inputer * lnk_inputer_init(void); + +internal LNK_Input * lnk_input_push(Arena *arena, LNK_InputList *list, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_linkgen(Arena *arena, LNK_InputList *list, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_thin(Arena *arena, LNK_InputList *list, HashTable *ht, String8 full_path); + +internal LNK_Input * lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path); + +internal LNK_Input * lnk_inputer_push_lib(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_lib_linkgen(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSourceType input_source, String8 lib_path); + +internal B32 lnk_inputer_has_items(LNK_Inputer *inputer); +internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs); + // --- Link Context ------------------------------------------------------------ -internal String8 lnk_get_lib_name(String8 path); -internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path); -internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path); -internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path); -internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); +internal void lnk_lib_member_ref_list_push_node(LNK_LibMemberRefList *list, LNK_LibMemberRef *node); +internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b); +internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list); -internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal LNK_ObjNode * lnk_load_objs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out); +internal void lnk_load_libs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link); +internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, LNK_ImportTables *imps); +internal LNK_Link * lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab); -internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); +// --- Optimizations ----------------------------------------------------------- + +internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs); // --- Win32 Image ------------------------------------------------------------- diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 6bedf521..aa5ab473 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -944,6 +944,57 @@ lnk_is_dll_delay_load(LNK_Config *config, String8 dll_name) return hash_table_search_path_u64(config->delay_load_ht, dll_name, 0); } +internal String8 +lnk_get_lib_name(String8 path) +{ + static String8 LIB_EXT = str8_lit_comp(".LIB"); + + // strip path + String8 name = str8_skip_last_slash(path); + + // strip extension + String8 name_ext = str8_postfix(name, LIB_EXT.size); + if (str8_match(name_ext, LIB_EXT, StringMatchFlag_CaseInsensitive)) { + name = str8_chop(name, LIB_EXT.size); + } + + return name; +} + +internal void +lnk_push_disallow_lib(LNK_Config *config, String8 path) +{ + String8 lib_name = lnk_get_lib_name(path); + hash_table_push_path_u64(config->arena, config->disallow_lib_ht, lib_name, 0); +} + +internal B32 +lnk_is_lib_disallowed(LNK_Config *config, String8 path) +{ + String8 lib_name = lnk_get_lib_name(path); + return hash_table_search_path(config->disallow_lib_ht, lib_name) != 0; +} + +internal void +lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj) +{ + // is this a duplicate symbol? + if (hash_table_search_string_raw(config->include_symbol_ht, name, 0)) { + return; + } + + name = push_str8_copy(config->arena, name); + + LNK_IncludeSymbolNode *node = push_array(config->arena, LNK_IncludeSymbolNode, 1); + node->v.name = name; + node->v.obj = obj; + + SLLQueuePush(config->include_symbol_list.first, config->include_symbol_list.last, node); + config->include_symbol_list.count += 1; + + hash_table_push_string_raw(config->arena, config->include_symbol_ht, name, node); +} + internal void lnk_print_build_info() { @@ -1068,9 +1119,9 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list) } internal void -lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj) +lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj) { - Temp scratch = scratch_begin(&arena,1); + Temp scratch = scratch_begin(&config->arena, 1); LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); @@ -1111,12 +1162,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", alt_name.from, to_extant, alt_name.from, alt_name.to); } } else { - hash_table_push_string_string(arena, config->alt_name_ht, alt_name.from, alt_name.to); + hash_table_push_string_string(config->arena, config->alt_name_ht, alt_name.from, alt_name.to); - alt_name.from = push_str8_copy(arena, alt_name.from); - alt_name.to = push_str8_copy(arena, alt_name.to); + alt_name.from = push_str8_copy(config->arena, alt_name.from); + alt_name.to = push_str8_copy(config->arena, alt_name.to); - LNK_AltNameNode *alt_name_n = push_array(arena, LNK_AltNameNode, 1); + LNK_AltNameNode *alt_name_n = push_array(config->arena, LNK_AltNameNode, 1); alt_name_n->data = alt_name; SLLQueuePush(config->alt_name_list.first, config->alt_name_list.last, alt_name_n); @@ -1182,7 +1233,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_DefaultLib: { - String8List default_lib_list = str8_list_copy(arena, &value_strings); + String8List default_lib_list = str8_list_copy(config->arena, &value_strings); if (obj) { str8_list_concat_in_place(&config->input_obj_lib_list, &default_lib_list); } else { @@ -1208,9 +1259,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_DelayLoad: { for (String8Node *name_n = value_strings.first; name_n != 0; name_n = name_n->next) { if (hash_table_search_path_u64(config->delay_load_ht, name_n->string, 0)) { continue; } - String8 name = push_str8_copy(arena, name_n->string); - hash_table_push_path_u64(arena, config->delay_load_ht, name, 0); - str8_list_push(arena, &config->delay_load_dll_list, name); + String8 name = push_str8_copy(config->arena, name_n->string); + hash_table_push_path_u64(config->arena, config->delay_load_ht, name, 0); + str8_list_push(config->arena, &config->delay_load_dll_list, name); } } break; @@ -1228,7 +1279,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Entry: { String8 new_entry_point_name = {0}; - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &new_entry_point_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &new_entry_point_name); if (config->entry_point_name.size) { lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, cmd_switch, "unable to redefine entry point \"%S\" to \"%S\"", config->entry_point_name, new_entry_point_name); @@ -1240,7 +1291,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Export: { PE_ExportParse export_parse = {0}; - if (lnk_parse_export_directive_ex(arena, value_strings, obj, &export_parse)) { + if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) { PE_ExportParseNode *exp_n = 0; String8 export_name = pe_name_from_export_parse(&export_parse); hash_table_search_string_raw(config->export_ht, export_name, &exp_n); @@ -1248,13 +1299,13 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (exp_n == 0) { // make sure export is defined if (!export_parse.is_forwarder) { - str8_list_push(arena, &config->include_symbol_list, export_parse.name); + lnk_include_symbol(config, export_parse.name, 0); } // push new export - exp_n = pe_export_parse_list_push(arena, &config->export_symbol_list, export_parse); + exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse); - hash_table_push_string_raw(arena, config->export_ht, export_name, exp_n); + hash_table_push_string_raw(config->arena, config->export_ht, export_name, exp_n); } else { B32 is_ambiguous = 1; PE_ExportParse *extant_export = &exp_n->data; @@ -1352,19 +1403,12 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_ImpLib: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->imp_lib_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->imp_lib_name); } break; case LNK_CmdSwitch_Include: { for (String8Node *value_n = value_strings.first; value_n != 0; value_n = value_n->next) { - // is this a duplicate symbol? - if (hash_table_search_string_raw(config->include_symbol_ht, value_n->string, 0)) { - continue; - } - - String8 include_symbol = push_str8_copy(arena, value_n->string); - hash_table_push_string_raw(arena, config->include_symbol_ht, include_symbol, 0); - str8_list_push(arena, &config->include_symbol_list, include_symbol); + lnk_include_symbol(config, value_n->string, obj); } } break; @@ -1386,7 +1430,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_LibPath: { - String8List lib_dir_list = str8_list_copy(arena, &value_strings); + String8List lib_dir_list = str8_list_copy(config->arena, &value_strings); for (String8Node *dir_n = lib_dir_list.first; dir_n != 0; dir_n = dir_n->next) { if (!os_folder_path_exists(dir_n->string)) { String8 full_path = os_full_path_from_path(scratch.arena, dir_n->string); @@ -1426,7 +1470,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (res_id_arr.count == 2) { U64 resource_id; if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) { - config->manifest_resource_id = push_u64(arena, resource_id); + config->manifest_resource_id = push_u64(config->arena, resource_id); } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); } @@ -1455,7 +1499,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_ManifestDependency: { - String8List manifest_dependency_list = str8_list_copy(arena, &value_strings); + String8List manifest_dependency_list = str8_list_copy(config->arena, &value_strings); str8_list_concat_in_place(&config->manifest_dependency_list, &manifest_dependency_list); if (config->manifest_opt == LNK_ManifestOpt_Null) { @@ -1464,7 +1508,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_ManifestFile: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->manifest_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->manifest_name); } break; case LNK_CmdSwitch_ManifestInput: { @@ -1488,7 +1532,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam str8_match_lit("'requireAdministrator'", level, 0)) { // manifest level was parsed! config->manifest_uac = 1; - config->manifest_level = push_str8_copy(arena, level); + config->manifest_level = push_str8_copy(config->arena, level); if (param_arr.count > 1) { String8 ui_access_param = param_arr.v[1]; String8List ui_access_list = str8_split_by_string_chars(scratch.arena, ui_access_param, str8_lit("="), 0); @@ -1497,7 +1541,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (str8_match_lit("'true'", ui_access, 0) || str8_match_lit("'false'", ui_access, 0)) { // ui access was parsed! - config->manifest_ui_access = push_str8_copy(arena, ui_access); + config->manifest_ui_access = push_str8_copy(config->arena, ui_access); } else { lnk_error_invalid_uac_ui_access_param(LNK_Error_Cmdl, obj, cmd_switch, ui_access_param); } @@ -1531,9 +1575,9 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (value_strings.node_count == 1) { LNK_MergeDirective merge = {0}; if (lnk_parse_merge_directive(value_strings.first->string, obj, &merge)) { - merge.src = push_str8_copy(arena, merge.src); - merge.dst = push_str8_copy(arena, merge.dst); - lnk_merge_directive_list_push(arena, &config->merge_list, merge); + merge.src = push_str8_copy(config->arena, merge.src); + merge.dst = push_str8_copy(config->arena, merge.dst); + lnk_merge_directive_list_push(config->arena, &config->merge_list, merge); } } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "invalid number of parameters %d", value_strings.node_count); @@ -1549,7 +1593,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } - String8List natvis_list = str8_list_copy(arena, &value_strings); + String8List natvis_list = str8_list_copy(config->arena, &value_strings); str8_list_concat_in_place(&config->natvis_list, &natvis_list); } break; @@ -1558,8 +1602,13 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam if (value_strings.node_count == 0) { config->no_default_libs = 1; } else { - String8List no_default_lib_list = str8_list_copy(arena, &value_strings); - str8_list_concat_in_place(&config->disallow_lib_list, &no_default_lib_list); + for (String8Node *lib_n = value_strings.first; lib_n != 0; lib_n = lib_n->next) { + String8 lib_name = lnk_get_lib_name(lib_n->string); + if (hash_table_search_path_raw(config->disallow_lib_ht, lib_name)) { + continue; + } + hash_table_push_path_raw(config->arena, config->disallow_lib_ht, lib_name, 0); + } } } break; @@ -1614,16 +1663,16 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_Out: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->image_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->image_name); } break; case LNK_CmdSwitch_Pdb: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_name); } break; case LNK_CmdSwitch_PdbAltPath: { // see :PdbAltPath - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_alt_path); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_alt_path); } break; case LNK_CmdSwitch_PdbPageSize: { @@ -1723,7 +1772,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_Rad_Map: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_chunk_map_name); config->rad_chunk_map = LNK_SwitchState_Yes; } break; @@ -1737,11 +1786,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Rad_DebugName: { // :Rad_DebugAltPath - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_debug_name); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_debug_name); } break; case LNK_CmdSwitch_Rad_DebugAltPath: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->rad_debug_alt_path); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->rad_debug_alt_path); } break; case LNK_CmdSwitch_Rad_DelayBind: { @@ -1839,7 +1888,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_Rad_MtPath: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->mt_path); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->mt_path); } break; case LNK_CmdSwitch_Rad_OsVer: { @@ -1880,7 +1929,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } break; case LNK_CmdSwitch_Rad_PdbHashTypeNameMap: { - lnk_cmd_switch_parse_string_copy(arena, obj, cmd_switch, value_strings, &config->pdb_hash_type_name_map); + lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &config->pdb_hash_type_name_map); } break; case LNK_CmdSwitch_Rad_PdbHashTypeNameLength: { @@ -1890,8 +1939,8 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Rad_RemoveSection: { String8 sect_name = {0}; if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, §_name)) { - sect_name = push_str8_copy(arena, sect_name); - str8_list_push(arena, &config->remove_sections, sect_name); + sect_name = push_str8_copy(config->arena, sect_name); + str8_list_push(config->arena, &config->remove_sections, sect_name); } } break; @@ -1991,12 +2040,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } internal LNK_Config * -lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line) +lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) { ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); + Temp scratch = scratch_begin(0, 0); - LNK_Config *config = push_array(arena, LNK_Config, 1); + Arena *arena = arena_alloc(); + LNK_Config *config = push_array(arena, LNK_Config, 1); + config->arena = arena; config->raw_cmd_line = str8_list_copy(arena, &raw_cmd_line); config->work_dir = os_get_current_path(arena); config->build_imp_lib = 1; @@ -2012,10 +2063,11 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd config->alt_name_ht = hash_table_init(arena, 0x100); config->include_symbol_ht = hash_table_init(arena, 0x100); config->delay_load_ht = hash_table_init(arena, 0x100); + config->disallow_lib_ht = hash_table_init(arena, 0x100); // process command line switches for (LNK_CmdOption *cmd = cmd_line.first_option; cmd != 0; cmd = cmd->next) { - lnk_apply_cmd_option_to_config(arena, config, cmd->string, cmd->value_strings, 0); + lnk_apply_cmd_option_to_config(config, cmd->string, cmd->value_strings, 0); } // :manifest_input diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index bc0bce05..41b3e7f7 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -249,6 +249,25 @@ typedef enum LNK_ManifestOpt_No, } LNK_ManifestOpt; +typedef struct LNK_IncludeSymbol +{ + String8 name; + struct LNK_Obj *obj; +} LNK_IncludeSymbol; + +typedef struct LNK_IncludeSymbolNode +{ + struct LNK_IncludeSymbolNode *next; + LNK_IncludeSymbol v; +} LNK_IncludeSymbolNode; + +typedef struct LNK_IncludeSymbolList +{ + U64 count; + LNK_IncludeSymbolNode *first; + LNK_IncludeSymbolNode *last; +} LNK_IncludeSymbolList; + typedef struct LNK_AltName { String8 from; @@ -304,6 +323,7 @@ typedef enum typedef struct LNK_Config { + Arena *arena; LNK_ConfigFlags flags; LNK_DebugMode debug_mode; LNK_SwitchState opt_ref; @@ -362,7 +382,6 @@ typedef struct LNK_Config String8List input_list[LNK_Input_Count]; String8List input_obj_lib_list; String8List input_default_lib_list; - String8List disallow_lib_list; String8List delay_load_dll_list; String8List natvis_list; String8 manifest_name; @@ -375,7 +394,7 @@ typedef struct LNK_Config String8 rad_chunk_map_name; String8 rad_debug_name; String8 rad_debug_alt_path; - String8List include_symbol_list; + LNK_IncludeSymbolList include_symbol_list; LNK_AltNameList alt_name_list; LNK_MergeDirectiveList merge_list; U64 symbol_table_cap_defined; @@ -397,6 +416,7 @@ typedef struct LNK_Config HashTable *alt_name_ht; HashTable *include_symbol_ht; HashTable *delay_load_ht; + HashTable *disallow_lib_ht; } LNK_Config; // --- MSVC Error Codes -------------------------------------------------------- @@ -573,20 +593,26 @@ internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LN // --- Getters ----------------------------------------------------------------- -internal String8 lnk_get_image_name(LNK_Config *config); -internal U64 lnk_get_default_function_pad_min(COFF_MachineType machine); -internal U64 lnk_get_base_addr(LNK_Config *config); +internal String8 lnk_get_image_name (LNK_Config *config); +internal U64 lnk_get_default_function_pad_min (COFF_MachineType machine); +internal U64 lnk_get_base_addr (LNK_Config *config); internal Version lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine); -internal Version lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType machine); +internal Version lnk_get_min_subsystem_version (PE_WindowsSubsystem subsystem, COFF_MachineType machine); internal B32 lnk_do_debug_info (LNK_Config *config); internal B32 lnk_is_thread_pool_shared(LNK_Config *config); internal B32 lnk_is_section_removed (LNK_Config *config, String8 section_name); internal B32 lnk_is_dll_delay_load (LNK_Config *config, String8 dll_name); +internal String8 lnk_get_lib_name (String8 path); +internal void lnk_push_disallow_lib(LNK_Config *config, String8 path); +internal B32 lnk_is_lib_disallowed(LNK_Config *config, String8 path); + +internal void lnk_include_symbol(LNK_Config *config, String8 name, struct LNK_Obj *obj); + // --- Config ------------------------------------------------------------------ -internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj); +internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj); -internal LNK_Config * lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line, LNK_CmdLine cmd_line); +internal LNK_Config * lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line); diff --git a/src/linker/lnk_input.c b/src/linker/lnk_input.c deleted file mode 100644 index 16f8deef..00000000 --- a/src/linker/lnk_input.c +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2025 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal void -lnk_error_input_obj(LNK_ErrorCode code, LNK_InputObj *input, char *fmt, ...) -{ - va_list args; va_start(args, fmt); - lnk_error_with_loc_fv(code, input->path, input->lib ? input->lib->path : str8_zero(), fmt, args); - va_end(args); -} - -internal String8 -lnk_string_from_input_source(LNK_InputSourceType input_source) -{ - String8 result = str8_zero(); - switch (input_source) { - case LNK_InputSource_CmdLine: result = str8_lit("CmdLine"); break; - case LNK_InputSource_Default: result = str8_lit("Default"); break; - case LNK_InputSource_Obj: result = str8_lit("Obj"); break; - default: InvalidPath; - } - return result; -} - -internal void -lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node) -{ - SLLQueuePush(list->first, list->last, node); - ++list->count; -} - -internal LNK_InputObj * -lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list) -{ - LNK_InputObj *node = push_array(arena, LNK_InputObj, 1); - lnk_input_obj_list_push_node(list, node); - return node; -} - -internal void -lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat) -{ - SLLConcatInPlace(list, to_concat); -} - -internal LNK_InputObj ** -lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list) -{ - LNK_InputObj **result = push_array_no_zero(arena, LNK_InputObj *, list.count); - U64 i = 0; - for (LNK_InputObj *n = list.first; n != 0; n = n->next, ++i) { - Assert(i < list.count); - result[i] = n; - } - return result; -} - -internal LNK_InputObj ** -lnk_thin_array_from_input_obj_list(Arena *arena, LNK_InputObjList list, U64 *count_out) -{ - for (LNK_InputObj *input = list.first; input != 0; input = input->next) { - if (input->is_thin) { *count_out += 1; } - } - LNK_InputObj **thin_inputs = push_array(arena, LNK_InputObj *, *count_out); - U64 input_idx = 0; - for (LNK_InputObj *input = list.first; input != 0; input = input->next) { - if (input->is_thin) { thin_inputs[input_idx++] = input; } - } - return thin_inputs; -} - -internal String8Array -lnk_path_array_from_input_obj_array(Arena *arena, LNK_InputObj **arr, U64 count) -{ - String8Array paths = {0}; - paths.count = count; - paths.v = push_array(arena, String8, count); - for (U64 i = 0; i < count; i += 1) { - paths.v[i] = arr[i]->path; - } - return paths; -} - -internal int -lnk_input_obj_compar(const void *raw_a, const void *raw_b) -{ - LNK_InputObj * const *a = raw_a, * const *b = raw_b; - return u64_compar(&(*a)->input_idx, &(*b)->input_idx); -} - -internal int -lnk_input_obj_compar_is_before(void *raw_a, void *raw_b) -{ - LNK_InputObj **a = raw_a, **b = raw_b; - return lnk_input_obj_compar(a, b) < 0; -} - -internal LNK_InputObjList -lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count) -{ - LNK_InputObjList list = {0}; - for (U64 i = 0; i < count; ++i) { - SLLQueuePush(list.first, list.last, arr[i]); - ++list.count; - } - return list; -} - -internal LNK_InputObjList -lnk_input_obj_list_from_string_list(Arena *arena, String8List list) -{ - LNK_InputObjList input_list = {0}; - for (String8Node *path = list.first; path != 0; path = path->next) { - LNK_InputObj *input = lnk_input_obj_list_push(arena, &input_list); - input->is_thin = 1; - input->dedup_id = path->string; - input->path = path->string; - } - return input_list; -} - -internal LNK_InputImportNode * -lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list) -{ - LNK_InputImportNode *node = push_array(arena, LNK_InputImportNode, 1); - SLLQueuePush(list->first, list->last, node); - list->count += 1; - return node; -} - -internal void -lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat) -{ - SLLConcatInPlace(list, to_concat); -} - -internal LNK_InputImportNode ** -lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list) -{ - LNK_InputImportNode **result = push_array_no_zero(arena, LNK_InputImportNode *, list.count); - U64 idx = 0; - for (LNK_InputImportNode *node = list.first; node != 0; node = node->next) { - Assert(idx < list.count); - result[idx++] = node; - } - return result; -} - -internal LNK_InputImportList -lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count) -{ - LNK_InputImportList list = {0}; - for (U64 i = 0; i < count; i += 1) { - SLLQueuePush(list.first, list.last, arr[i]); - list.count += 1; - } - return list; -} - -int -lnk_input_import_is_before(void *raw_a, void *raw_b) -{ - LNK_InputImport *a = *(LNK_InputImport **)raw_a; - LNK_InputImport *b = *(LNK_InputImport **)raw_b; - return a->input_idx < b->input_idx; -} - -int -lnk_input_import_node_compar(const void *raw_a, const void *raw_b) -{ - LNK_InputImportNode * const *a = raw_a; - LNK_InputImportNode * const *b = raw_b; - return u64_compar(&(*a)->data.input_idx, &(*b)->data.input_idx); -} - diff --git a/src/linker/lnk_input.h b/src/linker/lnk_input.h deleted file mode 100644 index a8869d37..00000000 --- a/src/linker/lnk_input.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2025 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#pragma once - -typedef enum -{ - LNK_InputSource_CmdLine, // specified on command line - LNK_InputSource_Default, // specified through defaultlib switch - LNK_InputSource_Obj, // refrenced from objects - LNK_InputSource_Count -} LNK_InputSourceType; - -typedef String8Node LNK_InputLib; -typedef String8List LNK_InputLibList; - -typedef struct LNK_InputImport -{ - String8 coff_import; - U64 input_idx; - struct LNK_Lib *lib; -} LNK_InputImport; - -typedef struct LNK_InputImportNode -{ - struct LNK_InputImportNode *next; - LNK_InputImport data; -} LNK_InputImportNode; - -typedef struct LNK_InputImportList -{ - U64 count; - LNK_InputImportNode *first; - LNK_InputImportNode *last; -} LNK_InputImportList; - -typedef struct LNK_InputObj -{ - String8 path; - String8 dedup_id; - String8 data; - B8 is_thin; - B8 exclude_from_debug_info; - B8 has_disk_read_failed; - struct LNK_Lib *lib; - U64 input_idx; - struct LNK_InputObj *next; -} LNK_InputObj; - -typedef struct LNK_InputObjList -{ - U64 count; - LNK_InputObj *first; - LNK_InputObj *last; -} LNK_InputObjList; - -//////////////////////////////// - -internal void lnk_error_input_obj(LNK_ErrorCode code, LNK_InputObj *input, char *fmt, ...); - -internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source); - -internal void lnk_input_obj_list_push_node(LNK_InputObjList *list, LNK_InputObj *node); -internal LNK_InputObj * lnk_input_obj_list_push(Arena *arena, LNK_InputObjList *list); -internal void lnk_input_obj_list_concat_in_place(LNK_InputObjList *list, LNK_InputObjList *to_concat); - -internal LNK_InputObj ** lnk_array_from_input_obj_list(Arena *arena, LNK_InputObjList list); -internal LNK_InputObj ** lnk_thin_array_from_input_obj_list(Arena *arena, LNK_InputObjList list, U64 *count_out); -internal String8Array lnk_path_array_from_input_obj_array(Arena *arena, LNK_InputObj **arr, U64 count); -internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count); -internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list); - -internal LNK_InputImportNode * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list); -internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat); -internal LNK_InputImportNode ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list); -internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count); - diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index d620f2cb..6002046b 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -10,8 +10,7 @@ lnk_lib_node_is_before(void *a, void *b) internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b) { - LNK_LibNode **a = raw_a, **b = raw_b; - return lnk_lib_node_is_before(*a, *b); + return raw_a < raw_b; } internal B32 @@ -117,7 +116,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) lib_out->symbol_count = symbol_count; lib_out->member_offsets = member_offsets; lib_out->symbol_indices = symbol_indices; - lib_out->was_member_queued = push_array(arena, B8, member_count); + lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count); lib_out->symbol_names = symbol_names; lib_out->long_names = parse.long_names; @@ -128,13 +127,13 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) internal THREAD_POOL_TASK_FUNC(lnk_lib_initer) { - LNK_LibIniter *task = raw_task; + LNK_LibIniter *task = raw_task; + LNK_Input *input = task->inputs[task_id]; U64 lib_node_idx = ins_atomic_u64_inc_eval(&task->next_free_lib_idx)-1; LNK_LibNode *lib_node = &task->free_libs[lib_node_idx]; - lib_node->data.input_idx = task_id; - B32 is_valid_lib = lnk_lib_from_data(arena, task->data_arr[task_id], task->path_arr[task_id], &lib_node->data); + B32 is_valid_lib = lnk_lib_from_data(arena, input->data, input->path, &lib_node->data); if (is_valid_lib) { U64 valid_lib_idx = ins_atomic_u64_inc_eval(&task->valid_libs_count)-1; task->valid_libs[valid_lib_idx] = lib_node; @@ -144,6 +143,17 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer) } } +internal LNK_Lib ** +lnk_array_from_lib_list(Arena *arena, LNK_LibList list) +{ + LNK_Lib **arr = push_array_no_zero(arena, LNK_Lib *, list.count); + U64 idx = 0; + for (LNK_LibNode *node = list.first; node != 0; node = node->next, ++idx) { + arr[idx] = &node->data; + } + return arr; +} + internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node) { @@ -152,32 +162,31 @@ lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node) } internal LNK_LibNodeArray -lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr) +lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, LNK_Input **inputs) { Temp scratch = scratch_begin(arena->v, arena->count); - Assert(data_arr.count == path_arr.count); - U64 lib_count = data_arr.count; + U64 lib_id_base = list->count; // parse libs in parallel LNK_LibIniter task = {0}; - task.free_libs = push_array(arena->v[0], LNK_LibNode, lib_count); - task.valid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count); - task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, lib_count); - task.data_arr = data_arr.v; - task.path_arr = path_arr.v; - tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task); + task.free_libs = push_array(arena->v[0], LNK_LibNode, inputs_count); + task.valid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count); + task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count); + task.inputs = inputs; + tp_for_parallel(tp, arena, inputs_count, lnk_lib_initer, &task); // report invalid libs radsort(task.invalid_libs, task.invalid_libs_count, lnk_lib_node_ptr_is_before); for EachIndex(i, task.invalid_libs_count) { U64 input_idx = task.invalid_libs[i]->data.input_idx; - lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", path_arr.v[input_idx]); + lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", inputs[input_idx]->path); } // push parsed libs radsort(task.valid_libs, task.valid_libs_count, lnk_lib_node_ptr_is_before); for EachIndex(i, task.valid_libs_count) { + task.valid_libs[i]->data.input_idx = lib_id_base + i; lnk_lib_list_push_node(list, task.valid_libs[i]); } @@ -187,6 +196,14 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S return result; } +internal B32 +lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger) +{ + LNK_Symbol *slot = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], trigger, 0); + B32 is_first_queue_attempt = (slot == 0); + return is_first_queue_attempt; +} + internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out) { diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index b585d302..e266dbc7 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -11,7 +11,7 @@ typedef struct LNK_Lib U32 symbol_count; U32 *member_offsets; U16 *symbol_indices; - B8 *was_member_queued; + LNK_Symbol **was_member_linked; String8Array symbol_names; String8 long_names; U64 input_idx; @@ -40,14 +40,13 @@ typedef struct LNK_LibList typedef struct { - String8 *data_arr; - String8 *path_arr; - U64 next_free_lib_idx; - U64 valid_libs_count; - U64 invalid_libs_count; - LNK_LibNode *free_libs; - LNK_LibNode **valid_libs; - LNK_LibNode **invalid_libs; + struct LNK_Input **inputs; + U64 next_free_lib_idx; + U64 valid_libs_count; + U64 invalid_libs_count; + LNK_LibNode *free_libs; + LNK_LibNode **valid_libs; + LNK_LibNode **invalid_libs; } LNK_LibIniter; // ----------------------------------------------------------------------------- @@ -56,8 +55,11 @@ internal int lnk_lib_node_is_before(void *a, void *b); internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b); internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out); +internal LNK_Lib ** lnk_array_from_lib_list(Arena *arena, LNK_LibList list); internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node); -internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr); +internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, struct LNK_Input **inputs); + +internal B32 lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger); internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index bb15bcc2..734da57e 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -11,6 +11,14 @@ lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...) va_end(args); } +internal void +lnk_error_input_obj(LNK_ErrorCode code, LNK_Input *input, char *fmt, ...) +{ + va_list args; va_start(args, fmt); + lnk_error_with_loc_fv(code, input->path, input->trigger->lib ? input->trigger->lib->path : str8_zero(), fmt, args); + va_end(args); +} + internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list) { @@ -26,9 +34,8 @@ internal THREAD_POOL_TASK_FUNC(lnk_obj_initer) { LNK_ObjIniter *task = raw_task; - LNK_InputObj *input = task->inputs[task_id]; - LNK_Obj *obj = &task->objs.v[task_id].data; - U64 obj_idx = task->obj_id_base + task_id; + LNK_Input *input = task->inputs[task_id]; + LNK_Obj *obj = &task->objs[task_id].data; ProfBeginV("Init Obj [%S%s%S]", input->lib_path, (input->lib_path.size ? ": " : 0), input->path); @@ -281,58 +288,60 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // fill out obj obj->data = input->data; obj->path = push_str8_copy(arena, input->path); - obj->lib = input->lib; - obj->input_idx = obj_idx; + obj->lib = input->trigger ? input->trigger->lib : 0; obj->header = header; obj->comdats = comdats; obj->exclude_from_debug_info = input->exclude_from_debug_info; obj->hotpatch = hotpatch; obj->associated_sections = associated_sections; + obj->node = &task->objs[task_id]; + obj->trigger_symbol = input->trigger; ProfEnd(); } -internal LNK_ObjNodeArray -lnk_obj_list_push_parallel(TP_Context *tp, - TP_Arena *arena, - LNK_ObjList *list, - COFF_MachineType machine, - U64 input_count, - LNK_InputObj **inputs) +internal LNK_ObjNode * +lnk_obj_from_input_many(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, U64 inputs_count, LNK_Input **inputs) { - ProfBeginFunction(); - - // store base id - U64 obj_id_base = list->count; - - // reserve obj nodes - LNK_ObjNodeArray objs = {0}; - if (input_count > 0) { - objs.count = input_count; - objs.v = push_array(arena->v[0], LNK_ObjNode, input_count); - for (LNK_ObjNode *ptr = objs.v, *opl = objs.v + input_count; ptr < opl; ++ptr) { - SLLQueuePush(list->first, list->last, ptr); - } - list->count += input_count; + LNK_ObjNode *objs = 0; + if (inputs_count) { + objs = push_array(arena->v[0], LNK_ObjNode, inputs_count); + tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &(LNK_ObjIniter){ .inputs = inputs, .objs = objs, .machine = machine }); } - - // fill out & run task - LNK_ObjIniter task = {0}; - task.inputs = inputs; - task.obj_id_base = obj_id_base; - task.objs = objs; - task.machine = machine; - tp_for_parallel(tp, arena, input_count, lnk_obj_initer, &task); - - ProfEnd(); return objs; } +internal LNK_ObjNode * +lnk_obj_from_input(Arena *arena, COFF_MachineType machine, LNK_Input *input) +{ + Temp scratch = scratch_begin(&arena, 1); + TP_Context *tp = tp_alloc(scratch.arena, 1, 1, str8_zero()); + TP_Arena tp_arena = { .count = 1, .v = &arena }; + LNK_ObjNode *result = lnk_obj_from_input_many(tp, &tp_arena, machine, 1, &input); + scratch_end(scratch); + return result; +} + +internal void +lnk_obj_list_push_node_many(LNK_ObjList *list, U64 count, LNK_ObjNode *nodes) +{ + for EachIndex(i, count) { + DLLPushBack(list->first, list->last, &nodes[i]); + } + list->count += count; +} + +internal void +lnk_obj_list_push_node(LNK_ObjList *list, LNK_ObjNode *node) +{ + lnk_obj_list_push_node_many(list, 1, node); +} + internal THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) { LNK_InputCoffSymbolTable *task = raw_task; - LNK_Obj *obj = &task->objs.v[task_id].data; + LNK_Obj *obj = task->objs[task_id]; COFF_ParsedSymbol symbol = {0}; for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); @@ -400,17 +409,17 @@ internal THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task) { LNK_InputCoffSymbolTable *task = raw_task; - LNK_Obj *obj = &task->objs.v[task_id].data; + LNK_Obj *obj = task->objs[task_id]; obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj); } internal void -lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs) +lnk_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs) { ProfBeginFunction(); LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs }; - tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task); - tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task); + tp_for_parallel(tp, arena, objs_count, lnk_input_coff_symbol_table, &task); + tp_for_parallel(tp, arena, objs_count, lnk_assign_comdat_symlinks_task, &task); ProfEnd(); } diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 52ac822e..5ce71547 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -7,21 +7,25 @@ typedef struct LNK_Obj { - String8 data; - String8 path; - struct LNK_Lib *lib; - U32 input_idx; - COFF_FileHeaderInfo header; - U32 *comdats; - B8 hotpatch; - B8 exclude_from_debug_info; - U32Node **associated_sections; - LNK_SymbolHashTrie **symlinks; + String8 path; + String8 data; + struct LNK_Lib *lib; + struct LNK_LibMemberRef *trigger_symbol; + U32 input_idx; + COFF_FileHeaderInfo header; + U32 *comdats; + B8 hotpatch; + B8 exclude_from_debug_info; + U32Node **associated_sections; + LNK_SymbolHashTrie **symlinks; + + struct LNK_ObjNode *node; } LNK_Obj; typedef struct LNK_ObjNode { struct LNK_ObjNode *next; + struct LNK_ObjNode *prev; LNK_Obj data; } LNK_ObjNode; @@ -63,16 +67,16 @@ typedef struct LNK_DirectiveInfo typedef struct { - LNK_InputObj **inputs; - LNK_ObjNodeArray objs; - U64 obj_id_base; - U32 machine; + struct LNK_Input **inputs; + LNK_ObjNode *objs; + U64 obj_id_base; + U32 machine; } LNK_ObjIniter; typedef struct { - LNK_SymbolTable *symtab; - LNK_ObjNodeArray objs; + LNK_SymbolTable *symtab; + LNK_Obj **objs; } LNK_InputCoffSymbolTable; typedef struct @@ -86,12 +90,15 @@ typedef struct // --- Error ------------------------------------------------------------------- internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...); +internal void lnk_error_input_obj(LNK_ErrorCode code, struct LNK_Input *input, char *fmt, ...); // --- Input ------------------------------------------------------------------- -internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list); -internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs); -internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs); +internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list); +internal void lnk_obj_list_push_node_many(LNK_ObjList *list, U64 count, LNK_ObjNode *nodes); +internal void lnk_obj_list_push_node(LNK_ObjList *list, LNK_ObjNode *node); + +internal void lnk_inputer_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_ObjNode *objs); // --- Metadata ---------------------------------------------------------------- diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 47e709c4..161ac01d 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -15,7 +15,18 @@ internal B32 lnk_symbol_defined_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - return a->defined.obj->input_idx < b->defined.obj->input_idx; + + + U32 a_lib_input_idx = a->defined.obj->lib ? a->defined.obj->lib->input_idx : 0; + U32 b_lib_input_idx = b->defined.obj->lib ? b->defined.obj->lib->input_idx : 0; + + if (a_lib_input_idx == b_lib_input_idx) { + if (a->defined.obj->input_idx == b->defined.obj->input_idx) { + return a->defined.symbol_idx < b->defined.symbol_idx; + } + return a->defined.obj->input_idx < b->defined.obj->input_idx; + } + return a_lib_input_idx < b_lib_input_idx; } internal B32 diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index b87fa44b..c789a270 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -14,6 +14,7 @@ typedef struct LNK_SymbolDefined typedef struct LNK_Symbol { String8 name; + B8 is_lib_member_linked; LNK_SymbolDefined defined; } LNK_Symbol; From 78b1f7e7015b8c60d3f27c312ad87ce303aec09a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 21:56:15 -0700 Subject: [PATCH 120/302] optionally emit import thunks --- src/pe/pe_make_import_table.c | 54 ++++++++++++++++++++++++----------- src/pe/pe_make_import_table.h | 30 +++++++++++++++++-- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/pe/pe_make_import_table.c b/src/pe/pe_make_import_table.c index 2c1adcb9..9fe829eb 100644 --- a/src/pe/pe_make_import_table.c +++ b/src/pe/pe_make_import_table.c @@ -1,6 +1,22 @@ // Copyright (c) 2025 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal void +pe_make_import_header_list_push_node(PE_MakeImportList *list, PE_MakeImportNode *node) +{ + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal PE_MakeImportNode * +pe_make_import_header_list_push(Arena *arena, PE_MakeImportList *list, PE_MakeImport v) +{ + PE_MakeImportNode *node = push_array(arena, PE_MakeImportNode, 1); + node->v = v; + pe_make_import_header_list_push_node(list, node); + return node; +} + internal COFF_ObjSymbol * pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name) { @@ -237,7 +253,7 @@ pe_make_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_ } internal String8 -pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, String8List import_headers) +pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, PE_MakeImportList import_headers) { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); @@ -252,7 +268,7 @@ pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mach COFF_ObjSection *iat_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), PE_IDATA_SECTION_FLAGS|import_align, str8_zero()); COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero()); COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr); - COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$i"), PE_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero()); + COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$zz"), PE_TEXT_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero()); COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect); COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect); @@ -263,8 +279,8 @@ pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mach coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, name_voff), dll_name_symbol); coff_obj_writer_section_push_reloc_voff(obj_writer, dll_sect, OffsetOf(PE_ImportEntry, import_addr_table_voff), iat_symbol); - for (String8Node *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) { - COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->string); + for (PE_MakeImportNode *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) { + COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->v.header); COFF_ObjSymbol *iat_symbol = 0; switch (import_header.import_by) { @@ -300,12 +316,15 @@ pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mach } // emit thunks - COFF_ObjSymbol *jmp_thunk_symbol = 0; - if (import_header.type == COFF_ImportHeader_Code) { - switch (import_header.machine) { - case COFF_MachineType_Unknown: {} break; - case COFF_MachineType_X64: { jmp_thunk_symbol = pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); } break; - default: { NotImplemented; } break; + if (import_header_n->v.make_jump_thunk) { + if (import_header.type == COFF_ImportHeader_Code) { + switch (import_header.machine) { + case COFF_MachineType_Unknown: {} break; + case COFF_MachineType_X64: { pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); } break; + default: { NotImplemented; } break; + } + } else { + Assert(0 && "unable to make a jump thunk for non-code target"); } } } @@ -314,12 +333,13 @@ pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mach str8_list_push(obj_writer->arena, &iat_sect->data, str8(0, coff_word_size_from_machine(machine))); String8 dll_obj = coff_obj_writer_serialize(arena, obj_writer); + coff_obj_writer_release(&obj_writer); return dll_obj; } internal String8 -pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, String8List import_headers, B32 emit_biat, B32 emit_uiat) +pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, PE_MakeImportList import_headers, B32 emit_biat, B32 emit_uiat) { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); @@ -385,11 +405,10 @@ pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mac default: { NotImplemented; } break; } - for (String8Node *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) { - COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->string); + for (PE_MakeImportNode *import_header_n = import_headers.first; import_header_n != 0; import_header_n = import_header_n->next) { + COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(import_header_n->v.header); // emit thunks - COFF_ObjSymbol *jmp_thunk_symbol = 0; COFF_ObjSymbol *load_thunk_symbol = 0; if (import_header.type == COFF_ImportHeader_Code) { switch (machine) { @@ -398,8 +417,11 @@ pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mac String8 iat_symbol_name = push_str8f(obj_writer->arena, "__imp_%S", import_header.func_name); iat_symbol = coff_obj_writer_push_symbol_extern(obj_writer, iat_symbol_name, iat_sect->data.total_size, iat_sect); - // emit thunks - jmp_thunk_symbol = pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); + if (import_header_n->v.make_jump_thunk) { + pe_make_indirect_jump_thunk_x64(obj_writer, code_sect, iat_symbol, import_header.func_name); + } + + // emit load thunk load_thunk_symbol = pe_make_load_thunk_x64(obj_writer, code_sect, iat_symbol, tail_merge_symbol, import_header.func_name); } break; default: { NotImplemented; } break; diff --git a/src/pe/pe_make_import_table.h b/src/pe/pe_make_import_table.h index 5ff7006e..a89703a2 100644 --- a/src/pe/pe_make_import_table.h +++ b/src/pe/pe_make_import_table.h @@ -4,12 +4,36 @@ #ifndef PE_MAKE_IMPORT_TABLE_H #define PE_MAKE_IMPORT_TABLE_H +typedef struct PE_MakeImport +{ + String8 header; + B32 make_jump_thunk; +} PE_MakeImport; + +typedef struct PE_MakeImportNode +{ + PE_MakeImport v; + struct PE_MakeImportNode *next; +} PE_MakeImportNode; + +typedef struct PE_MakeImportList +{ + U64 count; + PE_MakeImportNode *first; + PE_MakeImportNode *last; +} PE_MakeImportList; + +// ----------------------------------------------------------------------------- + +internal void pe_make_import_header_list_push_node(PE_MakeImportList *list, PE_MakeImportNode *node); +internal PE_MakeImportNode * pe_make_import_header_list_push(Arena *arena, PE_MakeImportList *list, PE_MakeImport header); + internal COFF_ObjSymbol * pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *iat_symbol, String8 thunk_name); internal COFF_ObjSymbol * pe_make_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, COFF_ObjSymbol *imp_addr_ptr, COFF_ObjSymbol *tail_merge, String8 func_name); internal COFF_ObjSymbol * pe_make_tail_merge_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, String8 dll_name, String8 delay_load_helper_name, COFF_ObjSymbol *dll_import_descriptor); -internal String8 pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stmap, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, String8List import_headers); -internal String8 pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, String8List import_headers, B32 emit_biat, B32 emit_uiat); +internal String8 pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stmap, COFF_MachineType machine, String8 dll_name, String8 debug_symbols, PE_MakeImportList import_headers); +internal String8 pe_make_import_dll_obj_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 dll_name, String8 delay_load_helper_name, String8 debug_symbols, PE_MakeImportList import_headers, B32 emit_biat, B32 emit_uiat); internal String8 pe_make_import_entry_obj_delayed(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols); internal String8 pe_make_null_import_descriptor_delayed(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols); @@ -19,4 +43,4 @@ internal String8 pe_make_import_entry_obj(Arena *arena, String8 dll_name, COFF_T internal String8 pe_make_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols); internal String8 pe_make_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 debug_symbols); -#endif // PE_MAKE_IMPORT_TABLE_H \ No newline at end of file +#endif // PE_MAKE_IMPORT_TABLE_H From fdad3f4f58dc914c81267c3deb091c677e6eb6b8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 21:56:48 -0700 Subject: [PATCH 121/302] natvis for lib member ref --- src/linker/linker.natvis | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index 9c69c117..b8c5aaf9 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -4,6 +4,14 @@ {{ name={name} flags={flags} id={id} sort_index={sort_index} }} + + + lib->was_member_linked[member_idx] + lib + member_idx + + + From 845e225e81679d6bfa3b30a80c12011e5b15ccdf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 21:57:41 -0700 Subject: [PATCH 122/302] push alt name strings after they are copied to the config arena --- src/linker/lnk_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index aa5ab473..adc468d2 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1162,8 +1162,6 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List lnk_error_obj(LNK_Error_AlternateNameConflict, obj, "conflicting alternative name: existing '%S=%S' vs. new '%S=%S'", alt_name.from, to_extant, alt_name.from, alt_name.to); } } else { - hash_table_push_string_string(config->arena, config->alt_name_ht, alt_name.from, alt_name.to); - alt_name.from = push_str8_copy(config->arena, alt_name.from); alt_name.to = push_str8_copy(config->arena, alt_name.to); @@ -1172,6 +1170,8 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List SLLQueuePush(config->alt_name_list.first, config->alt_name_list.last, alt_name_n); config->alt_name_list.count += 1; + + hash_table_push_string_string(config->arena, config->alt_name_ht, alt_name.from, alt_name.to); } } } else { From 43b35d43dc12c87017850113241ad1ab264d7c0b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 21:59:00 -0700 Subject: [PATCH 123/302] change lib sort to preserve input order --- src/linker/lnk_lib.c | 13 +++++++------ src/linker/lnk_lib.h | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 6002046b..5885b933 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -10,11 +10,11 @@ lnk_lib_node_is_before(void *a, void *b) internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b) { - return raw_a < raw_b; + return lnk_lib_node_is_before(*(LNK_Lib **)raw_a, *(LNK_Lib **)raw_b); } internal B32 -lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) +lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_Lib *lib_out) { ProfBeginFunction(); @@ -119,6 +119,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out) lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count); lib_out->symbol_names = symbol_names; lib_out->long_names = parse.long_names; + lib_out->input_idx = input_idx; ProfEnd(); return 1; @@ -133,7 +134,7 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer) U64 lib_node_idx = ins_atomic_u64_inc_eval(&task->next_free_lib_idx)-1; LNK_LibNode *lib_node = &task->free_libs[lib_node_idx]; - B32 is_valid_lib = lnk_lib_from_data(arena, input->data, input->path, &lib_node->data); + B32 is_valid_lib = lnk_lib_from_data(arena, input->data, input->path, task->lib_id_base + task_id, &lib_node->data); if (is_valid_lib) { U64 valid_lib_idx = ins_atomic_u64_inc_eval(&task->valid_libs_count)-1; task->valid_libs[valid_lib_idx] = lib_node; @@ -170,6 +171,7 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U // parse libs in parallel LNK_LibIniter task = {0}; + task.lib_id_base = list->count; task.free_libs = push_array(arena->v[0], LNK_LibNode, inputs_count); task.valid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count); task.invalid_libs = push_array(scratch.arena, LNK_LibNode *, inputs_count); @@ -186,7 +188,6 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U // push parsed libs radsort(task.valid_libs, task.valid_libs_count, lnk_lib_node_ptr_is_before); for EachIndex(i, task.valid_libs_count) { - task.valid_libs[i]->data.input_idx = lib_id_base + i; lnk_lib_list_push_node(list, task.valid_libs[i]); } @@ -197,9 +198,9 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U } internal B32 -lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger) +lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) { - LNK_Symbol *slot = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], trigger, 0); + LNK_Symbol *slot = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], link_symbol, 0); B32 is_first_queue_attempt = (slot == 0); return is_first_queue_attempt; } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index e266dbc7..90e3a983 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -41,6 +41,7 @@ typedef struct LNK_LibList typedef struct { struct LNK_Input **inputs; + U64 lib_id_base; U64 next_free_lib_idx; U64 valid_libs_count; U64 invalid_libs_count; @@ -54,12 +55,12 @@ typedef struct internal int lnk_lib_node_is_before(void *a, void *b); internal int lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b); -internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out); +internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_Lib *lib_out); internal LNK_Lib ** lnk_array_from_lib_list(Arena *arena, LNK_LibList list); internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node); internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, struct LNK_Input **inputs); -internal B32 lnk_flag_member_as_queued(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger); +internal B32 lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger); internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out); From 9f6da0ec63531eb29eedc23cf2c0d685b655fba3 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:01:02 -0700 Subject: [PATCH 124/302] simplify section removal and purging --- src/linker/lnk_section_table.c | 74 ++++++++++++++++------------------ src/linker/lnk_section_table.h | 1 + 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index dd85728f..84d8dd6f 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -57,6 +57,20 @@ lnk_array_from_section_contrib_chunk_list(Arena *arena, LNK_SectionContribChunkL return result; } +internal void +lnk_section_list_push_node(LNK_SectionList *list, LNK_SectionNode *node) +{ + DLLPushBack(list->first, list->last, node); + list->count += 1; +} + +internal void +lnk_section_list_remove_node(LNK_SectionList *list, LNK_SectionNode *node) +{ + DLLRemove(list->first, list->last, node); + list->count -= 1; +} + internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionList list) { @@ -115,7 +129,7 @@ lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags sect->flags = flags; LNK_SectionList *sect_list = §ab->list; - SLLQueuePush(sect_list->first, sect_list->last, sect_node); + DLLPushBack(sect_list->first, sect_list->last, sect_node); sect_list->count += 1; String8 name_with_flags = lnk_make_name_with_flags(sectab->arena, name, flags); @@ -129,47 +143,31 @@ internal LNK_SectionNode * lnk_section_table_remove(LNK_SectionTable *sectab, String8 name) { ProfBeginFunction(); - - // find node LNK_SectionNode *node; for (node = sectab->list.first; node != 0; node = node->next) { if (str8_match(node->data.name, name, 0)) { + lnk_section_list_remove_node(§ab->list, node); break; } } - - // remove node - { - LNK_SectionList *list = §ab->list; - if (list->count > 0) { - if (list->first == node) { - list->first = list->first->next; - list->count -= 1; - - if (list->last == node) { - list->last = 0; - } - } else { - for (LNK_SectionNode *curr = list->first, *prev = 0; curr != 0; prev = curr, curr = curr->next) { - if (curr == node) { - prev->next = curr->next; - list->count -= 1; - - if (list->last == curr) { - list->last = prev; - } - - break; - } - } - } - } - } - ProfEnd(); return node; } +internal void +lnk_section_table_purge(LNK_SectionTable *sectab, String8 name) +{ + Temp scratch = scratch_begin(0,0); + + LNK_SectionNode *node = lnk_section_table_remove(sectab, name); + String8 name_with_flags = lnk_make_name_with_flags(scratch.arena, name, node->data.flags); + KeyValuePair *kv = hash_table_search_string(sectab->sect_ht, name_with_flags); + kv->key_string = str8_zero(); + kv->value_raw = 0; + + scratch_end(scratch); +} + internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 full_or_partial_name, COFF_SectionFlags flags) { @@ -232,7 +230,7 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l str8_lit_comp(".rsrc"), str8_lit_comp(".reloc"), }; - for (U64 i = 0; i < ArrayCount(illegal_merge_sections); i += 1) { + for EachIndex(i, ArrayCount(illegal_merge_sections)) { if (str8_match(merge->src, illegal_merge_sections[i], 0)) { lnk_error(LNK_Error_IllegalSectionMerge, "illegal to merge %S with %S", illegal_merge_sections[i], merge->dst); } @@ -248,8 +246,7 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->data.src, merge_node->data.dst); } for (LNK_SectionNode *sect_n = sectab->merge_list.first; sect_n != 0; sect_n = sect_n->next) { - if (str8_match(sect_n->data.name, merge_node->data.dst, 0) || - str8_match(sect_n->data.name, merge_node->data.src, 0)) { + if (str8_match(sect_n->data.name, merge_node->data.dst, 0)) { lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->data.src, merge_node->data.dst); } } @@ -292,7 +289,7 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l } } - for (U64 src_idx = 0; src_idx < src_matches.count; src_idx += 1) { + for EachIndex(src_idx, src_matches.count) { LNK_Section *src = src_matches.v[src_idx]; if (src->flags != dst->flags) { @@ -304,12 +301,11 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l lnk_section_contrib_chunk_list_concat_in_place(&dst->contribs, &src->contribs); src->merge_dst = dst; - // remove from output section list + // remove node from output section list LNK_SectionNode *merge_node = lnk_section_table_remove(sectab, src->name); // move node to the merge list - SLLQueuePush(sectab->merge_list.first, sectab->merge_list.last, merge_node); - sectab->merge_list.count += 1; + lnk_section_list_push_node(§ab->merge_list, merge_node); } } scratch_end(scratch); diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index 4f08c3c1..b1999443 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -106,6 +106,7 @@ internal LNK_SectionTable * lnk_section_table_alloc(void); internal void lnk_section_table_release(LNK_SectionTable **sectab_ptr); internal LNK_Section * lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); internal LNK_SectionNode * lnk_section_table_remove(LNK_SectionTable *sectab, String8 name); +internal void lnk_section_table_purge(LNK_SectionTable *sectab, String8 name); internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); internal LNK_SectionArray lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 full_or_partial_name); internal void lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list); From a64f8f4196d227af04ed86a53fb2cedef175402d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:02:48 -0700 Subject: [PATCH 125/302] clean up over base strings in the linker layer --- src/linker/base_ext/base_strings.c | 55 ++---------------------------- src/linker/base_ext/base_strings.h | 9 +---- src/linker/codeview_ext/codeview.c | 2 +- 3 files changed, 5 insertions(+), 61 deletions(-) diff --git a/src/linker/base_ext/base_strings.c b/src/linker/base_ext/base_strings.c index fe465f5e..5688bb4a 100644 --- a/src/linker/base_ext/base_strings.c +++ b/src/linker/base_ext/base_strings.c @@ -1,52 +1,10 @@ // Copyright (c) 2025 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal String8Node * -str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size) +internal B32 +str8_starts_with(String8 string, String8 expected_prefix) { - String8 data = str8((U8 *)data_ptr, data_size); - String8Node *node = str8_list_push(arena, list, data); - return node; -} - -internal U64 -str8_list_push_pad(Arena *arena, String8List *list, U64 offset, U64 align) -{ - U64 pad_size = AlignPow2(offset, align) - offset; - U8 *pad = push_array(arena, U8, pad_size); - MemorySet(pad, 0, pad_size); - str8_list_push(arena, list, str8(pad, pad_size)); - return pad_size; -} - -internal U64 -str8_list_push_pad_front(Arena *arena, String8List *list, U64 offset, U64 align) -{ - U64 pad_size = AlignPow2(offset, align) - offset; - U8 *pad = push_array(arena, U8, pad_size); - MemorySet(pad, 0, pad_size); - str8_list_push_front(arena, list, str8(pad, pad_size)); - return pad_size; -} - -internal String8List -str8_list_arr_concat(String8List *v, U64 count) -{ - String8List result = {0}; - for (U64 i = 0; i < count; i += 1) { - str8_list_concat_in_place(&result, &v[i]); - } - return result; -} - -internal String8Node * -str8_list_push_many(Arena *arena, String8List *list, U64 count) -{ - String8Node *arr = push_array(arena, String8Node, count); - for (U64 i = 0; i < count; ++i) { - str8_list_push_node(list, arr + i); - } - return arr; + return str8_match(str8_prefix(string, expected_prefix.size), expected_prefix, 0); } internal String8Node * @@ -63,10 +21,3 @@ str8_list_pop_front(String8List *list) return node; } -internal U64 -hash_from_str8(String8 string) -{ - XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size); - return hash64; -} - diff --git a/src/linker/base_ext/base_strings.h b/src/linker/base_ext/base_strings.h index b469cccf..500f2fa0 100644 --- a/src/linker/base_ext/base_strings.h +++ b/src/linker/base_ext/base_strings.h @@ -3,15 +3,8 @@ #pragma once -#define str8_list_push_struct(a,l,d) str8_list_push_raw(a, l, d, sizeof(*d)) -internal String8Node * str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size); -internal U64 str8_list_push_pad(Arena *arena, String8List *list, U64 offset, U64 align); -internal U64 str8_list_push_pad_front(Arena *arena, String8List *list, U64 offset, U64 align); -internal String8List str8_list_arr_concat(String8List *v, U64 count); -internal String8Node * str8_list_push_many(Arena *arena, String8List *list, U64 count); - // TODO: remove internal String8Node * str8_list_pop_front(String8List *list); -internal U64 hash_from_str8(String8 string); +internal B32 str8_starts_with(String8 string, String8 expected_prefix); diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index af4aeba7..672d1689 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -587,7 +587,7 @@ cv_file_chksms_from_debug_s(CV_DebugS debug_s) internal U64 cv_string_hash_table_hash(String8 string) { - return hash_from_str8(string); + return u64_hash_from_str8(string); } internal int From 0b0a2664d1ad13b91f31c85110ec3780a0c288cf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:04:02 -0700 Subject: [PATCH 126/302] merge .idata with .rdata --- src/linker/lnk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 3f9ce0e0..7013b784 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -183,9 +183,9 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".00cfg=.rdata"); // TODO: .tls must be always first contribution in .data section because compiler generates TLS relative movs //lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".tls=.data"); - lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".edata=.rdata"); - //lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".idata=.rdata"); + lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".idata=.data"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".didat=.data"); + lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".edata=.rdata"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".RAD_LINK_PE_DEBUG_DIR=.rdata"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Merge, ".RAD_LINK_PE_DEBUG_DATA=.rdata"); From 8d75497bba4c75123667805eb1479511cc4c375e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:04:33 -0700 Subject: [PATCH 127/302] do not set function pad min switch by default --- src/linker/lnk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7013b784..e3437ab5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -144,7 +144,6 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); } - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_FunctionPadMin, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); From 43e81b934b307c633dab6c43ed183204d8ce16cb Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:15:31 -0700 Subject: [PATCH 128/302] move weak symbol replacer to the symbol table layer --- src/linker/lnk.c | 164 ++++++++++++---------------------- src/linker/lnk.h | 6 -- src/linker/lnk_symbol_table.c | 67 +++++++++++++- src/linker/lnk_symbol_table.h | 8 ++ 4 files changed, 131 insertions(+), 114 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e3437ab5..7c66679b 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1676,40 +1676,6 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 1); } -internal -THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) -{ - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); - COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); - COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); - if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); - if (symbol->defined.obj->header.is_big_obj) { - COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; - symbol32->section_number = COFF_Symbol_UndefinedSection; - symbol32->value = 0; - symbol32->storage_class = COFF_SymStorageClass_External; - } else { - COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; - symbol16->section_number = COFF_Symbol_UndefinedSection; - symbol16->value = 0; - symbol16->storage_class = COFF_SymStorageClass_External; - } - } else { - symbol->defined = resolve; - } - } - } -} - internal LNK_Link * lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab) { @@ -1945,6 +1911,65 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); + // + // finalize symbol table + // + lnk_replace_weak_with_default_symbols(tp, symtab); + + // + // was entry point resolved? + // + if (config->entry_point_name.size == 0 || link->try_to_resolve_entry_point) { + lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); + } + + // + // report undefined symbols + // + { + ProfBegin("Report Unresolved Symbols"); + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); + + U64 count = 0; + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + count += 1; + } + } + } + + U64 cursor = 0; + LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + unresolved[cursor++] = chunk->v[i].symbol; + } + } + } + + radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); + + for EachIndex(i, count) { + LNK_Symbol *symbol = unresolved[i]; + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); + } + + // TODO: /FORCE + if (count) { + lnk_exit(LNK_Error_UnresolvedSymbol); + } + ProfEnd(); + } + // // warn about unused delayloads // @@ -1956,77 +1981,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } } - // - // report undefined symbols - // - { - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); - - ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); - { - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); -#if BUILD_DEBUG - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); - } - } -#endif - } - ProfEnd(); - - - if (config->entry_point_name.size == 0) { - lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); - } - - ProfBegin("Report Unresolved Symbols"); - { - U64 count = 0; - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - count += 1; - } - } - } - - U64 cursor = 0; - LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - unresolved[cursor++] = chunk->v[i].symbol; - } - } - } - - radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); - - for EachIndex(i, count) { - LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); - } - - // TODO: /FORCE - if (count) { - lnk_exit(LNK_Error_UnresolvedSymbol); - } - } - ProfEnd(); - } - // // discard COMDAT sections that are not referenced // diff --git a/src/linker/lnk.h b/src/linker/lnk.h index f26c5f24..e3563083 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -154,12 +154,6 @@ typedef struct LNK_BaseRelocPageArray // --- Workers Contexts -------------------------------------------------------- -typedef struct -{ - LNK_SymbolTable *symtab; - LNK_SymbolHashTrieChunk **chunks; -} LNK_ReplaceWeakSymbolsWithDefaultSymbolTask; - typedef struct { LNK_SymbolTable *symtab; diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 161ac01d..02f45b5a 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -16,9 +16,10 @@ lnk_symbol_defined_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - - U32 a_lib_input_idx = a->defined.obj->lib ? a->defined.obj->lib->input_idx : 0; - U32 b_lib_input_idx = b->defined.obj->lib ? b->defined.obj->lib->input_idx : 0; + LNK_Lib *a_lib = lnk_obj_get_lib(a->defined.obj); + LNK_Lib *b_lib = lnk_obj_get_lib(b->defined.obj); + U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0; + U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0; if (a_lib_input_idx == b_lib_input_idx) { if (a->defined.obj->input_idx == b->defined.obj->input_idx) { @@ -657,6 +658,66 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...) return symbol; } +internal +THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) +{ + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); + COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); + COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); + if (resolve_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); + if (symbol->defined.obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; + symbol32->section_number = COFF_Symbol_UndefinedSection; + symbol32->value = 0; + symbol32->storage_class = COFF_SymStorageClass_External; + } else { + COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; + symbol16->section_number = COFF_Symbol_UndefinedSection; + symbol16->value = 0; + symbol16->storage_class = COFF_SymStorageClass_External; + } + } else { + symbol->defined = resolve; + } + } + } +} + +internal void +lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) +{ + Temp scratch = scratch_begin(0,0); + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); + + ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); + LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); + +#if BUILD_DEBUG + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); + } + } +#endif + + scratch_end(scratch); + ProfEnd(); +} + internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index c789a270..04d01ead 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -78,6 +78,14 @@ typedef struct LNK_SymbolTable LNK_SymbolHashTrieChunkList *chunks; } LNK_SymbolTable; +// --- Workers Contexts -------------------------------------------------------- + +typedef struct +{ + LNK_SymbolTable *symtab; + LNK_SymbolHashTrieChunk **chunks; +} LNK_ReplaceWeakSymbolsWithDefaultSymbolTask; + // --- Symbol Make ------------------------------------------------------------- internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); From 580303b0dd3388fc25561b87c996a5f21fd6efce Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:20:34 -0700 Subject: [PATCH 129/302] emit jump thunks for imports only when needed --- src/linker/lnk.c | 139 +++++++++++++++++++++++-------------------- src/linker/lnk.h | 11 ++-- src/linker/lnk_obj.c | 33 ++++++---- src/linker/lnk_obj.h | 17 +++--- 4 files changed, 110 insertions(+), 90 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7c66679b..43435687 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -998,31 +998,31 @@ lnk_inputer_push_thin(Arena *arena, LNK_InputList *list, HashTable *ht, String8 } internal LNK_Input * -lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data) +lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path, String8 data) { lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); LNK_Input *input = lnk_input_push(inputer->arena, &inputer->new_objs, path, data); - input->trigger = trigger; + input->link_member = link_member; return input; } internal LNK_Input * -lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data) +lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path, String8 data) { lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); LNK_Input *input = lnk_inputer_push_linkgen(inputer->arena, &inputer->new_objs, path, data); - input->trigger = trigger; + input->link_member = link_member; return input; } internal LNK_Input * -lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path) +lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path) { lnk_log(LNK_Log_InputObj, "Input Obj: %S", path); Temp scratch = scratch_begin(0,0); String8 full_path = os_full_path_from_path(scratch.arena, path); LNK_Input *input = lnk_inputer_push_thin(inputer->arena, &inputer->new_objs, inputer->objs_ht, full_path); - input->trigger = trigger; + input->link_member = link_member; scratch_end(scratch); return input; } @@ -1257,7 +1257,7 @@ internal void lnk_load_libs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link) { for EachIndex(input_source, LNK_InputSource_Count) { - ProfBegin("Input Libs [Count %llu]", inputer->new_libs[i].count); + //ProfBegin("Input Libs [Count %llu]", inputer->new_libs[i].count); LNK_InputPtrArray new_input_libs = lnk_inputer_flush(arena->v[0], tp, inputer, config->io_flags, &inputer->libs, &inputer->new_libs[input_source]); @@ -1315,7 +1315,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_Obj *obj_with_includes = objs_with_includes[i]; String8 include_obj_path = obj_with_includes ? obj_with_includes->path : str8_lit("RADLINK"); String8 include_obj_data = lnk_make_obj_with_undefined_symbols(arena->v[0], *include_names[i]); - lnk_inputer_push_obj_linkgen(inputer, obj_with_includes ? obj_with_includes->trigger_symbol : 0, include_obj_path, include_obj_data); + lnk_inputer_push_obj_linkgen(inputer, obj_with_includes ? obj_with_includes->link_member : 0, include_obj_path, include_obj_data); U64 include_obj_count = 0; LNK_ObjNode *include_obj = lnk_load_objs(tp, arena, config, inputer, symtab, link, &include_obj_count); @@ -1462,7 +1462,7 @@ subsystem_inferred_from_entry:; internal void lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *trigger_symbol, LNK_Lib *lib, U32 member_idx) { - if (lnk_flag_member_as_queued(lib, member_idx, trigger_symbol)) { + if (lnk_lib_set_link_symbol(lib, member_idx, trigger_symbol)) { LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1); member_ref->lib = lib; member_ref->member_idx = member_idx; @@ -1494,6 +1494,8 @@ lnk_link_inputs_(TP_Context *tp, for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { do { + lnk_load_inputs(tp, arena, config, inputer, symtab, link); + LNK_LibMemberRefList queued_members = {0}; for EachIndex(worker_id, symtab->arena->count) { for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { @@ -1539,6 +1541,7 @@ lnk_link_inputs_(TP_Context *tp, LNK_LibMemberRef *member_ref = member_refs[i]; LNK_Lib *lib = member_ref->lib; U32 member_offset = lib->member_offsets[member_ref->member_idx]; + LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; // parse member COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); @@ -1565,23 +1568,25 @@ lnk_link_inputs_(TP_Context *tp, if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name, 0)) { break; } hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); - // create import stubs (later replaced with acutal imports generated by linker) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->defined.obj, import_stub->defined.symbol_idx); - LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(symtab->arena->v[0], "__imp_%S", import_header.func_name), import_stub->defined.obj, import_stub->defined.symbol_idx); - lnk_symbol_table_push(symtab, thunk_symbol); - lnk_symbol_table_push(symtab, imp_symbol); + // create import stub (later replaced with acutal import generated by linker) + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + LNK_Symbol *import_symbol = lnk_make_defined_symbol(symtab->arena->v[0], link_symbol->name, import_stub->defined.obj, import_stub->defined.symbol_idx); + lnk_symbol_table_push(symtab, import_symbol); // search DLL symbol list - HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? imps->delayed_imports : imps->static_imports; - String8List *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); + String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; + HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; + PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); if (import_symbols == 0) { - import_symbols = push_array(imps->arena, String8List, 1); + import_symbols = push_array(imps->arena, PE_MakeImportList, 1); + str8_list_push(imps->arena, dll_names, import_header.dll_name); hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols); } // push symbol - str8_list_push(imps->arena, import_symbols, member_info.data); + PE_MakeImport make_import = { .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }; + pe_make_import_header_list_push(imps->arena, import_symbols, make_import); } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { @@ -1614,8 +1619,6 @@ lnk_link_inputs_(TP_Context *tp, } } - lnk_load_inputs(tp, arena, config, inputer, symtab, link); - resolved_members_count += queued_members.count; } while (lnk_inputer_has_items(inputer)); } @@ -1631,7 +1634,7 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer { lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 0); - // input /ALTERNATENAME + // handle /ALTERNATENAME { // replace undefined symbols that have an alternate name with a weak symbol for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { @@ -1641,6 +1644,7 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer if (interp == COFF_SymbolValueInterp_Undefined) { // clear out slot so weak symbol can replace undefined symbol (general rule is // weak symbol is not allowed to replace undefined) + LNK_Symbol *undef_symbol = symbol_ht->symbol; symbol_ht->symbol = 0; // make obj with alternamte name symbol @@ -1654,10 +1658,11 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer coff_obj_writer_release(&obj_writer); } - // input alt name obj - LNK_Obj *obj_with_alt_name = alt_name_n->data.obj; - String8 alt_name_obj_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); - lnk_inputer_push_obj_linkgen(inputer, 0, alt_name_obj_path, alt_name_obj_data); + LNK_Obj *obj_with_alt_name = alt_name_n->data.obj; + String8 obj_with_alt_name_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); + lnk_inputer_push_obj_linkgen(inputer, obj_with_alt_name ? obj_with_alt_name->link_member : 0, obj_with_alt_name_path, alt_name_obj_data); + + lnk_load_inputs(tp, arena, config, inputer, symtab, link); } } } @@ -1721,7 +1726,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // link inputer lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); - // TODO: need to know under which condition to include load config + // TODO: need to figure out under what condition to include load config //lnk_include_symbol(config, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME), 0); { @@ -1733,27 +1738,28 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // make and input delayed imports { - HashTable *delayed_imports = imps->delayed_imports; - if (delayed_imports->count) { + String8List delayed_dll_names = imps->delayed_dll_names; + HashTable *delayed_imports_ht = imps->delayed_imports; + AssertAlways(delayed_dll_names.node_count == delayed_imports_ht->count); + if (delayed_imports_ht->count) { ProfBegin("Build Delay Import Table"); - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; - B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; + B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; - for EachIndex(dll_idx, delayed_imports->count) { - String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); - String8 import_obj = pe_make_import_dll_obj_delayed(arena->v[0], time_stamp, config->machine, dll_names[dll_idx], config->delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); - lnk_inputer_push_obj(inputer, 0, dll_names[dll_idx], import_obj); + for (String8Node *dll_name_n = delayed_dll_names.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { + PE_MakeImportList *imports = hash_table_search_path_raw(delayed_imports_ht, dll_name_n->string); + String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_name_n->string); + String8 import_obj = pe_make_import_dll_obj_delayed(arena->v[0], time_stamp, config->machine, dll_name_n->string, config->delay_load_helper_name, import_debug_symbols, *imports, emit_biat, emit_uiat); + lnk_inputer_push_obj(inputer, 0, dll_name_n->string, import_obj); } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(arena->v[0], config->machine); String8 null_desc_obj = pe_make_null_import_descriptor_delayed(arena->v[0], time_stamp, config->machine, linker_debug_symbols); String8 null_thunk_obj = pe_make_null_thunk_data_obj_delayed(arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); lnk_inputer_push_obj(inputer, 0, str8_lit("* Delayed Null Import Descriptor *"), null_desc_obj); - lnk_inputer_push_obj(inputer, 0, str8_lit("* Delayed Null Thunk Data *"), null_thunk_obj); + lnk_inputer_push_obj(inputer, 0, str8_lit("* Delayed Null Thunk Data *"), null_thunk_obj); ProfEnd(); } @@ -1761,24 +1767,26 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // make and input static imports { - HashTable *static_imports = imps->static_imports; - if (static_imports->count) { + String8List static_dll_names = imps->static_dll_names; + HashTable *static_imports_ht = imps->static_imports; + AssertAlways(static_dll_names.node_count == static_imports_ht->count); + if (static_imports_ht->count) { ProfBegin("Build Static Import Table"); - COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; - String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); - String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); - for EachIndex(dll_idx, static_imports->count) { - String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); - String8 import_obj = pe_make_import_dll_obj_static(arena->v[0], time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); - lnk_inputer_push_obj(inputer, 0, dll_names[dll_idx], import_obj); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; + + for (String8Node *dll_name_n = static_dll_names.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { + PE_MakeImportList *imports = hash_table_search_path_raw(static_imports_ht, dll_name_n->string); + String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_name_n->string); + String8 import_obj = pe_make_import_dll_obj_static(arena->v[0], time_stamp, config->machine, dll_name_n->string, import_debug_symbols, *imports); + lnk_inputer_push_obj(inputer, 0, dll_name_n->string, import_obj); } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); - String8 null_desc_obj = pe_make_null_import_descriptor_obj(arena->v[0], time_stamp, config->machine, linker_debug_symbols); - String8 null_thunk_obj = pe_make_null_thunk_data_obj(arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); + String8 null_desc_obj = pe_make_null_import_descriptor_obj(arena->v[0], time_stamp, config->machine, linker_debug_symbols); + String8 null_thunk_obj = pe_make_null_thunk_data_obj(arena->v[0], lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null Import Descriptor *"), null_desc_obj); - lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null Thunk Data *"), null_thunk_obj); + lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null Thunk Data *"), null_thunk_obj); ProfEnd(); } @@ -2272,7 +2280,7 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_definitions_task) for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - if (~sect_header->flags & COFF_SectionFlag_LnkRemove && sect_header->fsize > 0) { + if (~sect_header->flags & COFF_SectionFlag_LnkRemove && ~sect_header->flags & COFF_SectionFlag_LnkInfo && sect_header->fsize > 0) { Temp temp = temp_begin(scratch.arena); // was section defined? @@ -2319,7 +2327,7 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task) for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { LNK_SectionContrib *sc = task->null_sc; COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - if (~sect_header->flags & COFF_SectionFlag_LnkRemove && sect_header->fsize > 0) { + if (~sect_header->flags & COFF_SectionFlag_LnkRemove && ~sect_header->flags & COFF_SectionFlag_LnkInfo && sect_header->fsize > 0) { LNK_SectionContribChunk *sc_chunk = 0; { Temp temp = temp_begin(scratch.arena); @@ -4029,13 +4037,12 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT { String8List empty_sect_list = {0}; for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { - LNK_Section *sect = §_n->data; - if (sect->vsize == 0) { - str8_list_push(scratch.arena, &empty_sect_list, sect->name); + if (sect_n->data.vsize == 0) { + str8_list_push(scratch.arena, &empty_sect_list, sect_n->data.name); } } for (String8Node *name_n = empty_sect_list.first; name_n != 0; name_n = name_n->next) { - lnk_section_table_remove(sectab, name_n->string); + lnk_section_table_purge(sectab, name_n->string); } } @@ -4579,11 +4586,11 @@ lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs String8List source_list = {0}; if (obj) { COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1); - String8 string_table = str8_substr(obj->data, obj->header.string_table_range); - String8 section_name = coff_name_from_section_header(string_table, section_header); - if (obj->lib) { - String8 lib_path = lnk_obj_get_lib_path(obj); - String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib_path)); + String8 string_table = str8_substr(obj->data, obj->header.string_table_range); + String8 section_name = coff_name_from_section_header(string_table, section_header); + LNK_Lib *lib = lnk_obj_get_lib(obj); + if (lib) { + String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); String8 obj_name = str8_skip_last_slash(obj->path); str8_list_pushf(temp.arena, &source_list, "%S(%S) SECT%X (%S)", lib_name, obj_name, sect_idx+1, section_name); } else { @@ -4612,9 +4619,9 @@ lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs if (lnk_is_coff_section_debug(obj, sect_idx)) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; if (~section_header->flags & COFF_SectionFlag_LnkRemove) { - if (obj->lib) { - String8 lib_path = lnk_obj_get_lib_path(obj); - String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib_path)); + LNK_Lib *lib = lnk_obj_get_lib(obj); + if (lib) { + String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); String8 obj_name = str8_skip_last_slash(obj->path); str8_list_pushf(arena, &map, "%S(%S) SECT%X\n", lib_name, obj_name, sect_idx+1); } else { @@ -4844,6 +4851,8 @@ entry_point(CmdLine *cmdline) TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name); TP_Arena *tp_arena = tp_arena_alloc(tp); lnk_run(tp, tp_arena, config); + +exit:; scratch_end(scratch); } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index e3563083..6f1f925d 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -9,7 +9,6 @@ typedef struct LNK_LibMemberRef { LNK_Lib *lib; U32 member_idx; - struct LNK_LibMemberRef *next; } LNK_LibMemberRef; @@ -36,7 +35,7 @@ typedef struct LNK_Input B32 is_thin; B32 has_disk_read_failed; B32 exclude_from_debug_info; - LNK_LibMemberRef *trigger; + LNK_LibMemberRef *link_member; void *loaded_input; struct LNK_Input *next; @@ -79,6 +78,8 @@ typedef struct LNK_Inputer typedef struct LNK_ImportTables { Arena *arena; + String8List delayed_dll_names; + String8List static_dll_names; HashTable *static_imports; HashTable *delayed_imports; HashTable *import_stub_ht; @@ -269,9 +270,9 @@ internal LNK_Input * lnk_input_push(Arena *arena, LNK_InputList *list, String8 p internal LNK_Input * lnk_inputer_push_linkgen(Arena *arena, LNK_InputList *list, String8 path, String8 data); internal LNK_Input * lnk_inputer_push_thin(Arena *arena, LNK_InputList *list, HashTable *ht, String8 full_path); -internal LNK_Input * lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data); -internal LNK_Input * lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path, String8 data); -internal LNK_Input * lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *trigger, String8 path); +internal LNK_Input * lnk_inputer_push_obj(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_obj_linkgen(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path, String8 data); +internal LNK_Input * lnk_inputer_push_obj_thin(LNK_Inputer *inputer, LNK_LibMemberRef *link_member, String8 path); internal LNK_Input * lnk_inputer_push_lib(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data); internal LNK_Input * lnk_inputer_push_lib_linkgen(LNK_Inputer *inputer, LNK_InputSourceType input_source, String8 path, String8 data); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 734da57e..608dc8d4 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -15,7 +15,9 @@ internal void lnk_error_input_obj(LNK_ErrorCode code, LNK_Input *input, char *fmt, ...) { va_list args; va_start(args, fmt); - lnk_error_with_loc_fv(code, input->path, input->trigger->lib ? input->trigger->lib->path : str8_zero(), fmt, args); + LNK_LibMemberRef *link_member = input->link_member; + LNK_Lib *link_lib = link_member ? link_member->lib : 0; + lnk_error_with_loc_fv(code, input->path, link_lib ? link_lib->path : str8_zero(), fmt, args); va_end(args); } @@ -37,7 +39,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) LNK_Input *input = task->inputs[task_id]; LNK_Obj *obj = &task->objs[task_id].data; - ProfBeginV("Init Obj [%S%s%S]", input->lib_path, (input->lib_path.size ? ": " : 0), input->path); + //ProfBeginV("Init Obj [%S%s%S]", input->lib_path, (input->lib_path.size ? ": " : 0), input->path); // // parse obj header @@ -244,19 +246,20 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } } - // - // extract obj features from compile symbol in .debug$S - // B8 hotpatch = 0; if (header.machine == COFF_MachineType_X64) { hotpatch = 1; - } else { + } + // + // extract obj features from compile symbol in .debug$S + // + else { Temp scratch = scratch_begin(&arena, 1); CV_Symbol comp_symbol = {0}; - for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { + for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; - String8 name = str8_cstring_capped_reverse(sect_header->name, sect_header->name+sizeof(sect_header->name)); + String8 name = str8_cstring_capped(sect_header->name, sect_header->name+sizeof(sect_header->name)); if (str8_match(name, str8_lit(".debug$S"), 0)) { Temp temp = temp_begin(scratch.arena); String8 debug_s_data = str8_substr(input->data, rng_1u64(sect_header->foff, sect_header->foff+sect_header->fsize)); @@ -288,14 +291,13 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) // fill out obj obj->data = input->data; obj->path = push_str8_copy(arena, input->path); - obj->lib = input->trigger ? input->trigger->lib : 0; obj->header = header; obj->comdats = comdats; obj->exclude_from_debug_info = input->exclude_from_debug_info; obj->hotpatch = hotpatch; obj->associated_sections = associated_sections; obj->node = &task->objs[task_id]; - obj->trigger_symbol = input->trigger; + obj->link_member = input->link_member; ProfEnd(); } @@ -454,12 +456,19 @@ lnk_obj_get_vol_md(LNK_Obj *obj) return lnk_obj_match_symbol(obj, str8_lit("@vol.md")).value; } +internal LNK_Lib * +lnk_obj_get_lib(LNK_Obj *obj) +{ + return obj->link_member ? obj->link_member->lib : 0; +} + internal String8 lnk_obj_get_lib_path(LNK_Obj *obj) { String8 lib_path = {0}; - if (obj && obj->lib) { - lib_path = obj->lib->path; + if (obj) { + LNK_Lib *lib = lnk_obj_get_lib(obj); + lib_path = lib ? lib->path : str8_zero(); } return lib_path; } diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 5ce71547..b7f8840f 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -9,8 +9,6 @@ typedef struct LNK_Obj { String8 path; String8 data; - struct LNK_Lib *lib; - struct LNK_LibMemberRef *trigger_symbol; U32 input_idx; COFF_FileHeaderInfo header; U32 *comdats; @@ -19,6 +17,8 @@ typedef struct LNK_Obj U32Node **associated_sections; LNK_SymbolHashTrie **symlinks; + struct LNK_LibMemberRef *link_member; + struct LNK_ObjNode *node; } LNK_Obj; @@ -102,12 +102,13 @@ internal void lnk_inputer_push_obj_symbols(TP_Context *tp, TP_Arena *arena // --- Metadata ---------------------------------------------------------------- -internal U32 lnk_obj_get_features(LNK_Obj *obj); -internal U32 lnk_obj_get_comp_id(LNK_Obj *obj); -internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); -internal String8 lnk_obj_get_lib_path(LNK_Obj *obj); -internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj); -internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number); +internal U32 lnk_obj_get_features(LNK_Obj *obj); +internal U32 lnk_obj_get_comp_id(LNK_Obj *obj); +internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); +internal struct LNK_Lib * lnk_obj_get_lib(LNK_Obj *obj); +internal String8 lnk_obj_get_lib_path(LNK_Obj *obj); +internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj); +internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number); // --- Symbol & Section Helpers ------------------------------------------------ From e88dc44f31ea18f068b080b9eda82f6cb2243094 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:23:30 -0700 Subject: [PATCH 130/302] clean up debug leftovers --- src/linker/lnk.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 43435687..ebb7a1c1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1560,10 +1560,6 @@ lnk_link_inputs_(TP_Context *tp, break; } - if (str8_match(import_header.func_name, str8_lit("LoadLibraryA"), 0)) { - int x = 0; - } - // skip duplicate import inputer if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name, 0)) { break; } hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); @@ -4851,8 +4847,6 @@ entry_point(CmdLine *cmdline) TP_Context *tp = tp_alloc(scratch.arena, config->worker_count, config->max_worker_count, config->shared_thread_pool_name); TP_Arena *tp_arena = tp_arena_alloc(tp); lnk_run(tp, tp_arena, config); - -exit:; scratch_end(scratch); } From 6a3d7e65f31c6751a7125f5c735a490b8f6139a6 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 22:29:30 -0700 Subject: [PATCH 131/302] remove year from the copyright --- src/coff/coff_lib_writer.c | 2 +- src/coff/coff_lib_writer.h | 2 +- src/dwarf/dwarf_elf.c | 2 +- src/dwarf/dwarf_elf.h | 2 +- src/elf/elf.c | 2 +- src/elf/elf.h | 2 +- src/elf/elf_parse.c | 2 +- src/elf/elf_parse.h | 2 +- src/linker/base_ext/base_arena.c | 2 +- src/linker/base_ext/base_arena.h | 2 +- src/linker/base_ext/base_arrays.c | 2 +- src/linker/base_ext/base_arrays.h | 2 +- src/linker/base_ext/base_bit_array.c | 2 +- src/linker/base_ext/base_bit_array.h | 2 +- src/linker/base_ext/base_blake3.c | 2 +- src/linker/base_ext/base_blake3.h | 2 +- src/linker/base_ext/base_blake3_asm.c | 2 +- src/linker/base_ext/base_blake3_asm.h | 2 +- src/linker/base_ext/base_core.c | 2 +- src/linker/base_ext/base_core.h | 2 +- src/linker/base_ext/base_crc32.c | 2 +- src/linker/base_ext/base_crc32.h | 2 +- src/linker/base_ext/base_inc.c | 2 +- src/linker/base_ext/base_inc.h | 2 +- src/linker/base_ext/base_md5.c | 2 +- src/linker/base_ext/base_md5.h | 2 +- src/linker/base_ext/base_strings.c | 2 +- src/linker/base_ext/base_strings.h | 2 +- src/linker/codeview_ext/codeview.c | 2 +- src/linker/codeview_ext/codeview.h | 2 +- src/linker/hash_table.c | 2 +- src/linker/hash_table.h | 2 +- src/linker/lnk.c | 2 +- src/linker/lnk.h | 2 +- src/linker/lnk_cmd_line.c | 2 +- src/linker/lnk_cmd_line.h | 2 +- src/linker/lnk_config.c | 2 +- src/linker/lnk_config.h | 2 +- src/linker/lnk_debug_helper.c | 2 +- src/linker/lnk_debug_helper.h | 2 +- src/linker/lnk_debug_info.c | 2 +- src/linker/lnk_debug_info.h | 2 +- src/linker/lnk_error.c | 2 +- src/linker/lnk_error.h | 2 +- src/linker/lnk_lib.c | 2 +- src/linker/lnk_lib.h | 2 +- src/linker/lnk_log.c | 2 +- src/linker/lnk_log.h | 2 +- src/linker/lnk_obj.c | 2 +- src/linker/lnk_obj.h | 2 +- src/linker/lnk_section_table.c | 2 +- src/linker/lnk_section_table.h | 2 +- src/linker/lnk_symbol_table.c | 2 +- src/linker/lnk_symbol_table.h | 2 +- src/linker/lnk_timer.c | 2 +- src/linker/lnk_timer.h | 2 +- src/linker/pdb_ext/msf_builder.c | 2 +- src/linker/pdb_ext/msf_builder.h | 2 +- src/linker/pdb_ext/pdb.c | 2 +- src/linker/pdb_ext/pdb.h | 2 +- src/linker/pdb_ext/pdb_builder.c | 2 +- src/linker/pdb_ext/pdb_builder.h | 2 +- src/linker/pdb_ext/pdb_helpers.c | 2 +- src/linker/pdb_ext/pdb_helpers.h | 2 +- src/linker/rdi/rdi_builder.c | 2 +- src/linker/rdi/rdi_builder.h | 2 +- src/linker/rdi/rdi_coff.c | 2 +- src/linker/rdi/rdi_coff.h | 2 +- src/linker/rdi/rdi_cv.c | 2 +- src/linker/rdi/rdi_cv.h | 2 +- src/linker/thread_pool/thread_pool.c | 2 +- src/linker/thread_pool/thread_pool.h | 2 +- src/pe/pe_make_debug_dir.c | 2 +- src/pe/pe_make_debug_dir.h | 2 +- src/pe/pe_make_export_table.c | 2 +- src/pe/pe_make_export_table.h | 2 +- src/pe/pe_make_import_table.c | 2 +- src/pe/pe_make_import_table.h | 2 +- src/pe/pe_section_flags.h | 2 +- src/strip_lib_debug/strip_lib_debug.c | 2 +- src/torture/torture.c | 2 +- 81 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index 25670f2c..aaf590e0 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal COFF_LibWriterSymbolNode * diff --git a/src/coff/coff_lib_writer.h b/src/coff/coff_lib_writer.h index 8a8c2327..2c501409 100644 --- a/src/coff/coff_lib_writer.h +++ b/src/coff/coff_lib_writer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef COFF_LIB_WRITER_H diff --git a/src/dwarf/dwarf_elf.c b/src/dwarf/dwarf_elf.c index 0f1ecdc8..6ea144f8 100644 --- a/src/dwarf/dwarf_elf.c +++ b/src/dwarf/dwarf_elf.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal B32 diff --git a/src/dwarf/dwarf_elf.h b/src/dwarf/dwarf_elf.h index f4ec79ce..a9a54f38 100644 --- a/src/dwarf/dwarf_elf.h +++ b/src/dwarf/dwarf_elf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef DWARF_ELF_H diff --git a/src/elf/elf.c b/src/elf/elf.c index ac3473cb..2eb6d0b3 100644 --- a/src/elf/elf.c +++ b/src/elf/elf.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// diff --git a/src/elf/elf.h b/src/elf/elf.h index 15577bbc..14955224 100644 --- a/src/elf/elf.h +++ b/src/elf/elf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef ELF_H diff --git a/src/elf/elf_parse.c b/src/elf/elf_parse.c index 3b804c0f..5949ebad 100644 --- a/src/elf/elf_parse.c +++ b/src/elf/elf_parse.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //- rjf: top-level binary parsing diff --git a/src/elf/elf_parse.h b/src/elf/elf_parse.h index 1eec7c09..70a467e8 100644 --- a/src/elf/elf_parse.h +++ b/src/elf/elf_parse.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef ELF_PARSE_H diff --git a/src/linker/base_ext/base_arena.c b/src/linker/base_ext/base_arena.c index 669cf47f..f01b9cb8 100644 --- a/src/linker/base_ext/base_arena.c +++ b/src/linker/base_ext/base_arena.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U32 * diff --git a/src/linker/base_ext/base_arena.h b/src/linker/base_ext/base_arena.h index cb7f00ee..3a0e1de4 100644 --- a/src/linker/base_ext/base_arena.h +++ b/src/linker/base_ext/base_arena.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_arrays.c b/src/linker/base_ext/base_arrays.c index 040f220d..fa50c36f 100644 --- a/src/linker/base_ext/base_arrays.c +++ b/src/linker/base_ext/base_arrays.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U64 diff --git a/src/linker/base_ext/base_arrays.h b/src/linker/base_ext/base_arrays.h index 1c6f6f4d..45ad68e8 100644 --- a/src/linker/base_ext/base_arrays.h +++ b/src/linker/base_ext/base_arrays.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_bit_array.c b/src/linker/base_ext/base_bit_array.c index 2ab94b77..a4f39b4a 100644 --- a/src/linker/base_ext/base_bit_array.c +++ b/src/linker/base_ext/base_bit_array.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U32Array diff --git a/src/linker/base_ext/base_bit_array.h b/src/linker/base_ext/base_bit_array.h index 76e19f87..dcffb77d 100644 --- a/src/linker/base_ext/base_bit_array.h +++ b/src/linker/base_ext/base_bit_array.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_blake3.c b/src/linker/base_ext/base_blake3.c index ce380e6b..59f063c4 100644 --- a/src/linker/base_ext/base_blake3.c +++ b/src/linker/base_ext/base_blake3.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #if defined(__clang__) diff --git a/src/linker/base_ext/base_blake3.h b/src/linker/base_ext/base_blake3.h index 72e8986f..0018d9f1 100644 --- a/src/linker/base_ext/base_blake3.h +++ b/src/linker/base_ext/base_blake3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_blake3_asm.c b/src/linker/base_ext/base_blake3_asm.c index 1b91df31..b9d4c470 100644 --- a/src/linker/base_ext/base_blake3_asm.c +++ b/src/linker/base_ext/base_blake3_asm.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #include "../third_party_ext/blake3/blake3_portable.c" diff --git a/src/linker/base_ext/base_blake3_asm.h b/src/linker/base_ext/base_blake3_asm.h index e39c3b41..1efded7e 100644 --- a/src/linker/base_ext/base_blake3_asm.h +++ b/src/linker/base_ext/base_blake3_asm.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef BASE_BLAKE3_H diff --git a/src/linker/base_ext/base_core.c b/src/linker/base_ext/base_core.c index b1873b10..890b0831 100644 --- a/src/linker/base_ext/base_core.c +++ b/src/linker/base_ext/base_core.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U16 diff --git a/src/linker/base_ext/base_core.h b/src/linker/base_ext/base_core.h index e3d53292..c7b07e3d 100644 --- a/src/linker/base_ext/base_core.h +++ b/src/linker/base_ext/base_core.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_crc32.c b/src/linker/base_ext/base_crc32.c index 28b90da6..30ec7c2a 100644 --- a/src/linker/base_ext/base_crc32.c +++ b/src/linker/base_ext/base_crc32.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U32 diff --git a/src/linker/base_ext/base_crc32.h b/src/linker/base_ext/base_crc32.h index e6d55bae..7a062237 100644 --- a/src/linker/base_ext/base_crc32.h +++ b/src/linker/base_ext/base_crc32.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_inc.c b/src/linker/base_ext/base_inc.c index c3886302..8a99d53d 100644 --- a/src/linker/base_ext/base_inc.c +++ b/src/linker/base_ext/base_inc.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #include "base_core.c" diff --git a/src/linker/base_ext/base_inc.h b/src/linker/base_ext/base_inc.h index 67081bf6..2074a32d 100644 --- a/src/linker/base_ext/base_inc.h +++ b/src/linker/base_ext/base_inc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_md5.c b/src/linker/base_ext/base_md5.c index 38ffac51..5e77bd7b 100644 --- a/src/linker/base_ext/base_md5.c +++ b/src/linker/base_ext/base_md5.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal MD5Hash diff --git a/src/linker/base_ext/base_md5.h b/src/linker/base_ext/base_md5.h index b435fe58..288cddc4 100644 --- a/src/linker/base_ext/base_md5.h +++ b/src/linker/base_ext/base_md5.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/base_ext/base_strings.c b/src/linker/base_ext/base_strings.c index 5688bb4a..4f085bcd 100644 --- a/src/linker/base_ext/base_strings.c +++ b/src/linker/base_ext/base_strings.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal B32 diff --git a/src/linker/base_ext/base_strings.h b/src/linker/base_ext/base_strings.h index 500f2fa0..85377c4c 100644 --- a/src/linker/base_ext/base_strings.h +++ b/src/linker/base_ext/base_strings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index 672d1689..27d0d30a 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// diff --git a/src/linker/codeview_ext/codeview.h b/src/linker/codeview_ext/codeview.h index 3b0315ad..c8d09c0a 100644 --- a/src/linker/codeview_ext/codeview.h +++ b/src/linker/codeview_ext/codeview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index 4a4c462f..b6c60031 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal void diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index d7458adc..98078ef6 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk.c b/src/linker/lnk.c index ebb7a1c1..10e386c7 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) // --- Build Options ----------------------------------------------------------- diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 6f1f925d..3712a5d9 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_cmd_line.c b/src/linker/lnk_cmd_line.c index f2828156..cf1909dd 100644 --- a/src/linker/lnk_cmd_line.c +++ b/src/linker/lnk_cmd_line.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal String8List diff --git a/src/linker/lnk_cmd_line.h b/src/linker/lnk_cmd_line.h index b130715f..4330bc09 100644 --- a/src/linker/lnk_cmd_line.h +++ b/src/linker/lnk_cmd_line.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index adc468d2..5f16fb56 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) global read_only LNK_CmdSwitch g_cmd_switch_map[] = diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 41b3e7f7..7c90df99 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_debug_helper.c b/src/linker/lnk_debug_helper.c index 9602f296..6c0da272 100644 --- a/src/linker/lnk_debug_helper.c +++ b/src/linker/lnk_debug_helper.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal String8 diff --git a/src/linker/lnk_debug_helper.h b/src/linker/lnk_debug_helper.h index a0627d17..dd1df4b3 100644 --- a/src/linker/lnk_debug_helper.h +++ b/src/linker/lnk_debug_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index e940de6b..1c7581a9 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index 663edf44..8f086ba3 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_error.c b/src/linker/lnk_error.c index a0235975..f06a3b7e 100644 --- a/src/linker/lnk_error.c +++ b/src/linker/lnk_error.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) static LNK_ErrorMode g_error_mode_arr[LNK_Error_Count]; diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 40e52eeb..2c34eee4 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 5885b933..3d3c7cfb 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal int diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 90e3a983..056456e1 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_log.c b/src/linker/lnk_log.c index 905b26ba..a78a7ca9 100644 --- a/src/linker/lnk_log.c +++ b/src/linker/lnk_log.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal void diff --git a/src/linker/lnk_log.h b/src/linker/lnk_log.h index a878803f..6e43393b 100644 --- a/src/linker/lnk_log.h +++ b/src/linker/lnk_log.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 608dc8d4..514f0df7 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal void diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index b7f8840f..48a4c880 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 84d8dd6f..5db94bae 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_SectionContrib * diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index b1999443..cd61810f 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 02f45b5a..869ea4bc 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_Symbol * diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 04d01ead..d7554022 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/lnk_timer.c b/src/linker/lnk_timer.c index 51460d58..4ce4522e 100644 --- a/src/linker/lnk_timer.c +++ b/src/linker/lnk_timer.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) global LNK_Timer g_timers[LNK_Timer_Count]; diff --git a/src/linker/lnk_timer.h b/src/linker/lnk_timer.h index ade95ae2..9e586454 100644 --- a/src/linker/lnk_timer.h +++ b/src/linker/lnk_timer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/pdb_ext/msf_builder.c b/src/linker/pdb_ext/msf_builder.c index 5a1cf862..b0e9bfc2 100644 --- a/src/linker/pdb_ext/msf_builder.c +++ b/src/linker/pdb_ext/msf_builder.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U64 diff --git a/src/linker/pdb_ext/msf_builder.h b/src/linker/pdb_ext/msf_builder.h index a2d10322..e39ef838 100644 --- a/src/linker/pdb_ext/msf_builder.h +++ b/src/linker/pdb_ext/msf_builder.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/pdb_ext/pdb.c b/src/linker/pdb_ext/pdb.c index 3ddd666f..9ffadf35 100644 --- a/src/linker/pdb_ext/pdb.c +++ b/src/linker/pdb_ext/pdb.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U32 diff --git a/src/linker/pdb_ext/pdb.h b/src/linker/pdb_ext/pdb.h index 6b31f4ee..87c2c5c3 100644 --- a/src/linker/pdb_ext/pdb.h +++ b/src/linker/pdb_ext/pdb.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 103a2b4c..02e470ac 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// diff --git a/src/linker/pdb_ext/pdb_builder.h b/src/linker/pdb_ext/pdb_builder.h index 8ca8ed93..f682e31e 100644 --- a/src/linker/pdb_ext/pdb_builder.h +++ b/src/linker/pdb_ext/pdb_builder.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/pdb_ext/pdb_helpers.c b/src/linker/pdb_ext/pdb_helpers.c index 0f8dcc28..8bdef67e 100644 --- a/src/linker/pdb_ext/pdb_helpers.c +++ b/src/linker/pdb_ext/pdb_helpers.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U64 diff --git a/src/linker/pdb_ext/pdb_helpers.h b/src/linker/pdb_ext/pdb_helpers.h index 7ba2d47b..007eb64f 100644 --- a/src/linker/pdb_ext/pdb_helpers.h +++ b/src/linker/pdb_ext/pdb_helpers.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/rdi/rdi_builder.c b/src/linker/rdi/rdi_builder.c index 623f0a9f..a7a567f5 100644 --- a/src/linker/rdi/rdi_builder.c +++ b/src/linker/rdi/rdi_builder.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal RDIB_DataModel diff --git a/src/linker/rdi/rdi_builder.h b/src/linker/rdi/rdi_builder.h index 50bb1965..8afb0122 100644 --- a/src/linker/rdi/rdi_builder.h +++ b/src/linker/rdi/rdi_builder.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/rdi/rdi_coff.c b/src/linker/rdi/rdi_coff.c index 57072743..4db328bc 100644 --- a/src/linker/rdi/rdi_coff.c +++ b/src/linker/rdi/rdi_coff.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal RDI_Arch diff --git a/src/linker/rdi/rdi_coff.h b/src/linker/rdi/rdi_coff.h index c68e4dc5..caefb833 100644 --- a/src/linker/rdi/rdi_coff.h +++ b/src/linker/rdi/rdi_coff.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/rdi/rdi_cv.c b/src/linker/rdi/rdi_cv.c index 0f8e9de2..e5f31251 100644 --- a/src/linker/rdi/rdi_cv.c +++ b/src/linker/rdi/rdi_cv.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal RDI_Arch diff --git a/src/linker/rdi/rdi_cv.h b/src/linker/rdi/rdi_cv.h index fb6ca4da..98aa8244 100644 --- a/src/linker/rdi/rdi_cv.h +++ b/src/linker/rdi/rdi_cv.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index 4a171756..d4cbec81 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal void diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index e2487560..c7e534df 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #pragma once diff --git a/src/pe/pe_make_debug_dir.c b/src/pe/pe_make_debug_dir.c index 0da26141..fe716b7c 100644 --- a/src/pe/pe_make_debug_dir.c +++ b/src/pe/pe_make_debug_dir.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal String8 diff --git a/src/pe/pe_make_debug_dir.h b/src/pe/pe_make_debug_dir.h index e63a64ca..5ab4d2f5 100644 --- a/src/pe/pe_make_debug_dir.h +++ b/src/pe/pe_make_debug_dir.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef PE_MAKE_DEBUG_DIR_H diff --git a/src/pe/pe_make_export_table.c b/src/pe/pe_make_export_table.c index 6e47b3a0..27e5d9e8 100644 --- a/src/pe/pe_make_export_table.c +++ b/src/pe/pe_make_export_table.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal String8 diff --git a/src/pe/pe_make_export_table.h b/src/pe/pe_make_export_table.h index 349007b8..6b3d1ff8 100644 --- a/src/pe/pe_make_export_table.h +++ b/src/pe/pe_make_export_table.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef PE_MAKE_EXPORT_TABLE_H diff --git a/src/pe/pe_make_import_table.c b/src/pe/pe_make_import_table.c index 9fe829eb..d4fcf1e2 100644 --- a/src/pe/pe_make_import_table.c +++ b/src/pe/pe_make_import_table.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal void diff --git a/src/pe/pe_make_import_table.h b/src/pe/pe_make_import_table.h index a89703a2..c1a48c38 100644 --- a/src/pe/pe_make_import_table.h +++ b/src/pe/pe_make_import_table.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef PE_MAKE_IMPORT_TABLE_H diff --git a/src/pe/pe_section_flags.h b/src/pe/pe_section_flags.h index b6adfff1..cd835b38 100644 --- a/src/pe/pe_section_flags.h +++ b/src/pe/pe_section_flags.h @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #ifndef PE_SECTION_FLAGS_H diff --git a/src/strip_lib_debug/strip_lib_debug.c b/src/strip_lib_debug/strip_lib_debug.c index 6cae4820..23c15b1c 100644 --- a/src/strip_lib_debug/strip_lib_debug.c +++ b/src/strip_lib_debug/strip_lib_debug.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #define BUILD_TITLE "Epic Games Tools (R) Lib Strip Debug" diff --git a/src/torture/torture.c b/src/torture/torture.c index d5cd912f..e3f80040 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -1,4 +1,4 @@ -// Copyright (c) 2025 Epic Games Tools +// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// From 56c43ad61466c37ec112952a40e43c62d89253f8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 23:19:30 -0700 Subject: [PATCH 132/302] clean up HashTable, removed unused command line switches, added list wrapper for alt names, added natvis for HashTable, AltNameList, MergeDirectiveList, and IncludeSymbolList --- src/linker/base_ext/base_arena.c | 8 -- src/linker/base_ext/base_arena.h | 6 +- src/linker/base_ext/base_bit_array.h | 18 ++-- src/linker/hash_table.c | 125 ++++++++++++--------------- src/linker/hash_table.h | 50 +++++------ src/linker/linker.natvis | 23 ++++- src/linker/lnk.c | 69 +++++++-------- src/linker/lnk_config.c | 61 +++++-------- src/linker/lnk_config.h | 16 +--- src/linker/lnk_section_table.c | 16 ++-- 10 files changed, 178 insertions(+), 214 deletions(-) diff --git a/src/linker/base_ext/base_arena.c b/src/linker/base_ext/base_arena.c index f01b9cb8..166d3ea6 100644 --- a/src/linker/base_ext/base_arena.c +++ b/src/linker/base_ext/base_arena.c @@ -1,14 +1,6 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal U32 * -push_u32(Arena *arena, U32 value) -{ - U32 *result = push_array_no_zero(arena, U32, 1); - *result = value; - return result; -} - internal U64 * push_u64(Arena *arena, U64 value) { diff --git a/src/linker/base_ext/base_arena.h b/src/linker/base_ext/base_arena.h index 3a0e1de4..4cb25d21 100644 --- a/src/linker/base_ext/base_arena.h +++ b/src/linker/base_ext/base_arena.h @@ -3,12 +3,10 @@ #pragma once -internal U32 * push_u32(Arena *arena, U32 value); -internal U64 * push_u64(Arena *arena, U64 value); +internal U64 * push_u64 (Arena *arena, U64 value); internal U32 * push_array_copy_u32(Arena *arena, U32 *v, U64 count); internal U64 * push_array_copy_u64(Arena *arena, U64 *v, U64 count); -internal U64 ** push_matrix_u64(Arena *arena, U64 rows, U64 columns); -internal String8 push_cstr(Arena *arena, String8 str); +internal U64 ** push_matrix_u64 (Arena *arena, U64 rows, U64 columns); internal Arena ** alloc_fixed_size_arena_array(Arena *arena, U64 count, U64 res, U64 cmt); internal void release_arena_array(Arena **arr); diff --git a/src/linker/base_ext/base_bit_array.h b/src/linker/base_ext/base_bit_array.h index dcffb77d..995facd7 100644 --- a/src/linker/base_ext/base_bit_array.h +++ b/src/linker/base_ext/base_bit_array.h @@ -3,16 +3,16 @@ #pragma once -internal U32Array bit_array_init32(Arena *arena, U64 word_count); -internal U64 bit_array_scan_left_to_right32(U32Array bit_array, U64 lo, U64 hi, B32 state); -internal U64 bit_array_scan_right_to_left32(U32Array bit_array, U64 lo, U64 hi, B32 state); +internal U32Array bit_array_init32 (Arena *arena, U64 word_count); +internal U64 bit_array_scan_left_to_right32 (U32Array bit_array, U64 lo, U64 hi, B32 state); +internal U64 bit_array_scan_right_to_left32 (U32Array bit_array, U64 lo, U64 hi, B32 state); internal Rng1U64 bit_array_scan_left_to_right32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count); internal Rng1U64 bit_array_scan_right_to_left32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count); -internal B32 byte_scan_right_to_left(U8 *start, U8 *opl, U8 byte, U64 *offset_out); -internal U64 bit_array_find_next_unset_bit32(U32Array bit_array); -internal U64 bit_array_find_next_set_bit32(U32Array bit_array); -internal void bit_array_set_bit32(U32Array bit_array, U64 idx, B32 state); -internal void bit_array_set_bit_range32(U32Array bit_array, Rng1U64 range, B32 state); -internal U32 bit_array_get_bit32(U32Array bit_array, U64 idx); +internal B32 byte_scan_right_to_left (U8 *start, U8 *opl, U8 byte, U64 *offset_out); +internal U64 bit_array_find_next_unset_bit32 (U32Array bit_array); +internal U64 bit_array_find_next_set_bit32 (U32Array bit_array); +internal void bit_array_set_bit32 (U32Array bit_array, U64 idx, B32 state); +internal void bit_array_set_bit_range32 (U32Array bit_array, Rng1U64 range, B32 state); +internal U32 bit_array_get_bit32 (U32Array bit_array, U64 idx); diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index b6c60031..22276591 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -24,17 +24,10 @@ bucket_list_pop(BucketList *list) return result; } -//////////////////////////////// - -#define XXH_STATIC_LINKING_ONLY -#include "third_party/xxHash/xxhash.c" -#include "third_party/xxHash/xxhash.h" - internal U64 hash_table_hasher(String8 string) { - XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size); - return hash64; + return u64_hash_from_str8(string); } internal HashTable * @@ -211,6 +204,18 @@ hash_table_search_u64(HashTable *ht, U64 key_u64) return 0; } +internal KeyValuePair * +hash_table_search_path(HashTable *ht, String8 path) +{ + Temp scratch = scratch_begin(0,0); + String8 path_canon = path; + path_canon = lower_from_str8(scratch.arena, path_canon); + path_canon = path_convert_slashes(scratch.arena, path_canon, PathStyle_UnixAbsolute); + KeyValuePair *result = hash_table_search_string(ht, path_canon); + scratch_end(scratch); + return result; +} + internal KeyValuePair * hash_table_search_raw(HashTable *ht, void *key) { @@ -225,18 +230,6 @@ hash_table_search_raw(HashTable *ht, void *key) return 0; } -internal KeyValuePair * -hash_table_search_path(HashTable *ht, String8 path) -{ - Temp scratch = scratch_begin(0,0); - String8 path_canon = path; - path_canon = lower_from_str8(scratch.arena, path_canon); - path_canon = path_convert_slashes(scratch.arena, path_canon, PathStyle_UnixAbsolute); - KeyValuePair *result = hash_table_search_string(ht, path_canon); - scratch_end(scratch); - return result; -} - internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) { @@ -250,53 +243,6 @@ hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) return 0; } -internal void * -hash_table_search_u64_raw(HashTable *ht, U64 key_u64) -{ - KeyValuePair *kv = hash_table_search_u64(ht, key_u64); - return kv ? kv->value_raw : 0; -} - -internal void * -hash_table_search_path_raw(HashTable *ht, String8 path) -{ - KeyValuePair *kv = hash_table_search_path(ht, path); - return kv ? kv->value_raw : 0; -} - -internal void * -hash_table_search_raw_raw(HashTable *ht, void *key) -{ - KeyValuePair *kv = hash_table_search_raw(ht, key); - return kv ? kv->value_raw : 0; -} - -internal B32 -hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) -{ - KeyValuePair *result = hash_table_search_string(ht, key); - if (result != 0) { - if (value_out != 0) { - *value_out = result->value_u64; - } - return 1; - } - return 0; -} - -internal B32 -hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out) -{ - KeyValuePair *result = hash_table_search_string(ht, key); - if (result) { - if (value_out) { - (*(void **)value_out) = result->value_raw; - } - return 1; - } - return 0; -} - internal BucketNode * hash_table_push_u32_u32(Arena *arena, HashTable *ht, U32 key, U32 value) { @@ -311,6 +257,19 @@ hash_table_push_raw_raw(Arena *arena, HashTable *ht, void *key, void *value) return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_raw = key, .value_raw = value }); } +internal B32 +hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) +{ + KeyValuePair *result = hash_table_search_string(ht, key); + if (result != 0) { + if (value_out != 0) { + *value_out = result->value_u64; + } + return 1; + } + return 0; +} + internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) { @@ -337,7 +296,36 @@ hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out) return 0; } -//////////////////////////////// +internal void * +hash_table_search_string_raw(HashTable *ht, String8 key) +{ + KeyValuePair *result = hash_table_search_string(ht, key); + if (result) { + return result->value_raw; + } + return 0; +} + +internal void * +hash_table_search_u64_raw(HashTable *ht, U64 key_u64) +{ + KeyValuePair *kv = hash_table_search_u64(ht, key_u64); + return kv ? kv->value_raw : 0; +} + +internal void * +hash_table_search_path_raw(HashTable *ht, String8 path) +{ + KeyValuePair *kv = hash_table_search_path(ht, path); + return kv ? kv->value_raw : 0; +} + +internal void * +hash_table_search_raw_raw(HashTable *ht, void *key) +{ + KeyValuePair *kv = hash_table_search_raw(ht, key); + return kv ? kv->value_raw : 0; +} internal int key_value_pair_is_before_u32(void *a, void *b) @@ -434,6 +422,7 @@ values_from_hash_table_raw(Arena *arena, HashTable *ht) } return result; } + #include "third_party/radsort/radsort.h" internal void diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 98078ef6..67e9e3dd 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -39,22 +39,20 @@ typedef struct HashTable BucketList free_buckets; } HashTable; -//////////////////////////////// - -//- bucket list helpers +// --- Bucket List ------------------------------------------------------------- internal void bucket_list_concat_in_place(BucketList *list, BucketList *to_concat); -internal BucketNode * bucket_list_pop(BucketList *list); +internal BucketNode * bucket_list_pop (BucketList *list); -//- main +// --- Hash Table -------------------------------------------------------------- -internal U64 hash_table_hasher(String8 string); -internal HashTable * hash_table_init(Arena *arena, U64 cap); +internal U64 hash_table_hasher(String8 string); + +internal HashTable * hash_table_init (Arena *arena, U64 cap); internal void hash_table_purge(HashTable *ht); -//- push +internal BucketNode * hash_table_push(Arena *arena, HashTable *ht, U64 hash, KeyValuePair kv); -internal BucketNode * hash_table_push (Arena *arena, HashTable *ht, U64 hash, KeyValuePair v); internal BucketNode * hash_table_push_u32_string (Arena *arena, HashTable *ht, U32 key, String8 value); internal BucketNode * hash_table_push_u64_string (Arena *arena, HashTable *ht, U64 key, String8 value); internal BucketNode * hash_table_push_string_string(Arena *arena, HashTable *ht, String8 key, String8 value); @@ -66,35 +64,37 @@ internal BucketNode * hash_table_push_path_u64 (Arena *arena, HashTable *ht, internal BucketNode * hash_table_push_u64_u64 (Arena *arena, HashTable *ht, U64 key, U64 value); internal BucketNode * hash_table_push_u32_u32 (Arena *arena, HashTable *ht, U32 key, U32 value); -//- search +internal KeyValuePair * hash_table_search_string (HashTable *ht, String8 key); +internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key); +internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key); +internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 key); +internal KeyValuePair * hash_table_search_raw (HashTable *ht, void *key); -internal KeyValuePair * hash_table_search_string (HashTable *ht, String8 string); -internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key ); -internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key ); -internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 path ); -internal void * hash_table_search_path_raw(HashTable *ht, String8 path ); - -internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out); -internal B32 hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out); -internal B32 hash_table_search_string_raw(HashTable *ht, String8 key, void *value_out); +internal B32 hash_table_search_path_u64 (HashTable *ht, String8 key, U64 *value_out); +internal B32 hash_table_search_string_u64 (HashTable *ht, String8 key, U64 *value_out); internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out); -internal B32 hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out); +internal B32 hash_table_search_u32_u32 (HashTable *ht, U32 key, U32 *value_out); -//- key-value helpers +internal void * hash_table_search_string_raw(HashTable *ht, String8 key); +internal void * hash_table_search_u64_raw (HashTable *ht, U64 key); +internal void * hash_table_search_path_raw (HashTable *ht, String8 key); +internal void * hash_table_search_raw_raw (HashTable *ht, void *key); + +// --- Key Value Helpers ------------------------------------------------------- internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable *ht); internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable *ht); internal String8 keys_from_hash_table_str8 (Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); -internal void * keys_from_hash_table_raw(Arena *arena, HashTable *ht); +internal void * keys_from_hash_table_raw (Arena *arena, HashTable *ht); internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht); -internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); -internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); +internal void sort_key_value_pairs_as_u32 (KeyValuePair *pairs, U64 count); +internal void sort_key_value_pairs_as_u64 (KeyValuePair *pairs, U64 count); internal void sort_key_value_pairs_as_string_sensitive(KeyValuePair *pairs, U64 count); -//////////////////////////////// +// --- Misc -------------------------------------------------------------------- internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr); internal String8List remove_duplicates_str8_list(Arena *arena, String8List list); diff --git a/src/linker/linker.natvis b/src/linker/linker.natvis index b8c5aaf9..64de6bfb 100644 --- a/src/linker/linker.natvis +++ b/src/linker/linker.natvis @@ -184,6 +184,9 @@ + + + empty @@ -193,16 +196,28 @@ + cap count free_buckets - - cap - buckets - + + + + + node = buckets[bucket_idx].first + + + + node + node = node->next + + bucket_idx += 1 + + + diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 10e386c7..268a6fd4 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -144,32 +144,28 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_SubSystem, "%S", pe_string_from_subsystem(PE_WindowsSubsystem_WINDOWS_GUI)); } - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_EnvLib, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Exe, ""); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Guid, "imageblake3"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LargePages, "no"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LinkVer, "14.0"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_OsVer, "6.0"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PageSize, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapDefined, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapInternal, "0x1000"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MemoryMapFiles, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_HighEntropyVa, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_ManifestUac, "\"level='asInvoker' uiAccess='false'\""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_NxCompat, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_EnvLib, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Exe, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Guid, "imageblake3"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LargePages, "no"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_LinkVer, "14.0"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_OsVer, "6.0"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PageSize, "%u", KB(4)); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_PathStyle, "system"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Workers, "%u", os_get_system_info()->logical_processor_count); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TargetOs, "windows"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MemoryMapFiles, ""); #if BUILD_DEBUG lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); @@ -1561,7 +1557,7 @@ lnk_link_inputs_(TP_Context *tp, } // skip duplicate import inputer - if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name, 0)) { break; } + if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name)) { break; } hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); // create import stub (later replaced with acutal import generated by linker) @@ -1634,7 +1630,7 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer { // replace undefined symbols that have an alternate name with a weak symbol for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { - LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->data.from); + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->v.from); if (symbol_ht) { COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { @@ -1647,14 +1643,14 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer String8 alt_name_obj_data; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.from, COFF_WeakExt_SearchLibrary, 0); - COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->data.to, COFF_WeakExt_AntiDependency, from_symbol); + COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.from, COFF_WeakExt_SearchLibrary, 0); + COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.to, COFF_WeakExt_AntiDependency, from_symbol); coff_obj_writer_set_default_symbol(from_symbol, to_symbol); alt_name_obj_data = coff_obj_writer_serialize(arena->v[0], obj_writer); coff_obj_writer_release(&obj_writer); } - LNK_Obj *obj_with_alt_name = alt_name_n->data.obj; + LNK_Obj *obj_with_alt_name = alt_name_n->v.obj; String8 obj_with_alt_name_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); lnk_inputer_push_obj_linkgen(inputer, obj_with_alt_name ? obj_with_alt_name->link_member : 0, obj_with_alt_name_path, alt_name_obj_data); @@ -2282,8 +2278,7 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_definitions_task) // was section defined? String8 sect_name = coff_name_from_section_header(string_table, sect_header); String8 sect_name_with_flags = lnk_make_name_with_flags(temp.arena, sect_name, sect_header->flags & ~COFF_SectionFlags_LnkFlags); - LNK_SectionDefinition *sect_defn = 0; - hash_table_search_string_raw(sect_defn_ht, sect_name_with_flags, §_defn); + LNK_SectionDefinition *sect_defn = hash_table_search_string_raw(sect_defn_ht, sect_name_with_flags); // push new section definition if (sect_defn == 0) { @@ -2329,7 +2324,7 @@ THREAD_POOL_TASK_FUNC(lnk_gather_section_contribs_task) Temp temp = temp_begin(scratch.arena); String8 sect_name = coff_name_from_section_header(string_table, sect_header); String8 sect_name_with_flags = lnk_make_name_with_flags(temp.arena, sect_name, sect_header->flags & ~COFF_SectionFlags_LnkFlags); - hash_table_search_string_raw(task->contribs_ht, sect_name_with_flags, &sc_chunk); + sc_chunk = hash_table_search_string_raw(task->contribs_ht, sect_name_with_flags); temp_end(temp); } @@ -3835,8 +3830,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT for EachIndex(defn_idx, sect_defns_count) { LNK_SectionDefinition *defn = sect_defns[defn_idx]; String8 name_with_flags = lnk_make_name_with_flags(arena->v[0], defn->name, defn->flags); - LNK_SectionDefinition *main_defn = 0; - hash_table_search_string_raw(task.u.gather_sects.defns[0], name_with_flags, &main_defn); + LNK_SectionDefinition *main_defn = hash_table_search_string_raw(task.u.gather_sects.defns[0], name_with_flags); if (main_defn == 0) { main_defn = sect_defns[defn_idx]; hash_table_push_string_raw(arena->v[0], task.u.gather_sects.defns[0], name_with_flags, main_defn); @@ -3891,8 +3885,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT } String8 defn_name_with_flags = lnk_make_name_with_flags(sectab->arena, sect_defn->name, sect_defn->flags); - LNK_SectionContribChunk *contrib_chunk = 0; - hash_table_search_string_raw(task.contribs_ht, defn_name_with_flags, &contrib_chunk); + LNK_SectionContribChunk *contrib_chunk = hash_table_search_string_raw(task.contribs_ht, defn_name_with_flags); if (!contrib_chunk) { contrib_chunk = lnk_section_contrib_chunk_list_push_chunk(arena->v[0], §->contribs, sect_defn->contribs_count, sort_idx); hash_table_push_string_raw(sectab->arena, task.contribs_ht, defn_name_with_flags, contrib_chunk); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 5f16fb56..79a413a4 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -148,10 +148,6 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = { LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, { LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" }, - { LNK_CmdSwitch_Rad_SymbolTableCapDefined, 0, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapInternal, 0, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapLib, 0, "RAD_SYMBOL_TABLE_CAP_LIB", ":#", "Number of buckets allocated in the symbol table for library symbols." }, - { LNK_CmdSwitch_Rad_SymbolTableCapWeak, 0, "RAD_SYMBOL_TABLE_CAP_WEAK", ":#", "Number of buckets allocated in the symbol table for weak symbols." }, { LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, { LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, { LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, @@ -741,16 +737,6 @@ lnk_parse_export_directive(Arena *arena, String8 directive, LNK_Obj *obj, PE_Exp return is_parsed; } -internal LNK_MergeDirectiveNode * -lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data) -{ - LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1); - node->data = data; - SLLQueuePush(list->first, list->last, node); - list->count += 1; - return node; -} - internal B32 lnk_parse_merge_directive(String8 string, LNK_Obj *obj, LNK_MergeDirective *out) { @@ -768,6 +754,26 @@ lnk_parse_merge_directive(String8 string, LNK_Obj *obj, LNK_MergeDirective *out) return is_parse_ok; } +internal LNK_AltNameNode * +lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName v) +{ + LNK_AltNameNode *node = push_array(arena, LNK_AltNameNode, 1); + node->v = v; + SLLQueuePush(list->first, list->last, node); + list->count += 1; + return node; +} + +internal LNK_MergeDirectiveNode * +lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective v) +{ + LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1); + node->v = v; + SLLQueuePush(list->first, list->last, node); + list->count += 1; + return node; +} + internal String8 lnk_get_image_name(LNK_Config *config) { @@ -979,7 +985,7 @@ internal void lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj) { // is this a duplicate symbol? - if (hash_table_search_string_raw(config->include_symbol_ht, name, 0)) { + if (hash_table_search_string_raw(config->include_symbol_ht, name)) { return; } @@ -1165,12 +1171,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List alt_name.from = push_str8_copy(config->arena, alt_name.from); alt_name.to = push_str8_copy(config->arena, alt_name.to); - LNK_AltNameNode *alt_name_n = push_array(config->arena, LNK_AltNameNode, 1); - alt_name_n->data = alt_name; - - SLLQueuePush(config->alt_name_list.first, config->alt_name_list.last, alt_name_n); - config->alt_name_list.count += 1; - + lnk_alt_name_list_push(config->arena, &config->alt_name_list, alt_name); hash_table_push_string_string(config->arena, config->alt_name_ht, alt_name.from, alt_name.to); } } @@ -1292,9 +1293,8 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List case LNK_CmdSwitch_Export: { PE_ExportParse export_parse = {0}; if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) { - PE_ExportParseNode *exp_n = 0; - String8 export_name = pe_name_from_export_parse(&export_parse); - hash_table_search_string_raw(config->export_ht, export_name, &exp_n); + String8 export_name = pe_name_from_export_parse(&export_parse); + PE_ExportParseNode *exp_n = hash_table_search_string_raw(config->export_ht, export_name); if (exp_n == 0) { // make sure export is defined @@ -1983,19 +1983,6 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List } } break; - case LNK_CmdSwitch_Rad_SymbolTableCapDefined: { - lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->symbol_table_cap_defined, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapInternal: { - lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->symbol_table_cap_internal, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapWeak: { - lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->symbol_table_cap_weak, 0); - } break; - case LNK_CmdSwitch_Rad_SymbolTableCapLib: { - lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->symbol_table_cap_lib, 0); - } break; - case LNK_CmdSwitch_Rad_TargetOs: { if (value_strings.node_count == 1) { String8 os_string = str8_list_first(&value_strings); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 7c90df99..780a2e12 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -176,10 +176,6 @@ typedef enum LNK_CmdSwitch_Rad_SharedThreadPool, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, LNK_CmdSwitch_Rad_SuppressError, - LNK_CmdSwitch_Rad_SymbolTableCapDefined, - LNK_CmdSwitch_Rad_SymbolTableCapInternal, - LNK_CmdSwitch_Rad_SymbolTableCapLib, - LNK_CmdSwitch_Rad_SymbolTableCapWeak, LNK_CmdSwitch_Rad_TargetOs, LNK_CmdSwitch_Rad_TimeStamp, LNK_CmdSwitch_Rad_Version, @@ -278,7 +274,7 @@ typedef struct LNK_AltName typedef struct LNK_AltNameNode { struct LNK_AltNameNode *next; - LNK_AltName data; + LNK_AltName v; } LNK_AltNameNode; typedef struct LNK_AltNameList @@ -297,7 +293,7 @@ typedef struct LNK_MergeDirective typedef struct LNK_MergeDirectiveNode { struct LNK_MergeDirectiveNode *next; - LNK_MergeDirective data; + LNK_MergeDirective v; } LNK_MergeDirectiveNode; typedef struct LNK_MergeDirectiveList @@ -397,10 +393,6 @@ typedef struct LNK_Config LNK_IncludeSymbolList include_symbol_list; LNK_AltNameList alt_name_list; LNK_MergeDirectiveList merge_list; - U64 symbol_table_cap_defined; - U64 symbol_table_cap_internal; - U64 symbol_table_cap_weak; - U64 symbol_table_cap_lib; U64 data_dir_count; B32 build_imp_lib; B32 build_exp; @@ -588,8 +580,8 @@ internal B32 lnk_parse_merge_directive (String8 string, struct LNK_Obj *obj, internal B32 lnk_parse_export_directive (Arena *arena, String8 directive, struct LNK_Obj *obj, PE_ExportParse *export_out); internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, struct LNK_Obj *obj, PE_ExportParse *export_out); -internal LNK_AltNameNode * lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName data); -internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data); +internal LNK_AltNameNode * lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName v); +internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective v); // --- Getters ----------------------------------------------------------------- diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 5db94bae..c37d906f 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -178,8 +178,7 @@ lnk_section_table_search(LNK_SectionTable *sectab, String8 full_or_partial_name, coff_parse_section_name(full_or_partial_name, &name, &postfix); String8 name_with_flags = lnk_make_name_with_flags(scratch.arena, name, flags); - LNK_Section *section = 0; - hash_table_search_string_raw(sectab->sect_ht, name_with_flags, §ion); + LNK_Section *section = hash_table_search_string_raw(sectab->sect_ht, name_with_flags); scratch_end(scratch); return section; @@ -222,7 +221,7 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l Temp scratch = scratch_begin(0, 0); for (LNK_MergeDirectiveNode *merge_node = merge_list.first; merge_node != 0; merge_node = merge_node->next) { - LNK_MergeDirective *merge = &merge_node->data; + LNK_MergeDirective *merge = &merge_node->v; // guard against illegal merges { @@ -242,19 +241,18 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l // guard against circular merges { - if (str8_match(merge_node->data.dst, merge_node->data.src, 0)) { - lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->data.src, merge_node->data.dst); + if (str8_match(merge_node->v.dst, merge_node->v.src, 0)) { + lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->v.src, merge_node->v.dst); } for (LNK_SectionNode *sect_n = sectab->merge_list.first; sect_n != 0; sect_n = sect_n->next) { - if (str8_match(sect_n->data.name, merge_node->data.dst, 0)) { - lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->data.src, merge_node->data.dst); + if (str8_match(sect_n->data.name, merge_node->v.dst, 0)) { + lnk_error(LNK_Error_CircularMerge, "detected circular /MERGE:%S=%S", merge_node->v.src, merge_node->v.dst); } } } // are we trying to merge section that was already merged? - LNK_Section *merge_sect = 0; - hash_table_search_string_raw(sectab->sect_ht, merge->src, &merge_sect); + LNK_Section *merge_sect = hash_table_search_string_raw(sectab->sect_ht, merge->src); if (merge_sect && merge_sect->merge_dst) { LNK_Section *dst = merge_sect->merge_dst; B32 is_ambiguous_merge = !str8_match(dst->name, merge->dst, 0); From f2ee135439f74e9024a7896b1e9fe831b84e83c2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 2 Sep 2025 23:42:21 -0700 Subject: [PATCH 133/302] fix up symbols visibility --- src/coff/coff.c | 4 ++-- src/linker/base_ext/base_blake3.h | 3 +++ src/linker/codeview_ext/codeview.c | 3 ++- src/linker/lnk.c | 8 ++++++-- src/linker/pdb_ext/pdb_builder.c | 6 ++++++ src/linker/rdi/rdi_builder.c | 3 +++ src/pe/pe.c | 2 +- src/third_party/md5/md5.c | 6 +++--- src/third_party/md5/md5.h | 10 +++++++--- 9 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/coff/coff.c b/src/coff/coff.c index 08bc3123..e3879768 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -477,7 +477,7 @@ coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp) return result; } -read_only struct +global read_only struct { String8 string; COFF_MachineType machine; @@ -509,7 +509,7 @@ read_only struct { str8_lit_comp("WceMipsV2"), COFF_MachineType_WceMipsV2 }, }; -read_only static struct { +global read_only struct { char * name; COFF_ImportType type; } g_coff_import_header_type_map[] = { diff --git a/src/linker/base_ext/base_blake3.h b/src/linker/base_ext/base_blake3.h index 0018d9f1..4c426ea2 100644 --- a/src/linker/base_ext/base_blake3.h +++ b/src/linker/base_ext/base_blake3.h @@ -3,6 +3,9 @@ #pragma once +#define BLAKE3_API static +#define BLAKE3_PRIVATE static + #if defined(__clang__) && defined(__x86_64__) # if defined(__IMMINTRIN_H) # error "include this header before immintrin.h / x86intrin.h / intrin.h" diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index 27d0d30a..b427c911 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1175,6 +1175,7 @@ cv_debug_t_array_count_leaves(U64 count, CV_DebugT *arr) return total_leaf_count; } +internal THREAD_POOL_TASK_FUNC(cv_str8_list_from_debug_t_task) { CV_Str8ListFromDebugT *task = raw_task; @@ -1785,7 +1786,7 @@ cv_c13_patch_checksum_offsets_in_frame_data_list(String8List frame_data, U32 che //////////////////////////////// // $$Lines Accel -int +internal int cv_c13_voff_map_compar(const void *raw_a, const void *raw_b) { CV_Line *a = (CV_Line*)raw_a; diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 268a6fd4..49ec85d8 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -14,8 +14,12 @@ #include "base_ext/base_blake3.h" #include "base_ext/base_blake3.c" +#define MD5_API static #include "third_party/md5/md5.c" #include "third_party/md5/md5.h" +#define XXH_PRIVATE_API +#define XXH_IMPLEMENTATION +#define XXH_STATIC_LINKING_ONLY #include "third_party/xxHash/xxhash.c" #include "third_party/xxHash/xxhash.h" #include "third_party/radsort/radsort.h" @@ -3386,14 +3390,14 @@ THREAD_POOL_TASK_FUNC(lnk_patch_section_symbols_task) ProfEnd(); } -int +internal int lnk_base_reloc_page_compar(const void *raw_a, const void *raw_b) { const LNK_BaseRelocPage *a = raw_a, *b = raw_b; return u64_compar(&a->voff, &b->voff); } -int +internal int lnk_base_reloc_page_is_before(void *raw_a, void *raw_b) { LNK_BaseRelocPage* a = raw_a; diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index 02e470ac..153bc759 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -345,6 +345,7 @@ pdb_hash_table_get_present_keys_and_values(Arena *arena, PDB_HashTable *ht, Stri //////////////////////////////// +internal PDB_HASH_TABLE_UNPACK_FUNC(pdb_named_stream_ht_unpack) { Assert(!ud); @@ -366,6 +367,7 @@ PDB_HASH_TABLE_UNPACK_FUNC(pdb_named_stream_ht_unpack) return 0; } +internal PDB_HASH_TABLE_UNPACK_FUNC(pdb_hash_adj_ht_unpack) { Assert(local_data.size == 0); @@ -391,6 +393,7 @@ PDB_HASH_TABLE_UNPACK_FUNC(pdb_hash_adj_ht_unpack) return 0; } +internal PDB_HASH_TABLE_UNPACK_FUNC(pdb_src_header_block_ht_unpack) { if (*key_value_cursor + sizeof(PDB_StringOffset) > key_value_data.size) { @@ -414,6 +417,7 @@ PDB_HASH_TABLE_UNPACK_FUNC(pdb_src_header_block_ht_unpack) return 0; } +internal PDB_HASH_TABLE_PACK_FUNC(pdb_named_stream_ht_pack) { Assert(!ud); @@ -427,6 +431,7 @@ PDB_HASH_TABLE_PACK_FUNC(pdb_named_stream_ht_pack) str8_serial_push_string(arena, key_value_srl, value); } +internal PDB_HASH_TABLE_PACK_FUNC(pdb_hash_adj_ht_pack) { Assert(value.size == sizeof(CV_TypeIndex)); @@ -443,6 +448,7 @@ PDB_HASH_TABLE_PACK_FUNC(pdb_hash_adj_ht_pack) str8_serial_push_string(arena, key_value_srl, value); } +internal PDB_HASH_TABLE_PACK_FUNC(pdb_src_header_block_ht_pack) { Assert(value.size == sizeof(PDB_SrcHeaderBlockEntry)); diff --git a/src/linker/rdi/rdi_builder.c b/src/linker/rdi/rdi_builder.c index a7a567f5..91a31d7a 100644 --- a/src/linker/rdi/rdi_builder.c +++ b/src/linker/rdi/rdi_builder.c @@ -2201,11 +2201,13 @@ rdib_string_map_insert_name_map_item(Arena *arena, RDIB_CollectStringsTask *task rdib_string_map_insert_item(arena, task, task_id, string, node); } +internal RDIB_STRING_MAP_UPDATE_FUNC(rdib_string_map_update_null) { // null update } +internal RDIB_STRING_MAP_UPDATE_FUNC(rdib_string_map_update_concat_void_list_atomic) { node->next = ins_atomic_ptr_eval_assign(head, node); @@ -3549,6 +3551,7 @@ rdib_data_from_vmap(Arena *arena, U64 range_count, RDIB_VMapRange *ranges) return raw_vmap; } +internal THREAD_POOL_TASK_FUNC(rdib_fill_scope_vmaps_task) { ProfBeginFunction(); diff --git a/src/pe/pe.c b/src/pe/pe.c index 19714fc0..1789d154 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -25,7 +25,7 @@ pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode) return result; } -read_only struct +global read_only struct { String8 string; PE_WindowsSubsystem type; diff --git a/src/third_party/md5/md5.c b/src/third_party/md5/md5.c index 57f429d4..c31e1c82 100644 --- a/src/third_party/md5/md5.c +++ b/src/third_party/md5/md5.c @@ -204,7 +204,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) return ptr; } -void MD5_Init(MD5_CTX *ctx) +MD5_API void MD5_Init(MD5_CTX *ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; @@ -215,7 +215,7 @@ void MD5_Init(MD5_CTX *ctx) ctx->hi = 0; } -void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +MD5_API void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) { MD5_u32plus saved_lo; unsigned long used, available; @@ -255,7 +255,7 @@ void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) (dst)[2] = (unsigned char)((src) >> 16); \ (dst)[3] = (unsigned char)((src) >> 24); -void MD5_Final(unsigned char *result, MD5_CTX *ctx) +MD5_API void MD5_Final(unsigned char *result, MD5_CTX *ctx) { unsigned long used, available; diff --git a/src/third_party/md5/md5.h b/src/third_party/md5/md5.h index 2da44bf3..ce5e0c92 100644 --- a/src/third_party/md5/md5.h +++ b/src/third_party/md5/md5.h @@ -23,6 +23,10 @@ * See md5.c for more information. */ +#ifndef MD5_API +# define MD5_API +#endif + #ifdef HAVE_OPENSSL #include #elif !defined(_MD5_H) @@ -38,8 +42,8 @@ typedef struct { MD5_u32plus block[16]; } MD5_CTX; -extern void MD5_Init(MD5_CTX *ctx); -extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); -extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); +MD5_API void MD5_Init(MD5_CTX *ctx); +MD5_API void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); +MD5_API void MD5_Final(unsigned char *result, MD5_CTX *ctx); #endif From 11373f4432613d1b7d09944c5be6771dea9597d2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 3 Sep 2025 11:13:13 -0700 Subject: [PATCH 134/302] disable COFF group info generation --- build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.bat b/build.bat index 426caafa..34a69c08 100644 --- a/build.bat +++ b/build.bat @@ -48,7 +48,7 @@ if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_ set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags% set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% -set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp +set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo set cl_out= /out: set cl_linker= set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 From a2b4e7bdc5e2a38c75d652ed78e72d248abf07a7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 16:02:38 -0700 Subject: [PATCH 135/302] fix missing null voff in scope voff data section --- src/rdi_make/rdi_make_local_2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c index e8efd781..28a244d7 100644 --- a/src/rdi_make/rdi_make_local_2.c +++ b/src/rdi_make/rdi_make_local_2.c @@ -2213,7 +2213,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) if(lane_idx() == 0) { U64 local_layout_off = 1; - U64 voff_layout_off = 0; + U64 voff_layout_off = 1; U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) { @@ -2245,7 +2245,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count; + rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); } if(lane_idx() == lane_from_task_idx(2)) From 78530fb10d6dd81c3f16a40c5eff838438239c53 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 16:35:35 -0700 Subject: [PATCH 136/302] merge p2r2 into original p2r, delete old conversion path; replace pdb -> breakpad converter & dependency on old converter --- project.4coder | 2 +- src/radbin/radbin.c | 144 +- src/rdi_from_pdb/rdi_from_pdb.c | 3848 +++++++++++++++++++++++----- src/rdi_from_pdb/rdi_from_pdb.h | 5 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 3950 ----------------------------- src/rdi_from_pdb/rdi_from_pdb_2.h | 5 - 6 files changed, 3417 insertions(+), 4537 deletions(-) diff --git a/project.4coder b/project.4coder index 2d3325c2..1bb5aad9 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 6ab8173c..f1b61f6b 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -751,6 +751,13 @@ rb_thread_entry_point(void *p) log_user_errorf("Could not load debug info from the specified inputs. You must provide either a valid PDB file or an executable image (PE, ELF) file with DWARF debug info."); } + //- rjf: bake + RDIM_BakeResults bake_results = {0}; + if(convert_done) ProfScope("bake") + { + bake_results = rdim2_bake(arena, &bake_params); + } + //- rjf: convert done => generate output if(convert_done) switch(output_kind) { @@ -759,10 +766,6 @@ rb_thread_entry_point(void *p) //- rjf: generate RDI blobs case OutputKind_RDI: { - // rjf: bake - RDIM_BakeResults bake_results = {0}; - ProfScope("bake") bake_results = rdim2_bake(arena, &bake_params); - // rjf: serialize RDIM_SerializedSectionBundle serialized_section_bundle = {0}; ProfScope("serialize") serialized_section_bundle = rdim_serialized_section_bundle_from_bake_results(&bake_results); @@ -782,8 +785,138 @@ rb_thread_entry_point(void *p) //- rjf: generate breakpad text case OutputKind_Breakpad: { - String8List dump = {0}; + //- rjf: set up shared state + typedef struct P2B_Shared P2B_Shared; + struct P2B_Shared + { + String8List dump; + String8List *lane_chunk_file_dumps; + String8List *lane_chunk_func_dumps; + }; + local_persist P2B_Shared *p2b_shared = 0; + if(lane_idx() == 0) + { + p2b_shared = push_array(arena, P2B_Shared, 1); + p2b_shared->lane_chunk_file_dumps = push_array(arena, String8List, lane_count()*bake_params.src_files.chunk_count); + p2b_shared->lane_chunk_func_dumps = push_array(arena, String8List, lane_count()*bake_params.procedures.chunk_count); + } + lane_sync(); + //- rjf: dump MODULE record + if(lane_idx() == 0) + { + str8_list_pushf(arena, &p2b_shared->dump, "MODULE windows x86_64 %I64x %S\n", bake_params.top_level_info.exe_hash, bake_params.top_level_info.exe_name); + } + + //- rjf: dump FILE records + ProfScope("dump FILE records") + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, bake_params.src_files.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + U64 file_idx = rdim_idx_from_src_file(&n->v[idx]); + String8 src_path = n->v[idx].path; + str8_list_pushf(arena, &p2b_shared->lane_chunk_file_dumps[lane_idx()*bake_params.src_files.chunk_count + chunk_idx], "FILE %I64u %S\n", file_idx, src_path); + } + chunk_idx += 1; + } + } + + //- rjf: dump FUNC records + ProfScope("dump FUNC records") + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, bake_params.procedures.first) + { + String8List *out = &p2b_shared->lane_chunk_func_dumps[lane_idx()*bake_params.procedures.chunk_count + chunk_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. + RDIM_Symbol *proc = &n->v[idx]; + RDIM_Scope *root_scope = proc->root_scope; + if(root_scope != 0 && root_scope->voff_ranges.first != 0) + { + // rjf: dump function record + RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; + str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); + + // rjf: dump function lines + U64 unit_idx = rdi_vmap_idx_from_voff(bake_results.unit_vmap.vmap.vmap, bake_results.unit_vmap.vmap.count, voff_range.min); + if(0 < unit_idx && unit_idx <= bake_results.units.units_count) + { + U32 line_table_idx = bake_results.units.units[unit_idx].line_table_idx; + if(0 < line_table_idx && line_table_idx <= bake_results.line_tables.line_tables_count) + { + // rjf: unpack unit line info + RDI_LineTable *line_table = &bake_results.line_tables.line_tables[line_table_idx]; + RDI_ParsedLineTable line_info = + { + bake_results.line_tables.line_table_voffs + line_table->voffs_base_idx, + bake_results.line_tables.line_table_lines + line_table->lines_base_idx, + 0, + line_table->lines_count, + 0 + }; + for(U64 voff = voff_range.min, last_voff = 0; + voff < voff_range.max && voff > last_voff;) + { + RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); + if(line_info_idx < line_info.count) + { + RDI_Line *line = &line_info.lines[line_info_idx]; + U64 line_voff_min = line_info.voffs[line_info_idx]; + U64 line_voff_opl = line_info.voffs[line_info_idx+1]; + if(line->file_idx != 0) + { + str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n", + line_voff_min, + line_voff_opl-line_voff_min, + (U64)line->line_num, + (U64)line->file_idx); + } + last_voff = voff; + voff = line_voff_opl; + } + else + { + break; + } + } + } + } + } + } + chunk_idx += 1; + } + } + + //- rjf: join + lane_sync(); + if(lane_idx() == 0) + { + for EachIndex(chunk_idx, bake_params.src_files.chunk_count) + { + for EachIndex(ln_idx, lane_count()) + { + str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_file_dumps[ln_idx*bake_params.src_files.chunk_count + chunk_idx]); + } + } + for EachIndex(chunk_idx, bake_params.procedures.chunk_count) + { + for EachIndex(ln_idx, lane_count()) + { + str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_func_dumps[ln_idx*bake_params.procedures.chunk_count + chunk_idx]); + } + } + } + lane_sync(); + output_blobs = p2b_shared->dump; + +#if 0 //- rjf: kick off unit vmap baking P2B_BakeUnitVMapIn bake_unit_vmap_in = {&bake_params.units}; ASYNC_Task *bake_unit_vmap_task = async_task_launch(arena, p2b_bake_unit_vmap_work, .input = &bake_unit_vmap_in); @@ -864,6 +997,7 @@ rb_thread_entry_point(void *p) } str8_list_concat_in_place(&output_blobs, &dump); +#endif }break; } }break; diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 0b29493b..a4ba1308 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -381,6 +381,78 @@ p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDI } } +internal RDIM_LocationInfo +p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) +{ + RDIM_LocationInfo result = {0}; + if(0 <= offset && offset <= (S64)max_U16) + { + if(extra_indirection) + { + result.kind = RDI_LocationKind_AddrAddrRegPlusU16; + result.reg_code = reg_code; + result.offset = offset; + } + else + { + result.kind = RDI_LocationKind_AddrRegPlusU16; + result.reg_code = reg_code; + result.offset = offset; + } + } + else + { + RDIM_EvalBytecode bytecode = {0}; + U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); + rdim_bytecode_push_sconst(arena, &bytecode, offset); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); + if(extra_indirection) + { + U64 addr_size = rdi_addr_size_from_arch(arch); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); + } + result.kind = RDI_LocationKind_AddrBytecodeStream; + result.bytecode = bytecode; + } + return result; +} + +internal void +p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +{ + //- rjf: extract range info + U64 voff_first = 0; + U64 voff_opl = 0; + if(section != 0) + { + voff_first = section->voff + range->off; + voff_opl = voff_first + range->len; + } + + //- rjf: emit location for ranges not coverd by gaps + CV_LvarAddrGap *gap_ptr = gaps; + U64 voff_cursor = voff_first; + for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) + { + U64 voff_gap_first = voff_first + gap_ptr->off; + U64 voff_gap_opl = voff_gap_first + gap_ptr->len; + if(voff_cursor < voff_gap_first) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; + rdim_local_push_location_case(arena, scopes, local, loc, voff_range); + } + voff_cursor = voff_gap_opl; + } + + //- rjf: emit remaining range + if(voff_cursor < voff_opl) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; + rdim_local_push_location_case(arena, scopes, local, loc, voff_range); + } +} + //////////////////////////////// //~ rjf: Initial Parsing & Preparation Pass Tasks @@ -3158,266 +3230,268 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) //~ rjf: Top-Level Conversion Entry Point internal RDIM_BakeParams -p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) +p2r2_convert(Arena *arena, P2R_ConvertParams *params) { - Temp scratch = scratch_begin(&arena, 1); - p2r_async_root = async_root; - ////////////////////////////////////////////////////////////// - //- rjf: parse MSF structure + //- rjf: do base MSF parse // - MSF_Parsed *msf = 0; - if(in->input_pdb_data.size != 0) ProfScope("parse MSF structure") { - msf = msf_parsed_from_data(arena, in->input_pdb_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse PDB auth_guid & named streams table - // - PDB_NamedStreamTable *named_streams = 0; - Guid auth_guid = {0}; - if(msf != 0) ProfScope("parse PDB auth_guid & named streams table") - { - Temp scratch = scratch_begin(&arena, 1); - String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); - PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); - named_streams = pdb_named_stream_table_from_info(arena, info); - MemoryCopyStruct(&auth_guid, &info->auth_guid); - scratch_end(scratch); - - if (info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { - fprintf(stderr, "ERROR: PDB was linked with /DEBUG:FASTLINK (partial debug info is not supported). Please relink using /DEBUG:FULL."); - os_abort(1); - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse PDB strtbl - // - PDB_Strtbl *strtbl = 0; - String8 raw_strtbl = {0}; - if(named_streams != 0) ProfScope("parse PDB strtbl") - { - MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; - String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - strtbl = pdb_strtbl_from_data(arena, strtbl_data); - raw_strtbl = str8_substr(strtbl_data, rng_1u64(strtbl->strblock_min, strtbl->strblock_max)); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse dbi - // - PDB_DbiParsed *dbi = 0; - if(msf != 0) ProfScope("parse dbi") - { - String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); - dbi = pdb_dbi_from_data(arena, dbi_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse tpi - // - PDB_TpiParsed *tpi = 0; - if(msf != 0) ProfScope("parse tpi") - { - String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); - tpi = pdb_tpi_from_data(arena, tpi_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse ipi - // - PDB_TpiParsed *ipi = 0; - if(msf != 0) ProfScope("parse ipi") - { - String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); - ipi = pdb_tpi_from_data(arena, ipi_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse coff sections - // - COFF_SectionHeaderArray coff_sections = {0}; - if(dbi != 0) ProfScope("parse coff sections") - { - MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; - String8 section_data = msf_data_from_stream(msf, section_stream); - coff_sections = pdb_coff_section_array_from_data(arena, section_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse gsi - // - PDB_GsiParsed *gsi = 0; - if(dbi != 0) ProfScope("parse gsi") - { - String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); - gsi = pdb_gsi_from_data(arena, gsi_data); - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse psi - // - PDB_GsiParsed *psi_gsi_part = 0; - if(dbi != 0) ProfScope("parse psi") - { - String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); - String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); - psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); - } - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff EXE hash - // - P2R_EXEHashIn exe_hash_in = {in->input_exe_data}; - ASYNC_Task *exe_hash_task = async_task_launch(scratch.arena, p2r_exe_hash_work, .input = &exe_hash_in); - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff TPI hash parse - // - P2R_TPIHashParseIn tpi_hash_in = {0}; - ASYNC_Task *tpi_hash_task = 0; - if(tpi != 0) - { - tpi_hash_in.strtbl = strtbl; - tpi_hash_in.tpi = tpi; - tpi_hash_in.hash_data = msf_data_from_stream(msf, tpi->hash_sn); - tpi_hash_in.aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); - tpi_hash_task = async_task_launch(scratch.arena, p2r_tpi_hash_parse_work, .input = &tpi_hash_in); - } - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff TPI leaf parse - // - P2R_TPILeafParseIn tpi_leaf_in = {0}; - ASYNC_Task *tpi_leaf_task = 0; - if(tpi != 0) - { - tpi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(tpi); - tpi_leaf_in.itype_first = tpi->itype_first; - tpi_leaf_task = async_task_launch(scratch.arena, p2r_tpi_leaf_parse_work, .input = &tpi_leaf_in); - } - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff IPI hash parse - // - P2R_TPIHashParseIn ipi_hash_in = {0}; - ASYNC_Task *ipi_hash_task = 0; - if(ipi != 0) - { - ipi_hash_in.strtbl = strtbl; - ipi_hash_in.tpi = ipi; - ipi_hash_in.hash_data = msf_data_from_stream(msf, ipi->hash_sn); - ipi_hash_in.aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); - ipi_hash_task = async_task_launch(scratch.arena, p2r_tpi_hash_parse_work, .input = &ipi_hash_in); - } - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff IPI leaf parse - // - P2R_TPILeafParseIn ipi_leaf_in = {0}; - ASYNC_Task *ipi_leaf_task = 0; - if(ipi != 0) - { - ipi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(ipi); - ipi_leaf_in.itype_first = ipi->itype_first; - ipi_leaf_task = async_task_launch(scratch.arena, p2r_tpi_leaf_parse_work, .input = &ipi_leaf_in); - } - - ////////////////////////////////////////////////////////////// - //- rjf: kickoff top-level global symbol stream parse - // - P2R_SymbolStreamParseIn sym_parse_in = {dbi ? msf_data_from_stream(msf, dbi->sym_sn) : str8_zero()}; - ASYNC_Task *sym_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_symbol_stream_parse_work, .input = &sym_parse_in); - - ////////////////////////////////////////////////////////////// - //- rjf: do compilation unit parse - // - PDB_CompUnitArray *comp_units = 0; - U64 comp_unit_count = 0; - { - P2R_CompUnitParseIn comp_unit_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo) : str8_zero()}; - ASYNC_Task *comp_unit_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_comp_unit_parse_work, .input = &comp_unit_parse_in); - comp_units = async_task_join_struct(comp_unit_parse_task, PDB_CompUnitArray); - comp_unit_count = comp_units ? comp_units->count : 0; - } - - ////////////////////////////////////////////////////////////// - //- rjf: do compilation unit contributions parse - // - PDB_CompUnitContributionArray *comp_unit_contributions = 0; - U64 comp_unit_contribution_count = 0; - { - P2R_CompUnitContributionsParseIn comp_unit_contributions_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon) : str8_zero(), coff_sections}; - ASYNC_Task *comp_unit_contributions_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_comp_unit_contributions_parse_work, .input = &comp_unit_contributions_parse_in); - comp_unit_contributions = async_task_join_struct(comp_unit_contributions_parse_task, PDB_CompUnitContributionArray); - comp_unit_contribution_count = comp_unit_contributions ? comp_unit_contributions->count : 0; - } - - ////////////////////////////////////////////////////////////// - //- rjf: do compilation unit contributions bucket - // - RDIM_Rng1U64ChunkList *unit_ranges = 0; - if(comp_unit_contributions) - { - P2R_CompUnitContributionsBucketIn in = {comp_unit_count, *comp_unit_contributions}; - ASYNC_Task *task = async_task_launch(scratch.arena, p2r_comp_unit_contributions_bucket_work, .input = &in); - P2R_CompUnitContributionsBucketOut *out = async_task_join_struct(task, P2R_CompUnitContributionsBucketOut); - unit_ranges = out->unit_ranges; - } - - ////////////////////////////////////////////////////////////// - //- rjf: parse syms & line info for each compilation unit - // - CV_SymParsed **sym_for_unit = push_array(arena, CV_SymParsed *, comp_unit_count); - CV_C13Parsed **c13_for_unit = push_array(arena, CV_C13Parsed *, comp_unit_count); - if(comp_units != 0) ProfScope("parse syms & line info for each compilation unit") - { - //- rjf: kick off tasks - P2R_SymbolStreamParseIn *sym_tasks_inputs = push_array(scratch.arena, P2R_SymbolStreamParseIn, comp_unit_count); - ASYNC_Task **sym_tasks = push_array(scratch.arena, ASYNC_Task *, comp_unit_count); - P2R_C13StreamParseIn *c13_tasks_inputs = push_array(scratch.arena, P2R_C13StreamParseIn, comp_unit_count); - ASYNC_Task **c13_tasks = push_array(scratch.arena, ASYNC_Task *, comp_unit_count); - for(U64 idx = 0; idx < comp_unit_count; idx += 1) + // rjf: setup output buckets + if(lane_idx() == 0) { - PDB_CompUnit *unit = comp_units->units[idx]; - sym_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); - sym_tasks[idx] = async_task_launch(scratch.arena, p2r_symbol_stream_parse_work, .input = &sym_tasks_inputs[idx]); - c13_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - c13_tasks_inputs[idx].strtbl = raw_strtbl; - c13_tasks_inputs[idx].coff_sections = coff_sections; - c13_tasks[idx] = async_task_launch(scratch.arena, p2r_c13_stream_parse_work, .input = &c13_tasks_inputs[idx]); + p2r2_shared = push_array(arena, P2R2_Shared, 1); + p2r2_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); + p2r2_shared->msf = push_array(arena, MSF_Parsed, 1); + p2r2_shared->msf->page_size = p2r2_shared->msf_raw_stream_table->page_size; + p2r2_shared->msf->page_count = p2r2_shared->msf_raw_stream_table->total_page_count; + p2r2_shared->msf->stream_count = p2r2_shared->msf_raw_stream_table->stream_count; + p2r2_shared->msf->streams = push_array(arena, String8, p2r2_shared->msf->stream_count); + p2r2_shared->msf_stream_lane_counter = 0; } + lane_sync(); - //- rjf: join tasks - for(U64 idx = 0; idx < comp_unit_count; idx += 1) + // rjf: do wide fill { - sym_for_unit[idx] = async_task_join_struct(sym_tasks[idx], CV_SymParsed); - c13_for_unit[idx] = async_task_join_struct(c13_tasks[idx], CV_C13Parsed); + for(;;) + { + U64 stream_num = ins_atomic_u64_inc_eval(&p2r2_shared->msf_stream_lane_counter); + if(stream_num < 1 || p2r2_shared->msf->stream_count < stream_num) + { + break; + } + U64 stream_idx = stream_num-1; + p2r2_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, stream_idx); + } } } + lane_sync(); + MSF_Parsed *msf = p2r2_shared->msf; + + ////////////////////////////////////////////////////////////// + //- rjf: do top-level MSF/PDB extraction + // + ProfScope("do top-level MSF/PDB extraction") if(lane_idx() == 0) + { + ProfScope("parse PDB info") + { + String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); + p2r2_shared->pdb_info = pdb_info_from_data(arena, info_data); + if(p2r2_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) + { + log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); + } + } + ProfScope("parse named streams table") + { + p2r2_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r2_shared->pdb_info); + } + } + lane_sync(); + PDB_Info *pdb_info = p2r2_shared->pdb_info; + PDB_NamedStreamTable *named_streams = p2r2_shared->named_streams; + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB strtbl & top-level streams + // + ProfScope("parse PDB strtbl & top-level streams") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") + { + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; + String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); + p2r2_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); + p2r2_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r2_shared->strtbl->strblock_min, p2r2_shared->strtbl->strblock_max)); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") + { + String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); + p2r2_shared->dbi = pdb_dbi_from_data(arena, dbi_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") + { + String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); + p2r2_shared->tpi = pdb_tpi_from_data(arena, tpi_data); + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") + { + String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); + p2r2_shared->ipi = pdb_tpi_from_data(arena, ipi_data); + } + } + lane_sync(); + PDB_Strtbl *strtbl = p2r2_shared->strtbl; + String8 raw_strtbl = p2r2_shared->raw_strtbl; + PDB_DbiParsed *dbi = p2r2_shared->dbi; + PDB_TpiParsed *tpi = p2r2_shared->tpi; + PDB_TpiParsed *ipi = p2r2_shared->ipi; + + ////////////////////////////////////////////////////////////// + //- rjf: unpack DBI + // + ProfScope("unpack DBI") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") + { + MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; + String8 section_data = msf_data_from_stream(msf, section_stream); + p2r2_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") + { + String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); + p2r2_shared->gsi = pdb_gsi_from_data(arena, gsi_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") + { + String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); + String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); + p2r2_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + } + } + lane_sync(); + COFF_SectionHeaderArray coff_sections = p2r2_shared->coff_sections; + PDB_GsiParsed *gsi = p2r2_shared->gsi; + PDB_GsiParsed *psi_gsi_part = p2r2_shared->psi_gsi_part; + + ////////////////////////////////////////////////////////////// + //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units + // + ProfScope("hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") + { + p2r2_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") + { + String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + p2r2_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") + { + String8 leaf_data = pdb_leaf_data_from_tpi(tpi); + p2r2_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") + { + String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); + String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + p2r2_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); + } + if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") + { + String8 leaf_data = pdb_leaf_data_from_tpi(ipi); + p2r2_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); + } + if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") + { + String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); + p2r2_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); + } + if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") + { + String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); + p2r2_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); + } + } + lane_sync(); + U64 exe_hash = p2r2_shared->exe_hash; + PDB_TpiHashParsed *tpi_hash = p2r2_shared->tpi_hash; + CV_LeafParsed *tpi_leaf = p2r2_shared->tpi_leaf; + PDB_TpiHashParsed *ipi_hash = p2r2_shared->ipi_hash; + CV_LeafParsed *ipi_leaf = p2r2_shared->ipi_leaf; + PDB_CompUnitArray *comp_units = p2r2_shared->comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions = p2r2_shared->comp_unit_contributions; + + ////////////////////////////////////////////////////////////// + //- rjf: bucket compilation unit contributions + // + ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) + { + p2r2_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); + for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) + { + PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[idx]; + if(contribution->mod < comp_units->count) + { + RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; + rdim_rng1u64_chunk_list_push(arena, &p2r2_shared->unit_ranges[contribution->mod], 256, r); + } + } + } + lane_sync(); + RDIM_Rng1U64ChunkList *unit_ranges = p2r2_shared->unit_ranges; + + ////////////////////////////////////////////////////////////// + //- rjf: parse all syms & c13 line info streams + // + ProfScope("parse all syms & c13 line info streams") + { + //- rjf: setup outputs + if(lane_idx() == 0) + { + p2r2_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI + p2r2_shared->all_syms = push_array(arena, CV_SymParsed *, p2r2_shared->all_syms_count); + p2r2_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r2_shared->all_syms_count); + p2r2_shared->sym_c13_unit_lane_counter = 0; + } + lane_sync(); + + //- rjf: wide fill + { + U64 task_count = p2r2_shared->all_syms_count; + for(;;) + { + U64 task_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_c13_unit_lane_counter); + if(task_num == 0 || task_count < task_num) + { + break; + } + U64 task_idx = task_num-1; + if(task_idx > 0) + { + PDB_CompUnit *unit = comp_units->units[task_idx-1]; + String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); + String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); + p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); + p2r2_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + } + else + { + String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); + p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); + } + } + } + } + lane_sync(); + U64 all_syms_count = p2r2_shared->all_syms_count; + CV_SymParsed **all_syms = p2r2_shared->all_syms; + CV_C13Parsed **all_c13s = p2r2_shared->all_c13s; ////////////////////////////////////////////////////////////// //- rjf: calculate EXE's max voff // - U64 exe_voff_max = 0; + if(lane_idx() == 0) { COFF_SectionHeader *coff_sec_ptr = coff_sections.v; COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_sections.count; for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) { U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; - exe_voff_max = Max(exe_voff_max, sec_voff_max); + p2r2_shared->exe_voff_max = Max(p2r2_shared->exe_voff_max, sec_voff_max); } } + lane_sync(); + U64 exe_voff_max = p2r2_shared->exe_voff_max; ////////////////////////////////////////////////////////////// //- rjf: determine architecture // - RDI_Arch arch = RDI_Arch_NULL; - U64 arch_addr_size = 0; + if(lane_idx() == 0) { + // // TODO(rjf): in some cases, the first compilation unit has a zero // architecture, as it's sometimes used as a "nil" unit. this causes bugs // in later stages of conversion - particularly, this was detected via @@ -3430,194 +3504,831 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) // case, we'll need to not only have this be a top-level "contextual" piece // of info, but to use the appropriate compilation unit's architecture when // possible. assuming, of course, that we care about supporting that case. - for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) + // + for EachIndex(idx, all_syms_count) { - if(sym_for_unit[comp_unit_idx] != 0) + p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); + if(p2r2_shared->arch != RDI_Arch_NULL) { - arch = p2r_rdi_arch_from_cv_arch(sym_for_unit[comp_unit_idx]->info.arch); - if(arch != RDI_Arch_NULL) + break; + } + } + } + lane_sync(); + RDI_Arch arch = p2r2_shared->arch; + U64 arch_addr_size = rdi_addr_size_from_arch(arch); + + ////////////////////////////////////////////////////////////// + //- rjf: predict total symbol count + // + if(lane_idx() == 0) + { + U64 rec_range_count = 0; + for EachIndex(idx, all_syms_count) + { + rec_range_count += all_syms[idx]->sym_ranges.count; + } + p2r2_shared->symbol_count_prediction = rec_range_count/8; + p2r2_shared->symbol_count_prediction = Max(p2r2_shared->symbol_count_prediction, 256); + } + lane_sync(); + U64 symbol_count_prediction = p2r2_shared->symbol_count_prediction; + + ////////////////////////////////////////////////////////////// + //- rjf: build link name map + // + ProfScope("build link name map") if(lane_idx() == 0 && all_syms_count != 0) + { + // rjf: set up + { + p2r2_shared->link_name_map.buckets_count = symbol_count_prediction; + p2r2_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r2_shared->link_name_map.buckets_count); + } + + // rjf: fill + { + CV_SymParsed *sym = all_syms[0]; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first + sym->sym_ranges.count; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: unpack symbol range info + CV_SymKind kind = rec_range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_sym_kind(kind); + U8 *sym_first = sym->data.str + rec_range->off + 2; + U8 *sym_opl = sym_first + rec_range->hdr.size; + + //- rjf: skip bad ranges + if(sym_opl > sym->data.str + sym->data.size || sym_first + header_struct_size > sym->data.str + sym->data.size) + { + continue; + } + + //- rjf: consume symbol + switch(kind) + { + default:{}break; + case CV_SymKind_PUB32: + { + // rjf: unpack sym + CV_SymPub32 *pub32 = (CV_SymPub32 *)sym_first; + String8 name = str8_cstring_capped(pub32+1, sym_opl); + COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= coff_sections.count) ? &coff_sections.v[pub32->sec-1] : 0; + U64 voff = 0; + if(section != 0) + { + voff = section->voff + pub32->off; + } + + // rjf: commit to link name map + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%p2r2_shared->link_name_map.buckets_count; + P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); + SLLStackPush(p2r2_shared->link_name_map.buckets[bucket_idx], node); + node->voff = voff; + node->name = name; + }break; + } + } + } + } + lane_sync(); + P2R_LinkNameMap link_name_map = p2r2_shared->link_name_map; + + ////////////////////////////////////////////////////////////// + //- rjf: gather all file paths + // + ProfScope("gather all file paths") + { + //- rjf: prep outputs + ProfScope("prep outputs") if(lane_idx() == 0) + { + p2r2_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); + p2r2_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); + p2r2_shared->sym_lane_take_counter = 0; + } + lane_sync(); + + //- rjf: do wide gather + ProfScope("do wide gather") + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: build local hash table to dedup files within this lane + U64 hit_path_slots_count = 4096; + String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); + + //- rjf: take units across lanes, find all file paths + ProfScope("take units across lanes, find all file paths") + for(;;) + { + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) { break; } - } - } - arch_addr_size = rdi_addr_size_from_arch(arch); - } - - ////////////////////////////////////////////////////////////// - //- rjf: join EXE hash - // - U64 exe_hash = *async_task_join_struct(exe_hash_task, U64); - - ////////////////////////////////////////////////////////////// - //- rjf: produce top-level-info - // - RDIM_TopLevelInfo top_level_info = {0}; - { - top_level_info.arch = arch; - top_level_info.exe_name = str8_skip_last_slash(in->input_exe_name); - top_level_info.exe_hash = exe_hash; - top_level_info.voff_max = exe_voff_max; - if(in->deterministic) - { - top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: build binary sections list - // - RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") - { - COFF_SectionHeader *coff_ptr = coff_sections.v; - COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; - for(;coff_ptr < coff_opl; coff_ptr += 1) - { - char *name_first = (char*)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); - sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - sec->voff_first = coff_ptr->voff; - sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; - sec->foff_first = coff_ptr->foff; - sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: gather all source file paths; build nodes - // - RDIM_SrcFileChunkList all_src_files__sequenceless = {0}; - P2R_SrcFileMap src_file_map = {0}; - ProfScope("gather all source file paths; build nodes") - { - U64 tasks_count = comp_unit_count; - P2R_GatherUnitSrcFilesIn *tasks_inputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesIn, tasks_count); - P2R_GatherUnitSrcFilesOut *tasks_outputs = push_array(scratch.arena, P2R_GatherUnitSrcFilesOut, tasks_count); - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); - for EachIndex(idx, tasks_count) - { - tasks_inputs[idx].pdb_strtbl = strtbl; - tasks_inputs[idx].coff_sections = coff_sections; - tasks_inputs[idx].comp_unit = comp_units->units[idx]; - tasks_inputs[idx].comp_unit_syms = sym_for_unit[idx]; - tasks_inputs[idx].comp_unit_c13s = c13_for_unit[idx]; - tasks[idx] = async_task_launch(scratch.arena, p2r_gather_unit_src_file_work, .input = &tasks_inputs[idx]); - } - U64 total_path_count = 0; - for EachIndex(idx, tasks_count) - { - tasks_outputs[idx] = *async_task_join_struct(tasks[idx], P2R_GatherUnitSrcFilesOut); - total_path_count += tasks_outputs[idx].src_file_paths.count; - } - src_file_map.slots_count = total_path_count + total_path_count/2 + 1; - src_file_map.slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map.slots_count); - for EachIndex(idx, tasks_count) - { - for EachIndex(path_idx, tasks_outputs[idx].src_file_paths.count) - { - String8 file_path_sanitized = tasks_outputs[idx].src_file_paths.v[path_idx]; - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + U64 unit_idx = unit_num-1; + + //- rjf: unpack unit + PDB_CompUnit *unit = comp_units->units[unit_idx]; + CV_SymParsed *sym = all_syms[unit_idx+1]; + CV_C13Parsed *c13 = all_c13s[unit_idx+1]; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym->sym_ranges.count; + + //- rjf: produce obj name/path + String8 obj_name = unit->obj_name; { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { - src_file_node = n; - break; + MemoryZeroStruct(&obj_name); } } - if(src_file_node == 0) + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: find all inline site symbols & gather filenames + String8List src_file_paths = {0}; + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) { - src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); - SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &all_src_files__sequenceless, total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = c13->file_chksms_sub_section; + + // rjf: gathered lines + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + U64 line_count = 0; + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> gather new file name + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum *)(c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // rjf: file name -> normalized file path + String8 file_path = seq_file_name; + String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + if(file_path_normalized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); + file_path_normalized_parts = obj_folder_path_parts; + file_path_normalized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); + } + + // rjf: normalized file path -> source file node + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_normalized, 0)) + { + hit_path_node = n; + break; + } + } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_normalized; + str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); + } + line_count = 0; + } + + // rjf: count lines + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + + // rjf: find all files in this unit's (non-inline) line info + ProfScope("find all files in this unit's (non-inline) line info") + for(CV_C13SubSectionNode *node = c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) + { + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) + { + // rjf: file name -> sanitized file path + String8 file_path = lines_n->v.file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; + String8Node *hit_path_node = 0; + for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) + { + if(str8_match(n->string, file_path_sanitized, 0)) + { + hit_path_node = n; + break; + } + } + if(hit_path_node == 0) + { + hit_path_node = push_array(scratch.arena, String8Node, 1); + SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); + hit_path_node->string = file_path_sanitized; + str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); + } + } + } + } + + //- rjf: merge into array for this unit + p2r2_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); + + //- rjf: hash this unit's file paths + U64Array hashes = {0}; + hashes.count = p2r2_shared->unit_file_paths[unit_idx].count; + hashes.v = push_array(arena, U64, hashes.count); + for EachIndex(idx, p2r2_shared->unit_file_paths[unit_idx].count) + { + hashes.v[idx] = rdi_hash(p2r2_shared->unit_file_paths[unit_idx].v[idx].str, p2r2_shared->unit_file_paths[unit_idx].v[idx].size); + } + p2r2_shared->unit_file_paths_hashes[unit_idx] = hashes; + } + scratch_end(scratch); + } + } + lane_sync(); + String8Array *unit_file_paths = p2r2_shared->unit_file_paths; + U64Array *unit_file_paths_hashes = p2r2_shared->unit_file_paths_hashes; + + ////////////////////////////////////////////////////////////// + //- rjf: build unified collection & map for source files + // + { + //- rjf: set up table + ProfScope("set up table") if(lane_idx() == 0) + { + p2r2_shared->total_path_count = 0; + for EachIndex(idx, comp_units->count) + { + p2r2_shared->total_path_count += unit_file_paths[idx].count; + } + p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; + p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); + } + lane_sync(); + + //- rjf: fill table + ProfScope("fill table") if(lane_idx() == 0) + { + for EachIndex(idx, comp_units->count) + { + String8Array paths = unit_file_paths[idx]; + U64Array hashes = unit_file_paths_hashes[idx]; + for EachIndex(path_idx, paths.count) + { + String8 file_path_sanitized = paths.v[path_idx]; + U64 file_path_sanitized_hash = hashes.v[path_idx]; + U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(arena, P2R_SrcFileNode, 1); + SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); + src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); + } } } } } + lane_sync(); + RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; + P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; ////////////////////////////////////////////////////////////// - //- rjf: kick off unit conversion tasks + //- rjf: convert unit info // - U64 unit_convert_tasks_count = comp_unit_count; - P2R_UnitConvertIn *unit_convert_tasks_ins = push_array(scratch.arena, P2R_UnitConvertIn, unit_convert_tasks_count); - ASYNC_Task **unit_convert_tasks = push_array(scratch.arena, ASYNC_Task *, unit_convert_tasks_count); - for EachIndex(idx, unit_convert_tasks_count) + ProfScope("convert unit info") { - P2R_UnitConvertIn *in = &unit_convert_tasks_ins[idx]; - in->comp_unit_idx = idx; - in->pdb_strtbl = strtbl; - in->coff_sections = coff_sections; - in->comp_unit = comp_units->units[idx]; - in->comp_unit_ranges = unit_ranges[idx]; - in->comp_unit_syms = sym_for_unit[idx]; - in->comp_unit_c13s = c13_for_unit[idx]; - in->src_file_map = &src_file_map; - unit_convert_tasks[idx] = async_task_launch(scratch.arena, p2r_unit_convert_work, .input = in); - } - - ////////////////////////////////////////////////////////////// - //- rjf: join global sym stream parse - // - CV_SymParsed *sym = async_task_join_struct(sym_parse_task, CV_SymParsed); - - ////////////////////////////// - //- rjf: predict symbol count - // - U64 symbol_count_prediction = 0; - ProfScope("predict symbol count") - { - U64 rec_range_count = 0; - if(sym != 0) + //- rjf: set up outputs + ProfScope("set up outputs") if(lane_idx() == 0) { - rec_range_count += sym->sym_ranges.count; + for EachIndex(idx, comp_units->count) + { + rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); + } + p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); + p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); + p2r2_shared->sym_lane_take_counter = 0; } - for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) + lane_sync(); + RDIM_Unit *units = p2r2_shared->all_units.first->v; + U64 units_count = p2r2_shared->all_units.first->count; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + Assert(units_count == comp_units->count); + + //- rjf: do per-lane work + ProfScope("wide fill") for(;;) { - CV_SymParsed *unit_sym = sym_for_unit[comp_unit_idx]; - rec_range_count += unit_sym->sym_ranges.count; - } - symbol_count_prediction = rec_range_count/8; - if(symbol_count_prediction < 256) - { - symbol_count_prediction = 256; + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) + { + break; + } + Temp scratch = scratch_begin(&arena, 1); + U64 unit_idx = unit_num-1; + RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; + PDB_CompUnit *src_unit = comp_units->units[unit_idx]; + CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; + CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; + RDIM_Unit *dst_unit = &units[unit_idx]; + + // rjf: extract unit name + String8 unit_name = src_unit->obj_name; + if(unit_name.size != 0) + { + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) + { + unit_name = unit_name_past_last_slash; + } + } + + // rjf: produce obj name/path + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: main unit line table conversion + ProfScope("main unit line table conversion") + { + RDIM_LineTable *line_table = 0; + for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) + { + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) + { + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> sanitized file path + String8 file_path = lines->file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + if(lines->line_count != 0) + { + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + } + + // rjf: push sequence into both line table & source file's line map + if(src_file_node != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); + } + } + } + } + + // rjf: fill unit + dst_unit->unit_name = unit_name; + dst_unit->compiler_name = src_unit_sym->info.compiler_name; + dst_unit->object_file = obj_name; + dst_unit->archive_file = src_unit->group_name; + dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); + dst_unit->line_table = line_table; + dst_unit->voff_ranges = unit_ranges[unit_idx]; + } + + //- rjf: build per-inline-site line tables + ProfScope("build per-inline-site line tables") + { + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; + void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + typedef struct LineChunk LineChunk; + struct LineChunk + { + LineChunk *next; + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + }; + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && total_line_chunk_line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> push line chunks gathered for this file + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // rjf: file name -> sanitized file path + String8 file_path = seq_file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + + // rjf: gather all lines + RDI_U64 *voffs = 0; + RDI_U32 *line_nums = 0; + RDI_U64 line_count = 0; + if(src_file_node != 0) + { + voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + line_count = total_line_chunk_line_count; + U64 dst_idx = 0; + for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) + { + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); + MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); + dst_idx += chunk->count; + } + } + + // rjf: push + if(line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(p2r2_shared->units_first_inline_site_line_tables[unit_idx] == 0) + { + p2r2_shared->units_first_inline_site_line_tables[unit_idx] = line_table; + } + } + rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + } + + // rjf: clear line chunks for subsequent sequences + first_line_chunk = last_line_chunk = 0; + total_line_chunk_line_count = 0; + } + + // rjf: new line -> emit to chunk + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 8; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + } + + scratch_end(scratch); } } + lane_sync(); + RDIM_UnitChunkList all_units = p2r2_shared->all_units; + RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// - //- rjf: kick off link name map production + //- rjf: join all line tables // - P2R_LinkNameMap link_name_map__in_progress = {0}; - P2R_LinkNameMapBuildIn link_name_map_build_in = {0}; - ASYNC_Task *link_name_map_task = 0; - if(sym != 0) ProfScope("kick off link name map build task") + ProfScope("join all line tables") if(lane_idx() == 0) { - link_name_map__in_progress.buckets_count = symbol_count_prediction; - link_name_map__in_progress.buckets = push_array(arena, P2R_LinkNameNode *, link_name_map__in_progress.buckets_count); - link_name_map_build_in.sym = sym; - link_name_map_build_in.coff_sections = coff_sections; - link_name_map_build_in.link_name_map = &link_name_map__in_progress; - link_name_map_task = async_task_launch(scratch.arena, p2r_link_name_map_build_work, .input = &link_name_map_build_in); + for EachIndex(idx, comp_units->count) + { + rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &units_line_tables[idx]); + } } + lane_sync(); + RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; ////////////////////////////////////////////////////////////// - //- rjf: join ipi/tpi hash/leaf parses + //- rjf: equip source files with line sequences // - PDB_TpiHashParsed *tpi_hash = 0; - CV_LeafParsed *tpi_leaf = 0; - PDB_TpiHashParsed *ipi_hash = 0; - CV_LeafParsed *ipi_leaf = 0; + ProfScope("equip source files with line sequences") if(lane_idx() == 0) { - tpi_hash = async_task_join_struct(tpi_hash_task, PDB_TpiHashParsed); - tpi_leaf = async_task_join_struct(tpi_leaf_task, CV_LeafParsed); - ipi_hash = async_task_join_struct(ipi_hash_task, PDB_TpiHashParsed); - ipi_leaf = async_task_join_struct(ipi_leaf_task, CV_LeafParsed); + for(RDIM_LineTableChunkNode *line_table_chunk_n = all_line_tables.first; + line_table_chunk_n != 0; + line_table_chunk_n = line_table_chunk_n->next) + { + for EachIndex(chunk_line_table_idx, line_table_chunk_n->count) + { + RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; + for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) + { + rdim_src_file_push_line_sequence(arena, &p2r2_shared->all_src_files__sequenceless, s->v.src_file, &s->v); + } + } + } } + lane_sync(); + RDIM_SrcFileChunkList all_src_files = p2r2_shared->all_src_files__sequenceless; ////////////////////////////////////////////////////////////// //- rjf: types pass 1: produce type forward resolution map @@ -3628,38 +4339,144 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) // to hook types up to their actual destination complete types wherever // possible, and so this map can be used to do that in subsequent stages. // - CV_TypeId *itype_fwd_map = 0; - CV_TypeId itype_first = 0; - CV_TypeId itype_opl = 0; - if(tpi_leaf != 0 && in->subset_flags & RDIM_SubsetFlag_Types) ProfScope("types pass 1: produce type forward resolution map") + ProfScope("types pass 1: produce type forward resolution map") { //- rjf: allocate forward resolution map - itype_first = tpi_leaf->itype_first; - itype_opl = tpi_leaf->itype_opl; - itype_fwd_map = push_array(arena, CV_TypeId, (U64)itype_opl); - - //- rjf: kick off tasks to fill forward resolution map - U64 task_size_itypes = 1024; - U64 tasks_count = ((U64)itype_opl+(task_size_itypes-1))/task_size_itypes; - P2R_ITypeFwdMapFillIn *tasks_inputs = push_array(scratch.arena, P2R_ITypeFwdMapFillIn, tasks_count); - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); - for(U64 idx = 0; idx < tasks_count; idx += 1) + if(lane_idx() == 0) { - tasks_inputs[idx].tpi_hash = tpi_hash; - tasks_inputs[idx].tpi_leaf = tpi_leaf; - tasks_inputs[idx].itype_first = idx*task_size_itypes; - tasks_inputs[idx].itype_opl = tasks_inputs[idx].itype_first + task_size_itypes; - tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); - tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - tasks[idx] = async_task_launch(scratch.arena, p2r_itype_fwd_map_fill_work, .input = &tasks_inputs[idx]); + p2r2_shared->itype_first = tpi_leaf->itype_first; + p2r2_shared->itype_opl = tpi_leaf->itype_opl; + p2r2_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r2_shared->itype_opl); } + lane_sync(); - //- rjf: join all tasks - for(U64 idx = 0; idx < tasks_count; idx += 1) + //- rjf: do wide fill { - async_task_join(tasks[idx]); + Rng1U64 range = lane_range(p2r2_shared->itype_opl); + for EachInRange(idx, range) + { + CV_TypeId itype = (CV_TypeId)idx; + if(itype < p2r2_shared->itype_first) { continue; } + + //- rjf: determine if this itype resolves to another + CV_TypeId itype_fwd = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // rjf: unpack leaf header + CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // rjf: unpack leaf header + CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // rjf: unpack leaf + CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8 *)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves tos + if(lf_union->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && + ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // rjf: unpack leaf + CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; + U8 *name_ptr = (U8 *)(lf_enum + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_enum->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && + ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + } + } + + //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map + if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) + { + p2r2_shared->itype_fwd_map[itype] = itype_fwd; + } + } } } + lane_sync(); + CV_TypeId *itype_fwd_map = p2r2_shared->itype_fwd_map; + CV_TypeId itype_first = p2r2_shared->itype_first; + CV_TypeId itype_opl = p2r2_shared->itype_opl; ////////////////////////////////////////////////////////////// //- rjf: types pass 2: produce per-itype itype chain @@ -3671,34 +4488,313 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) // this chain is walked, so that deeper dependencies are built first, and // as such, always show up *earlier* in the actually built types. // - P2R_TypeIdChain **itype_chains = 0; - if(tpi_leaf != 0 && in->subset_flags & RDIM_SubsetFlag_Types) ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") + ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") { //- rjf: allocate itype chain table - itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)itype_opl); - - //- rjf: kick off tasks to fill itype chain table - U64 task_size_itypes = 1024; - U64 tasks_count = ((U64)itype_opl+(task_size_itypes-1))/task_size_itypes; - P2R_ITypeChainBuildIn *tasks_inputs = push_array(scratch.arena, P2R_ITypeChainBuildIn, tasks_count); - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); - for(U64 idx = 0; idx < tasks_count; idx += 1) + if(lane_idx() == 0) { - tasks_inputs[idx].tpi_leaf = tpi_leaf; - tasks_inputs[idx].itype_first = idx*task_size_itypes; - tasks_inputs[idx].itype_opl = tasks_inputs[idx].itype_first + task_size_itypes; - tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); - tasks_inputs[idx].itype_chains = itype_chains; - tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - tasks[idx] = async_task_launch(scratch.arena, p2r_itype_chain_build_work, .input = &tasks_inputs[idx]); + p2r2_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r2_shared->itype_opl); } + lane_sync(); - //- rjf: join all tasks - for(U64 idx = 0; idx < tasks_count; idx += 1) + //- rjf: do wide fill { - async_task_join(tasks[idx]); + Rng1U64 range = lane_range(p2r2_shared->itype_opl); + for EachInRange(idx, range) + { + CV_TypeId itype = (CV_TypeId)idx; + if(itype < p2r2_shared->itype_first) { continue; } + + //- rjf: push initial itype - should be final-visited-itype for this itype + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + //- rjf: skip basic types for dependency walk + if(itype < tpi_leaf->itype_first) + { + continue; + } + + //- rjf: walk dependent types, push to chain + Temp scratch = scratch_begin(&arena, 1); + P2R_TypeIdChain start_walk_task = {0, itype}; + P2R_TypeIdChain *first_walk_task = &start_walk_task; + P2R_TypeIdChain *last_walk_task = &start_walk_task; + for(P2R_TypeIdChain *walk_task = first_walk_task; + walk_task != 0; + walk_task = walk_task->next) + { + CV_TypeId walk_itype = itype_fwd_map[walk_task->itype] ? itype_fwd_map[walk_task->itype] : walk_task->itype; + if(walk_itype < tpi_leaf->itype_first) + { + continue; + } + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[walk_itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + + // rjf: push return itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk return itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ARRAY + case CV_LeafKind_ARRAY: + { + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLStackPush(p2r2_shared->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + } + } + } + scratch_end(scratch); + } } } + lane_sync(); + P2R_TypeIdChain **itype_chains = p2r2_shared->itype_chains; ////////////////////////////////////////////////////////////// //- rjf: types pass 3: construct all types from TPI @@ -3707,15 +4803,13 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) // subsequent passes, to build RDI "UDT" information, which is distinct // from regular type info. // - RDIM_Type **itype_type_ptrs = 0; - RDIM_Type **basic_type_ptrs = 0; - RDIM_TypeChunkList all_types = {0}; + if(lane_idx() == 0) ProfScope("types pass 3: construct all root/stub types from TPI") + { #define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - if(in->subset_flags & RDIM_SubsetFlag_Types) ProfScope("types pass 3: construct all root/stub types from TPI") - { - itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); - basic_type_ptrs = push_array(arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); + RDIM_Type **itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); + RDIM_Type **basic_type_ptrs = push_array(arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); + RDIM_TypeChunkList all_types = {0}; //////////////////////////// //- rjf: build basic types @@ -3737,7 +4831,7 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) //- rjf: build basic type aliases // { - RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, top_level_info.arch); + RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, arch); RDI_TypeKind short_type = rdim_short_type_kind_from_data_model(data_model); RDI_TypeKind ushort_type = rdim_unsigned_short_type_kind_from_data_model(data_model); RDI_TypeKind long_type = rdim_long_type_kind_from_data_model(data_model); @@ -4240,171 +5334,1775 @@ p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in) } } } - } + p2r2_shared->itype_type_ptrs = itype_type_ptrs; + p2r2_shared->basic_type_ptrs = basic_type_ptrs; + p2r2_shared->all_types__pre_typedefs = all_types; #undef p2r_type_ptr_from_itype #undef p2r_builtin_type_ptr_from_kind + } + lane_sync(); + RDIM_Type **itype_type_ptrs = p2r2_shared->itype_type_ptrs; + RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; + RDIM_TypeChunkList all_types__pre_typedefs = p2r2_shared->all_types__pre_typedefs; ////////////////////////////////////////////////////////////// - //- rjf: types pass 4: kick off UDT build + //- rjf: types pass 4: build UDTs // - U64 udt_task_size_itypes = 4096; - U64 udt_tasks_count = ((U64)itype_opl+(udt_task_size_itypes-1))/udt_task_size_itypes; - P2R_UDTConvertIn *udt_tasks_inputs = push_array(scratch.arena, P2R_UDTConvertIn, udt_tasks_count); - ASYNC_Task **udt_tasks = push_array(scratch.arena, ASYNC_Task *, udt_tasks_count); - if(in->subset_flags & RDIM_SubsetFlag_UDTs) ProfScope("types pass 4: kick off UDT build") + ProfScope("types pass 4: build UDTs") { - for(U64 idx = 0; idx < udt_tasks_count; idx += 1) +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + + //- rjf: set up + if(lane_idx() == 0) { - udt_tasks_inputs[idx].tpi_leaf = tpi_leaf; - udt_tasks_inputs[idx].itype_first = idx*udt_task_size_itypes; - udt_tasks_inputs[idx].itype_opl = udt_tasks_inputs[idx].itype_first + udt_task_size_itypes; - udt_tasks_inputs[idx].itype_opl = ClampTop(udt_tasks_inputs[idx].itype_opl, itype_opl); - udt_tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - udt_tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; - udt_tasks[idx] = async_task_launch(scratch.arena, p2r_udt_convert_work, .input = &udt_tasks_inputs[idx]); + p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); + } + lane_sync(); + + //- rjf: do wide fill + { + U64 udts_chunk_cap = 4096; + RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; + Rng1U64 range = lane_range(itype_opl); + for EachInRange(idx, range) + { + //- rjf: skip basics + CV_TypeId itype = (CV_TypeId)idx; + if(itype < itype_first) { continue; } + + //- rjf: grab type for this itype - skip if empty + RDIM_Type *dst_type = itype_type_ptrs[itype]; + if(dst_type == 0) { continue; } + + //- rjf: unpack itype leaf range - skip if out-of-range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->off+2+header_struct_size > tpi_leaf->data.size || + range->hdr.size < 2) + { + continue; + } + + //- rjf: build UDT + CV_TypeId field_itype = 0; + switch(kind) + { + default:{}break; + + //////////////////////// + //- rjf: structs/unions/classes -> equip members + // + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_UNION: + { + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + equip_members: + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_list_opl; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: MEMBER + case CV_LeafKind_MEMBER: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + U8 *name_ptr = offset_ptr + offset.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_DataField; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: STMEMBER + case CV_LeafKind_STMEMBER: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticData; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: METHOD + case CV_LeafKind_METHOD: + { + // rjf: unpack leaf + CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + //- rjf: method list itype -> range + CV_RecRange *method_list_range = &tpi_leaf->leaf_ranges.ranges[lf->list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad method lists + if(method_list_range->off+method_list_range->hdr.size > tpi_leaf->data.size || + method_list_range->hdr.size < 2 || + method_list_range->hdr.kind != CV_LeafKind_METHODLIST) + { + break; + } + + //- rjf: loop through all methods & emit members + U8 *method_list_first = tpi_leaf->data.str + method_list_range->off + 2; + U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; + for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; + method_read_ptr < method_list_opl; + method_read_ptr = next_method_read_ptr) + { + CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); + RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); + next_method_read_ptr = (U8 *)(method+1); + + // TODO(allen): PROBLEM + // We only get offsets for virtual functions (the "vbaseoff") from + // "Intro" and "PureIntro". In C++ inheritance, when we have a chain + // of inheritance (let's just talk single inheritance for now) the + // first class in the chain that introduces a new virtual function + // has this "Intro" method. If a later class in the chain redefines + // the virtual function it only has a "Virtual" method which does + // not update the offset. There is a "Virtual" and "PureVirtual" + // variant of "Virtual". The "Pure" in either case means there + // is no concrete procedure. When there is no "Pure" the method + // should have a corresponding procedure symbol id. + // + // The issue is we will want to mark all of our virtual methods as + // virtual and give them an offset, but that means we have to do + // some extra figuring to propogate offsets from "Intro" methods + // to "Virtual" methods in inheritance trees. That is - IF we want + // to start preserving the offsets of virtuals. There is room in + // the method struct to make this work, but for now I've just + // decided to drop this information. It is not urgently useful to + // us and greatly complicates matters. + + // rjf: read vbaseoff + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + if(next_method_read_ptr+4 <= method_list_opl) + { + vbaseoff = *(U32 *)next_method_read_ptr; + } + next_method_read_ptr += 4; + } + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + } + + }break; + + //- rjf: ONEMETHOD + case CV_LeafKind_ONEMETHOD: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); + U8 *vbaseoff_ptr = (U8 *)(lf+1); + U8 *vbaseoff_opl_ptr = vbaseoff_ptr; + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + vbaseoff = *(U32 *)(vbaseoff_ptr); + vbaseoff_opl_ptr += sizeof(U32); + } + U8 *name_ptr = vbaseoff_opl_ptr; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + }break; + + //- rjf: NESTTYPE + case CV_LeafKind_NESTTYPE: + { + // rjf: unpack leaf + CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: NESTTYPEEX + case CV_LeafKind_NESTTYPEEX: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: BCLASS + case CV_LeafKind_BCLASS: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = offset_ptr+offset.encoded_size; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Base; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: VBCLASS/IVBCLASS + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + { + // TODO(rjf): log on bad offsets + // TODO(rjf): handle attribs + // TODO(rjf): offsets? + + // rjf: unpack leaf + CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; + U8 *num1_ptr = (U8 *)(lf+1); + CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); + U8 *num2_ptr = num1_ptr + num1.encoded_size; + CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualBase; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: VFUNCTAB + case CV_LeafKind_VFUNCTAB: + { + CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // NOTE(rjf): currently no-op this case + (void)lf; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + + //////////////////////// + //- rjf: enums -> equip enumerates + // + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_enum_vals; + equip_enum_vals:; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: ENUMERATE + case CV_LeafKind_ENUMERATE: + { + // TODO(rjf): attribs + + // rjf: unpack leaf + CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; + U8 *val_ptr = (U8 *)(lf+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); + enum_val->name = name; + enum_val->val = val64; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + } + } + } +#undef p2r_type_ptr_from_itype + } + lane_sync(); + RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; + + ////////////////////////////////////////////////////////////// + //- rjf: join all UDTs + // + ProfScope("join all UDTs") if(lane_idx() == 0) + { + for EachIndex(idx, lane_count()) + { + rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); } } - - ////////////////////////////////////////////////////////////// - //- rjf: join link name map building task - // - P2R_LinkNameMap *link_name_map = 0; - ProfScope("join link name map building task") - { - async_task_join(link_name_map_task); - link_name_map = &link_name_map__in_progress; - } - - ////////////////////////////////////////////////////////////// - //- rjf: join unit conversion tasks - // - RDIM_UnitChunkList all_units = {0}; - RDIM_LineTableChunkList all_line_tables = {0}; - RDIM_LineTable **units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, unit_convert_tasks_count); - ProfScope("join unit conversion & src file tasks") - { - for EachIndex(idx, unit_convert_tasks_count) - { - P2R_UnitConvertOut *out = async_task_join_struct(unit_convert_tasks[idx], P2R_UnitConvertOut); - rdim_unit_chunk_list_concat_in_place(&all_units, &out->units); - rdim_line_table_chunk_list_concat_in_place(&all_line_tables, &out->line_tables); - units_first_inline_site_line_tables[idx] = out->unit_first_inline_site_line_table; - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: kick off source file line sequence equipping task - // - RDIM_SrcFileChunkList all_src_files = {0}; - { - P2R_SrcFileSeqEquipIn in = {all_src_files__sequenceless, all_line_tables}; - ASYNC_Task *task = async_task_launch(scratch.arena, p2r_src_file_seq_equip_work, .input = &in); - async_task_join(task); - all_src_files = in.src_files; - } + lane_sync(); + RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams // - RDIM_SymbolChunkList all_procedures = {0}; - RDIM_SymbolChunkList all_global_variables = {0}; - RDIM_SymbolChunkList all_thread_variables = {0}; - RDIM_SymbolChunkList all_constants = {0}; - RDIM_ScopeChunkList all_scopes = {0}; - RDIM_InlineSiteChunkList all_inline_sites = {0}; ProfScope("produce symbols from all streams") { +#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) + //////////////////////////// - //- rjf: kick off all symbol conversion tasks + //- rjf: set up // - U64 global_stream_subdivision_tasks_count = sym ? (sym->sym_ranges.count+16383)/16384 : 0; - U64 global_stream_syms_per_task = sym ? sym->sym_ranges.count/global_stream_subdivision_tasks_count : 0; - U64 tasks_count = comp_unit_count + global_stream_subdivision_tasks_count; - P2R_SymbolStreamConvertIn *tasks_inputs = push_array(scratch.arena, P2R_SymbolStreamConvertIn, tasks_count); - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); - ProfScope("kick off all symbol conversion tasks") + if(lane_idx() == 0) { - for(U64 idx = 0; idx < tasks_count; idx += 1) + p2r2_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); + p2r2_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r2_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); + p2r2_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); + p2r2_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); + p2r2_shared->sym_lane_take_counter = 0; + } + lane_sync(); + + //////////////////////////// + //- rjf: fill outputs for all unit sym blocks in this lane + // + for(;;) + { + //- rjf: take next sym + U64 sym_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + if(sym_num > all_syms_count) { - tasks_inputs[idx].arch = arch; - tasks_inputs[idx].coff_sections = coff_sections; - tasks_inputs[idx].tpi_hash = tpi_hash; - tasks_inputs[idx].tpi_leaf = tpi_leaf; - tasks_inputs[idx].ipi_leaf = ipi_leaf; - tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; - tasks_inputs[idx].link_name_map = link_name_map; - if(idx < global_stream_subdivision_tasks_count) + break; + } + U64 sym_idx = sym_num-1; + + //- rjf: unpack sym + Temp scratch = scratch_begin(&arena, 1); + CV_SymParsed *sym = all_syms[sym_idx]; + Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); + U64 sym_locations_chunk_cap = 16384; + U64 sym_procedures_chunk_cap = 16384; + U64 sym_global_variables_chunk_cap = 16384; + U64 sym_thread_variables_chunk_cap = 16384; + U64 sym_constants_chunk_cap = 16384; + U64 sym_scopes_chunk_cap = 16384; + U64 sym_inline_sites_chunk_cap = 16384; + RDIM_LocationChunkList *sym_locations = &p2r2_shared->syms_locations[sym_idx]; + RDIM_SymbolChunkList *sym_procedures = &p2r2_shared->syms_procedures[sym_idx]; + RDIM_SymbolChunkList *sym_global_variables = &p2r2_shared->syms_global_variables[sym_idx]; + RDIM_SymbolChunkList *sym_thread_variables = &p2r2_shared->syms_thread_variables[sym_idx]; + RDIM_SymbolChunkList *sym_constants = &p2r2_shared->syms_constants[sym_idx]; + RDIM_ScopeChunkList *sym_scopes = &p2r2_shared->syms_scopes[sym_idx]; + RDIM_InlineSiteChunkList *sym_inline_sites = &p2r2_shared->syms_inline_sites[sym_idx]; + RDIM_TypeChunkList *typedefs = &p2r2_shared->syms_typedefs[sym_idx]; + + ////////////////////////// + //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) + // + U64 procedure_frameprocs_count = 0; + U64 procedure_frameprocs_cap = dim_1u64(sym_rec_range); + CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); + ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") + { + U64 procedure_num = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) { - tasks_inputs[idx].parsing_global_stream = 1; - tasks_inputs[idx].sym = sym; - tasks_inputs[idx].sym_ranges_first = idx*global_stream_syms_per_task; - tasks_inputs[idx].sym_ranges_opl = tasks_inputs[idx].sym_ranges_first + global_stream_syms_per_task; - tasks_inputs[idx].sym_ranges_opl = ClampTop(tasks_inputs[idx].sym_ranges_opl, sym->sym_ranges.count); + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: FRAMEPROC + case CV_SymKind_FRAMEPROC: + { + if(procedure_num == 0) { break; } + if(procedure_num > procedure_frameprocs_cap) { break; } + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; + procedure_frameprocs[procedure_num-1] = frameproc; + procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + procedure_num += 1; + }break; + } } - else + U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); + arena_pop(scratch.arena, scratch_overkill); + } + + ////////////////////////// + //- rjf: symbols pass 2: construct all symbols, given procedure frame info map + // + ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") + { + RDIM_LocationSet *defrange_target = 0; + RDIM_Local *defrange_target2 = 0; + B32 defrange_target_is_param = 0; + U64 procedure_num = 0; + U64 procedure_base_voff = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + typedef struct P2R_ScopeNode P2R_ScopeNode; + struct P2R_ScopeNode { - tasks_inputs[idx].sym = sym_for_unit[idx-global_stream_subdivision_tasks_count]; - tasks_inputs[idx].sym_ranges_first= 0; - tasks_inputs[idx].sym_ranges_opl = sym_for_unit[idx-global_stream_subdivision_tasks_count]->sym_ranges.count; - tasks_inputs[idx].first_inline_site_line_table = units_first_inline_site_line_tables[idx-global_stream_subdivision_tasks_count]; + P2R_ScopeNode *next; + RDIM_Scope *scope; + }; + P2R_ScopeNode *top_scope_node = 0; + P2R_ScopeNode *free_scope_node = 0; + RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: END + case CV_SymKind_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target2 = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: BLOCK32 + case CV_SymKind_BLOCK32: + { + // rjf: unpack sym + CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; + + // rjf: build scope, insert into current parent scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + { + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + block32->off; + U64 voff_last = voff_first + block32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); + } + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + }break; + + //- rjf: LDATA32/GDATA32 + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + // rjf: unpack sym + CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(data32+1, sym_data_opl); + COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; + U64 voff = (section ? section->voff : 0) + data32->off; + + // rjf: determine if this is an exact duplicate global + // + // PDB likes to have duplicates of these spread across different + // symbol streams so we deduplicate across the entire translation + // context. + // + B32 is_duplicate = 0; + { + // TODO(rjf): @important global symbol dedup + } + + // rjf: is not duplicate -> push new global + if(!is_duplicate) + { + // rjf: unpack global variable's type + RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); + + // rjf: unpack global's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack global's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); + symbol->is_extern = (kind == CV_SymKind_GDATA32); + symbol->name = name; + symbol->type = type; + symbol->offset = voff; + symbol->container_symbol = container_symbol; + symbol->container_type = container_type; + } + }break; + + //- rjf: UDT (typedefs) + case CV_SymKind_UDT: + if(sym == all_syms[0] && top_scope_node == 0) + { + CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; + String8 name = str8_cstring_capped(udt+1, sym_data_opl); + RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); + type->kind = RDI_TypeKind_Alias; + type->name = name; + type->direct_type = p2r_type_ptr_from_itype(udt->itype); + if(type->direct_type != 0) + { + type->byte_size = type->direct_type->byte_size; + } + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + // rjf: unpack sym + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(proc32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); + + // rjf: unpack proc's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2 && tpi_hash != 0 && tpi_leaf != 0) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack proc's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build procedure's root scope + // + // NOTE: even if there could be a containing scope at this point (which should be + // illegal in C/C++ but not necessarily in another language) we would not use + // it here because these scopes refer to the ranges of code that make up a + // procedure *not* the namespaces, so a procedure's root scope always has + // no parent. + RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + { + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + proc32->off; + U64 voff_last = voff_first + proc32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); + procedure_base_voff = voff_first; + } + } + + // rjf: root scope voff minimum range -> link name + String8 link_name = {0}; + if(procedure_root_scope->voff_ranges.min != 0) + { + U64 voff = procedure_root_scope->voff_ranges.min; + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%link_name_map.buckets_count; + P2R_LinkNameNode *node = 0; + for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) + { + if(n->voff == voff) + { + link_name = n->name; + break; + } + } + } + + // rjf: build procedure symbol + RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); + procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); + procedure_symbol->name = name; + procedure_symbol->link_name = link_name; + procedure_symbol->type = type; + procedure_symbol->container_symbol = container_symbol; + procedure_symbol->container_type = container_type; + procedure_symbol->root_scope = procedure_root_scope; + + // rjf: fill root scope's symbol + procedure_root_scope->symbol = procedure_symbol; + + // rjf: push scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = procedure_root_scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: increment procedure counter + procedure_num += 1; + }break; + + //- rjf: REGREL32 + case CV_SymKind_REGREL32: + { + // TODO(rjf): apparently some of the information here may end up being + // redundant with "better" information from CV_SymKind_LOCAL record. + // we don't currently handle this, but if those cases arise then it + // will obviously be better to prefer the better information from both + // records. + + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); + CV_Reg cv_reg = regrel32->reg; + U32 var_off = regrel32->reg_off; + + // rjf: determine if this is a parameter + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + { + B32 is_stack_reg = 0; + switch(arch) + { + default:{}break; + case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; + case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + } + if(is_stack_reg) + { + U32 frame_size = 0xFFFFFFFF; + if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) + { + CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; + frame_size = frameproc->frame_size; + } + if(var_off > frame_size) + { + local_kind = RDI_LocalKind_Parameter; + } + } + } + + // TODO(rjf): is this correct? + // rjf: redirect type, if 0, and if outside frame, to the return type of the + // containing procedure + if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && + top_scope_node->scope->symbol != 0 && + top_scope_node->scope->symbol->type != 0) + { + type = top_scope_node->scope->symbol->type->direct_type; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: add location info to local + if(type != 0) + { + // rjf: determine if we need an extra indirection to the value + B32 extra_indirection_to_value = 0; + switch(arch) + { + case RDI_Arch_X86: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); + }break; + case RDI_Arch_X64: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); + }break; + } + + // rjf: get raddbg register code + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + // TODO(rjf): real byte_size & byte_pos from cv_reg goes here + U32 byte_size = 8; + U32 byte_pos = 0; + + // rjf: build location + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + rdim_local_push_location_case(arena, sym_scopes, local, loc2, (RDIM_Rng1U64){0, max_U64}); + + // rjf: set location case + RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, sym_scopes, &local->locset, voff_range, loc); + } + }break; + + //- rjf: LTHREAD32/GTHREAD32 + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + { + // rjf: unpack sym + CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(thread32+1, sym_data_opl); + U32 tls_off = thread32->tls_off; + RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); + + // rjf: unpack thread variable's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack thread variable's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); + tvar->name = name; + tvar->type = type; + tvar->is_extern = (kind == CV_SymKind_GTHREAD32); + tvar->offset = tls_off; + tvar->container_type = container_type; + tvar->container_symbol = container_symbol; + }break; + + //- rjf: LOCAL + case CV_SymKind_LOCAL: + { + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; + String8 name = str8_cstring_capped(slocal+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); + + // rjf: determine if this symbol encodes the beginning of a global modification + B32 is_global_modification = 0; + if((slocal->flags & CV_LocalFlag_Global) || + (slocal->flags & CV_LocalFlag_Static)) + { + is_global_modification = 1; + } + + // rjf: is global modification -> emit global modification symbol + if(is_global_modification) + { + // TODO(rjf): add global modification symbols + defrange_target = 0; + defrange_target2 = 0; + defrange_target_is_param = 0; + } + + // rjf: is not a global modification -> emit a local variable + if(!is_global_modification) + { + // rjf: determine local kind + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + if(slocal->flags & CV_LocalFlag_Param) + { + local_kind = RDI_LocalKind_Parameter; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: save defrange target, for subsequent defrange symbols + defrange_target = &local->locset; + defrange_target2 = local; + defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); + } + }break; + + //- rjf: DEFRANGE_REGISTER + case CV_SymKind_DEFRANGE_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + if(defrange_target2 == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register->reg; + CV_LvarAddrRange *range = &defrange_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + if(defrange_target2 == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; + CV_LvarAddrRange *range = &defrange_fprel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel->off; + RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); + + // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, location, range, range_section, gaps, gap_count); + // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_SUBFIELD_REGISTER + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + if(defrange_target2 == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_subfield_register->reg; + CV_LvarAddrRange *range = &defrange_subfield_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: skip "subfield" location info - currently not supported + if(defrange_subfield_register->field_offset != 0) + { + break; + } + + // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + if(defrange_target2 == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel_full_scope->off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + + // rjf: emit location over ranges + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, sym_scopes, defrange_target, voff_range, location); + rdim_local_push_location_case(arena, sym_scopes, defrange_target2, loc, voff_range); + }break; + + //- rjf: DEFRANGE_REGISTER_REL + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + if(defrange_target2 == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register_rel->reg; + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + CV_LvarAddrRange *range = &defrange_register_rel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: build location + // TODO(rjf): offset & size from cv_reg code + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + B32 extra_indirection_to_value = 0; + S64 var_off = defrange_register_rel->reg_off; + RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + + // rjf: emit locations over ranges + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); + p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: FILESTATIC + case CV_SymKind_FILESTATIC: + { + CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; + String8 name = str8_cstring_capped(file_static+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); + // TODO(rjf): emit a global modifier symbol + defrange_target = 0; + defrange_target2 = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: extract external info about inline site + String8 name = str8_zero(); + RDIM_Type *type = 0; + RDIM_Type *owner = 0; + if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) + { + CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; + String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); + void *raw_leaf = rec_data.str + sizeof(U16); + + // rjf: extract method inline info + if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) + { + CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; + name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(mfunc_id->itype); + owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; + } + + // rjf: extract non-method function inline info + else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafFuncId)) + { + CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; + name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(func_id->itype); + owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; + } + } + + // rjf: build inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); + inline_site->name = name; + inline_site->type = type; + inline_site->owner = owner; + inline_site->line_table = inline_site_line_table; + + // rjf: increment to next inline site line table in this unit + if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) + { + RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; + U64 current_idx = (U64)(inline_site_line_table - chunk->v); + if(current_idx+1 < chunk->count) + { + inline_site_line_table += 1; + } + else + { + chunk = chunk->next; + inline_site_line_table = 0; + if(chunk != 0) + { + inline_site_line_table = chunk->v; + } + } + } + + // rjf: build scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + scope->inline_site = inline_site; + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: parse offset ranges of this inline site - attach to scope + { + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); + for(;;) + { + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) + { + // rjf: build new range & add to scope + RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); + } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) + { + if(scope->voff_ranges.last != 0) + { + scope->voff_ranges.last->v.max = step.range.max; + } + } + + if(step.flags == 0) + { + break; + } + } + } + }break; + + //- rjf: INLINESITE_END + case CV_SymKind_INLINESITE_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target2 = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: CONSTANT + case CV_SymKind_CONSTANT: + { + // rjf: unpack + CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; + RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); + U8 *val_ptr = (U8 *)(sym+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, sym_data_opl); + String8 val_data = str8_struct(&val64); + U64 container_name_opl = 0; + if(type != 0) + { + container_name_opl = p2r_end_of_cplusplus_container_name(type->name); + } + String8 name_qualified = name; + if(container_name_opl != 0) + { + name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); + } + + // rjf: build constant symbol + if(name_qualified.size != 0) + { + RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); + cnst->name = name_qualified; + cnst->type = type; + rdim_symbol_push_value_data(arena, sym_constants, cnst, val_data); + } + }break; + } } - tasks[idx] = async_task_launch(scratch.arena, p2r_symbol_stream_convert_work, .input = &tasks_inputs[idx]); + } + + scratch_end(scratch); + } +#undef p2r_type_ptr_from_itype + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: join all lane symbols + // + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("join locations") + { + for EachIndex(idx, all_syms_count) + { + rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->syms_locations[idx]); + } + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("join procedures") + { + for EachIndex(idx, all_syms_count) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->syms_procedures[idx]); + } + } + if(lane_idx() == lane_from_task_idx(2)) ProfScope("join global variables") + { + for EachIndex(idx, all_syms_count) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->syms_global_variables[idx]); + } + } + if(lane_idx() == lane_from_task_idx(3)) ProfScope("join thread variables") + { + for EachIndex(idx, all_syms_count) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->syms_thread_variables[idx]); + } + } + if(lane_idx() == lane_from_task_idx(4)) ProfScope("join constants") + { + for EachIndex(idx, all_syms_count) + { + rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->syms_constants[idx]); + } + } + if(lane_idx() == lane_from_task_idx(5)) ProfScope("join scopes") + { + for EachIndex(idx, all_syms_count) + { + rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->syms_scopes[idx]); + } + } + if(lane_idx() == lane_from_task_idx(6)) ProfScope("join inline sites") + { + for EachIndex(idx, all_syms_count) + { + rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->syms_inline_sites[idx]); + } + } + if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") + { + for EachIndex(idx, all_syms_count) + { + rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->syms_typedefs[idx]); + } + p2r2_shared->all_types = p2r2_shared->all_types__pre_typedefs; + } + } + lane_sync(); + RDIM_LocationChunkList all_locations = p2r2_shared->all_locations; + RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; + RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; + RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; + RDIM_SymbolChunkList all_constants = p2r2_shared->all_constants; + RDIM_ScopeChunkList all_scopes = p2r2_shared->all_scopes; + RDIM_InlineSiteChunkList all_inline_sites = p2r2_shared->all_inline_sites; + RDIM_TypeChunkList all_types = p2r2_shared->all_types; + + ////////////////////////////////////////////////////////////// + //- rjf: bundle all outputs + // + RDIM_BakeParams result = {0}; + { + //- rjf: produce top-level-info + RDIM_TopLevelInfo top_level_info = {0}; + { + top_level_info.arch = arch; + top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + if(!params->deterministic) + { + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); } } - //////////////////////////// - //- rjf: join tasks, merge with top-level collections - // - ProfScope("join tasks, merge with top-level collections") + //- rjf: build binary sections list + RDIM_BinarySectionList binary_sections = {0}; + ProfScope("build binary section list") { - for(U64 idx = 0; idx < tasks_count; idx += 1) + COFF_SectionHeader *coff_ptr = coff_sections.v; + COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; + for(;coff_ptr < coff_opl; coff_ptr += 1) { - P2R_SymbolStreamConvertOut *out = async_task_join_struct(tasks[idx], P2R_SymbolStreamConvertOut); - rdim_symbol_chunk_list_concat_in_place(&all_procedures, &out->procedures); - rdim_symbol_chunk_list_concat_in_place(&all_global_variables, &out->global_variables); - rdim_symbol_chunk_list_concat_in_place(&all_thread_variables, &out->thread_variables); - rdim_symbol_chunk_list_concat_in_place(&all_constants, &out->constants); - rdim_scope_chunk_list_concat_in_place(&all_scopes, &out->scopes); - rdim_inline_site_chunk_list_concat_in_place(&all_inline_sites,&out->inline_sites); - rdim_type_chunk_list_concat_in_place(&all_types, &out->typedefs); + char *name_first = (char *)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + sec->name = str8_cstring_capped(name_first, name_opl); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->voff_first = coff_ptr->voff; + sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; + sec->foff_first = coff_ptr->foff; + sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; } } + + //- rjf: fill + result.top_level_info = top_level_info; + result.binary_sections = binary_sections; + result.units = all_units; + result.types = all_types; + result.udts = all_udts; + result.src_files = all_src_files; + result.line_tables = all_line_tables; + result.locations = all_locations; + result.global_variables = all_global_variables; + result.thread_variables = all_thread_variables; + result.constants = all_constants; + result.procedures = all_procedures; + result.scopes = all_scopes; + result.inline_sites = all_inline_sites; } - ////////////////////////////////////////////////////////////// - //- rjf: types pass 5: join UDT build tasks - // - RDIM_UDTChunkList all_udts = {0}; - for(U64 idx = 0; idx < udt_tasks_count; idx += 1) - { - RDIM_UDTChunkList *udts = async_task_join_struct(udt_tasks[idx], RDIM_UDTChunkList); - rdim_udt_chunk_list_concat_in_place(&all_udts, udts); - } - - ////////////////////////////////////////////////////////////// - //- rjf: fill output - // - RDIM_BakeParams out = {0}; - { - out.top_level_info = top_level_info; - out.binary_sections = binary_sections; - out.units = all_units; - out.types = all_types; - out.udts = all_udts; - out.src_files = all_src_files; - out.line_tables = all_line_tables; - out.global_variables = all_global_variables; - out.thread_variables = all_thread_variables; - out.constants = all_constants; - out.procedures = all_procedures; - out.scopes = all_scopes; - out.inline_sites = all_inline_sites; - } - - scratch_end(scratch); - return out; + return result; } - -//////////////////////////////// - diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 90c61514..d3ef3fa3 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -303,6 +303,9 @@ internal RDIM_Location *p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch ar internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); internal void p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); +internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); +internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); + //////////////////////////////// //~ rjf: Initial Parsing & Preparation Pass Tasks @@ -354,6 +357,6 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work); //////////////////////////////// //~ rjf: Top-Level Conversion Entry Point -internal RDIM_BakeParams p2r_convert(Arena *arena, ASYNC_Root *async_root, P2R_ConvertParams *in); +internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); #endif // RDI_FROM_PDB_H diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c index 1e4cc181..29202cab 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ b/src/rdi_from_pdb/rdi_from_pdb_2.c @@ -1,3952 +1,2 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) - -internal RDIM_LocationInfo -p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) -{ - RDIM_LocationInfo result = {0}; - if(0 <= offset && offset <= (S64)max_U16) - { - if(extra_indirection) - { - result.kind = RDI_LocationKind_AddrAddrRegPlusU16; - result.reg_code = reg_code; - result.offset = offset; - } - else - { - result.kind = RDI_LocationKind_AddrRegPlusU16; - result.reg_code = reg_code; - result.offset = offset; - } - } - else - { - RDIM_EvalBytecode bytecode = {0}; - U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); - rdim_bytecode_push_sconst(arena, &bytecode, offset); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); - if(extra_indirection) - { - U64 addr_size = rdi_addr_size_from_arch(arch); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); - } - result.kind = RDI_LocationKind_AddrBytecodeStream; - result.bytecode = bytecode; - } - return result; -} - -internal void -p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) -{ - //- rjf: extract range info - U64 voff_first = 0; - U64 voff_opl = 0; - if(section != 0) - { - voff_first = section->voff + range->off; - voff_opl = voff_first + range->len; - } - - //- rjf: emit location for ranges not coverd by gaps - CV_LvarAddrGap *gap_ptr = gaps; - U64 voff_cursor = voff_first; - for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) - { - U64 voff_gap_first = voff_first + gap_ptr->off; - U64 voff_gap_opl = voff_gap_first + gap_ptr->len; - if(voff_cursor < voff_gap_first) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; - rdim_local_push_location_case(arena, scopes, local, loc, voff_range); - } - voff_cursor = voff_gap_opl; - } - - //- rjf: emit remaining range - if(voff_cursor < voff_opl) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; - rdim_local_push_location_case(arena, scopes, local, loc, voff_range); - } -} - -internal RDIM_BakeParams -p2r2_convert(Arena *arena, P2R_ConvertParams *params) -{ - ////////////////////////////////////////////////////////////// - //- rjf: do base MSF parse - // - { - // rjf: setup output buckets - if(lane_idx() == 0) - { - p2r2_shared = push_array(arena, P2R2_Shared, 1); - p2r2_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); - p2r2_shared->msf = push_array(arena, MSF_Parsed, 1); - p2r2_shared->msf->page_size = p2r2_shared->msf_raw_stream_table->page_size; - p2r2_shared->msf->page_count = p2r2_shared->msf_raw_stream_table->total_page_count; - p2r2_shared->msf->stream_count = p2r2_shared->msf_raw_stream_table->stream_count; - p2r2_shared->msf->streams = push_array(arena, String8, p2r2_shared->msf->stream_count); - p2r2_shared->msf_stream_lane_counter = 0; - } - lane_sync(); - - // rjf: do wide fill - { - for(;;) - { - U64 stream_num = ins_atomic_u64_inc_eval(&p2r2_shared->msf_stream_lane_counter); - if(stream_num < 1 || p2r2_shared->msf->stream_count < stream_num) - { - break; - } - U64 stream_idx = stream_num-1; - p2r2_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, stream_idx); - } - } - } - lane_sync(); - MSF_Parsed *msf = p2r2_shared->msf; - - ////////////////////////////////////////////////////////////// - //- rjf: do top-level MSF/PDB extraction - // - ProfScope("do top-level MSF/PDB extraction") if(lane_idx() == 0) - { - ProfScope("parse PDB info") - { - String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); - p2r2_shared->pdb_info = pdb_info_from_data(arena, info_data); - if(p2r2_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) - { - log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); - } - } - ProfScope("parse named streams table") - { - p2r2_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r2_shared->pdb_info); - } - } - lane_sync(); - PDB_Info *pdb_info = p2r2_shared->pdb_info; - PDB_NamedStreamTable *named_streams = p2r2_shared->named_streams; - - ////////////////////////////////////////////////////////////// - //- rjf: parse PDB strtbl & top-level streams - // - ProfScope("parse PDB strtbl & top-level streams") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse PDB strtbl") - { - MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; - String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - p2r2_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); - p2r2_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r2_shared->strtbl->strblock_min, p2r2_shared->strtbl->strblock_max)); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") - { - String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); - p2r2_shared->dbi = pdb_dbi_from_data(arena, dbi_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") - { - String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); - p2r2_shared->tpi = pdb_tpi_from_data(arena, tpi_data); - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") - { - String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); - p2r2_shared->ipi = pdb_tpi_from_data(arena, ipi_data); - } - } - lane_sync(); - PDB_Strtbl *strtbl = p2r2_shared->strtbl; - String8 raw_strtbl = p2r2_shared->raw_strtbl; - PDB_DbiParsed *dbi = p2r2_shared->dbi; - PDB_TpiParsed *tpi = p2r2_shared->tpi; - PDB_TpiParsed *ipi = p2r2_shared->ipi; - - ////////////////////////////////////////////////////////////// - //- rjf: unpack DBI - // - ProfScope("unpack DBI") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("parse COFF sections") - { - MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; - String8 section_data = msf_data_from_stream(msf, section_stream); - p2r2_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") - { - String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); - p2r2_shared->gsi = pdb_gsi_from_data(arena, gsi_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") - { - String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); - String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); - p2r2_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); - } - } - lane_sync(); - COFF_SectionHeaderArray coff_sections = p2r2_shared->coff_sections; - PDB_GsiParsed *gsi = p2r2_shared->gsi; - PDB_GsiParsed *psi_gsi_part = p2r2_shared->psi_gsi_part; - - ////////////////////////////////////////////////////////////// - //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units - // - ProfScope("hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") - { - p2r2_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") - { - String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); - String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); - p2r2_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") - { - String8 leaf_data = pdb_leaf_data_from_tpi(tpi); - p2r2_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") - { - String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); - String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); - p2r2_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); - } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") - { - String8 leaf_data = pdb_leaf_data_from_tpi(ipi); - p2r2_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); - } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") - { - String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); - p2r2_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); - } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") - { - String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); - p2r2_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); - } - } - lane_sync(); - U64 exe_hash = p2r2_shared->exe_hash; - PDB_TpiHashParsed *tpi_hash = p2r2_shared->tpi_hash; - CV_LeafParsed *tpi_leaf = p2r2_shared->tpi_leaf; - PDB_TpiHashParsed *ipi_hash = p2r2_shared->ipi_hash; - CV_LeafParsed *ipi_leaf = p2r2_shared->ipi_leaf; - PDB_CompUnitArray *comp_units = p2r2_shared->comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions = p2r2_shared->comp_unit_contributions; - - ////////////////////////////////////////////////////////////// - //- rjf: bucket compilation unit contributions - // - ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) - { - p2r2_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); - for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) - { - PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[idx]; - if(contribution->mod < comp_units->count) - { - RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; - rdim_rng1u64_chunk_list_push(arena, &p2r2_shared->unit_ranges[contribution->mod], 256, r); - } - } - } - lane_sync(); - RDIM_Rng1U64ChunkList *unit_ranges = p2r2_shared->unit_ranges; - - ////////////////////////////////////////////////////////////// - //- rjf: parse all syms & c13 line info streams - // - ProfScope("parse all syms & c13 line info streams") - { - //- rjf: setup outputs - if(lane_idx() == 0) - { - p2r2_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI - p2r2_shared->all_syms = push_array(arena, CV_SymParsed *, p2r2_shared->all_syms_count); - p2r2_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r2_shared->all_syms_count); - p2r2_shared->sym_c13_unit_lane_counter = 0; - } - lane_sync(); - - //- rjf: wide fill - { - U64 task_count = p2r2_shared->all_syms_count; - for(;;) - { - U64 task_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_c13_unit_lane_counter); - if(task_num == 0 || task_count < task_num) - { - break; - } - U64 task_idx = task_num-1; - if(task_idx > 0) - { - PDB_CompUnit *unit = comp_units->units[task_idx-1]; - String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); - String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); - p2r2_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); - } - else - { - String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); - p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); - } - } - } - } - lane_sync(); - U64 all_syms_count = p2r2_shared->all_syms_count; - CV_SymParsed **all_syms = p2r2_shared->all_syms; - CV_C13Parsed **all_c13s = p2r2_shared->all_c13s; - - ////////////////////////////////////////////////////////////// - //- rjf: calculate EXE's max voff - // - if(lane_idx() == 0) - { - COFF_SectionHeader *coff_sec_ptr = coff_sections.v; - COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_sections.count; - for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) - { - U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; - p2r2_shared->exe_voff_max = Max(p2r2_shared->exe_voff_max, sec_voff_max); - } - } - lane_sync(); - U64 exe_voff_max = p2r2_shared->exe_voff_max; - - ////////////////////////////////////////////////////////////// - //- rjf: determine architecture - // - if(lane_idx() == 0) - { - // - // TODO(rjf): in some cases, the first compilation unit has a zero - // architecture, as it's sometimes used as a "nil" unit. this causes bugs - // in later stages of conversion - particularly, this was detected via - // busted location info. so i've converted this to a scan-until-we-find-an- - // architecture. however, this may still be fundamentally insufficient, - // because Nick has informed me that x86 units can be linked with x64 - // units, meaning the appropriate architecture at any point in time is not - // a top-level concept, and is rather dependent on to which compilation - // unit particular symbols belong. so in the future, to support that (odd) - // case, we'll need to not only have this be a top-level "contextual" piece - // of info, but to use the appropriate compilation unit's architecture when - // possible. assuming, of course, that we care about supporting that case. - // - for EachIndex(idx, all_syms_count) - { - p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); - if(p2r2_shared->arch != RDI_Arch_NULL) - { - break; - } - } - } - lane_sync(); - RDI_Arch arch = p2r2_shared->arch; - U64 arch_addr_size = rdi_addr_size_from_arch(arch); - - ////////////////////////////////////////////////////////////// - //- rjf: predict total symbol count - // - if(lane_idx() == 0) - { - U64 rec_range_count = 0; - for EachIndex(idx, all_syms_count) - { - rec_range_count += all_syms[idx]->sym_ranges.count; - } - p2r2_shared->symbol_count_prediction = rec_range_count/8; - p2r2_shared->symbol_count_prediction = Max(p2r2_shared->symbol_count_prediction, 256); - } - lane_sync(); - U64 symbol_count_prediction = p2r2_shared->symbol_count_prediction; - - ////////////////////////////////////////////////////////////// - //- rjf: build link name map - // - ProfScope("build link name map") if(lane_idx() == 0 && all_syms_count != 0) - { - // rjf: set up - { - p2r2_shared->link_name_map.buckets_count = symbol_count_prediction; - p2r2_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r2_shared->link_name_map.buckets_count); - } - - // rjf: fill - { - CV_SymParsed *sym = all_syms[0]; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first + sym->sym_ranges.count; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: unpack symbol range info - CV_SymKind kind = rec_range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_sym_kind(kind); - U8 *sym_first = sym->data.str + rec_range->off + 2; - U8 *sym_opl = sym_first + rec_range->hdr.size; - - //- rjf: skip bad ranges - if(sym_opl > sym->data.str + sym->data.size || sym_first + header_struct_size > sym->data.str + sym->data.size) - { - continue; - } - - //- rjf: consume symbol - switch(kind) - { - default:{}break; - case CV_SymKind_PUB32: - { - // rjf: unpack sym - CV_SymPub32 *pub32 = (CV_SymPub32 *)sym_first; - String8 name = str8_cstring_capped(pub32+1, sym_opl); - COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= coff_sections.count) ? &coff_sections.v[pub32->sec-1] : 0; - U64 voff = 0; - if(section != 0) - { - voff = section->voff + pub32->off; - } - - // rjf: commit to link name map - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%p2r2_shared->link_name_map.buckets_count; - P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); - SLLStackPush(p2r2_shared->link_name_map.buckets[bucket_idx], node); - node->voff = voff; - node->name = name; - }break; - } - } - } - } - lane_sync(); - P2R_LinkNameMap link_name_map = p2r2_shared->link_name_map; - - ////////////////////////////////////////////////////////////// - //- rjf: gather all file paths - // - ProfScope("gather all file paths") - { - //- rjf: prep outputs - ProfScope("prep outputs") if(lane_idx() == 0) - { - p2r2_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); - p2r2_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); - p2r2_shared->sym_lane_take_counter = 0; - } - lane_sync(); - - //- rjf: do wide gather - ProfScope("do wide gather") - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: build local hash table to dedup files within this lane - U64 hit_path_slots_count = 4096; - String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); - - //- rjf: take units across lanes, find all file paths - ProfScope("take units across lanes, find all file paths") - for(;;) - { - //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) - { - break; - } - U64 unit_idx = unit_num-1; - - //- rjf: unpack unit - PDB_CompUnit *unit = comp_units->units[unit_idx]; - CV_SymParsed *sym = all_syms[unit_idx+1]; - CV_C13Parsed *c13 = all_c13s[unit_idx+1]; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym->sym_ranges.count; - - //- rjf: produce obj name/path - String8 obj_name = unit->obj_name; - { - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: find all inline site symbols & gather filenames - String8List src_file_paths = {0}; - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - void *sym_data_opl = sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = c13->file_chksms_sub_section; - - // rjf: gathered lines - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - U64 line_count = 0; - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> gather new file name - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum *)(c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // rjf: file name -> normalized file path - String8 file_path = seq_file_name; - String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); - String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); - if(file_path_normalized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); - file_path_normalized_parts = obj_folder_path_parts; - file_path_normalized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); - file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); - } - - // rjf: normalized file path -> source file node - U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); - U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_normalized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_normalized; - str8_list_push(arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); - } - line_count = 0; - } - - // rjf: count lines - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - - // rjf: find all files in this unit's (non-inline) line info - ProfScope("find all files in this unit's (non-inline) line info") - for(CV_C13SubSectionNode *node = c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - // rjf: file name -> sanitized file path - String8 file_path = lines_n->v.file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_sanitized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_sanitized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); - } - } - } - } - - //- rjf: merge into array for this unit - p2r2_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); - - //- rjf: hash this unit's file paths - U64Array hashes = {0}; - hashes.count = p2r2_shared->unit_file_paths[unit_idx].count; - hashes.v = push_array(arena, U64, hashes.count); - for EachIndex(idx, p2r2_shared->unit_file_paths[unit_idx].count) - { - hashes.v[idx] = rdi_hash(p2r2_shared->unit_file_paths[unit_idx].v[idx].str, p2r2_shared->unit_file_paths[unit_idx].v[idx].size); - } - p2r2_shared->unit_file_paths_hashes[unit_idx] = hashes; - } - scratch_end(scratch); - } - } - lane_sync(); - String8Array *unit_file_paths = p2r2_shared->unit_file_paths; - U64Array *unit_file_paths_hashes = p2r2_shared->unit_file_paths_hashes; - - ////////////////////////////////////////////////////////////// - //- rjf: build unified collection & map for source files - // - { - //- rjf: set up table - ProfScope("set up table") if(lane_idx() == 0) - { - p2r2_shared->total_path_count = 0; - for EachIndex(idx, comp_units->count) - { - p2r2_shared->total_path_count += unit_file_paths[idx].count; - } - p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; - p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); - } - lane_sync(); - - //- rjf: fill table - ProfScope("fill table") if(lane_idx() == 0) - { - for EachIndex(idx, comp_units->count) - { - String8Array paths = unit_file_paths[idx]; - U64Array hashes = unit_file_paths_hashes[idx]; - for EachIndex(path_idx, paths.count) - { - String8 file_path_sanitized = paths.v[path_idx]; - U64 file_path_sanitized_hash = hashes.v[path_idx]; - U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - if(src_file_node == 0) - { - src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); - src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); - } - } - } - } - } - lane_sync(); - RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; - P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; - - ////////////////////////////////////////////////////////////// - //- rjf: convert unit info - // - ProfScope("convert unit info") - { - //- rjf: set up outputs - ProfScope("set up outputs") if(lane_idx() == 0) - { - for EachIndex(idx, comp_units->count) - { - rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); - } - p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); - p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); - p2r2_shared->sym_lane_take_counter = 0; - } - lane_sync(); - RDIM_Unit *units = p2r2_shared->all_units.first->v; - U64 units_count = p2r2_shared->all_units.first->count; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; - Assert(units_count == comp_units->count); - - //- rjf: do per-lane work - ProfScope("wide fill") for(;;) - { - //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) - { - break; - } - Temp scratch = scratch_begin(&arena, 1); - U64 unit_idx = unit_num-1; - RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; - PDB_CompUnit *src_unit = comp_units->units[unit_idx]; - CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; - CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; - RDIM_Unit *dst_unit = &units[unit_idx]; - - // rjf: extract unit name - String8 unit_name = src_unit->obj_name; - if(unit_name.size != 0) - { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) - { - unit_name = unit_name_past_last_slash; - } - } - - // rjf: produce obj name/path - String8 obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: main unit line table conversion - ProfScope("main unit line table conversion") - { - RDIM_LineTable *line_table = 0; - for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) - { - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); - } - } - } - } - - // rjf: fill unit - dst_unit->unit_name = unit_name; - dst_unit->compiler_name = src_unit_sym->info.compiler_name; - dst_unit->object_file = obj_name; - dst_unit->archive_file = src_unit->group_name; - dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); - dst_unit->line_table = line_table; - dst_unit->voff_ranges = unit_ranges[unit_idx]; - } - - //- rjf: build per-inline-site line tables - ProfScope("build per-inline-site line tables") - { - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; - void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - typedef struct LineChunk LineChunk; - struct LineChunk - { - LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - RDIM_LineTable* line_table = 0; - - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && total_line_chunk_line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> push line chunks gathered for this file - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - - // rjf: gather all lines - RDI_U64 *voffs = 0; - RDI_U32 *line_nums = 0; - RDI_U64 line_count = 0; - if(src_file_node != 0) - { - voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - line_count = total_line_chunk_line_count; - U64 dst_idx = 0; - for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) - { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); - MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); - dst_idx += chunk->count; - } - } - - // rjf: push - if(line_count != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(p2r2_shared->units_first_inline_site_line_tables[unit_idx] == 0) - { - p2r2_shared->units_first_inline_site_line_tables[unit_idx] = line_table; - } - } - rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); - } - - // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; - total_line_chunk_line_count = 0; - } - - // rjf: new line -> emit to chunk - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) - { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 8; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); - } - chunk->voffs[chunk->count] = step.line_voff; - chunk->voffs[chunk->count+1] = step.line_voff_end; - chunk->line_nums[chunk->count] = step.ln; - chunk->count += 1; - total_line_chunk_line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - - scratch_end(scratch); - } - } - lane_sync(); - RDIM_UnitChunkList all_units = p2r2_shared->all_units; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; - - ////////////////////////////////////////////////////////////// - //- rjf: join all line tables - // - ProfScope("join all line tables") if(lane_idx() == 0) - { - for EachIndex(idx, comp_units->count) - { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &units_line_tables[idx]); - } - } - lane_sync(); - RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; - - ////////////////////////////////////////////////////////////// - //- rjf: equip source files with line sequences - // - ProfScope("equip source files with line sequences") if(lane_idx() == 0) - { - for(RDIM_LineTableChunkNode *line_table_chunk_n = all_line_tables.first; - line_table_chunk_n != 0; - line_table_chunk_n = line_table_chunk_n->next) - { - for EachIndex(chunk_line_table_idx, line_table_chunk_n->count) - { - RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; - for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) - { - rdim_src_file_push_line_sequence(arena, &p2r2_shared->all_src_files__sequenceless, s->v.src_file, &s->v); - } - } - } - } - lane_sync(); - RDIM_SrcFileChunkList all_src_files = p2r2_shared->all_src_files__sequenceless; - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 1: produce type forward resolution map - // - // this map is used to resolve usage of "incomplete structs" in codeview's - // type info. this often happens when e.g. "struct Foo" is used to refer to - // a later-defined "Foo", which actually contains members and so on. we want - // to hook types up to their actual destination complete types wherever - // possible, and so this map can be used to do that in subsequent stages. - // - ProfScope("types pass 1: produce type forward resolution map") - { - //- rjf: allocate forward resolution map - if(lane_idx() == 0) - { - p2r2_shared->itype_first = tpi_leaf->itype_first; - p2r2_shared->itype_opl = tpi_leaf->itype_opl; - p2r2_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r2_shared->itype_opl); - } - lane_sync(); - - //- rjf: do wide fill - { - Rng1U64 range = lane_range(p2r2_shared->itype_opl); - for EachInRange(idx, range) - { - CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r2_shared->itype_first) { continue; } - - //- rjf: determine if this itype resolves to another - CV_TypeId itype_fwd = 0; - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // rjf: unpack leaf header - CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // rjf: unpack leaf header - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // rjf: unpack leaf - CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves tos - if(lf_union->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && - ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // rjf: unpack leaf - CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf_enum + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_enum->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && - ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - } - } - - //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map - if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) - { - p2r2_shared->itype_fwd_map[itype] = itype_fwd; - } - } - } - } - lane_sync(); - CV_TypeId *itype_fwd_map = p2r2_shared->itype_fwd_map; - CV_TypeId itype_first = p2r2_shared->itype_first; - CV_TypeId itype_opl = p2r2_shared->itype_opl; - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 2: produce per-itype itype chain - // - // this pass is to ensure that subsequent passes always produce types for - // dependent itypes first - guaranteeing rdi's "only reference backward" - // rule (which eliminates cycles). each itype slot gets a list of itypes, - // starting with the deepest dependency - when types are produced per-itype, - // this chain is walked, so that deeper dependencies are built first, and - // as such, always show up *earlier* in the actually built types. - // - ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") - { - //- rjf: allocate itype chain table - if(lane_idx() == 0) - { - p2r2_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r2_shared->itype_opl); - } - lane_sync(); - - //- rjf: do wide fill - { - Rng1U64 range = lane_range(p2r2_shared->itype_opl); - for EachInRange(idx, range) - { - CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r2_shared->itype_first) { continue; } - - //- rjf: push initial itype - should be final-visited-itype for this itype - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - //- rjf: skip basic types for dependency walk - if(itype < tpi_leaf->itype_first) - { - continue; - } - - //- rjf: walk dependent types, push to chain - Temp scratch = scratch_begin(&arena, 1); - P2R_TypeIdChain start_walk_task = {0, itype}; - P2R_TypeIdChain *first_walk_task = &start_walk_task; - P2R_TypeIdChain *last_walk_task = &start_walk_task; - for(P2R_TypeIdChain *walk_task = first_walk_task; - walk_task != 0; - walk_task = walk_task->next) - { - CV_TypeId walk_itype = itype_fwd_map[walk_task->itype] ? itype_fwd_map[walk_task->itype] : walk_task->itype; - if(walk_itype < tpi_leaf->itype_first) - { - continue; - } - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[walk_itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - - // rjf: push return itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk return itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - } - } - } - scratch_end(scratch); - } - } - } - lane_sync(); - P2R_TypeIdChain **itype_chains = p2r2_shared->itype_chains; - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 3: construct all types from TPI - // - // this doesn't gather struct/class/union/enum members, which is done by - // subsequent passes, to build RDI "UDT" information, which is distinct - // from regular type info. - // - if(lane_idx() == 0) ProfScope("types pass 3: construct all root/stub types from TPI") - { -#define p2r_builtin_type_ptr_from_kind(kind) ((basic_type_ptrs && RDI_TypeKind_FirstBuiltIn <= (kind) && (kind) <= RDI_TypeKind_LastBuiltIn) ? (basic_type_ptrs[(kind) - RDI_TypeKind_FirstBuiltIn]) : 0) -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - RDIM_Type **itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); - RDIM_Type **basic_type_ptrs = push_array(arena, RDIM_Type *, (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn + 1)); - RDIM_TypeChunkList all_types = {0}; - - //////////////////////////// - //- rjf: build basic types - // - { - for(RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; - type_kind <= RDI_TypeKind_LastBuiltIn; - type_kind += 1) - { - RDIM_Type *type = rdim_type_chunk_list_push(arena, &all_types, 512); - type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); - type->kind = type_kind; - type->byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type_ptrs[type_kind - RDI_TypeKind_FirstBuiltIn] = type; - } - } - - //////////////////////////// - //- rjf: build basic type aliases - // - { - RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, arch); - RDI_TypeKind short_type = rdim_short_type_kind_from_data_model(data_model); - RDI_TypeKind ushort_type = rdim_unsigned_short_type_kind_from_data_model(data_model); - RDI_TypeKind long_type = rdim_long_type_kind_from_data_model(data_model); - RDI_TypeKind ulong_type = rdim_unsigned_long_type_kind_from_data_model(data_model); - RDI_TypeKind long_long_type = rdim_long_long_type_kind_from_data_model(data_model); - RDI_TypeKind ulong_long_type = rdim_unsigned_long_long_type_kind_from_data_model(data_model); - RDI_TypeKind ptr_type = rdim_pointer_size_t_type_kind_from_data_model(data_model); - struct - { - char * name; - RDI_TypeKind kind_rdi; - CV_LeafKind kind_cv; - } - table[] = - { - { "signed char" , RDI_TypeKind_Char8 , CV_BasicType_CHAR }, - { "short" , short_type , CV_BasicType_SHORT }, - { "long" , long_type , CV_BasicType_LONG }, - { "long long" , long_long_type , CV_BasicType_QUAD }, - { "__int128" , RDI_TypeKind_S128 , CV_BasicType_OCT }, // Clang type - { "unsigned char" , RDI_TypeKind_UChar8 , CV_BasicType_UCHAR }, - { "unsigned short" , ushort_type , CV_BasicType_USHORT }, - { "unsigned long" , ulong_type , CV_BasicType_ULONG }, - { "unsigned long long" , ulong_long_type , CV_BasicType_UQUAD }, - { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UOCT }, // Clang type - { "bool" , RDI_TypeKind_S8 , CV_BasicType_BOOL8 }, - { "__bool16" , RDI_TypeKind_S16 , CV_BasicType_BOOL16 }, // not real C type - { "__bool32" , RDI_TypeKind_S32 , CV_BasicType_BOOL32 }, // not real C type - { "float" , RDI_TypeKind_F32 , CV_BasicType_FLOAT32 }, - { "double" , RDI_TypeKind_F64 , CV_BasicType_FLOAT64 }, - { "long double" , RDI_TypeKind_F80 , CV_BasicType_FLOAT80 }, - { "__float128" , RDI_TypeKind_F128 , CV_BasicType_FLOAT128 }, // Clang type - { "__float48" , RDI_TypeKind_F48 , CV_BasicType_FLOAT48 }, // not real C type - { "__float32pp" , RDI_TypeKind_F32PP , CV_BasicType_FLOAT32PP }, // not real C type - { "__float16" , RDI_TypeKind_F16 , CV_BasicType_FLOAT16 }, - { "_Complex float" , RDI_TypeKind_ComplexF32 , CV_BasicType_COMPLEX32 }, - { "_Complex double" , RDI_TypeKind_ComplexF64 , CV_BasicType_COMPLEX64 }, - { "_Complex long double" , RDI_TypeKind_ComplexF80 , CV_BasicType_COMPLEX80 }, - { "_Complex __float128" , RDI_TypeKind_ComplexF128, CV_BasicType_COMPLEX128 }, - { "__int8" , RDI_TypeKind_S8 , CV_BasicType_INT8 }, - { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 }, - { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 }, - { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 }, - { "int" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, - { "int32" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, - { "uint32" , RDI_TypeKind_U32 , CV_BasicType_UINT32 }, - { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 }, - { "__uint64" , RDI_TypeKind_U64 , CV_BasicType_UINT64 }, - { "__int128" , RDI_TypeKind_S128 , CV_BasicType_INT128 }, - { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UINT128 }, - { "char" , RDI_TypeKind_Char8 , CV_BasicType_RCHAR }, // always ASCII - { "wchar_t" , RDI_TypeKind_UChar16 , CV_BasicType_WCHAR }, // on windows always UTF-16 - { "char8_t" , RDI_TypeKind_Char8 , CV_BasicType_CHAR8 }, // always UTF-8 - { "char16_t" , RDI_TypeKind_Char16 , CV_BasicType_CHAR16 }, // always UTF-16 - { "char32_t" , RDI_TypeKind_Char32 , CV_BasicType_CHAR32 }, // always UTF-32 - { "__pointer" , ptr_type , CV_BasicType_PTR } - }; - for EachElement(idx, table) - { - RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); - builtin_alias->kind = RDI_TypeKind_Alias; - builtin_alias->name = str8_cstring(table[idx].name); - builtin_alias->direct_type = p2r_builtin_type_ptr_from_kind(table[idx].kind_rdi); - builtin_alias->byte_size = rdi_size_from_basic_type_kind(table[idx].kind_rdi); - itype_type_ptrs[table[idx].kind_cv] = builtin_alias; - } - itype_type_ptrs[CV_BasicType_HRESULT] = basic_type_ptrs[RDI_TypeKind_HResult - RDI_TypeKind_FirstBuiltIn]; - itype_type_ptrs[CV_BasicType_VOID] = basic_type_ptrs[RDI_TypeKind_Void - RDI_TypeKind_FirstBuiltIn]; - } - - //////////////////////////// - //- rjf: build types from TPI - // - for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) - { - for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; - itype_chain != 0; - itype_chain = itype_chain->next) - { - CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; - B32 itype_is_basic = (itype < tpi->itype_first); - - ////////////////////////// - //- rjf: skip forward-reference itypes - all future resolutions will - // reference whatever this itype resolves to, and so there is no point - // in filling out this slot - // - if(itype_fwd_map[root_itype] != 0) - { - continue; - } - - ////////////////////////// - //- rjf: skip already produced dependencies - // - if(itype_type_ptrs[itype] != 0) - { - continue; - } - - ////////////////////////// - //- rjf: build basic type - // - if(itype_is_basic) - { - RDIM_Type *dst_type = 0; - - // rjf: unpack itype - CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); - CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); - - // rjf: get basic type slot, fill if unfilled - RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; - if(basic_type == 0) - { - RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); - U32 byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(byte_size == 0xffffffff) - { - byte_size = arch_addr_size; - } - basic_type->kind = type_kind; - basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); - basic_type->byte_size = byte_size; - } - - // rjf: nonzero ptr kind -> form ptr type to basic tpye - if(cv_basic_ptr_kind != 0) - { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Ptr; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = basic_type; - } - - // rjf: fill this itype's slot with the finished type - itype_type_ptrs[itype] = dst_type; - } - - ////////////////////////// - //- rjf: build non-basic type - // - if(!itype_is_basic && itype >= itype_first) - { - RDIM_Type *dst_type = 0; - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: - { - // rjf: unpack leaf - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: cv -> rdi flags - RDI_TypeModifierFlags flags = 0; - if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} - if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} - - // rjf: fill type - if(flags == 0) - { - dst_type = p2r_type_ptr_from_itype(lf->itype); - } - else - { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = flags; - dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); - dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead - - // rjf: unpack leaf - CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); - U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); - - // rjf: cv -> rdi modifier flags - RDI_TypeModifierFlags modifier_flags = 0; - if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} - if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} - if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} - - // rjf: cv info -> rdi pointer type kind - RDI_TypeKind type_kind = RDI_TypeKind_Ptr; - { - if(lf->attribs & CV_PointerAttrib_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(lf->attribs & CV_PointerAttrib_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - if(ptr_mode == CV_PointerMode_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(ptr_mode == CV_PointerMode_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - } - - // rjf: fill type - if(modifier_flags != 0) - { - RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = modifier_flags; - dst_type->direct_type = pointer_type; - dst_type->byte_size = arch_addr_size; - pointer_type->kind = type_kind; - pointer_type->byte_size = arch_addr_size; - pointer_type->direct_type = direct_type; - } - else - { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = type_kind; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = direct_type; - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - // TODO(rjf): handle call_kind & attribs - - // rjf: unpack leaf - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type's basics - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: build param type array - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count); - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - params[idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_count; - dst_type->param_types = params; - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - // TODO(rjf): handle call_kind & attribs - // TODO(rjf): preserve "this_adjust" - - // rjf: unpack leaf - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: build param type array - U64 num_this_extras = 1; - if(lf->this_itype == 0) - { - num_this_extras = 0; - } - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - } - if(lf->this_itype != 0) - { - params[0] = p2r_type_ptr_from_itype(lf->this_itype); - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_count+num_this_extras; - dst_type->param_types = params; - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - // rjf: unpack leaf - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Bitfield; - dst_type->off = lf->pos; - dst_type->count = lf->len; - dst_type->byte_size = direct_type?direct_type->byte_size:0; - dst_type->direct_type = direct_type; - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - // rjf: unpack leaf - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 full_size = cv_u64_from_numeric(&array_count); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Array; - dst_type->direct_type = direct_type; - dst_type->byte_size = full_size; - dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; - }break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteUnion; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Union; - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); - U8 *name_ptr = (U8 *)(lf + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteEnum; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Enum; - dst_type->direct_type = direct_type; - dst_type->byte_size = direct_type ? direct_type->byte_size : 0; - dst_type->name = name; - } - }break; - } - } - - //- rjf: store finalized type to this itype's slot - itype_type_ptrs[itype] = dst_type; - } - } - } - p2r2_shared->itype_type_ptrs = itype_type_ptrs; - p2r2_shared->basic_type_ptrs = basic_type_ptrs; - p2r2_shared->all_types__pre_typedefs = all_types; -#undef p2r_type_ptr_from_itype -#undef p2r_builtin_type_ptr_from_kind - } - lane_sync(); - RDIM_Type **itype_type_ptrs = p2r2_shared->itype_type_ptrs; - RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; - RDIM_TypeChunkList all_types__pre_typedefs = p2r2_shared->all_types__pre_typedefs; - - ////////////////////////////////////////////////////////////// - //- rjf: types pass 4: build UDTs - // - ProfScope("types pass 4: build UDTs") - { -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < tpi_leaf->itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - - //- rjf: set up - if(lane_idx() == 0) - { - p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); - } - lane_sync(); - - //- rjf: do wide fill - { - U64 udts_chunk_cap = 4096; - RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; - Rng1U64 range = lane_range(itype_opl); - for EachInRange(idx, range) - { - //- rjf: skip basics - CV_TypeId itype = (CV_TypeId)idx; - if(itype < itype_first) { continue; } - - //- rjf: grab type for this itype - skip if empty - RDIM_Type *dst_type = itype_type_ptrs[itype]; - if(dst_type == 0) { continue; } - - //- rjf: unpack itype leaf range - skip if out-of-range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->off+2+header_struct_size > tpi_leaf->data.size || - range->hdr.size < 2) - { - continue; - } - - //- rjf: build UDT - CV_TypeId field_itype = 0; - switch(kind) - { - default:{}break; - - //////////////////////// - //- rjf: structs/unions/classes -> equip members - // - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - case CV_LeafKind_UNION: - { - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - equip_members: - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_list_opl; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: MEMBER - case CV_LeafKind_MEMBER: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - U8 *name_ptr = offset_ptr + offset.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_DataField; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: STMEMBER - case CV_LeafKind_STMEMBER: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticData; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: METHOD - case CV_LeafKind_METHOD: - { - // rjf: unpack leaf - CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - //- rjf: method list itype -> range - CV_RecRange *method_list_range = &tpi_leaf->leaf_ranges.ranges[lf->list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad method lists - if(method_list_range->off+method_list_range->hdr.size > tpi_leaf->data.size || - method_list_range->hdr.size < 2 || - method_list_range->hdr.kind != CV_LeafKind_METHODLIST) - { - break; - } - - //- rjf: loop through all methods & emit members - U8 *method_list_first = tpi_leaf->data.str + method_list_range->off + 2; - U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; - for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; - method_read_ptr < method_list_opl; - method_read_ptr = next_method_read_ptr) - { - CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); - RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); - next_method_read_ptr = (U8 *)(method+1); - - // TODO(allen): PROBLEM - // We only get offsets for virtual functions (the "vbaseoff") from - // "Intro" and "PureIntro". In C++ inheritance, when we have a chain - // of inheritance (let's just talk single inheritance for now) the - // first class in the chain that introduces a new virtual function - // has this "Intro" method. If a later class in the chain redefines - // the virtual function it only has a "Virtual" method which does - // not update the offset. There is a "Virtual" and "PureVirtual" - // variant of "Virtual". The "Pure" in either case means there - // is no concrete procedure. When there is no "Pure" the method - // should have a corresponding procedure symbol id. - // - // The issue is we will want to mark all of our virtual methods as - // virtual and give them an offset, but that means we have to do - // some extra figuring to propogate offsets from "Intro" methods - // to "Virtual" methods in inheritance trees. That is - IF we want - // to start preserving the offsets of virtuals. There is room in - // the method struct to make this work, but for now I've just - // decided to drop this information. It is not urgently useful to - // us and greatly complicates matters. - - // rjf: read vbaseoff - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - if(next_method_read_ptr+4 <= method_list_opl) - { - vbaseoff = *(U32 *)next_method_read_ptr; - } - next_method_read_ptr += 4; - } - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - } - - }break; - - //- rjf: ONEMETHOD - case CV_LeafKind_ONEMETHOD: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); - U8 *vbaseoff_ptr = (U8 *)(lf+1); - U8 *vbaseoff_opl_ptr = vbaseoff_ptr; - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - vbaseoff = *(U32 *)(vbaseoff_ptr); - vbaseoff_opl_ptr += sizeof(U32); - } - U8 *name_ptr = vbaseoff_opl_ptr; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - }break; - - //- rjf: NESTTYPE - case CV_LeafKind_NESTTYPE: - { - // rjf: unpack leaf - CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: NESTTYPEEX - case CV_LeafKind_NESTTYPEEX: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: BCLASS - case CV_LeafKind_BCLASS: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = offset_ptr+offset.encoded_size; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Base; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: VBCLASS/IVBCLASS - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - { - // TODO(rjf): log on bad offsets - // TODO(rjf): handle attribs - // TODO(rjf): offsets? - - // rjf: unpack leaf - CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; - U8 *num1_ptr = (U8 *)(lf+1); - CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); - U8 *num2_ptr = num1_ptr + num1.encoded_size; - CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualBase; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: VFUNCTAB - case CV_LeafKind_VFUNCTAB: - { - CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // NOTE(rjf): currently no-op this case - (void)lf; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - - //////////////////////// - //- rjf: enums -> equip enumerates - // - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_enum_vals; - equip_enum_vals:; - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < tpi_leaf->itype_first || tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[field_list_itype-tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: ENUMERATE - case CV_LeafKind_ENUMERATE: - { - // TODO(rjf): attribs - - // rjf: unpack leaf - CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; - U8 *val_ptr = (U8 *)(lf+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); - enum_val->name = name; - enum_val->val = val64; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - } - } - } -#undef p2r_type_ptr_from_itype - } - lane_sync(); - RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; - - ////////////////////////////////////////////////////////////// - //- rjf: join all UDTs - // - ProfScope("join all UDTs") if(lane_idx() == 0) - { - for EachIndex(idx, lane_count()) - { - rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); - } - } - lane_sync(); - RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; - - ////////////////////////////////////////////////////////////// - //- rjf: produce symbols from all streams - // - ProfScope("produce symbols from all streams") - { -#define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) - - //////////////////////////// - //- rjf: set up - // - if(lane_idx() == 0) - { - p2r2_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); - p2r2_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); - p2r2_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); - p2r2_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); - p2r2_shared->sym_lane_take_counter = 0; - } - lane_sync(); - - //////////////////////////// - //- rjf: fill outputs for all unit sym blocks in this lane - // - for(;;) - { - //- rjf: take next sym - U64 sym_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); - if(sym_num > all_syms_count) - { - break; - } - U64 sym_idx = sym_num-1; - - //- rjf: unpack sym - Temp scratch = scratch_begin(&arena, 1); - CV_SymParsed *sym = all_syms[sym_idx]; - Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); - U64 sym_locations_chunk_cap = 16384; - U64 sym_procedures_chunk_cap = 16384; - U64 sym_global_variables_chunk_cap = 16384; - U64 sym_thread_variables_chunk_cap = 16384; - U64 sym_constants_chunk_cap = 16384; - U64 sym_scopes_chunk_cap = 16384; - U64 sym_inline_sites_chunk_cap = 16384; - RDIM_LocationChunkList *sym_locations = &p2r2_shared->syms_locations[sym_idx]; - RDIM_SymbolChunkList *sym_procedures = &p2r2_shared->syms_procedures[sym_idx]; - RDIM_SymbolChunkList *sym_global_variables = &p2r2_shared->syms_global_variables[sym_idx]; - RDIM_SymbolChunkList *sym_thread_variables = &p2r2_shared->syms_thread_variables[sym_idx]; - RDIM_SymbolChunkList *sym_constants = &p2r2_shared->syms_constants[sym_idx]; - RDIM_ScopeChunkList *sym_scopes = &p2r2_shared->syms_scopes[sym_idx]; - RDIM_InlineSiteChunkList *sym_inline_sites = &p2r2_shared->syms_inline_sites[sym_idx]; - RDIM_TypeChunkList *typedefs = &p2r2_shared->syms_typedefs[sym_idx]; - - ////////////////////////// - //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) - // - U64 procedure_frameprocs_count = 0; - U64 procedure_frameprocs_cap = dim_1u64(sym_rec_range); - CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); - ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") - { - U64 procedure_num = 0; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; - - //- rjf: FRAMEPROC - case CV_SymKind_FRAMEPROC: - { - if(procedure_num == 0) { break; } - if(procedure_num > procedure_frameprocs_cap) { break; } - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; - procedure_frameprocs[procedure_num-1] = frameproc; - procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - procedure_num += 1; - }break; - } - } - U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); - arena_pop(scratch.arena, scratch_overkill); - } - - ////////////////////////// - //- rjf: symbols pass 2: construct all symbols, given procedure frame info map - // - ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") - { - RDIM_LocationSet *defrange_target = 0; - RDIM_Local *defrange_target2 = 0; - B32 defrange_target_is_param = 0; - U64 procedure_num = 0; - U64 procedure_base_voff = 0; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; - typedef struct P2R_ScopeNode P2R_ScopeNode; - struct P2R_ScopeNode - { - P2R_ScopeNode *next; - RDIM_Scope *scope; - }; - P2R_ScopeNode *top_scope_node = 0; - P2R_ScopeNode *free_scope_node = 0; - RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - void *sym_data_opl = sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; - - //- rjf: END - case CV_SymKind_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target2 = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: BLOCK32 - case CV_SymKind_BLOCK32: - { - // rjf: unpack sym - CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; - - // rjf: build scope, insert into current parent scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - { - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + block32->off; - U64 voff_last = voff_first + block32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - }break; - - //- rjf: LDATA32/GDATA32 - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - // rjf: unpack sym - CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(data32+1, sym_data_opl); - COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; - U64 voff = (section ? section->voff : 0) + data32->off; - - // rjf: determine if this is an exact duplicate global - // - // PDB likes to have duplicates of these spread across different - // symbol streams so we deduplicate across the entire translation - // context. - // - B32 is_duplicate = 0; - { - // TODO(rjf): @important global symbol dedup - } - - // rjf: is not duplicate -> push new global - if(!is_duplicate) - { - // rjf: unpack global variable's type - RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); - - // rjf: unpack global's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack global's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); - symbol->is_extern = (kind == CV_SymKind_GDATA32); - symbol->name = name; - symbol->type = type; - symbol->offset = voff; - symbol->container_symbol = container_symbol; - symbol->container_type = container_type; - } - }break; - - //- rjf: UDT (typedefs) - case CV_SymKind_UDT: - if(sym == all_syms[0] && top_scope_node == 0) - { - CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; - String8 name = str8_cstring_capped(udt+1, sym_data_opl); - RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); - type->kind = RDI_TypeKind_Alias; - type->name = name; - type->direct_type = p2r_type_ptr_from_itype(udt->itype); - if(type->direct_type != 0) - { - type->byte_size = type->direct_type->byte_size; - } - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - // rjf: unpack sym - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(proc32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); - - // rjf: unpack proc's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2 && tpi_hash != 0 && tpi_leaf != 0) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack proc's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build procedure's root scope - // - // NOTE: even if there could be a containing scope at this point (which should be - // illegal in C/C++ but not necessarily in another language) we would not use - // it here because these scopes refer to the ranges of code that make up a - // procedure *not* the namespaces, so a procedure's root scope always has - // no parent. - RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - { - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + proc32->off; - U64 voff_last = voff_first + proc32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); - procedure_base_voff = voff_first; - } - } - - // rjf: root scope voff minimum range -> link name - String8 link_name = {0}; - if(procedure_root_scope->voff_ranges.min != 0) - { - U64 voff = procedure_root_scope->voff_ranges.min; - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%link_name_map.buckets_count; - P2R_LinkNameNode *node = 0; - for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) - { - if(n->voff == voff) - { - link_name = n->name; - break; - } - } - } - - // rjf: build procedure symbol - RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); - procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); - procedure_symbol->name = name; - procedure_symbol->link_name = link_name; - procedure_symbol->type = type; - procedure_symbol->container_symbol = container_symbol; - procedure_symbol->container_type = container_type; - procedure_symbol->root_scope = procedure_root_scope; - - // rjf: fill root scope's symbol - procedure_root_scope->symbol = procedure_symbol; - - // rjf: push scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = procedure_root_scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: increment procedure counter - procedure_num += 1; - }break; - - //- rjf: REGREL32 - case CV_SymKind_REGREL32: - { - // TODO(rjf): apparently some of the information here may end up being - // redundant with "better" information from CV_SymKind_LOCAL record. - // we don't currently handle this, but if those cases arise then it - // will obviously be better to prefer the better information from both - // records. - - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); - CV_Reg cv_reg = regrel32->reg; - U32 var_off = regrel32->reg_off; - - // rjf: determine if this is a parameter - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - { - B32 is_stack_reg = 0; - switch(arch) - { - default:{}break; - case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; - case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; - } - if(is_stack_reg) - { - U32 frame_size = 0xFFFFFFFF; - if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) - { - CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; - frame_size = frameproc->frame_size; - } - if(var_off > frame_size) - { - local_kind = RDI_LocalKind_Parameter; - } - } - } - - // TODO(rjf): is this correct? - // rjf: redirect type, if 0, and if outside frame, to the return type of the - // containing procedure - if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && - top_scope_node->scope->symbol != 0 && - top_scope_node->scope->symbol->type != 0) - { - type = top_scope_node->scope->symbol->type->direct_type; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: add location info to local - if(type != 0) - { - // rjf: determine if we need an extra indirection to the value - B32 extra_indirection_to_value = 0; - switch(arch) - { - case RDI_Arch_X86: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); - }break; - case RDI_Arch_X64: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); - }break; - } - - // rjf: get raddbg register code - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - // TODO(rjf): real byte_size & byte_pos from cv_reg goes here - U32 byte_size = 8; - U32 byte_pos = 0; - - // rjf: build location - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - rdim_local_push_location_case(arena, sym_scopes, local, loc2, (RDIM_Rng1U64){0, max_U64}); - - // rjf: set location case - RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, sym_scopes, &local->locset, voff_range, loc); - } - }break; - - //- rjf: LTHREAD32/GTHREAD32 - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - // rjf: unpack sym - CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(thread32+1, sym_data_opl); - U32 tls_off = thread32->tls_off; - RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); - - // rjf: unpack thread variable's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack thread variable's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); - tvar->name = name; - tvar->type = type; - tvar->is_extern = (kind == CV_SymKind_GTHREAD32); - tvar->offset = tls_off; - tvar->container_type = container_type; - tvar->container_symbol = container_symbol; - }break; - - //- rjf: LOCAL - case CV_SymKind_LOCAL: - { - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; - String8 name = str8_cstring_capped(slocal+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); - - // rjf: determine if this symbol encodes the beginning of a global modification - B32 is_global_modification = 0; - if((slocal->flags & CV_LocalFlag_Global) || - (slocal->flags & CV_LocalFlag_Static)) - { - is_global_modification = 1; - } - - // rjf: is global modification -> emit global modification symbol - if(is_global_modification) - { - // TODO(rjf): add global modification symbols - defrange_target = 0; - defrange_target2 = 0; - defrange_target_is_param = 0; - } - - // rjf: is not a global modification -> emit a local variable - if(!is_global_modification) - { - // rjf: determine local kind - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - if(slocal->flags & CV_LocalFlag_Param) - { - local_kind = RDI_LocalKind_Parameter; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: save defrange target, for subsequent defrange symbols - defrange_target = &local->locset; - defrange_target2 = local; - defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); - } - }break; - - //- rjf: DEFRANGE_REGISTER - case CV_SymKind_DEFRANGE_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - if(defrange_target2 == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register->reg; - CV_LvarAddrRange *range = &defrange_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: build location - RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); - - // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - if(defrange_target2 == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; - CV_LvarAddrRange *range = &defrange_fprel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel->off; - RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); - - // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, location, range, range_section, gaps, gap_count); - // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_SUBFIELD_REGISTER - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - if(defrange_target2 == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_subfield_register->reg; - CV_LvarAddrRange *range = &defrange_subfield_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: skip "subfield" location info - currently not supported - if(defrange_subfield_register->field_offset != 0) - { - break; - } - - // rjf: build location - RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); - - // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - if(defrange_target2 == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - - // rjf: emit location over ranges - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, sym_scopes, defrange_target, voff_range, location); - rdim_local_push_location_case(arena, sym_scopes, defrange_target2, loc, voff_range); - }break; - - //- rjf: DEFRANGE_REGISTER_REL - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - if(defrange_target2 == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register_rel->reg; - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - CV_LvarAddrRange *range = &defrange_register_rel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: build location - // TODO(rjf): offset & size from cv_reg code - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - B32 extra_indirection_to_value = 0; - S64 var_off = defrange_register_rel->reg_off; - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - - // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: FILESTATIC - case CV_SymKind_FILESTATIC: - { - CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; - String8 name = str8_cstring_capped(file_static+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); - // TODO(rjf): emit a global modifier symbol - defrange_target = 0; - defrange_target2 = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: extract external info about inline site - String8 name = str8_zero(); - RDIM_Type *type = 0; - RDIM_Type *owner = 0; - if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) - { - CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; - String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); - void *raw_leaf = rec_data.str + sizeof(U16); - - // rjf: extract method inline info - if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) - { - CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; - name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(mfunc_id->itype); - owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; - } - - // rjf: extract non-method function inline info - else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafFuncId)) - { - CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; - name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(func_id->itype); - owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; - } - } - - // rjf: build inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); - inline_site->name = name; - inline_site->type = type; - inline_site->owner = owner; - inline_site->line_table = inline_site_line_table; - - // rjf: increment to next inline site line table in this unit - if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) - { - RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; - U64 current_idx = (U64)(inline_site_line_table - chunk->v); - if(current_idx+1 < chunk->count) - { - inline_site_line_table += 1; - } - else - { - chunk = chunk->next; - inline_site_line_table = 0; - if(chunk != 0) - { - inline_site_line_table = chunk->v; - } - } - } - - // rjf: build scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - scope->inline_site = inline_site; - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: parse offset ranges of this inline site - attach to scope - { - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); - for(;;) - { - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) - { - // rjf: build new range & add to scope - RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) - { - if(scope->voff_ranges.last != 0) - { - scope->voff_ranges.last->v.max = step.range.max; - } - } - - if(step.flags == 0) - { - break; - } - } - } - }break; - - //- rjf: INLINESITE_END - case CV_SymKind_INLINESITE_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target2 = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: CONSTANT - case CV_SymKind_CONSTANT: - { - // rjf: unpack - CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; - RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); - U8 *val_ptr = (U8 *)(sym+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, sym_data_opl); - String8 val_data = str8_struct(&val64); - U64 container_name_opl = 0; - if(type != 0) - { - container_name_opl = p2r_end_of_cplusplus_container_name(type->name); - } - String8 name_qualified = name; - if(container_name_opl != 0) - { - name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); - } - - // rjf: build constant symbol - if(name_qualified.size != 0) - { - RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); - cnst->name = name_qualified; - cnst->type = type; - rdim_symbol_push_value_data(arena, sym_constants, cnst, val_data); - } - }break; - } - } - } - - scratch_end(scratch); - } -#undef p2r_type_ptr_from_itype - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: join all lane symbols - // - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("join locations") - { - for EachIndex(idx, all_syms_count) - { - rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->syms_locations[idx]); - } - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("join procedures") - { - for EachIndex(idx, all_syms_count) - { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->syms_procedures[idx]); - } - } - if(lane_idx() == lane_from_task_idx(2)) ProfScope("join global variables") - { - for EachIndex(idx, all_syms_count) - { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->syms_global_variables[idx]); - } - } - if(lane_idx() == lane_from_task_idx(3)) ProfScope("join thread variables") - { - for EachIndex(idx, all_syms_count) - { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->syms_thread_variables[idx]); - } - } - if(lane_idx() == lane_from_task_idx(4)) ProfScope("join constants") - { - for EachIndex(idx, all_syms_count) - { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->syms_constants[idx]); - } - } - if(lane_idx() == lane_from_task_idx(5)) ProfScope("join scopes") - { - for EachIndex(idx, all_syms_count) - { - rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->syms_scopes[idx]); - } - } - if(lane_idx() == lane_from_task_idx(6)) ProfScope("join inline sites") - { - for EachIndex(idx, all_syms_count) - { - rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->syms_inline_sites[idx]); - } - } - if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") - { - for EachIndex(idx, all_syms_count) - { - rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->syms_typedefs[idx]); - } - p2r2_shared->all_types = p2r2_shared->all_types__pre_typedefs; - } - } - lane_sync(); - RDIM_LocationChunkList all_locations = p2r2_shared->all_locations; - RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; - RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; - RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; - RDIM_SymbolChunkList all_constants = p2r2_shared->all_constants; - RDIM_ScopeChunkList all_scopes = p2r2_shared->all_scopes; - RDIM_InlineSiteChunkList all_inline_sites = p2r2_shared->all_inline_sites; - RDIM_TypeChunkList all_types = p2r2_shared->all_types; - - ////////////////////////////////////////////////////////////// - //- rjf: bundle all outputs - // - RDIM_BakeParams result = {0}; - { - //- rjf: produce top-level-info - RDIM_TopLevelInfo top_level_info = {0}; - { - top_level_info.arch = arch; - top_level_info.exe_name = str8_skip_last_slash(params->input_exe_name); - top_level_info.exe_hash = exe_hash; - top_level_info.voff_max = exe_voff_max; - if(!params->deterministic) - { - top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); - } - } - - //- rjf: build binary sections list - RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") - { - COFF_SectionHeader *coff_ptr = coff_sections.v; - COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; - for(;coff_ptr < coff_opl; coff_ptr += 1) - { - char *name_first = (char *)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); - sec->name = str8_cstring_capped(name_first, name_opl); - sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - sec->voff_first = coff_ptr->voff; - sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; - sec->foff_first = coff_ptr->foff; - sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; - } - } - - //- rjf: fill - result.top_level_info = top_level_info; - result.binary_sections = binary_sections; - result.units = all_units; - result.types = all_types; - result.udts = all_udts; - result.src_files = all_src_files; - result.line_tables = all_line_tables; - result.locations = all_locations; - result.global_variables = all_global_variables; - result.thread_variables = all_thread_variables; - result.constants = all_constants; - result.procedures = all_procedures; - result.scopes = all_scopes; - result.inline_sites = all_inline_sites; - } - - return result; -} diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h index e818c615..6ed82691 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ b/src/rdi_from_pdb/rdi_from_pdb_2.h @@ -108,9 +108,4 @@ struct P2R2_Shared global P2R2_Shared *p2r2_shared = 0; -internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); -internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); - -internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); - #endif // RDI_FROM_PDB_2_H From 51ef166e6023f6f118177db50364b772dcf292f9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 17:02:56 -0700 Subject: [PATCH 137/302] eliminate all old conversion/baking code --- src/lib_rdi_make/rdi_make.c | 2517 +---------- src/lib_rdi_make/rdi_make.h | 236 +- src/radbin/radbin.c | 87 +- src/radbin/radbin_main.c | 6 - src/raddbg/raddbg_main.c | 6 - .../rdi_breakpad_from_pdb.c | 106 - .../rdi_breakpad_from_pdb.h | 47 - src/rdi_from_dwarf/rdi_from_dwarf.c | 46 +- src/rdi_from_dwarf/rdi_from_dwarf.h | 34 +- src/rdi_from_pdb/rdi_from_pdb.c | 2911 +------------ src/rdi_from_pdb/rdi_from_pdb.h | 341 +- src/rdi_from_pdb/rdi_from_pdb_2.c | 2 - src/rdi_from_pdb/rdi_from_pdb_2.h | 111 - src/rdi_make/rdi_make_local.c | 3750 ++++++++++++----- src/rdi_make/rdi_make_local.h | 445 +- src/rdi_make/rdi_make_local_2.c | 2794 ------------ src/rdi_make/rdi_make_local_2.h | 141 - 17 files changed, 3149 insertions(+), 10431 deletions(-) delete mode 100644 src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c delete mode 100644 src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h delete mode 100644 src/rdi_from_pdb/rdi_from_pdb_2.c delete mode 100644 src/rdi_from_pdb/rdi_from_pdb_2.h delete mode 100644 src/rdi_make/rdi_make_local_2.c delete mode 100644 src/rdi_make/rdi_make_local_2.h diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index fd8cf483..a6d717ee 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -525,150 +525,150 @@ rdim_rng1u64_chunk_list_push(RDIM_Arena *arena, RDIM_Rng1U64ChunkList *list, RDI } //////////////////////////////// -//~ Data Model +//~ rjf: [Building] Data Model RDI_PROC RDI_TypeKind rdim_short_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_S16; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_S16; - case RDIM_DataModel_LP64 : return RDI_TypeKind_S16; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_S16; - case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_S16;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_S16;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_S16;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_S16;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_S64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_unsigned_short_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_U16; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_U16; - case RDIM_DataModel_LP64 : return RDI_TypeKind_U16; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_U16; - case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_U16;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_U16;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_U16;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_U16;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_U64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_int_type_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_S32; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_S32; - case RDIM_DataModel_LP64 : return RDI_TypeKind_S32; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_S32;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_S32;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_S32;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_S64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_U32; - case RDIM_DataModel_LP64 : return RDI_TypeKind_U32; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_U64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_long_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_S32; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_S32; - case RDIM_DataModel_LP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_S32;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_S32;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_S64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_unsigned_long_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_U32; - case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_U64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_long_long_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_S64; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_LP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_S64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_S64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_unsigned_long_long_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_U64; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_U64;}break; } - return RDI_TypeKind_NULL; + return result; } RDI_PROC RDI_TypeKind rdim_pointer_size_t_type_kind_from_data_model(RDIM_DataModel data_model) { - switch(data_model) + RDI_TypeKind result = RDI_TypeKind_NULL; + switch((RDIM_DataModelEnum)data_model) { - case RDIM_DataModel_Null : break; - case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; - case RDIM_DataModel_LLP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; - case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; - default: InvalidPath; + case RDIM_DataModel_Null:{}break; + case RDIM_DataModel_ILP32 :{result = RDI_TypeKind_U32;}break; + case RDIM_DataModel_LLP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_LP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_ILP64 :{result = RDI_TypeKind_U64;}break; + case RDIM_DataModel_SILP64:{result = RDI_TypeKind_U64;}break; } - return RDI_TypeKind_NULL; + return result; } //////////////////////////////// @@ -1051,10 +1051,10 @@ rdim_encoded_size_from_location_info(RDIM_LocationInfo *info) return result; } -RDI_PROC RDIM_Location2 * +RDI_PROC RDIM_Location * rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info) { - RDIM_IdxedChunkListPush(arena, list, RDIM_LocationChunkNode, RDIM_Location2, cap, result); + RDIM_IdxedChunkListPush(arena, list, RDIM_LocationChunkNode, RDIM_Location, cap, result); { RDI_U64 encoded_size = rdim_encoded_size_from_location_info(info); rdim_memcpy_struct(&result->info, info); @@ -1066,14 +1066,7 @@ rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *lis } RDI_PROC RDI_U64 -rdim_idx_from_location(RDIM_Location2 *location) -{ - RDIM_IdxedChunkListElementGetIdx(location, idx); - return idx; -} - -RDI_PROC RDI_U64 -rdim_off_from_location(RDIM_Location2 *location) +rdim_off_from_location(RDIM_Location *location) { RDI_U64 off = 0; if(location != 0 && location->chunk != 0) @@ -1096,8 +1089,6 @@ rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_Locat //////////////////////////////// //~ rjf: [Building] Scope Info Building -//- rjf: scopes - RDI_PROC RDIM_Scope * rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap) { @@ -1138,10 +1129,10 @@ rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope return local; } -RDI_PROC RDIM_LocationCase2 * -rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *location, RDIM_Rng1U64 voff_range) +RDI_PROC RDIM_LocationCase * +rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *location, RDIM_Rng1U64 voff_range) { - RDIM_LocationCase2 *loc_case = rdim_push_array(arena, RDIM_LocationCase2, 1); + RDIM_LocationCase *loc_case = rdim_push_array(arena, RDIM_LocationCase, 1); RDIM_SLLQueuePush(local->location_cases.first, local->location_cases.last, loc_case); local->location_cases.count += 1; loc_case->location = location; @@ -1150,242 +1141,6 @@ rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RD return loc_case; } -//- rjf: individual locations - -RDI_PROC RDIM_Location * -rdim_push_location_addr_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode) -{ - RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); - result->kind = RDI_LocationKind_AddrBytecodeStream; - result->bytecode = *bytecode; - return result; -} - -RDI_PROC RDIM_Location * -rdim_push_location_val_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode) -{ - RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); - result->kind = RDI_LocationKind_ValBytecodeStream; - result->bytecode = *bytecode; - return result; -} - -RDI_PROC RDIM_Location * -rdim_push_location_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset) -{ - RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); - result->kind = RDI_LocationKind_AddrRegPlusU16; - result->reg_code = reg_code; - result->offset = offset; - return result; -} - -RDI_PROC RDIM_Location * -rdim_push_location_addr_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset) -{ - RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); - result->kind = RDI_LocationKind_AddrAddrRegPlusU16; - result->reg_code = reg_code; - result->offset = offset; - return result; -} - -RDI_PROC RDIM_Location * -rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg_code) -{ - RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); - result->kind = RDI_LocationKind_ValReg; - result->reg_code = reg_code; - return result; -} - -//- rjf: location sets - -RDI_PROC void -rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location) -{ - RDIM_LocationCase *location_case = rdim_push_array(arena, RDIM_LocationCase, 1); - SLLQueuePush(locset->first_location_case, locset->last_location_case, location_case); - locset->location_case_count += 1; - location_case->voff_range = voff_range; - location_case->location = location; - scopes->location_case_count +=1; -} - -//- rjf:location block chunk list - -RDI_PROC RDI_LocationBlock * -rdim_location_block_chunk_list_push_array(RDIM_Arena *arena, RDIM_String8List *list, RDI_U32 count) -{ - RDI_LocationBlock *result = rdim_push_array(arena, RDI_LocationBlock, count); - RDIM_String8 string = rdim_str8((RDI_U8*)result, sizeof(result[0]) * count); - rdim_str8_list_push(arena, list, string); - return result; -} - -RDI_PROC RDI_U32 -rdim_count_from_location_block_chunk_list(RDIM_String8List *list) -{ - RDI_U32 count = list->total_size / sizeof(RDI_LocationBlock); - return count; -} - -//////////////////////////////// -//~ rjf: [Baking Helpers] Baked VMap Building - -RDI_PROC RDIM_BakeVMap -rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count) -{ - RDIM_ProfBegin("rdim_bake_vmap_from_markers"); - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - //- rjf: sort markers -#if 0 - RDIM_SortKey *sorted_keys = rdim_sort_key_array(scratch.arena, keys, marker_count); -#else - ProfBegin("sort markers"); - RDIM_SortKey *sorted_keys = rdim_push_array(scratch.arena, RDIM_SortKey, marker_count); - rdim_memcpy(sorted_keys, keys, marker_count*sizeof(keys[0])); - radsort(sorted_keys, marker_count, rdim_sort_key_is_before); - ProfEnd(); -#endif - - //- rjf: determine if an extra vmap entry for zero is needed - RDI_U32 extra_vmap_entry = 0; - if(marker_count > 0 && sorted_keys[0].key != 0) - { - extra_vmap_entry = 1; - } - - //- rjf: fill output vmap entries - RDI_U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; - RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw + 1); - RDI_U32 vmap_entry_count_pass_1 = 0; - ProfScope("fill output vmap entries") - { - typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; - struct RDIM_VMapRangeTracker - { - RDIM_VMapRangeTracker *next; - RDI_U32 idx; - }; - RDI_VMapEntry *vmap_ptr = vmap; - if(extra_vmap_entry) - { - vmap_ptr->voff = 0; - vmap_ptr->idx = 0; - vmap_ptr += 1; - } - RDIM_VMapRangeTracker *tracker_stack = 0; - RDIM_VMapRangeTracker *tracker_free = 0; - RDIM_SortKey *key_ptr = sorted_keys; - RDIM_SortKey *key_opl = sorted_keys + marker_count; - for(;key_ptr < key_opl;) - { - // rjf: get initial map state from tracker stack - RDI_U32 initial_idx = (RDI_U32)0xffffffff; - if(tracker_stack != 0) - { - initial_idx = tracker_stack->idx; - } - - // rjf: update tracker stack - // - // * we must process _all_ of the changes that apply at this voff before moving on - // - RDI_U64 voff = key_ptr->key; - - for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) - { - RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; - RDI_U32 idx = marker->idx; - - // rjf: range begin -> push to stack - if(marker->begin_range) - { - RDIM_VMapRangeTracker *new_tracker = tracker_free; - if(new_tracker != 0) - { - RDIM_SLLStackPop(tracker_free); - } - else - { - new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); - } - RDIM_SLLStackPush(tracker_stack, new_tracker); - new_tracker->idx = idx; - } - - // rjf: range ending -> pop matching node from stack (not always the top) - else - { - RDIM_VMapRangeTracker **ptr_in = &tracker_stack; - RDIM_VMapRangeTracker *match = 0; - for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) - { - if(node->idx == idx) - { - match = node; - break; - } - ptr_in = &node->next; - node = node->next; - } - if(match != 0) - { - *ptr_in = match->next; - RDIM_SLLStackPush(tracker_free, match); - } - } - } - - // rjf: get final map state from tracker stack - RDI_U32 final_idx = 0; - if(tracker_stack != 0) - { - final_idx = tracker_stack->idx; - } - - // rjf: if final is different from initial - emit new vmap entry - if(final_idx != initial_idx) - { - vmap_ptr->voff = voff; - vmap_ptr->idx = final_idx; - vmap_ptr += 1; - } - } - - vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: combine duplicate neighbors - RDI_U32 vmap_entry_count = 0; - ProfScope("combine duplicate neighbors") - { - RDI_VMapEntry *vmap_ptr = vmap; - RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; - RDI_VMapEntry *vmap_out = vmap; - for(;vmap_ptr < vmap_opl;) - { - RDI_VMapEntry *vmap_range_first = vmap_ptr; - RDI_U64 idx = vmap_ptr->idx; - vmap_ptr += 1; - for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; - rdim_memcpy_struct(vmap_out, vmap_range_first); - vmap_out += 1; - } - vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill result - RDIM_BakeVMap result = {0}; - result.vmap = vmap; - result.count = vmap_entry_count; - rdim_scratch_end(scratch); - RDIM_ProfEnd(); - return result; -} - //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated String Baking Map @@ -1554,23 +1309,6 @@ rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology } } -RDI_PROC void -rdim_bake_string_map_loose_join_in_place(RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *dst, RDIM_BakeStringMapLoose *src) -{ - for(RDI_U64 idx = 0; idx < map_topology->slots_count; idx += 1) - { - if(dst->slots[idx] == 0) - { - dst->slots[idx] = src->slots[idx]; - } - else if(src->slots[idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(dst->slots[idx], src->slots[idx]); - } - } - rdim_memzero_struct(src); -} - RDI_PROC RDIM_BakeStringMapBaseIndices rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map) { @@ -1591,24 +1329,6 @@ rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStr //- rjf: finalized / tight map -RDI_PROC RDIM_BakeStringMapTight -rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map) -{ - RDIM_BakeStringMapTight m = {0}; - m.slots_count = map_topology->slots_count; - m.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, m.slots_count); - m.slots_base_idxs = map_base_indices->slots_base_idxs; - for(RDI_U64 idx = 0; idx < m.slots_count; idx += 1) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&m.slots[idx], map->slots[idx]); - } - } - m.total_count = m.slots_base_idxs[m.slots_count]; - return m; -} - RDI_PROC RDI_U32 rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string) { @@ -1635,6 +1355,21 @@ rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string) //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated Index Run Baking Map +//- rjf: bake idx run map reading/writing + +RDI_PROC RDI_U64 +rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = 5381; + RDI_U32 *ptr = idx_run; + RDI_U32 *opl = idx_run + count; + for(;ptr < opl; ptr += 1) + { + hash = ((hash << 5) + hash) + (*ptr); + } + return hash; +} + //- rjf: chunk lists RDI_PROC RDIM_BakeIdxRun * @@ -1828,7 +1563,7 @@ rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology //- rjf: finalized / tight map RDI_PROC RDI_U32 -rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count) +rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idxes, RDI_U32 count) { RDI_U32 idx = 0; if(count != 0) @@ -1995,16 +1730,16 @@ rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameC //- rjf: bake name chunk list maps -RDI_PROC RDIM_BakeNameMap2 * -rdim_bake_name_map_2_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top) +RDI_PROC RDIM_BakeNameMap * +rdim_bake_name_map_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top) { - RDIM_BakeNameMap2 *map = rdim_push_array(arena, RDIM_BakeNameMap2, 1); + RDIM_BakeNameMap *map = rdim_push_array(arena, RDIM_BakeNameMap, 1); map->slots = rdim_push_array(arena, RDIM_BakeNameChunkList *, top->slots_count); return map; } RDI_PROC void -rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap2 *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx) +rdim_bake_name_map_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx) { if(string.RDIM_String8_SizeMember != 0) { @@ -2040,114 +1775,7 @@ rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_top } //////////////////////////////// -//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers - -//- rjf: bake idx run map reading/writing - -RDI_PROC RDI_U64 -rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count) -{ - RDI_U64 hash = 5381; - RDI_U32 *ptr = idx_run; - RDI_U32 *opl = idx_run + count; - for(;ptr < opl; ptr += 1) - { - hash = ((hash << 5) + hash) + (*ptr); - } - return hash; -} - -RDI_PROC RDI_U32 -rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count) -{ - RDI_U64 hash = rdim_hash_from_idx_run(idx_run, count); - RDI_U64 slot_idx = hash%map->slots_count; - - // rjf: find existing node - RDIM_BakeIdxRunNode *node = 0; - for(RDIM_BakeIdxRunNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->hash == hash) - { - RDI_S32 is_match = 1; - RDI_U32 *n_idx = n->idx_run; - for(RDI_U32 i = 0; i < count; i += 1) - { - if(n_idx[i] != idx_run[i]) - { - is_match = 0; - break; - } - } - if(is_match) - { - node = n; - break; - } - } - } - - // rjf: node -> index - RDI_U32 result = node ? node->first_idx : 0; - return result; -} - -RDI_PROC RDI_U32 -rdim_bake_idx_run_map_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count) -{ - RDI_U64 hash = rdim_hash_from_idx_run(idx_run, count); - RDI_U64 slot_idx = hash%map->slots_count; - - // rjf: find existing node - RDIM_BakeIdxRunNode *node = 0; - for(RDIM_BakeIdxRunNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->hash == hash) - { - RDI_S32 is_match = 1; - RDI_U32 *n_idx = n->idx_run; - for(RDI_U32 i = 0; i < count; i += 1) - { - if(n_idx[i] != idx_run[i]) - { - is_match = 0; - break; - } - } - if(is_match) - { - node = n; - break; - } - } - } - - // rjf: no node -> make new node - if(node == 0) - { - node = rdim_push_array_no_zero(arena, RDIM_BakeIdxRunNode, 1); - RDI_U32 *idx_run_copy = rdim_push_array_no_zero(arena, RDI_U32, count); - for(RDI_U32 i = 0; i < count; i += 1) - { - idx_run_copy[i] = idx_run[i]; - } - node->idx_run = idx_run_copy; - node->hash = hash; - node->count = count; - node->first_idx = map->idx_count; - map->count += 1; - map->idx_count += count; - RDIM_SLLQueuePush_N(map->order_first, map->order_last, node, order_next); - RDIM_SLLStackPush_N(map->slots[slot_idx], node, hash_next); - map->slot_collision_count += (node->hash_next != 0); - } - - // rjf: node -> index - RDI_U32 result = node->first_idx; - return result; -} - -//- rjf: bake path tree reading/writing +//~ rjf: [Baking Helpers] Deduplicated Path Baking Tree RDI_PROC RDIM_BakePathNode * rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) @@ -2295,81 +1923,6 @@ rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_Stri return node; } -//- rjf: bake name maps writing - -RDI_PROC RDIM_BakeNameMap * -rdim_bake_name_map_make(RDIM_Arena *arena, RDI_U64 expected_count) -{ - RDIM_BakeNameMap *map = push_array(arena, RDIM_BakeNameMap, 1); - map->slots_count = Max(64, expected_count); - map->slots = push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - return map; -} - -RDI_PROC void -rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx) -{ - if(string.size == 0) {return;} - - // rjf: hash - RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); - RDI_U64 slot_idx = hash%map->slots_count; - - // rjf: find existing node - RDIM_BakeNameMapNode *node = 0; - for(RDIM_BakeNameMapNode *n = map->slots[slot_idx]; n != 0; n = n->slot_next) - { - if(rdim_str8_match(string, n->string, 0)) - { - node = n; - break; - } - } - - // rjf: make node if necessary - if(node == 0) - { - node = rdim_push_array(arena, RDIM_BakeNameMapNode, 1); - node->string = string; - RDIM_SLLStackPush_N(map->slots[slot_idx], node, slot_next); - RDIM_SLLQueuePush_N(map->first, map->last, node, order_next); - map->name_count += 1; - map->slot_collision_count += (node->slot_next != 0); - } - - // rjf: find existing idx - RDI_S32 existing_idx = 0; - for(RDIM_BakeNameMapValNode *n = node->val_first; n != 0; n = n->next) - { - for(RDI_U32 i = 0; i < sizeof(n->val)/sizeof(n->val[0]); i += 1) - { - if(n->val[i] == 0) - { - break; - } - if(n->val[i] == idx) - { - existing_idx = 1; - break; - } - } - } - - // rjf: insert new idx if necessary - if(!existing_idx) - { - RDIM_BakeNameMapValNode *val_node = node->val_last; - RDI_U32 insert_i = node->val_count%(sizeof(val_node->val)/sizeof(val_node->val[0])); - if(insert_i == 0) - { - val_node = rdim_push_array(arena, RDIM_BakeNameMapValNode, 1); - SLLQueuePush(node->val_first, node->val_last, val_node); - } - val_node->val[insert_i] = idx; - node->val_count += 1; - } -} - //////////////////////////////// //~ rjf: [Baking Helpers] Data Section List Building Helpers @@ -2412,1858 +1965,6 @@ rdim_bake_section_list_concat_in_place(RDIM_BakeSectionList *dst, RDIM_BakeSecti rdim_memzero_struct(to_push); } -//////////////////////////////// -//~ rjf: [Baking] Build Artifacts -> Interned/Deduplicated Data Structures - -//- rjf: basic bake string gathering passes - -RDI_PROC void -rdim_bake_string_map_loose_push_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TopLevelInfo *tli) -{ - rdim_bake_string_map_loose_insert(arena, top, map, 1, tli->exe_name); - rdim_bake_string_map_loose_insert(arena, top, map, 1, tli->producer_name); -} - -RDI_PROC void -rdim_bake_string_map_loose_push_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BinarySectionList *secs) -{ - for(RDIM_BinarySectionNode *n = secs->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_insert(arena, top, map, 1, n->v.name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BakePathTree *path_tree) -{ - for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) - { - rdim_bake_string_map_loose_insert(arena, top, map, 1, n->name); - } -} - -//- rjf: chunk-granularity bake string gathering passes - -RDI_PROC void -rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFile *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, v[idx].path); - rdim_bake_string_map_loose_insert(arena, top, map, 1, normalized_path); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Unit *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].unit_name); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].compiler_name); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].source_file); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].object_file); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].archive_file); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].build_path); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_udt_member_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTMember *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_udt_enum_val_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTEnumVal *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - for(RDIM_UDTMember *mem = v[idx].first_member; mem != 0; mem = mem->next) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, mem->name); - } - for(RDIM_UDTEnumVal *mem = v[idx].first_enum_val; mem != 0; mem = mem->next) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, mem->name); - } - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].link_name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count) -{ - for(RDI_U64 idx = 0; idx < count; idx += 1) - { - for(RDIM_Local *local = v[idx].first_local; local != 0; local = local->next) - { - rdim_bake_string_map_loose_insert(arena, top, map, 4, local->name); - } - } -} - -//- rjf: list-granularity bake string gathering passes - -RDI_PROC void -rdim_bake_string_map_loose_push_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFileChunkList *list) -{ - for(RDIM_SrcFileChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_src_file_slice(arena, top, map, n->v, n->count); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_units(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UnitChunkList *list) -{ - for(RDIM_UnitChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_unit_slice(arena, top, map, n->v, n->count); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_types(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TypeChunkList *list) -{ - for(RDIM_TypeChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_type_slice(arena, top, map, n->v, n->count); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_udts(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTChunkList *list) -{ - for(RDIM_UDTChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_udt_slice(arena, top, map, n->v, n->count); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_symbols(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SymbolChunkList *list) -{ - for(RDIM_SymbolChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_symbol_slice(arena, top, map, n->v, n->count); - } -} - -RDI_PROC void -rdim_bake_string_map_loose_push_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_ScopeChunkList *list) -{ - for(RDIM_ScopeChunkNode *n = list->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_scope_slice(arena, top, map, n->v, n->count); - } -} - -//- rjf: bake name map building - -RDI_PROC RDIM_BakeNameMap * -rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDIM_BakeParams *params) -{ - RDIM_BakeNameMap *map = rdim_push_array(arena, RDIM_BakeNameMap, 1); - switch(kind) - { - default:{}break; - case RDI_NameMapKind_GlobalVariables: - { - map->slots_count = params->global_variables.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 - rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); - } - } - }break; - case RDI_NameMapKind_ThreadVariables: - { - map->slots_count = params->thread_variables.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SymbolChunkNode *n = params->thread_variables.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 - rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); - } - } - }break; - case RDI_NameMapKind_Constants: - { - map->slots_count = params->constants.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SymbolChunkNode *n = params->constants.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 - rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); - } - } - }break; - case RDI_NameMapKind_Procedures: - { - map->slots_count = params->procedures.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 - rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); - } - } - }break; - case RDI_NameMapKind_Types: - { - map->slots_count = params->types.total_count; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U32 type_idx = (RDI_U32)rdim_idx_from_type(&n->v[idx]); // TODO(rjf): @u64_to_u32 - if(type_idx == 0) {continue;} - rdim_bake_name_map_push(arena, map, n->v[idx].name, type_idx); - } - } - }break; - case RDI_NameMapKind_LinkNameProcedures: - { - map->slots_count = params->procedures.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - if(n->v[idx].link_name.size == 0) {continue;} - RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 - rdim_bake_name_map_push(arena, map, n->v[idx].link_name, symbol_idx); - } - } - }break; - case RDI_NameMapKind_NormalSourcePaths: - { - map->slots_count = params->src_files.total_count*2; - map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); - for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDI_U64 src_file_idx = rdim_idx_from_src_file(&n->v[idx]); - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[idx].path); - rdim_bake_name_map_push(arena, map, normalized_path, (RDI_U32)src_file_idx); // TODO(rjf): @u64_to_u32 - } - } - }break; - } - return map; -} - -//- rjf: idx run map building - -RDI_PROC RDIM_BakeIdxRunMap * -rdim_bake_idx_run_map_from_params(RDIM_Arena *arena, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT], RDIM_BakeParams *params) -{ - //- rjf: set up map - RDIM_BakeIdxRunMap *idx_runs = rdim_push_array(arena, RDIM_BakeIdxRunMap, 1); - idx_runs->slots_count = 64 + params->procedures.total_count*2 + params->global_variables.total_count*2 + params->thread_variables.total_count*2 + params->types.total_count*2; - idx_runs->slots = rdim_push_array(arena, RDIM_BakeIdxRunNode *, idx_runs->slots_count); - rdim_bake_idx_run_map_insert(arena, idx_runs, 0, 0); - - //- rjf: bake runs of function-type parameter lists - for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Type *type = &n->v[chunk_idx]; - if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = type->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - rdim_bake_idx_run_map_insert(arena, idx_runs, param_idx_run, param_idx_run_count); - } - } - } - - //- rjf: bake runs of name map match lists - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - RDIM_BakeNameMap *name_map = name_maps[k]; - if(name_map != 0 && name_map->name_count != 0) - { - for(RDIM_BakeNameMapNode *n = name_map->first; n != 0; n = n->order_next) - { - if(n->val_count > 1) - { - RDI_U32 *idx_run = rdim_push_array(arena, RDI_U32, n->val_count); - RDI_U64 val_idx = 0; - for(RDIM_BakeNameMapValNode *idxnode = n->val_first; - idxnode != 0; - idxnode = idxnode->next) - { - for(RDI_U32 i = 0; i < sizeof(idxnode->val)/sizeof(idxnode->val[0]); i += 1) - { - if(idxnode->val[i] == 0) - { - goto dblbreak; - } - idx_run[val_idx] = idxnode->val[i]; - val_idx += 1; - } - } - dblbreak:; - rdim_bake_idx_run_map_insert(arena, idx_runs, idx_run, (RDI_U32)n->val_count); // TODO(rjf): @u64_to_u32 - } - } - } - } - - return idx_runs; -} - -//- rjf: bake path tree building - -RDI_PROC RDIM_BakePathTree * -rdim_bake_path_tree_from_params(RDIM_Arena *arena, RDIM_BakeParams *params) -{ - //- rjf: set up tree - RDIM_BakePathTree *tree = rdim_push_array(arena, RDIM_BakePathTree, 1); - rdim_bake_path_tree_insert(arena, tree, rdim_str8_lit("")); - - //- rjf: bake unit file paths - RDIM_ProfScope("bake unit file paths") - { - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - rdim_bake_path_tree_insert(arena, tree, n->v[idx].source_file); - rdim_bake_path_tree_insert(arena, tree, n->v[idx].object_file); - rdim_bake_path_tree_insert(arena, tree, n->v[idx].archive_file); - rdim_bake_path_tree_insert(arena, tree, n->v[idx].build_path); - } - } - } - - //- rjf: bake source file paths - RDIM_ProfScope("bake source file paths") - { - for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, tree, n->v[idx].path); - node->src_file = &n->v[idx]; - } - } - } - - return tree; -} - -//////////////////////////////// -//~ rjf: [Baking] Build Artifacts -> Baked Versions - -//- rjf: partial/joinable baking functions - -RDI_PROC RDIM_NameMapBakeResult -rdim_bake_name_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeNameMap *src) -{ - RDIM_NameMapBakeResult result = {0}; - if(src->name_count != 0) - { - RDI_U32 baked_buckets_count = src->name_count; - RDI_U32 baked_nodes_count = src->name_count; - RDI_NameMapBucket *baked_buckets = rdim_push_array(arena, RDI_NameMapBucket, baked_buckets_count); - RDI_NameMapNode *baked_nodes = rdim_push_array_no_zero(arena, RDI_NameMapNode, baked_nodes_count); - { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - // rjf: setup the final bucket layouts - typedef struct RDIM_NameMapSemiNode RDIM_NameMapSemiNode; - struct RDIM_NameMapSemiNode - { - RDIM_NameMapSemiNode *next; - RDIM_BakeNameMapNode *node; - }; - typedef struct RDIM_NameMapSemiBucket RDIM_NameMapSemiBucket; - struct RDIM_NameMapSemiBucket - { - RDIM_NameMapSemiNode *first; - RDIM_NameMapSemiNode *last; - RDI_U64 count; - }; - RDIM_NameMapSemiBucket *sbuckets = rdim_push_array(scratch.arena, RDIM_NameMapSemiBucket, baked_buckets_count); - for(RDIM_BakeNameMapNode *node = src->first; - node != 0; - node = node->order_next) - { - RDI_U64 hash = rdi_hash(node->string.str, node->string.size); - RDI_U64 bi = hash%baked_buckets_count; - RDIM_NameMapSemiNode *snode = rdim_push_array(scratch.arena, RDIM_NameMapSemiNode, 1); - SLLQueuePush(sbuckets[bi].first, sbuckets[bi].last, snode); - snode->node = node; - sbuckets[bi].count += 1; - } - - // rjf: convert to serialized buckets & nodes - { - RDI_NameMapBucket *bucket_ptr = baked_buckets; - RDI_NameMapNode *node_ptr = baked_nodes; - for(RDI_U32 i = 0; i < baked_buckets_count; i += 1, bucket_ptr += 1) - { - bucket_ptr->first_node = (RDI_U32)((RDI_U64)(node_ptr - baked_nodes)); - bucket_ptr->node_count = sbuckets[i].count; - for(RDIM_NameMapSemiNode *snode = sbuckets[i].first; - snode != 0; - snode = snode->next) - { - RDIM_BakeNameMapNode *node = snode->node; - - // rjf: cons name and index(es) - RDI_U32 string_idx = rdim_bake_idx_from_string(strings, node->string); - RDI_U32 match_count = node->val_count; - RDI_U32 idx = 0; - if(match_count == 1) - { - idx = node->val_first->val[0]; - } - else - { - RDI_U64 temp_pos = rdim_arena_pos(scratch.arena); - RDI_U32 *idx_run = rdim_push_array_no_zero(scratch.arena, RDI_U32, match_count); - RDI_U32 *idx_ptr = idx_run; - for(RDIM_BakeNameMapValNode *idxnode = node->val_first; - idxnode != 0; - idxnode = idxnode->next) - { - for(RDI_U32 i = 0; i < sizeof(idxnode->val)/sizeof(idxnode->val[0]); i += 1) - { - if(idxnode->val[i] == 0) - { - goto dblbreak; - } - *idx_ptr = idxnode->val[i]; - idx_ptr += 1; - } - } - dblbreak:; - idx = rdim_bake_idx_from_idx_run(idx_runs, idx_run, match_count); - rdim_arena_pop_to(scratch.arena, temp_pos); - } - - // rjf: write to node - node_ptr->string_idx = string_idx; - node_ptr->match_count = match_count; - node_ptr->match_idx_or_idx_run_first = idx; - node_ptr += 1; - } - } - } - rdim_scratch_end(scratch); - } - - // rjf: sections for buckets/nodes - result.buckets = baked_buckets; - result.buckets_count = baked_buckets_count; - result.nodes = baked_nodes; - result.nodes_count = baked_nodes_count; - } - return result; -} - -//- rjf: partial bakes -> final bake functions - -RDI_PROC RDIM_NameMapBakeResult -rdim_name_map_bake_results_combine(RDIM_Arena *arena, RDIM_NameMapBakeResult *results, RDI_U64 results_count) -{ - RDIM_NameMapBakeResult result = {0}; - { - //- rjf: count needed # of buckets/nodes - RDI_U64 all_buckets_count = 0; - RDI_U64 all_nodes_count = 0; - for(RDI_U64 idx = 0; idx < results_count; idx += 1) - { - all_buckets_count += results[idx].buckets_count; - all_nodes_count += results[idx].nodes_count; - } - - //- rjf: allocate outputs - result.buckets_count = all_buckets_count; - result.buckets = rdim_push_array_no_zero(arena, RDI_NameMapBucket, result.buckets_count); - result.nodes_count = all_nodes_count; - result.nodes = rdim_push_array_no_zero(arena, RDI_NameMapNode, result.nodes_count); - - //- rjf: fill outputs - { - RDI_U64 buckets_off = 0; - RDI_U64 nodes_off = 0; - for(RDI_U64 idx = 0; idx < results_count; idx += 1) - { - rdim_memcpy(result.buckets + buckets_off, results[idx].buckets, sizeof(result.buckets[0])*results[idx].buckets_count); - rdim_memcpy(result.nodes + nodes_off, results[idx].nodes, sizeof(result.nodes[0])*results[idx].nodes_count); - buckets_off += results[idx].buckets_count; - nodes_off += results[idx].nodes_count; - } - } - } - return result; -} - -//- rjf: independent (top-level, global) baking functions - -RDI_PROC RDIM_TopLevelInfoBakeResult -rdim_bake_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_TopLevelInfo *src) -{ - RDIM_TopLevelInfoBakeResult result = {0}; - { - result.top_level_info.arch = src->arch; - result.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(strings, src->exe_name); - result.top_level_info.exe_hash = src->exe_hash; - result.top_level_info.voff_max = src->voff_max; - result.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(strings, src->producer_name); - } - return result; -} - -RDI_PROC RDIM_BinarySectionBakeResult -rdim_bake_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BinarySectionList *src) -{ - RDIM_BinarySectionBakeResult result = {0}; - { - RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src->count+1); - U64 dst_idx = 1; - for(RDIM_BinarySectionNode *src_n = src->first; src_n != 0; src_n = src_n->next, dst_idx += 1) - { - RDIM_BinarySection *src = &src_n->v; - RDI_BinarySection *dst = &dst_base[dst_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->flags = src->flags; - dst->voff_first = src->voff_first; - dst->voff_opl = src->voff_opl; - dst->foff_first = src->foff_first; - dst->foff_opl = src->foff_opl; - } - result.binary_sections = dst_base; - result.binary_sections_count = dst_idx; - } - return result; -} - -RDI_PROC RDIM_UnitBakeResult -rdim_bake_units(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_UnitChunkList *src) -{ - RDIM_UnitBakeResult result = {0}; - { - RDI_Unit *dst_base = rdim_push_array(arena, RDI_Unit, src->total_count+1); - RDI_U64 dst_idx = 1; - for(RDIM_UnitChunkNode *src_n = src->first; src_n != 0; src_n = src_n->next) - { - for(RDI_U64 src_chunk_idx = 0; src_chunk_idx < src_n->count; src_chunk_idx += 1, dst_idx += 1) - { - RDIM_Unit *src = &src_n->v[src_chunk_idx]; - RDI_Unit *dst = &dst_base[dst_idx]; - dst->unit_name_string_idx = rdim_bake_idx_from_string(strings, src->unit_name); - dst->compiler_name_string_idx = rdim_bake_idx_from_string(strings, src->compiler_name); - dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); - dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); - dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); - dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); - dst->language = src->language; - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - result.units = dst_base; - result.units_count = dst_idx; - } - return result; -} - -RDI_PROC RDIM_UnitVMapBakeResult -rdim_bake_unit_vmap(RDIM_Arena *arena, RDIM_UnitChunkList *units) -{ - //- rjf: build vmap from unit voff ranges - RDIM_BakeVMap unit_vmap = {0}; - { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - // rjf: count voff ranges - RDI_U64 voff_range_count = 0; - for(RDIM_UnitChunkNode *n = units->first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDIM_Unit *unit = &n->v[idx]; - voff_range_count += unit->voff_ranges.total_count; - } - } - - // rjf: count necessary markers - RDI_U64 marker_count = voff_range_count*2; - - // rjf: build keys/markers arrays - RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - RDI_U32 unit_idx = 1; - for(RDIM_UnitChunkNode *unit_chunk_n = units->first; - unit_chunk_n != 0; - unit_chunk_n = unit_chunk_n->next) - { - for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) - { - RDIM_Unit *unit = &unit_chunk_n->v[idx]; - for(RDIM_Rng1U64ChunkNode *n = unit->voff_ranges.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Rng1U64 range = n->v[chunk_idx]; - if(range.min < range.max) - { - key_ptr->key = range.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = range.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - unit_idx += 1; - } - } - } - - // rjf: keys/markers -> unit vmap - unit_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); - rdim_scratch_end(scratch); - } - - //- rjf: fill result - RDIM_UnitVMapBakeResult result = {unit_vmap}; - return result; -} - -RDI_PROC RDIM_SrcFileBakeResult -rdim_bake_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_SrcFileChunkList *src) -{ - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - //////////////////////////// - //- rjf: iterate all source files, fill serialized version, fill line maps, fill line map tables - // - typedef struct RDIM_DataNode RDIM_DataNode; - struct RDIM_DataNode - { - RDIM_DataNode *next; - void *data; - RDI_U64 size; - }; - RDI_U32 dst_files_count = src->total_count + 1; - RDI_U32 dst_maps_count = src->source_line_map_count + 1; - RDI_SourceFile *dst_files = rdim_push_array(arena, RDI_SourceFile, dst_files_count); - RDI_SourceLineMap *dst_maps = rdim_push_array(arena, RDI_SourceLineMap, dst_maps_count); - RDIM_DataNode *first_dst_nums_node = 0; - RDIM_DataNode *last_dst_nums_node = 0; - RDIM_DataNode *first_dst_rngs_node = 0; - RDIM_DataNode *last_dst_rngs_node = 0; - RDIM_DataNode *first_dst_voffs_node = 0; - RDIM_DataNode *last_dst_voffs_node = 0; - RDI_U64 dst_nums_idx = 0; - RDI_U64 dst_rngs_idx = 0; - RDI_U64 dst_voffs_idx = 0; - RDI_U32 dst_file_idx = 1; - RDI_U32 dst_map_idx = 1; - for(RDIM_SrcFileChunkNode *chunk_n = src->first; - chunk_n != 0; - chunk_n = chunk_n->next) - { - for(RDI_U64 idx = 0; idx < chunk_n->count; idx += 1, dst_file_idx += 1) - { - RDIM_SrcFile *src_file = &chunk_n->v[idx]; - RDI_SourceFile *dst_file = &dst_files[dst_file_idx]; - - //////////////////////// - //- rjf: produce combined source file line info - // - RDI_U32 *src_file_line_nums = 0; - RDI_U32 *src_file_line_ranges = 0; - RDI_U64 *src_file_voffs = 0; - RDI_U32 src_file_line_count = 0; - RDI_U32 src_file_voff_count = 0; - { - //- rjf: gather line number map - typedef struct RDIM_SrcLineMapVoffBlock RDIM_SrcLineMapVoffBlock; - struct RDIM_SrcLineMapVoffBlock - { - RDIM_SrcLineMapVoffBlock *next; - RDI_U64 voff; - }; - typedef struct RDIM_SrcLineMapBucket RDIM_SrcLineMapBucket; - struct RDIM_SrcLineMapBucket - { - RDIM_SrcLineMapBucket *order_next; - RDIM_SrcLineMapBucket *hash_next; - RDI_U32 line_num; - RDIM_SrcLineMapVoffBlock *first_voff_block; - RDIM_SrcLineMapVoffBlock *last_voff_block; - RDI_U64 voff_count; - }; - RDIM_SrcLineMapBucket *first_bucket = 0; - RDIM_SrcLineMapBucket *last_bucket = 0; - RDI_U64 line_hash_slots_count = 2048; - RDIM_SrcLineMapBucket **line_hash_slots = rdim_push_array(scratch.arena, RDIM_SrcLineMapBucket *, line_hash_slots_count); - RDI_U64 line_count = 0; - RDI_U64 voff_count = 0; - RDI_U64 max_line_num = 0; - { - for(RDIM_SrcFileLineMapFragment *map_fragment = src_file->first_line_map_fragment; - map_fragment != 0; - map_fragment = map_fragment->next) - { - RDIM_LineSequence *sequence = map_fragment->seq; - RDI_U64 *seq_voffs = sequence->voffs; - RDI_U32 *seq_line_nums = sequence->line_nums; - RDI_U64 seq_line_count = sequence->line_count; - for(RDI_U64 i = 0; i < seq_line_count; i += 1) - { - RDI_U32 line_num = seq_line_nums[i]; - RDI_U64 voff = seq_voffs[i]; - RDI_U64 line_hash_slot_idx = line_num%line_hash_slots_count; - - // rjf: update unique voff counter & max line number - voff_count += 1; - max_line_num = Max(max_line_num, line_num); - - // rjf: find match - RDIM_SrcLineMapBucket *match = 0; - { - for(RDIM_SrcLineMapBucket *node = line_hash_slots[line_hash_slot_idx]; - node != 0; - node = node->hash_next) - { - if(node->line_num == line_num) - { - match = node; - break; - } - } - } - - // rjf: introduce new map if no match - if(match == 0) - { - match = rdim_push_array(scratch.arena, RDIM_SrcLineMapBucket, 1); - RDIM_SLLQueuePush_N(first_bucket, last_bucket, match, order_next); - RDIM_SLLStackPush_N(line_hash_slots[line_hash_slot_idx], match, hash_next); - match->line_num = line_num; - line_count += 1; - } - - // rjf: insert new voff - { - RDIM_SrcLineMapVoffBlock *block = rdim_push_array(scratch.arena, RDIM_SrcLineMapVoffBlock, 1); - RDIM_SLLQueuePush(match->first_voff_block, match->last_voff_block, block); - match->voff_count += 1; - block->voff = voff; - } - } - } - } - - //- rjf: bake sortable keys array - RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, line_count); - { - RDIM_SortKey *key_ptr = keys; - for(RDIM_SrcLineMapBucket *node = first_bucket; - node != 0; - node = node->order_next, key_ptr += 1){ - key_ptr->key = node->line_num; - key_ptr->val = node; - } - } - - //- rjf: sort keys array - RDIM_SortKey *sorted_keys = rdim_sort_key_array(scratch.arena, keys, line_count); - - //- rjf: bake result - RDI_U32 *line_nums = rdim_push_array_no_zero(scratch.arena, RDI_U32, line_count); - RDI_U32 *line_ranges = rdim_push_array_no_zero(scratch.arena, RDI_U32, line_count + 1); - RDI_U64 *voffs = rdim_push_array_no_zero(scratch.arena, RDI_U64, voff_count); - { - RDI_U64 *voff_ptr = voffs; - for(RDI_U32 i = 0; i < line_count; i += 1) - { - line_nums[i] = sorted_keys[i].key; - line_ranges[i] = (RDI_U32)(voff_ptr - voffs); // TODO(rjf): @u64_to_u32 - RDIM_SrcLineMapBucket *bucket = (RDIM_SrcLineMapBucket*)sorted_keys[i].val; - for(RDIM_SrcLineMapVoffBlock *node = bucket->first_voff_block; node != 0; node = node->next) - { - *voff_ptr = node->voff; - voff_ptr += 1; - } - } - line_ranges[line_count] = voff_count; - } - - //- rjf: fill output - src_file_line_nums = line_nums; - src_file_line_ranges = line_ranges; - src_file_line_count = line_count; - src_file_voffs = voffs; - src_file_voff_count = voff_count; - } - - //////////////////////// - //- rjf: grab & fill the next line map, if this file has one - // - RDI_SourceLineMap *dst_map = 0; - if(src_file->first_line_map_fragment != 0) - { - dst_map = &dst_maps[dst_map_idx]; - dst_map_idx += 1; - dst_map->line_count = (RDI_U32)src_file_line_count; // TODO(rjf): @u64_to_u32 - dst_map->voff_count = (RDI_U32)src_file_voff_count; // TODO(rjf): @u64_to_u32 - dst_map->line_map_nums_base_idx = (RDI_U32)dst_nums_idx; // TODO(rjf): @u64_to_u32 - dst_map->line_map_range_base_idx = (RDI_U32)dst_rngs_idx; // TODO(rjf): @u64_to_u32 - dst_map->line_map_voff_base_idx = (RDI_U32)dst_voffs_idx; // TODO(rjf): @u64_to_u32 - } - - //////////////////////// - //- rjf: gather line map data chunks for later collation & storage into their own top-level sections - // - { - RDIM_DataNode *dst_num_node = rdim_push_array(scratch.arena, RDIM_DataNode, 1); - RDIM_SLLQueuePush(first_dst_nums_node, last_dst_nums_node, dst_num_node); - dst_num_node->data = src_file_line_nums; - dst_num_node->size = sizeof(RDI_U32)*src_file_line_count; - RDIM_DataNode *dst_rng_node = rdim_push_array(scratch.arena, RDIM_DataNode, 1); - RDIM_SLLQueuePush(first_dst_rngs_node, last_dst_rngs_node, dst_rng_node); - dst_rng_node->data = src_file_line_ranges; - dst_rng_node->size = sizeof(RDI_U32)*(src_file_line_count+1); - RDIM_DataNode *dst_voff_node = rdim_push_array(scratch.arena, RDIM_DataNode, 1); - RDIM_SLLQueuePush(first_dst_voffs_node, last_dst_voffs_node, dst_voff_node); - dst_voff_node->data = src_file_voffs; - dst_voff_node->size = sizeof(RDI_U64)*(src_file_voff_count); - dst_nums_idx += src_file_line_count; - dst_rngs_idx += src_file_line_count+1; - dst_voffs_idx+= src_file_voff_count; - } - - //////////////////////// - //- rjf: fill file info - // - RDI_U64 scratch_pos_restore = rdim_arena_pos(scratch.arena); - RDIM_String8 normalized_path = rdim_lower_from_str8(scratch.arena, src_file->path); - dst_file->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src_file->path); - dst_file->normal_full_path_string_idx = rdim_bake_idx_from_string(strings, normalized_path); - dst_file->source_line_map_idx = (RDI_U32)(dst_map ? (dst_map - dst_maps) : 0); - rdim_arena_pop_to(scratch.arena, scratch_pos_restore); - } - } - - //////////////////////////// - //- rjf: coalesce source line map data blobs - // - RDI_U32 *source_line_map_nums = rdim_push_array_no_zero(arena, RDI_U32, dst_nums_idx); - RDI_U32 *source_line_map_rngs = rdim_push_array_no_zero(arena, RDI_U32, dst_rngs_idx); - RDI_U64 *source_line_map_voffs= rdim_push_array_no_zero(arena, RDI_U64, dst_voffs_idx); - { - RDI_U64 num_idx = 0; - RDI_U64 rng_idx = 0; - RDI_U64 voff_idx= 0; - for(RDIM_DataNode *num_n = first_dst_nums_node; num_n != 0; num_n = num_n->next) - { - rdim_memcpy(source_line_map_nums+num_idx, num_n->data, num_n->size); - num_idx += num_n->size/sizeof(RDI_U32); - } - for(RDIM_DataNode *rng_n = first_dst_rngs_node; rng_n != 0; rng_n = rng_n->next) - { - rdim_memcpy(source_line_map_rngs+rng_idx, rng_n->data, rng_n->size); - rng_idx += rng_n->size/sizeof(RDI_U32); - } - for(RDIM_DataNode *voff_n = first_dst_voffs_node; voff_n != 0; voff_n = voff_n->next) - { - rdim_memcpy(source_line_map_voffs+voff_idx, voff_n->data, voff_n->size); - voff_idx += voff_n->size/sizeof(RDI_U64); - } - } - - //////////////////////////// - //- rjf: fill result - // - RDIM_SrcFileBakeResult result = {0}; - result.source_files = dst_files; - result.source_files_count = dst_files_count; - result.source_line_maps = dst_maps; - result.source_line_maps_count = dst_maps_count; - result.source_line_map_nums = source_line_map_nums; - result.source_line_map_nums_count = dst_nums_idx; - result.source_line_map_rngs = source_line_map_rngs; - result.source_line_map_rngs_count = dst_rngs_idx; - result.source_line_map_voffs = source_line_map_voffs; - result.source_line_map_voffs_count= dst_voffs_idx; - - rdim_scratch_end(scratch); - return result; -} - -RDI_PROC RDIM_LineTableBakeResult -rdim_bake_line_tables(RDIM_Arena *arena, RDIM_LineTableChunkList *src) -{ - ////////////////////////////// - //- rjf: build all combined line info - // - RDI_LineTable *dst_line_tables = push_array(arena, RDI_LineTable, src->total_count+1); - RDI_U64 *dst_line_voffs = push_array(arena, RDI_U64, src->total_line_count + 2*src->total_seq_count); - RDI_Line *dst_lines = push_array(arena, RDI_Line, src->total_line_count + src->total_seq_count); - RDI_Column *dst_cols = push_array(arena, RDI_Column, 1); - { - RDI_U64 dst_table_idx = 1; - RDI_U64 dst_voff_idx = 0; - RDI_U64 dst_line_idx = 0; - RDI_U64 dst_col_idx = 0; - for(RDIM_LineTableChunkNode *src_n = src->first; src_n != 0; src_n = src_n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < src_n->count; chunk_idx += 1) - { - RDIM_LineTable *src_line_table = &src_n->v[chunk_idx]; - RDI_LineTable *dst_line_table = &dst_line_tables[dst_table_idx]; - - //- rjf: fill combined line table info - { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - //- rjf: gather up all line info into two arrays: - // - // [1] keys: sortable array; pairs voffs with line info records; null records are sequence enders - // [2] recs: contains all the source coordinates for a range of voffs - // - RDI_U64 line_count = src_line_table->line_count; - RDI_U64 seq_count = src_line_table->seq_count; - RDI_U64 key_count = line_count + seq_count; - RDIM_SortKey *line_keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, key_count); - RDIM_LineRec *line_recs = rdim_push_array_no_zero(scratch.arena, RDIM_LineRec, line_count); - { - RDIM_SortKey *key_ptr = line_keys; - RDIM_LineRec *rec_ptr = line_recs; - for(RDIM_LineSequenceNode *seq_n = src_line_table->first_seq; seq_n != 0; seq_n = seq_n->next) - { - RDIM_LineSequence *seq = &seq_n->v; - for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) - { - key_ptr->key = seq->voffs[line_idx]; - key_ptr->val = rec_ptr; - key_ptr += 1; - rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 - rec_ptr->line_num = seq->line_nums[line_idx]; - if(seq->col_nums != 0) - { - rec_ptr->col_first = seq->col_nums[line_idx*2]; - rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; - } - rec_ptr += 1; - } - key_ptr->key = seq->voffs[seq->line_count]; - key_ptr->val = 0; - key_ptr += 1; - } - } - - //- rjf: sort - RDIM_SortKey *sorted_line_keys = 0; - { - sorted_line_keys = rdim_sort_key_array(scratch.arena, line_keys, key_count); - } - - // TODO(rjf): do a pass over sorted keys to make sure duplicate keys - // are sorted with null record first, and no more than one null - // record and one non-null record - - //- rjf: arrange output - RDI_U64 *arranged_voffs = dst_line_voffs + dst_voff_idx; - RDI_Line *arranged_lines = dst_lines + dst_line_idx; - { - for(RDI_U64 i = 0; i < key_count; i += 1) - { - arranged_voffs[i] = sorted_line_keys[i].key; - } - arranged_voffs[key_count] = ~0ull; - for(RDI_U64 i = 0; i < key_count; i += 1) - { - RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[i].val; - if(rec != 0) - { - arranged_lines[i].file_idx = rec->file_id; - arranged_lines[i].line_num = rec->line_num; - } - else - { - arranged_lines[i].file_idx = 0; - arranged_lines[i].line_num = 0; - } - } - } - - rdim_scratch_end(scratch); - } - - //- rjf: fill destination table - dst_line_table->voffs_base_idx = (RDI_U32)dst_voff_idx; // TODO(rjf): @u64_to_u32 - dst_line_table->lines_base_idx = (RDI_U32)dst_line_idx; // TODO(rjf): @u64_to_u32 - dst_line_table->cols_base_idx = (RDI_U32)dst_col_idx; // TODO(rjf): @u64_to_u32 - dst_line_table->lines_count = (RDI_U32)src_line_table->line_count + src_line_table->seq_count; // TODO(rjf): @u64_to_u32 - - //- rjf: increment - dst_table_idx += 1; - dst_voff_idx += src_line_table->line_count + 2*src_line_table->seq_count; - dst_line_idx += src_line_table->line_count + src_line_table->seq_count; - } - } - } - - ////////////////////////////// - //- rjf: fill result - // - RDIM_LineTableBakeResult result = {0}; - { - result.line_tables = dst_line_tables; - result.line_tables_count = src->total_count+1; - result.line_table_voffs = dst_line_voffs; - result.line_table_voffs_count = (src->total_line_count + 2*src->total_seq_count); - result.line_table_lines = dst_lines; - result.line_table_lines_count = (src->total_line_count + src->total_seq_count); - result.line_table_columns = dst_cols; - result.line_table_columns_count = src->total_col_count; - } - return result; -} - -RDI_PROC RDIM_TypeNodeBakeResult -rdim_bake_types(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_TypeChunkList *src) -{ - RDI_TypeNode *type_nodes = push_array(arena, RDI_TypeNode, src->total_count+1); - for(RDIM_TypeChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Type *src = &n->v[chunk_idx]; - U64 dst_idx = rdim_idx_from_type(src); - RDI_TypeNode *dst = &type_nodes[dst_idx]; - - //- rjf: fill shared type node info - dst->kind = src->kind; - dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 - dst->byte_size = src->byte_size; - - //- rjf: fill built-in-only type node info - if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) - { - dst->built_in.name_string_idx = rdim_bake_idx_from_string(strings, src->name); - } - - else if(dst->kind == RDI_TypeKind_Array) - { - U64 direct_byte_size = 1; - if(src->direct_type && src->direct_type->byte_size > 0) - { - direct_byte_size = src->direct_type->byte_size; - } - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); - dst->constructed.count = src->byte_size / direct_byte_size; - } - - //- rjf: fill constructed type node info - else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) - { - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->constructed.count = src->count; - if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = src->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run(idx_runs, param_idx_run, param_idx_run_count); - } - else if(dst->kind == RDI_TypeKind_MemberPtr) - { - // TODO(rjf): member pointers not currently supported. - } - } - - //- rjf: fill user-defined-type info - else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) - { - dst->user_defined.name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 - dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill bitfield info - else if(dst->kind == RDI_TypeKind_Bitfield) - { - dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->bitfield.off = src->off; - dst->bitfield.size = src->count; - } - } - } - RDIM_TypeNodeBakeResult result = {0}; - result.type_nodes = type_nodes; - result.type_nodes_count = (src->total_count+1); - return result; -} - -RDI_PROC RDIM_UDTBakeResult -rdim_bake_udts(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_UDTChunkList *src) -{ - //- rjf: build tables - RDI_UDT * udts = push_array(arena, RDI_UDT, src->total_count+1); - RDI_Member * members = push_array(arena, RDI_Member, src->total_member_count+1); - RDI_EnumMember *enum_members = push_array(arena, RDI_EnumMember, src->total_enum_val_count+1); - { - RDI_U32 dst_udt_idx = 1; - RDI_U32 dst_member_idx = 1; - RDI_U32 dst_enum_member_idx = 1; - for(RDIM_UDTChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_udt_idx += 1) - { - RDIM_UDT *src_udt = &n->v[chunk_idx]; - RDI_UDT *dst_udt = &udts[dst_udt_idx]; - - //- rjf: fill basics - dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 - dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 - dst_udt->line = src_udt->line; - dst_udt->col = src_udt->col; - - //- rjf: fill members - if(src_udt->member_count != 0) - { - dst_udt->member_first = dst_member_idx; - dst_udt->member_count = src_udt->member_count; - for(RDIM_UDTMember *src_member = src_udt->first_member; - src_member != 0; - src_member = src_member->next, dst_member_idx += 1) - { - RDI_Member *dst_member = &members[dst_member_idx]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - } - } - - //- rjf: fill enum members - else if(src_udt->enum_val_count != 0) - { - dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = dst_enum_member_idx; - dst_udt->member_count = src_udt->enum_val_count; - for(RDIM_UDTEnumVal *src_member = src_udt->first_enum_val; - src_member != 0; - src_member = src_member->next, dst_enum_member_idx += 1) - { - RDI_EnumMember *dst_member = &enum_members[dst_enum_member_idx]; - dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); - dst_member->val = src_member->val; - } - } - } - } - } - - //- rjf: fill result - RDIM_UDTBakeResult result = {0}; - { - result.udts = udts; - result.udts_count = src->total_count+1; - result.members = members; - result.members_count = src->total_member_count+1; - result.enum_members = enum_members; - result.enum_members_count = src->total_enum_val_count+1; - } - return result; -} - -RDI_PROC RDIM_GlobalVariableBakeResult -rdim_bake_global_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src) -{ - RDI_GlobalVariable *global_variables = push_array(arena, RDI_GlobalVariable, src->total_count+1); - RDI_U32 dst_idx = 1; - for(RDIM_SymbolChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) - { - RDIM_Symbol *src = &n->v[chunk_idx]; - RDI_GlobalVariable *dst = &global_variables[dst_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->voff = src->offset; - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - RDIM_GlobalVariableBakeResult result = {0}; - result.global_variables = global_variables; - result.global_variables_count = (src->total_count+1); - return result; -} - -RDI_PROC RDIM_GlobalVMapBakeResult -rdim_bake_global_vmap(RDIM_Arena *arena, RDIM_SymbolChunkList *src) -{ - //- rjf: build global vmap - RDIM_BakeVMap global_vmap = {0}; - { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - //- rjf: allocate keys/markers - RDI_U64 marker_count = src->total_count*2 + 2; - RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); - - //- rjf: fill - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - - // rjf: fill actual globals - for(RDIM_SymbolChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Symbol *global_var = &n->v[chunk_idx]; - RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 - RDI_U64 global_var_size = global_var->type ? global_var->type->byte_size : 1; - - RDI_U64 first = global_var->offset; - RDI_U64 opl = first + global_var_size; - - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - // rjf: fill nil global - { - RDI_U32 global_idx = 0; - RDI_U64 first = 0; - RDI_U64 opl = 0xffffffffffffffffull; - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - // rjf: construct vmap - global_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); - - rdim_scratch_end(scratch); - } - - //- rjf: fill result - RDIM_GlobalVMapBakeResult result = {global_vmap}; - return result; -} - -RDI_PROC RDIM_ThreadVariableBakeResult -rdim_bake_thread_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src) -{ - RDI_ThreadVariable *thread_variables = push_array(arena, RDI_ThreadVariable, src->total_count+1); - RDI_U32 dst_idx = 1; - for(RDIM_SymbolChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) - { - RDIM_Symbol *src = &n->v[chunk_idx]; - RDI_ThreadVariable *dst = &thread_variables[dst_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - RDIM_ThreadVariableBakeResult result = {0}; - result.thread_variables = thread_variables; - result.thread_variables_count = src->total_count+1; - return result; -} - -RDI_PROC RDIM_ConstantsBakeResult -rdim_bake_constants(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src) -{ - RDI_Constant *constants = push_array(arena, RDI_Constant, src->total_count+1); - RDI_U32 *constant_values = push_array(arena, RDI_U32, src->total_count+2); - RDI_U8 *constant_value_data = push_array(arena, RDI_U8, src->total_value_data_size+1); - RDI_U32 dst_idx = 1; - RDI_U64 dst_constant_value_data_off = 1; - for(RDIM_SymbolChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) - { - RDIM_Symbol *src = &n->v[chunk_idx]; - RDI_Constant *dst = &constants[dst_idx]; - RDI_U32 *dst_value_idx = &constant_values[dst_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->constant_value_idx = dst_idx; - dst_value_idx[0] = dst_constant_value_data_off; - rdim_memcpy(constant_value_data + dst_constant_value_data_off, src->value_data.str, src->value_data.size); - dst_constant_value_data_off += src->value_data.size; - } - } - constant_values[dst_idx] = dst_constant_value_data_off; - RDIM_ConstantsBakeResult result = {0}; - result.constants = constants; - result.constants_count = src->total_count+1; - result.constant_values = constant_values; - result.constant_values_count = src->total_count+1; - result.constant_value_data = constant_value_data; - result.constant_value_data_size = dst_constant_value_data_off; - return result; -} - -RDI_PROC U64 -rdim_bake_location(RDIM_Arena *arena, RDIM_String8List *location_data_blobs, RDIM_Location *src_location) -{ - U64 location_data_off = location_data_blobs->total_size; - - // rjf: nil location - if(src_location == 0) - { - rdim_str8_list_push_align(arena, location_data_blobs, 8); - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_lit("\0")); - } - - // rjf: valid location - else switch(src_location->kind) - { - // rjf: catchall unsupported case - default: - { - rdim_str8_list_push_align(arena, location_data_blobs, 8); - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_lit("\0")); - }break; - - // rjf: bytecode streams - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&src_location->kind))); - for(RDIM_EvalBytecodeOp *op_node = src_location->bytecode.first_op; - op_node != 0; - op_node = op_node->next) - { - RDI_U8 op_data[9]; - op_data[0] = op_node->op; - rdim_memcpy(op_data + 1, &op_node->p, op_node->p_size); - RDIM_String8 op_data_str = rdim_str8(op_data, 1 + op_node->p_size); - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, op_data_str)); - } - { - RDI_U64 data = 0; - RDIM_String8 data_str = rdim_str8((RDI_U8 *)&data, 1); - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, data_str)); - } - }break; - - // rjf: simple addr+off cases - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 loc = {0}; - loc.kind = src_location->kind; - loc.reg_code = src_location->reg_code; - loc.offset = src_location->offset; - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&loc))); - }break; - - // rjf: register cases - case RDI_LocationKind_ValReg: - { - RDI_LocationReg loc = {0}; - loc.kind = src_location->kind; - loc.reg_code = src_location->reg_code; - rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&loc))); - }break; - } - - return location_data_off; -} - -RDI_PROC RDI_U32 -rdim_bake_locset(RDIM_Arena *arena, - RDIM_String8List *location_blocks, - RDIM_String8List *location_data_blobs, - RDIM_LocationSet locset) -{ - RDI_U32 locset_idx = 0; - if(locset.location_case_count > 0) - { - locset_idx = rdim_count_from_location_block_chunk_list(location_blocks); - - RDI_LocationBlock *dst_arr = rdim_location_block_chunk_list_push_array(arena, location_blocks, locset.location_case_count); - RDI_LocationBlock *dst = dst_arr; - for(RDIM_LocationCase *src = locset.first_location_case; src != 0; src = src->next, ++dst) - { - dst->scope_off_first = src->voff_range.min; - dst->scope_off_opl = src->voff_range.max; - dst->location_data_off = rdim_bake_location(arena, location_data_blobs, src->location); - } - } - return locset_idx; -} - -RDI_PROC RDIM_ProcedureBakeResult -rdim_bake_procedures(RDIM_Arena *arena, - RDIM_BakeStringMapTight *strings, - RDIM_String8List *location_blocks, - RDIM_String8List *location_data_blobs, - RDIM_SymbolChunkList *src) -{ - RDI_Procedure *procedures = push_array(arena, RDI_Procedure, src->total_count+1); - RDI_U32 dst_idx = 1; - for(RDIM_SymbolChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) - { - RDIM_Symbol *src = &n->v[chunk_idx]; - RDI_Procedure *dst = &procedures[dst_idx]; - - RDI_U32 frame_base_location_first = rdim_bake_locset(arena, location_blocks, location_data_blobs, src->frame_base); - RDI_U32 frame_base_location_opl = frame_base_location_first + src->frame_base.location_case_count; - - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->link_name_string_idx = rdim_bake_idx_from_string(strings, src->link_name); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 - dst->frame_base_location_first = frame_base_location_first; - dst->frame_base_location_opl = frame_base_location_opl; - } - } - RDIM_ProcedureBakeResult result = {0}; - result.procedures = procedures; - result.procedures_count = src->total_count+1; - return result; -} - -RDI_PROC RDIM_ScopeBakeResult -rdim_bake_scopes(RDIM_Arena *arena, - RDIM_BakeStringMapTight *strings, - RDIM_String8List *location_blocks, - RDIM_String8List *location_data_blobs, - RDIM_ScopeChunkList *src) -{ - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - //////////////////////////// - //- rjf: build all scopes, scope voffs, locals, and location blocks - // - RDI_Scope *scopes = rdim_push_array(arena, RDI_Scope, src->total_count+1); - RDI_U64 *scope_voffs = rdim_push_array(arena, RDI_U64, src->scope_voff_count+1); - RDI_Local *locals = rdim_push_array(arena, RDI_Local, src->local_count+1); - - RDIM_ProfScope("build all scopes, scope voffs, locals, and location blocks") - { - RDI_U64 dst_scope_idx = 1; - RDI_U64 dst_scope_voff_idx = 1; - RDI_U64 dst_local_idx = 1; - for(RDIM_ScopeChunkNode *chunk_n = src->first; chunk_n != 0; chunk_n = chunk_n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1, dst_scope_idx += 1) - { - RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_Scope *dst_scope = &scopes[dst_scope_idx]; - - //- rjf: push scope's voffs - RDI_U64 voff_idx_first = dst_scope_voff_idx; - { - for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) - { - scope_voffs[dst_scope_voff_idx] = n->v.min; - dst_scope_voff_idx += 1; - scope_voffs[dst_scope_voff_idx] = n->v.max; - dst_scope_voff_idx += 1; - } - } - RDI_U64 voff_idx_opl = dst_scope_voff_idx; - - //- rjf: push locals - RDI_U64 local_idx_first = dst_local_idx; - for(RDIM_Local *src_local = src_scope->first_local; - src_local != 0; - src_local = src_local->next, dst_local_idx += 1) - { - // bake location sets - RDI_U32 location_block_idx_first = rdim_bake_locset(arena, location_blocks, location_data_blobs, src_local->locset); - RDI_U32 location_block_idx_opl = location_block_idx_first + src_local->locset.location_case_count; - - //- rjf: fill local - RDI_Local *dst_local = &locals[dst_local_idx]; - dst_local->kind = src_local->kind; - dst_local->name_string_idx = rdim_bake_idx_from_string(strings, src_local->name); - dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 - dst_local->location_first = location_block_idx_first; - dst_local->location_opl = location_block_idx_opl; - } - RDI_U64 local_idx_opl = dst_local_idx; - - //- rjf: fill scope - dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 - dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 - dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 - dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 - dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 - dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 - } - } - } - - //////////////////////////// - //- rjf: fill result - // - RDIM_ScopeBakeResult result = {0}; - result.scopes = scopes; - result.scopes_count = src->total_count+1; - result.scope_voffs = scope_voffs; - result.scope_voffs_count = src->scope_voff_count+1; - result.locals = locals; - result.locals_count = src->local_count+1; - rdim_scratch_end(scratch); - return result; -} - -RDI_PROC RDIM_ScopeVMapBakeResult -rdim_bake_scope_vmap(RDIM_Arena *arena, RDIM_ScopeChunkList *src) -{ - RDIM_BakeVMap scope_vmap = {0}; - { - RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); - - // rjf: allocate keys/markers - RDI_U64 marker_count = src->scope_voff_count; - RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); - - // rjf: fill - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - for(RDIM_ScopeChunkNode *chunk_n = src->first; chunk_n != 0; chunk_n = chunk_n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) - { - RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 - for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) - { - key_ptr->key = n->v.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = n->v.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - } - - // rjf: produce vmap - scope_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); - rdim_scratch_end(scratch); - } - RDIM_ScopeVMapBakeResult result = {scope_vmap}; - return result; -} - -RDI_PROC RDIM_InlineSiteBakeResult -rdim_bake_inline_sites(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_InlineSiteChunkList *src) -{ - RDIM_InlineSiteBakeResult result = {0}; - { - result.inline_sites_count = src->total_count+1; - result.inline_sites = rdim_push_array(arena, RDI_InlineSite, result.inline_sites_count+1); - RDI_U64 dst_idx = 1; - for(RDIM_InlineSiteChunkNode *n = src->first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) - { - RDI_InlineSite *dst = &result.inline_sites[dst_idx]; - RDIM_InlineSite *src = &n->v[chunk_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - return result; -} - -RDI_PROC RDIM_TopLevelNameMapBakeResult -rdim_bake_name_maps_top_level(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT]) -{ - RDI_NameMap *dst_maps = rdim_push_array(arena, RDI_NameMap, RDI_NameMapKind_COUNT); - { - RDI_U64 dst_map_bucket_idx = 0; - RDI_U64 dst_map_node_idx = 0; - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - RDI_NameMap *dst_map = &dst_maps[k]; - RDIM_BakeNameMap *src_map = name_maps[k]; - dst_map->bucket_base_idx = (RDI_U32)dst_map_bucket_idx; // TODO(rjf): @u64_to_u32 - dst_map->node_base_idx = (RDI_U32)dst_map_node_idx; // TODO(rjf): @u64_to_u32 - dst_map->bucket_count = (RDI_U32)src_map->name_count; // TODO(rjf): @u64_to_u32 - dst_map->node_count = (RDI_U32)src_map->name_count; // TODO(rjf): @u64_to_u32 - dst_map_bucket_idx += dst_map->bucket_count; - dst_map_node_idx += dst_map->node_count; - } - } - RDIM_TopLevelNameMapBakeResult result = {0}; - result.name_maps = dst_maps; - result.name_maps_count = RDI_NameMapKind_COUNT; - return result; -} - -RDI_PROC RDIM_FilePathBakeResult -rdim_bake_file_paths(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree) -{ - RDI_U32 dst_nodes_count = path_tree->count; - RDI_FilePathNode *dst_nodes = rdim_push_array(arena, RDI_FilePathNode, dst_nodes_count); - { - RDI_U32 dst_node_idx = 0; - for(RDIM_BakePathNode *src_node = path_tree->first; - src_node != 0; - src_node = src_node->next_order, dst_node_idx += 1) - { - RDI_FilePathNode *dst_node = &dst_nodes[dst_node_idx]; - dst_node->name_string_idx = rdim_bake_idx_from_string(strings, src_node->name); - dst_node->source_file_idx = rdim_idx_from_src_file(src_node->src_file); - if(src_node->parent != 0) - { - dst_node->parent_path_node = src_node->parent->idx; - } - if(src_node->first_child != 0) - { - dst_node->first_child = src_node->first_child->idx; - } - if(src_node->next_sibling != 0) - { - dst_node->next_sibling = src_node->next_sibling->idx; - } - } - } - RDIM_FilePathBakeResult result = {0}; - result.nodes = dst_nodes; - result.nodes_count = dst_nodes_count; - return result; -} - -RDI_PROC RDIM_StringBakeResult -rdim_bake_strings(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings) -{ - RDI_U32 *str_offs = rdim_push_array_no_zero(arena, RDI_U32, strings->total_count + 1); - RDI_U32 off_cursor = 0; - { - RDI_U32 *off_ptr = str_offs; - *off_ptr = 0; - off_ptr += 1; - for(RDI_U64 slot_idx = 0; slot_idx < strings->slots_count; slot_idx += 1) - { - for(RDIM_BakeStringChunkNode *n = strings->slots[slot_idx].first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_BakeString *bake_string = &n->v[chunk_idx]; - *off_ptr = off_cursor; - off_cursor += bake_string->string.size; - off_ptr += 1; - } - } - } - } - RDI_U8 *buf = rdim_push_array(arena, RDI_U8, off_cursor); - { - RDI_U8 *ptr = buf; - for(RDI_U64 slot_idx = 0; slot_idx < strings->slots_count; slot_idx += 1) - { - for(RDIM_BakeStringChunkNode *n = strings->slots[slot_idx].first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_BakeString *bake_string = &n->v[chunk_idx]; - rdim_memcpy(ptr, bake_string->string.str, bake_string->string.size); - ptr += bake_string->string.size; - } - } - } - } - RDIM_StringBakeResult result = {0}; - result.string_offs = str_offs; - result.string_offs_count = strings->total_count+1; - result.string_data = buf; - result.string_data_size = off_cursor; - return result; -} - -RDI_PROC RDIM_IndexRunBakeResult -rdim_bake_index_runs(RDIM_Arena *arena, RDIM_BakeIdxRunMap *idx_runs) -{ - RDI_U32 *idx_data = rdim_push_array_no_zero(arena, RDI_U32, idx_runs->idx_count); - { - RDI_U32 *out_ptr = idx_data; - RDI_U32 *opl = out_ptr + idx_runs->idx_count; - for(RDIM_BakeIdxRunNode *node = idx_runs->order_first; - node != 0 && out_ptr < opl; - node = node->order_next) - { - rdim_memcpy(out_ptr, node->idx_run, sizeof(*node->idx_run)*node->count); - out_ptr += node->count; - } - } - RDIM_IndexRunBakeResult result = {0}; - result.idx_runs = idx_data; - result.idx_count = idx_runs->idx_count; - return result; -} - //////////////////////////////// //~ rjf: [Serializing] Bake Results -> String Blobs diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 4e7ff0d4..9094f017 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -656,7 +656,7 @@ struct RDIM_UnitChunkList //~ rjf: Type System Node Types typedef RDI_U32 RDIM_DataModel; -enum RDIM_DataModelEnum +typedef enum RDIM_DataModelEnum { RDIM_DataModel_Null, RDIM_DataModel_ILP32, @@ -664,7 +664,8 @@ enum RDIM_DataModelEnum RDIM_DataModel_LP64, RDIM_DataModel_ILP64, RDIM_DataModel_SILP64 -}; +} +RDIM_DataModelEnum; typedef struct RDIM_Type RDIM_Type; struct RDIM_Type @@ -814,8 +815,8 @@ struct RDIM_LocationInfo RDIM_EvalBytecode bytecode; }; -typedef struct RDIM_Location2 RDIM_Location2; -struct RDIM_Location2 +typedef struct RDIM_Location RDIM_Location; +struct RDIM_Location { struct RDIM_LocationChunkNode *chunk; RDIM_LocationInfo info; @@ -826,7 +827,7 @@ typedef struct RDIM_LocationChunkNode RDIM_LocationChunkNode; struct RDIM_LocationChunkNode { RDIM_LocationChunkNode *next; - RDIM_Location2 *v; + RDIM_Location *v; RDI_U64 count; RDI_U64 cap; RDI_U64 base_idx; @@ -846,51 +847,22 @@ struct RDIM_LocationChunkList //- rjf: location cases -typedef struct RDIM_LocationCase2 RDIM_LocationCase2; -struct RDIM_LocationCase2 +typedef struct RDIM_LocationCase RDIM_LocationCase; +struct RDIM_LocationCase { - RDIM_LocationCase2 *next; - RDIM_Location2 *location; + RDIM_LocationCase *next; + RDIM_Location *location; RDIM_Rng1U64 voff_range; }; typedef struct RDIM_LocationCaseList RDIM_LocationCaseList; struct RDIM_LocationCaseList { - RDIM_LocationCase2 *first; - RDIM_LocationCase2 *last; + RDIM_LocationCase *first; + RDIM_LocationCase *last; RDI_U64 count; }; -//- rjf: locations (OLD) - -typedef struct RDIM_Location RDIM_Location; -struct RDIM_Location -{ - RDI_LocationKind kind; - RDI_U8 reg_code; - RDI_U16 offset; - RDIM_EvalBytecode bytecode; -}; - -//- rjf: location case types (location * voff range) (OLD) - -typedef struct RDIM_LocationCase RDIM_LocationCase; -struct RDIM_LocationCase -{ - RDIM_LocationCase *next; - RDIM_Rng1U64 voff_range; - RDIM_Location *location; -}; - -typedef struct RDIM_LocationSet RDIM_LocationSet; -struct RDIM_LocationSet -{ - RDIM_LocationCase *first_location_case; - RDIM_LocationCase *last_location_case; - RDI_U64 location_case_count; -}; - //////////////////////////////// //~ rjf: Symbol Info Types @@ -906,7 +878,6 @@ struct RDIM_Symbol RDIM_Symbol *container_symbol; RDIM_Type *container_type; struct RDIM_Scope *root_scope; - RDIM_LocationSet frame_base; RDIM_LocationCaseList location_cases; RDIM_String8 value_data; }; @@ -973,7 +944,6 @@ struct RDIM_Local RDI_LocalKind kind; RDIM_String8 name; RDIM_Type *type; - RDIM_LocationSet locset; RDIM_LocationCaseList location_cases; }; @@ -1163,39 +1133,14 @@ struct RDIM_BakeIdxRunMapLoose RDI_U64 *slots_idx_counts; }; -typedef struct RDIM_BakeIdxRunMap2 RDIM_BakeIdxRunMap2; -struct RDIM_BakeIdxRunMap2 +typedef struct RDIM_BakeIdxRunMap RDIM_BakeIdxRunMap; +struct RDIM_BakeIdxRunMap { RDIM_BakeIdxRunChunkList *slots; RDI_U64 *slots_base_idxs; // NOTE(rjf): [slots_count+1], [slots_count] holds total count RDI_U64 slots_count; }; -//- rjf: index runs (OLD) - -typedef struct RDIM_BakeIdxRunNode RDIM_BakeIdxRunNode; -struct RDIM_BakeIdxRunNode -{ - RDIM_BakeIdxRunNode *hash_next; - RDIM_BakeIdxRunNode *order_next; - RDI_U32 *idx_run; - RDI_U64 hash; - RDI_U32 count; - RDI_U32 first_idx; -}; - -typedef struct RDIM_BakeIdxRunMap RDIM_BakeIdxRunMap; -struct RDIM_BakeIdxRunMap -{ - RDIM_BakeIdxRunNode *order_first; - RDIM_BakeIdxRunNode *order_last; - RDIM_BakeIdxRunNode **slots; - RDI_U64 slots_count; - RDI_U64 slot_collision_count; - RDI_U32 count; - RDI_U32 idx_count; -}; - //- rjf: source info & path tree typedef struct RDIM_BakePathNode RDIM_BakePathNode; @@ -1262,41 +1207,10 @@ struct RDIM_BakeNameMapTopology RDI_U64 slots_count; }; -typedef struct RDIM_BakeNameMap2 RDIM_BakeNameMap2; -struct RDIM_BakeNameMap2 -{ - RDIM_BakeNameChunkList **slots; -}; - -//- rjf: name maps (OLD) - -typedef struct RDIM_BakeNameMapValNode RDIM_BakeNameMapValNode; -struct RDIM_BakeNameMapValNode -{ - RDIM_BakeNameMapValNode *next; - RDI_U32 val[6]; -}; - -typedef struct RDIM_BakeNameMapNode RDIM_BakeNameMapNode; -struct RDIM_BakeNameMapNode -{ - RDIM_BakeNameMapNode *slot_next; - RDIM_BakeNameMapNode *order_next; - RDIM_String8 string; - RDIM_BakeNameMapValNode *val_first; - RDIM_BakeNameMapValNode *val_last; - RDI_U64 val_count; -}; - typedef struct RDIM_BakeNameMap RDIM_BakeNameMap; struct RDIM_BakeNameMap { - RDIM_BakeNameMapNode **slots; - RDI_U64 slots_count; - RDI_U64 slot_collision_count; - RDIM_BakeNameMapNode *first; - RDIM_BakeNameMapNode *last; - RDI_U64 name_count; + RDIM_BakeNameChunkList **slots; }; //- rjf: vmaps @@ -1645,7 +1559,7 @@ RDI_PROC void rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDI_PROC void rdim_rng1u64_chunk_list_push(RDIM_Arena *arena, RDIM_Rng1U64ChunkList *list, RDI_U64 chunk_cap, RDIM_Rng1U64 r); //////////////////////////////// -//~ Data Model +//~ rjf: [Building] Data Model RDI_PROC RDI_TypeKind rdim_short_type_kind_from_data_model(RDIM_DataModel data_model); RDI_PROC RDI_TypeKind rdim_unsigned_short_type_kind_from_data_model(RDIM_DataModel data_model); @@ -1726,40 +1640,19 @@ RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_Ev //- rjf: locations RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info); -RDI_PROC RDIM_Location2 *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info); -RDI_PROC RDI_U64 rdim_idx_from_location(RDIM_Location2 *location); -RDI_PROC RDI_U64 rdim_off_from_location(RDIM_Location2 *location); +RDI_PROC RDIM_Location *rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info); +RDI_PROC RDI_U64 rdim_off_from_location(RDIM_Location *location); RDI_PROC void rdim_location_chunk_list_concat_in_place(RDIM_LocationChunkList *dst, RDIM_LocationChunkList *to_push); //////////////////////////////// //~ rjf: [Building] Scope Info Building -//- rjf: scopes RDI_PROC RDIM_Scope *rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap); RDI_PROC RDI_U64 rdim_idx_from_scope(RDIM_Scope *scope); RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push); RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDIM_Scope *scope, RDIM_Rng1U64 range); RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope); -RDI_PROC RDIM_LocationCase2 *rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *location, RDIM_Rng1U64 voff_range); - -//- rjf: individual locations -RDI_PROC RDIM_Location *rdim_push_location_addr_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode); -RDI_PROC RDIM_Location *rdim_push_location_val_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode); -RDI_PROC RDIM_Location *rdim_push_location_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset); -RDI_PROC RDIM_Location *rdim_push_location_addr_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset); -RDI_PROC RDIM_Location *rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg_code); - -//- rjf: location sets -RDI_PROC void rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location); - -//- rjf: location block chunk list -RDI_PROC RDI_LocationBlock *rdim_location_block_chunk_list_push_array(RDIM_Arena *arena, RDIM_String8List *list, RDI_U32 count); -RDI_PROC RDI_U32 rdim_count_from_location_block_chunk_list(RDIM_String8List *list); - -//////////////////////////////// -//~ rjf: [Baking Helpers] Baked VMap Building - -RDI_PROC RDIM_BakeVMap rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count); +RDI_PROC RDIM_LocationCase *rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *location, RDIM_Rng1U64 voff_range); //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated String Baking Map @@ -1772,16 +1665,17 @@ RDI_PROC RDIM_BakeStringChunkList rdim_bake_string_chunk_list_sorted_from_unsort //- rjf: loose map RDI_PROC RDIM_BakeStringMapLoose *rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top); RDI_PROC void rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map, RDI_U64 chunk_cap, RDIM_String8 string); -RDI_PROC void rdim_bake_string_map_loose_join_in_place(RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *dst, RDIM_BakeStringMapLoose *src); RDI_PROC RDIM_BakeStringMapBaseIndices rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map); //- rjf: finalized / tight map -RDI_PROC RDIM_BakeStringMapTight rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map); RDI_PROC RDI_U32 rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string); //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated Index Run Baking Map +//- rjf: bake idx run map reading/writing +RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); + //- rjf: chunk lists RDI_PROC RDIM_BakeIdxRun *rdim_bake_idx_run_chunk_list_push(RDIM_Arena *arena, RDIM_BakeIdxRunChunkList *list, RDI_U64 cap); RDI_PROC void rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM_BakeIdxRunChunkList *to_push); @@ -1792,7 +1686,7 @@ RDI_PROC RDIM_BakeIdxRunMapLoose *rdim_bake_idx_run_map_loose_make(RDIM_Arena *a RDI_PROC void rdim_bake_idx_run_map_loose_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMapTopology *map_topology, RDIM_BakeIdxRunMapLoose *map, RDI_U64 chunk_cap, RDI_U32 *idxes, RDI_U32 count); //- rjf: finalized / tight map -RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run_2(RDIM_BakeIdxRunMap2 *map, RDI_U32 *idxes, RDI_U32 count); +RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idxes, RDI_U32 count); //////////////////////////////// //~ rjf: [Baking Helpers] Deduplicated Name Map Baking Map @@ -1803,26 +1697,16 @@ RDI_PROC void rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList * RDI_PROC RDIM_BakeNameChunkList rdim_bake_name_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeNameChunkList *src); //- rjf: bake name chunk list maps -RDI_PROC RDIM_BakeNameMap2 *rdim_bake_name_map_2_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top); -RDI_PROC void rdim_bake_name_map_2_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap2 *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx); +RDI_PROC RDIM_BakeNameMap *rdim_bake_name_map_make(RDIM_Arena *arena, RDIM_BakeNameMapTopology *top); +RDI_PROC void rdim_bake_name_map_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topology, RDIM_BakeNameMap *map, RDI_U64 chunk_cap, RDIM_String8 string, RDI_U64 idx); //////////////////////////////// -//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers +//~ rjf: [Baking Helpers] Deduplicated Path Baking Tree -//- rjf: bake idx run map reading/writing -RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); -RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); -RDI_PROC RDI_U32 rdim_bake_idx_run_map_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); - -//- rjf: bake path tree reading/writing RDI_PROC RDIM_BakePathNode *rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string); RDI_PROC RDI_U32 rdim_bake_path_node_idx_from_string(RDIM_BakePathTree *tree, RDIM_String8 string); RDI_PROC RDIM_BakePathNode *rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string); -//- rjf: bake name maps writing -RDI_PROC RDIM_BakeNameMap *rdim_bake_name_map_make(RDIM_Arena *arena, RDI_U64 expected_count); -RDI_PROC void rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx); - //////////////////////////////// //~ rjf: [Baking Helpers] Data Section List Building Helpers @@ -1830,74 +1714,6 @@ RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_B RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push_new_unpacked(RDIM_Arena *arena, RDIM_BakeSectionList *list, void *data, RDI_U64 size, RDI_SectionKind tag, RDI_U64 tag_idx); RDI_PROC void rdim_bake_section_list_concat_in_place(RDIM_BakeSectionList *dst, RDIM_BakeSectionList *to_push); -//////////////////////////////// -//~ rjf: [Baking] Build Artifacts -> Interned/Deduplicated Data Structures - -//- rjf: basic bake string gathering passes -RDI_PROC void rdim_bake_string_map_loose_push_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TopLevelInfo *tli); -RDI_PROC void rdim_bake_string_map_loose_push_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BinarySectionList *secs); -RDI_PROC void rdim_bake_string_map_loose_push_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BakePathTree *path_tree); - -//- rjf: slice-granularity bake string gathering passes -RDI_PROC void rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFile *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Unit *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_udt_member_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTMember *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_udt_enum_val_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTEnumVal *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count); -RDI_PROC void rdim_bake_string_map_loose_push_inline_site_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_InlineSite *v, RDI_U64 count); - -RDI_PROC void rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count); - -//- rjf: list-granularity bake string gathering passes -RDI_PROC void rdim_bake_string_map_loose_push_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFileChunkList *list); -RDI_PROC void rdim_bake_string_map_loose_push_units(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UnitChunkList *list); -RDI_PROC void rdim_bake_string_map_loose_push_types(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TypeChunkList *list); -RDI_PROC void rdim_bake_string_map_loose_push_udts(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTChunkList *list); -RDI_PROC void rdim_bake_string_map_loose_push_symbols(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SymbolChunkList *list); -RDI_PROC void rdim_bake_string_map_loose_push_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_ScopeChunkList *list); - -//- rjf: bake name map building -RDI_PROC RDIM_BakeNameMap *rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDIM_BakeParams *params); - -//- rjf: bake idx run map building -RDI_PROC RDIM_BakeIdxRunMap *rdim_bake_idx_run_map_from_params(RDIM_Arena *arena, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT], RDIM_BakeParams *params); - -//- rjf: bake path tree building -RDI_PROC RDIM_BakePathTree *rdim_bake_path_tree_from_params(RDIM_Arena *arena, RDIM_BakeParams *params); - -//////////////////////////////// -//~ rjf: [Baking] Build Artifacts -> Baked Versions - -//- rjf: partial/joinable baking functions -RDI_PROC RDIM_NameMapBakeResult rdim_bake_name_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeNameMap *src); - -//- rjf: partial bakes -> final bake functions -RDI_PROC RDIM_NameMapBakeResult rdim_name_map_bake_results_combine(RDIM_Arena *arena, RDIM_NameMapBakeResult *results, RDI_U64 results_count); - -//- rjf: independent (top-level, global) baking functions -RDI_PROC RDIM_TopLevelInfoBakeResult rdim_bake_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_TopLevelInfo *src); -RDI_PROC RDIM_BinarySectionBakeResult rdim_bake_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BinarySectionList *src); -RDI_PROC RDIM_UnitBakeResult rdim_bake_units(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_UnitChunkList *src); -RDI_PROC RDIM_UnitVMapBakeResult rdim_bake_unit_vmap(RDIM_Arena *arena, RDIM_UnitChunkList *units); -RDI_PROC RDIM_SrcFileBakeResult rdim_bake_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_SrcFileChunkList *src); -RDI_PROC RDIM_LineTableBakeResult rdim_bake_line_tables(RDIM_Arena *arena, RDIM_LineTableChunkList *src); -RDI_PROC RDIM_TypeNodeBakeResult rdim_bake_types(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_TypeChunkList *src); -RDI_PROC RDIM_UDTBakeResult rdim_bake_udts(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_UDTChunkList *src); -RDI_PROC RDIM_GlobalVariableBakeResult rdim_bake_global_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_GlobalVMapBakeResult rdim_bake_global_vmap(RDIM_Arena *arena, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ThreadVariableBakeResult rdim_bake_thread_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ConstantsBakeResult rdim_bake_constants(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ProcedureBakeResult rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_String8List *location_blocks, RDIM_String8List *location_data_blobs, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ScopeBakeResult rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_String8List *location_blocks, RDIM_String8List *location_data_blobs, RDIM_ScopeChunkList *src); -RDI_PROC RDIM_ScopeVMapBakeResult rdim_bake_scope_vmap(RDIM_Arena *arena, RDIM_ScopeChunkList *src); -RDI_PROC RDIM_InlineSiteBakeResult rdim_bake_inline_sites(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_InlineSiteChunkList *src); -RDI_PROC RDIM_TopLevelNameMapBakeResult rdim_bake_name_maps_top_level(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT]); -RDI_PROC RDIM_FilePathBakeResult rdim_bake_file_paths(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree); -RDI_PROC RDIM_StringBakeResult rdim_bake_strings(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings); -RDI_PROC RDIM_IndexRunBakeResult rdim_bake_index_runs(RDIM_Arena *arena, RDIM_BakeIdxRunMap *idx_runs); - //////////////////////////////// //~ rjf: [Serializing] Bake Results -> String Blobs diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index f1b61f6b..132e821f 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -596,7 +596,7 @@ rb_thread_entry_point(void *p) }break; case OutputKind_Breakpad: { - subset_flags = RDIM_SubsetFlag_All & ~(RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs); + subset_flags = (RDIM_SubsetFlag_Units|RDIM_SubsetFlag_Procedures|RDIM_SubsetFlag_Scopes|RDIM_SubsetFlag_LineInfo|RDIM_SubsetFlag_InlineLineInfo); }break; } @@ -727,7 +727,7 @@ rb_thread_entry_point(void *p) convert_params.subset_flags = subset_flags; convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic")); } - ProfScope("convert") bake_params = p2r2_convert(arena, &convert_params); + ProfScope("convert") bake_params = p2r_convert(arena, &convert_params); // rjf: no output path? -> pick one based on PDB if(output_path.size == 0) switch(output_kind) @@ -915,89 +915,6 @@ rb_thread_entry_point(void *p) } lane_sync(); output_blobs = p2b_shared->dump; - -#if 0 - //- rjf: kick off unit vmap baking - P2B_BakeUnitVMapIn bake_unit_vmap_in = {&bake_params.units}; - ASYNC_Task *bake_unit_vmap_task = async_task_launch(arena, p2b_bake_unit_vmap_work, .input = &bake_unit_vmap_in); - - //- rjf: kick off line-table baking - P2B_BakeLineTablesIn bake_line_tables_in = {&bake_params.line_tables}; - ASYNC_Task *bake_line_tables_task = async_task_launch(arena, p2b_bake_line_table_work, .input = &bake_line_tables_in); - - //- rjf: build unit -> line table idx array - U64 unit_count = bake_params.units.total_count; - U32 *unit_line_table_idxs = push_array(arena, U32, unit_count+1); - { - U64 dst_idx = 1; - for(RDIM_UnitChunkNode *n = bake_params.units.first; n != 0; n = n->next) - { - for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, dst_idx += 1) - { - unit_line_table_idxs[dst_idx] = rdim_idx_from_line_table(n->v[n_idx].line_table); - } - } - } - - //- rjf: dump MODULE record - str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", bake_params.top_level_info.exe_hash, bake_params.top_level_info.exe_name); - - //- rjf: dump FILE records - ProfScope("dump FILE records") - { - for(RDIM_SrcFileChunkNode *n = bake_params.src_files.first; n != 0; n = n->next) - { - for(U64 idx = 0; idx < n->count; idx += 1) - { - U64 file_idx = rdim_idx_from_src_file(&n->v[idx]); - String8 src_path = n->v[idx].path; - str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path); - } - } - } - - //- rjf: join unit vmap - ProfBegin("join unit vmap"); - RDIM_UnitVMapBakeResult *bake_unit_vmap_out = async_task_join_struct(bake_unit_vmap_task, RDIM_UnitVMapBakeResult); - RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap.vmap; - U32 unit_vmap_count = bake_unit_vmap_out->vmap.count; - ProfEnd(); - - //- rjf: join line tables - ProfBegin("join line table"); - RDIM_LineTableBakeResult *bake_line_tables_out = async_task_join_struct(bake_line_tables_task, RDIM_LineTableBakeResult); - ProfEnd(); - - //- rjf: kick off FUNC & line record dump tasks - P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, bake_params.procedures.chunk_count); - ASYNC_Task **dump_proc_chunk_tasks = push_array(arena, ASYNC_Task *, bake_params.procedures.chunk_count); - ProfScope("kick off FUNC & line record dump tasks") - { - U64 task_idx = 0; - for(RDIM_SymbolChunkNode *n = bake_params.procedures.first; n != 0; n = n->next, task_idx += 1) - { - dump_proc_chunk_in[task_idx].unit_vmap = unit_vmap; - dump_proc_chunk_in[task_idx].unit_vmap_count = unit_vmap_count; - dump_proc_chunk_in[task_idx].unit_line_table_idxs = unit_line_table_idxs; - dump_proc_chunk_in[task_idx].unit_count = unit_count; - dump_proc_chunk_in[task_idx].line_tables_bake = bake_line_tables_out; - dump_proc_chunk_in[task_idx].chunk = n; - dump_proc_chunk_tasks[task_idx] = async_task_launch(arena, p2b_dump_proc_chunk_work, .input = &dump_proc_chunk_in[task_idx]); - } - } - - //- rjf: join FUNC & line record dump tasks - ProfScope("join FUNC & line record dump tasks") - { - for(U64 idx = 0; idx < bake_params.procedures.chunk_count; idx += 1) - { - String8List *out = async_task_join_struct(dump_proc_chunk_tasks[idx], String8List); - str8_list_concat_in_place(&dump, out); - } - } - - str8_list_concat_in_place(&output_blobs, &dump); -#endif }break; } }break; diff --git a/src/radbin/radbin_main.c b/src/radbin/radbin_main.c index f0b9d280..f72180de 100644 --- a/src/radbin/radbin_main.c +++ b/src/radbin/radbin_main.c @@ -17,7 +17,6 @@ #include "async/async.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" -#include "rdi_make/rdi_make_local_2.h" #include "coff/coff_inc.h" #include "pe/pe.h" #include "elf/elf.h" @@ -33,8 +32,6 @@ #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" #include "rdi_from_pdb/rdi_from_pdb.h" -#include "rdi_from_pdb/rdi_from_pdb_2.h" -#include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h" #include "rdi_from_dwarf/rdi_from_dwarf.h" #include "radbin/radbin.h" @@ -45,7 +42,6 @@ #include "async/async.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" -#include "rdi_make/rdi_make_local_2.c" #include "coff/coff_inc.c" #include "pe/pe.c" #include "elf/elf.c" @@ -61,8 +57,6 @@ #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" #include "rdi_from_pdb/rdi_from_pdb.c" -#include "rdi_from_pdb/rdi_from_pdb_2.c" -#include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c" #include "rdi_from_dwarf/rdi_from_dwarf.c" #include "radbin/radbin.c" diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 0a2dd7f3..588673d3 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -224,7 +224,6 @@ #include "async/async.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" -#include "rdi_make/rdi_make_local_2.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" @@ -246,9 +245,7 @@ #include "rdi_from_coff/rdi_from_coff.h" #include "rdi_from_elf/rdi_from_elf.h" #include "rdi_from_pdb/rdi_from_pdb.h" -#include "rdi_from_pdb/rdi_from_pdb_2.h" #include "rdi_from_dwarf/rdi_from_dwarf.h" -#include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h" #include "radbin/radbin.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" @@ -276,7 +273,6 @@ #include "async/async.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" -#include "rdi_make/rdi_make_local_2.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" @@ -298,9 +294,7 @@ #include "rdi_from_coff/rdi_from_coff.c" #include "rdi_from_elf/rdi_from_elf.c" #include "rdi_from_pdb/rdi_from_pdb.c" -#include "rdi_from_pdb/rdi_from_pdb_2.c" #include "rdi_from_dwarf/rdi_from_dwarf.c" -#include "rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c" #include "radbin/radbin.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" diff --git a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c deleted file mode 100644 index e60dd482..00000000 --- a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.c +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Baking Tasks - -//- rjf: unit vmap baking - -ASYNC_WORK_DEF(p2b_bake_unit_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2b_async_root); - P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)input; - RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); - *out = rdim_bake_unit_vmap(arena, in->units); - ProfEnd(); - return out; -} - -//- rjf: line table baking - -ASYNC_WORK_DEF(p2b_bake_line_table_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2b_async_root); - P2B_BakeLineTablesIn *in = (P2B_BakeLineTablesIn *)input; - RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); - *out = rdim_bake_line_tables(arena, in->line_tables); - ProfEnd(); - return out; -} - -//- rjf: per-procedure chunk dumping - -ASYNC_WORK_DEF(p2b_dump_proc_chunk_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2b_async_root); - P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)input; - String8List *out = push_array(arena, String8List, 1); - RDI_LineTable *line_tables = in->line_tables_bake->line_tables; - RDI_U64 line_tables_count = in->line_tables_bake->line_tables_count; - RDI_U64 *line_table_voffs = in->line_tables_bake->line_table_voffs; - RDI_U64 line_table_voffs_count = in->line_tables_bake->line_table_voffs_count; - RDI_Line *line_table_lines = in->line_tables_bake->line_table_lines; - RDI_U64 line_table_lines_count = in->line_tables_bake->line_table_lines_count; - for(U64 idx = 0; idx < in->chunk->count; idx += 1) - { - // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. - RDIM_Symbol *proc = &in->chunk->v[idx]; - RDIM_Scope *root_scope = proc->root_scope; - if(root_scope != 0 && root_scope->voff_ranges.first != 0) - { - // rjf: dump function record - RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; - str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); - - // rjf: dump function lines - U64 unit_idx = rdi_vmap_idx_from_voff(in->unit_vmap, in->unit_vmap_count, voff_range.min); - if(0 < unit_idx && unit_idx <= in->unit_count) - { - U32 line_table_idx = in->unit_line_table_idxs[unit_idx]; - if(0 < line_table_idx && line_table_idx <= line_tables_count) - { - // rjf: unpack unit line info - RDI_LineTable *line_table = &line_tables[line_table_idx]; - RDI_ParsedLineTable line_info = - { - line_table_voffs + line_table->voffs_base_idx, - line_table_lines + line_table->lines_base_idx, - 0, - line_table->lines_count, - 0 - }; - for(U64 voff = voff_range.min, last_voff = 0; - voff < voff_range.max && voff > last_voff;) - { - RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); - if(line_info_idx < line_info.count) - { - RDI_Line *line = &line_info.lines[line_info_idx]; - U64 line_voff_min = line_info.voffs[line_info_idx]; - U64 line_voff_opl = line_info.voffs[line_info_idx+1]; - if(line->file_idx != 0) - { - str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n", - line_voff_min, - line_voff_opl-line_voff_min, - (U64)line->line_num, - (U64)line->file_idx); - } - last_voff = voff; - voff = line_voff_opl; - } - else - { - break; - } - } - } - } - } - } - ProfEnd(); - return out; -} diff --git a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h deleted file mode 100644 index 1cc29d20..00000000 --- a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_BREAKPAD_FROM_PDB_H -#define RDI_BREAKPAD_FROM_PDB_H - -//////////////////////////////// -//~ rjf: Baking Tasks - -//- rjf: unit vmap baking - -typedef struct P2B_BakeUnitVMapIn P2B_BakeUnitVMapIn; -struct P2B_BakeUnitVMapIn -{ - RDIM_UnitChunkList *units; -}; -ASYNC_WORK_DEF(p2b_bake_unit_vmap_work); - -//- rjf: line table baking - -typedef struct P2B_BakeLineTablesIn P2B_BakeLineTablesIn; -struct P2B_BakeLineTablesIn -{ - RDIM_LineTableChunkList *line_tables; -}; -ASYNC_WORK_DEF(p2b_bake_line_table_work); - -//- rjf: per-procedure chunk dumping - -typedef struct P2B_DumpProcChunkIn P2B_DumpProcChunkIn; -struct P2B_DumpProcChunkIn -{ - RDI_VMapEntry *unit_vmap; - U32 unit_vmap_count; - U32 *unit_line_table_idxs; - U64 unit_count; - RDIM_LineTableBakeResult *line_tables_bake; - RDIM_SymbolChunkNode *chunk; -}; -ASYNC_WORK_DEF(p2b_dump_proc_chunk_work); - -//////////////////////////////// -//~ rjf: Globals - -global ASYNC_Root *p2b_async_root = 0; - -#endif // RDI_BREAKPAD_FROM_PDB_H diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 58b2d51c..71fe540a 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -871,9 +871,9 @@ d2r_transpile_expression(Arena *arena, DW_Input *input, U64 image_base, U64 addr B32 is_addr = 0; RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &is_addr); - loc = push_array(arena, RDIM_Location, 1); - loc->kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; - loc->bytecode = bytecode; + loc = push_array(arena, RDIM_Location, 1); + loc->info.kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; + loc->info.bytecode = bytecode; } return loc; } @@ -886,7 +886,7 @@ d2r_location_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 ima return location; } -internal RDIM_LocationSet +internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, @@ -897,7 +897,7 @@ d2r_locset_from_attrib(Arena *arena, DW_Tag tag, DW_AttribKind kind) { - RDIM_LocationSet locset = {0}; + RDIM_LocationCaseList locset = {0}; // extract attrib from tag DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); @@ -913,7 +913,8 @@ d2r_locset_from_attrib(Arena *arena, for (DW_LocNode *loc_n = loclist.first; loc_n != 0; loc_n = loc_n->next) { RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, loc_n->v.expr); RDIM_Rng1U64 voff_range = { .min = loc_n->v.range.min - image_base, .max = loc_n->v.range.max - image_base }; - rdim_location_set_push_case(arena, scopes, &locset, voff_range, location); + // rdim_location_set_push_case(arena, scopes, &locset, voff_range, location); + // TODO(rjf): need to use rdim_local_push_location_case here } scratch_end(scratch); @@ -924,7 +925,8 @@ d2r_locset_from_attrib(Arena *arena, // convert expression and inherit life-time ranges from enclosed scope RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { - rdim_location_set_push_case(arena, scopes, &locset, range_n->v, location); + // rdim_location_set_push_case(arena, scopes, &locset, range_n->v, location); + // TODO(rjf): need to use rdim_local_push_location_case here } } else if (attrib_class != DW_AttribClass_Null) { AssertAlways(!"unexpected attrib class"); @@ -933,7 +935,7 @@ d2r_locset_from_attrib(Arena *arena, return locset; } -internal RDIM_LocationSet +internal RDIM_LocationCaseList d2r_var_locset_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, @@ -943,7 +945,7 @@ d2r_var_locset_from_tag(Arena *arena, Arch arch, DW_Tag tag) { - RDIM_LocationSet locset = {0}; + RDIM_LocationCaseList locset = {0}; B32 has_const_value = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ConstValue); B32 has_location = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Location); @@ -962,13 +964,15 @@ d2r_var_locset_from_tag(Arena *arena, rdim_bytecode_push_uconst(arena, &bc, const_value); // fill out location + // TODO(rjf): these need to be pushed into a RDIM_LocationChunkList RDIM_Location *loc = push_array(arena, RDIM_Location, 1); - loc->kind = RDI_LocationKind_ValBytecodeStream; - loc->bytecode = bc; + loc->info.kind = RDI_LocationKind_ValBytecodeStream; + loc->info.bytecode = bc; // push location cases for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { - rdim_location_set_push_case(arena, scopes, &locset, range_n->v, loc); + // rdim_location_set_push_case(arena, scopes, &locset, range_n->v, loc); + // TODO(rjf): need to use rdim_local_push_location_case here } } else if (has_location) { locset = d2r_locset_from_attrib(arena, input, cu, scopes, curr_scope, image_base, arch, tag, DW_AttribKind_Location); @@ -1871,7 +1875,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) proc->container_symbol = 0; proc->container_type = container_type; proc->root_scope = root_scope; - proc->frame_base = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); + proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); // sub program with user-defined parent tag is a method DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; @@ -1947,10 +1951,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) parent_tag_kind == DW_TagKind_LexicalBlock) { RDIM_Scope *scope = tag_stack->next->scope; RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->locset = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); } else { // NOTE: due to a bug in clang in stb_sprint.h local variables @@ -1974,10 +1978,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine) { RDIM_Scope *scope = tag_stack->next->scope; RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - param->locset = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); } else { // TODO: error handling AssertAlways(!"this is a local variable"); diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 0c7ceff6..9eeb54f9 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -73,23 +73,23 @@ d2r_bytecode_from_expression(Arena *arena, B32 *is_addr_out); internal RDIM_Location *d2r_transpile_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); internal RDIM_Location *d2r_location_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); -internal RDIM_LocationSet d2r_locset_from_attrib(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag, - DW_AttribKind kind); -internal RDIM_LocationSet d2r_var_locset_from_tag(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag); +internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, + DW_Input *input, + DW_CompUnit *cu, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + U64 image_base, + Arch arch, + DW_Tag tag, + DW_AttribKind kind); +internal RDIM_LocationCaseList d2r_var_locset_from_tag(Arena *arena, + DW_Input *input, + DW_CompUnit *cu, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + U64 image_base, + Arch arch, + DW_Tag tag); //////////////////////////////// //~ rjf: Compilation Unit / Scope Conversion Helpers diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index a4ba1308..a42616c5 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -267,38 +267,6 @@ p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type) //////////////////////////////// //~ rjf: Location Info Building Helpers -internal RDIM_Location * -p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) -{ - RDIM_Location *result = 0; - if(0 <= offset && offset <= (S64)max_U16) - { - if(extra_indirection) - { - result = rdim_push_location_addr_addr_reg_plus_u16(arena, reg_code, (U16)offset); - } - else - { - result = rdim_push_location_addr_reg_plus_u16(arena, reg_code, (U16)offset); - } - } - else - { - RDIM_EvalBytecode bytecode = {0}; - U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); - rdim_bytecode_push_sconst(arena, &bytecode, offset); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); - if(extra_indirection) - { - U64 addr_size = rdi_addr_size_from_arch(arch); - rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); - } - result = rdim_push_location_addr_bytecode_stream(arena, &bytecode); - } - return result; -} - internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg) { @@ -346,41 +314,6 @@ p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encod return(result); } -internal void -p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) -{ - //- rjf: extract range info - U64 voff_first = 0; - U64 voff_opl = 0; - if(section != 0) - { - voff_first = section->voff + range->off; - voff_opl = voff_first + range->len; - } - - //- rjf: emit ranges - CV_LvarAddrGap *gap_ptr = gaps; - U64 voff_cursor = voff_first; - for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) - { - U64 voff_gap_first = voff_first + gap_ptr->off; - U64 voff_gap_opl = voff_gap_first + gap_ptr->len; - if(voff_cursor < voff_gap_first) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; - rdim_location_set_push_case(arena, scopes, locset, voff_range, location); - } - voff_cursor = voff_gap_opl; - } - - //- rjf: emit remaining range - if(voff_cursor < voff_opl) - { - RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; - rdim_location_set_push_case(arena, scopes, locset, voff_range, location); - } -} - internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) { @@ -419,7 +352,7 @@ p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode re } internal void -p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) { //- rjf: extract range info U64 voff_first = 0; @@ -453,2784 +386,11 @@ p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChun } } -//////////////////////////////// -//~ rjf: Initial Parsing & Preparation Pass Tasks - -ASYNC_WORK_DEF(p2r_exe_hash_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_EXEHashIn *in = (P2R_EXEHashIn *)input; - U64 *out = push_array(arena, U64, 1); - ProfScope("hash exe") *out = rdi_hash(in->exe_data.str, in->exe_data.size); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_tpi_hash_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_TPIHashParseIn *in = (P2R_TPIHashParseIn *)input; - void *out = 0; - ProfScope("parse tpi hash") out = pdb_tpi_hash_from_data(arena, in->strtbl, in->tpi, in->hash_data, in->aux_data); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_tpi_leaf_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_TPILeafParseIn *in = (P2R_TPILeafParseIn *)input; - void *out = 0; - ProfScope("parse tpi leaf") out = cv_leaf_from_data(arena, in->leaf_data, in->itype_first); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_symbol_stream_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_SymbolStreamParseIn *in = (P2R_SymbolStreamParseIn *)input; - void *out = 0; - ProfScope("parse symbol stream") out = cv_sym_from_data(arena, in->data, 4); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_c13_stream_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_C13StreamParseIn *in = (P2R_C13StreamParseIn *)input; - void *out = 0; - ProfScope("parse c13 stream") out = cv_c13_parsed_from_data(arena, in->data, in->strtbl, in->coff_sections); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_comp_unit_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_CompUnitParseIn *in = (P2R_CompUnitParseIn *)input; - void *out = 0; - ProfScope("parse comp units") out = pdb_comp_unit_array_from_data(arena, in->data); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_CompUnitContributionsParseIn *in = (P2R_CompUnitContributionsParseIn *)input; - void *out = 0; - ProfScope("parse comp unit contributions") out = pdb_comp_unit_contribution_array_from_data(arena, in->data, in->coff_sections); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_comp_unit_contributions_bucket_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_CompUnitContributionsBucketIn *in = (P2R_CompUnitContributionsBucketIn *)input; - P2R_CompUnitContributionsBucketOut *out = push_array(arena, P2R_CompUnitContributionsBucketOut, 1); - { - out->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, in->comp_unit_count); - for(U64 idx = 0; idx < in->contributions.count; idx += 1) - { - PDB_CompUnitContribution *contribution = &in->contributions.contributions[idx]; - if(contribution->mod < in->comp_unit_count) - { - RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; - rdim_rng1u64_chunk_list_push(arena, &out->unit_ranges[contribution->mod], 256, r); - } - } - } - ProfEnd(); - return out; -} - -//////////////////////////////// -//~ rjf: Unit Source File Gathering Tasks - -ASYNC_WORK_DEF(p2r_gather_unit_src_file_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - Temp scratch = scratch_begin(&arena, 1); - P2R_GatherUnitSrcFilesIn *in = (P2R_GatherUnitSrcFilesIn *)input; - P2R_GatherUnitSrcFilesOut *out = push_array(arena, P2R_GatherUnitSrcFilesOut, 1); - PDB_CompUnit *pdb_unit = in->comp_unit; - CV_SymParsed *pdb_unit_sym = in->comp_unit_syms; - CV_C13Parsed *pdb_unit_c13 = in->comp_unit_c13s; - CV_RecRange *rec_ranges_first = pdb_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first+pdb_unit_sym->sym_ranges.count; - String8List src_file_paths = {0}; - { - //- rjf: build local hash table to dedup files within this unit - U64 hit_path_slots_count = 4096; - String8Node **hit_path_slots = push_array(scratch.arena, String8Node *, hit_path_slots_count); - - //- rjf: produce obj name/path - String8 obj_name = pdb_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: find all files in this unit's (non-inline) line info - ProfScope("find all files in this unit's (non-inline) line info") - for(CV_C13SubSectionNode *node = pdb_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - // rjf: file name -> sanitized file path - String8 file_path = lines_n->v.file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 hit_path_slot = file_path_sanitized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_sanitized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_sanitized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_sanitized)); - } - } - } - } - - //- rjf: find all files in unit's inline line info - ProfScope("find all files in unit's inline line info") - { - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > pdb_unit_sym->data.size || sym_off_first > pdb_unit_sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = pdb_unit_sym->data.str + sym_off_first; - void *sym_data_opl = pdb_unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%pdb_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = pdb_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = pdb_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - U64 line_count = 0; - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> gather new file name - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(pdb_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); - } - - // rjf: file name -> normalized file path - String8 file_path = seq_file_name; - String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); - String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); - if(file_path_normalized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); - file_path_normalized_parts = obj_folder_path_parts; - file_path_normalized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); - file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); - } - - // rjf: normalized file path -> source file node - U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); - U64 hit_path_slot = file_path_normalized_hash%hit_path_slots_count; - String8Node *hit_path_node = 0; - for(String8Node *n = hit_path_slots[hit_path_slot]; n != 0; n = n->next) - { - if(str8_match(n->string, file_path_normalized, 0)) - { - hit_path_node = n; - break; - } - } - if(hit_path_node == 0) - { - hit_path_node = push_array(scratch.arena, String8Node, 1); - SLLStackPush(hit_path_slots[hit_path_slot], hit_path_node); - hit_path_node->string = file_path_normalized; - str8_list_push(scratch.arena, &src_file_paths, push_str8_copy(arena, file_path_normalized)); - } - line_count = 0; - } - - // rjf: count lines - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - } - out->src_file_paths = str8_array_from_list(arena, &src_file_paths); - scratch_end(scratch); - ProfEnd(); - return out; -} - -//////////////////////////////// -//~ rjf: Unit Conversion Tasks - -ASYNC_WORK_DEF(p2r_unit_convert_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - Temp scratch = scratch_begin(&arena, 1); - P2R_UnitConvertIn *in = (P2R_UnitConvertIn *)input; - P2R_UnitConvertOut *out = push_array(arena, P2R_UnitConvertOut, 1); - - //////////////////////////// - //- rjf: pass 1: build per-unit info & per-unit line table - // - ProfScope("pass 1: build per-unit info & per-unit line table") - { - PDB_CompUnit *pdb_unit = in->comp_unit; - CV_SymParsed *pdb_unit_sym = in->comp_unit_syms; - CV_C13Parsed *pdb_unit_c13 = in->comp_unit_c13s; - - //- rjf: produce unit name - String8 unit_name = pdb_unit->obj_name; - if(unit_name.size != 0) - { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) - { - unit_name = unit_name_past_last_slash; - } - } - - //- rjf: produce obj name/path - String8 obj_name = pdb_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: build this unit's line table, fill out primary line info (inline info added after) - RDIM_LineTable *line_table = 0; - for(CV_C13SubSectionNode *node = pdb_unit_c13->first_sub_section; - node != 0; - node = node->next) - { - if(node->kind == CV_C13SubSectionKind_Lines) - { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) - { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%in->src_file_map->slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) - { - for(P2R_SrcFileNode *n = in->src_file_map->slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, &out->line_tables, 256); - } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, &out->line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); - } - } - } - } - - //- rjf: build unit - RDIM_Unit *dst_unit = rdim_unit_chunk_list_push(arena, &out->units, 1); - dst_unit->unit_name = unit_name; - dst_unit->compiler_name = pdb_unit_sym->info.compiler_name; - dst_unit->object_file = obj_name; - dst_unit->archive_file = pdb_unit->group_name; - dst_unit->language = p2r_rdi_language_from_cv_language(pdb_unit_sym->info.language); - dst_unit->line_table = line_table; - dst_unit->voff_ranges = in->comp_unit_ranges; - } - - //////////////////////////// - //- rjf: pass 2: parse all inlinee line tables - // - ProfScope("pass 2: parse all inlinee line tables") - { - //- rjf: unpack unit - PDB_CompUnit *pdb_unit = in->comp_unit; - CV_SymParsed *pdb_unit_sym = in->comp_unit_syms; - CV_C13Parsed *pdb_unit_c13 = in->comp_unit_c13s; - CV_RecRange *rec_ranges_first = pdb_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first+pdb_unit_sym->sym_ranges.count; - - //- rjf: produce obj name/path - String8 obj_name = pdb_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: parse inlinee line tables - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > pdb_unit_sym->data.size || sym_off_first > pdb_unit_sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = pdb_unit_sym->data.str + sym_off_first; - void *sym_data_opl = pdb_unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%pdb_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = pdb_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = pdb_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - typedef struct LineChunk LineChunk; - struct LineChunk - { - LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - RDIM_LineTable* line_table = 0; - - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && total_line_chunk_line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> push line chunks gathered for this file - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(pdb_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); - } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%in->src_file_map->slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = in->src_file_map->slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - - // rjf: gather all lines - RDI_U64 *voffs = 0; - RDI_U32 *line_nums = 0; - RDI_U64 line_count = 0; - if(src_file_node != 0) - { - voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - line_count = total_line_chunk_line_count; - U64 dst_idx = 0; - for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) - { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); - MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); - dst_idx += chunk->count; - } - } - - // rjf: push - if(line_count != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, &out->line_tables, 256); - if(out->unit_first_inline_site_line_table == 0) - { - out->unit_first_inline_site_line_table = line_table; - } - } - rdim_line_table_push_sequence(arena, &out->line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); - } - - // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; - total_line_chunk_line_count = 0; - } - - // rjf: new line -> emit to chunk - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) - { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 8; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); - } - chunk->voffs[chunk->count] = step.line_voff; - chunk->voffs[chunk->count+1] = step.line_voff_end; - chunk->line_nums[chunk->count] = step.ln; - chunk->count += 1; - total_line_chunk_line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - scratch_end(scratch); - ProfEnd(); - return out; -} - -//////////////////////////////// -//~ rjf: Source File Sequence Equipping Task - -ASYNC_WORK_DEF(p2r_src_file_seq_equip_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_SrcFileSeqEquipIn *in = (P2R_SrcFileSeqEquipIn *)input; - for(RDIM_LineTableChunkNode *line_table_chunk_n = in->line_tables.first; line_table_chunk_n != 0; line_table_chunk_n = line_table_chunk_n->next) - { - for EachIndex(chunk_line_table_idx, line_table_chunk_n->count) - { - RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; - for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) - { - rdim_src_file_push_line_sequence(arena, &in->src_files, s->v.src_file, &s->v); - } - } - } - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Link Name Map Building Tasks - -ASYNC_WORK_DEF(p2r_link_name_map_build_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_LinkNameMapBuildIn *in = (P2R_LinkNameMapBuildIn *)input; - CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = rec_ranges_first + in->sym->sym_ranges.count; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: unpack symbol range info - CV_SymKind kind = rec_range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_sym_kind(kind); - U8 *sym_first = in->sym->data.str + rec_range->off + 2; - U8 *sym_opl = sym_first + rec_range->hdr.size; - - //- rjf: skip bad ranges - if(sym_opl > in->sym->data.str + in->sym->data.size || sym_first + header_struct_size > in->sym->data.str + in->sym->data.size) - { - continue; - } - - //- rjf: consume symbol - switch(kind) - { - default:{}break; - case CV_SymKind_PUB32: - { - // rjf: unpack sym - CV_SymPub32 *pub32 = (CV_SymPub32 *)sym_first; - String8 name = str8_cstring_capped(pub32+1, sym_opl); - COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= in->coff_sections.count) ? &in->coff_sections.v[pub32->sec-1] : 0; - U64 voff = 0; - if(section != 0) - { - voff = section->voff + pub32->off; - } - - // rjf: commit to link name map - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%in->link_name_map->buckets_count; - P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); - SLLStackPush(in->link_name_map->buckets[bucket_idx], node); - node->voff = voff; - node->name = name; - in->link_name_map->link_name_count += 1; - in->link_name_map->bucket_collision_count += (node->next != 0); - }break; - } - } - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Type Parsing/Conversion Tasks - -ASYNC_WORK_DEF(p2r_itype_fwd_map_fill_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_ITypeFwdMapFillIn *in = (P2R_ITypeFwdMapFillIn *)input; - ProfScope("fill itype fwd map") for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) - { - //- rjf: skip if not in the actually stored itype range - if(itype < in->tpi_leaf->itype_first) - { - continue; - } - - //- rjf: determine if this itype resolves to another - CV_TypeId itype_fwd = 0; - CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[itype-in->tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= in->tpi_leaf->data.size && - range->off+2+header_struct_size <= in->tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // rjf: unpack leaf header - CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // rjf: unpack leaf header - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_struct->props & CV_TypeProp_FwdRef) - { - // rjf: unpack rest of leaf - U8 *numeric_ptr = (U8 *)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: lookup - B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // rjf: unpack leaf - CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8 *)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves tos - if(lf_union->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && - ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // rjf: unpack leaf - CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; - U8 *name_ptr = (U8 *)(lf_enum + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); - - // rjf: has fwd ref flag -> lookup itype that this itype resolves to - if(lf_enum->props & CV_TypeProp_FwdRef) - { - B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && - ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); - itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); - } - }break; - } - } - - //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map - if(itype_fwd != 0 && itype_fwd < in->tpi_leaf->itype_opl) - { - in->itype_fwd_map[itype] = itype_fwd; - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_itype_chain_build_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - Temp scratch = scratch_begin(&arena, 1); - P2R_ITypeChainBuildIn *in = (P2R_ITypeChainBuildIn *)input; - ProfScope("dependency itype chain build") - { - for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) - { - //- rjf: push initial itype - should be final-visited-itype for this itype - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = itype; - SLLStackPush(in->itype_chains[itype], c); - } - - //- rjf: skip basic types for dependency walk - if(itype < in->tpi_leaf->itype_first) - { - continue; - } - - //- rjf: walk dependent types, push to chain - P2R_TypeIdChain start_walk_task = {0, itype}; - P2R_TypeIdChain *first_walk_task = &start_walk_task; - P2R_TypeIdChain *last_walk_task = &start_walk_task; - for(P2R_TypeIdChain *walk_task = first_walk_task; - walk_task != 0; - walk_task = walk_task->next) - { - CV_TypeId walk_itype = in->itype_fwd_map[walk_task->itype] ? in->itype_fwd_map[walk_task->itype] : walk_task->itype; - if(walk_itype < in->tpi_leaf->itype_first) - { - continue; - } - CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[walk_itype-in->tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= in->tpi_leaf->data.size && - range->off+2+header_struct_size <= in->tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) - { - default:{}break; - - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - - // rjf: push return itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk return itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &in->tpi_leaf->leaf_ranges.ranges[lf->arg_itype-in->tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > in->tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = in->tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLStackPush(in->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLStackPush(in->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->ret_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->arg_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->this_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &in->tpi_leaf->leaf_ranges.ranges[lf->arg_itype-in->tpi_leaf->itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > in->tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = in->tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: push arg types to chain - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk arg types - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = arglist_itypes_base[idx]; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - - // rjf: push dependent itype to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itype - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLStackPush(in->itype_chains[itype], c); - } - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->entry_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->index_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - - // rjf: push dependent itypes to chain - { - P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLStackPush(in->itype_chains[itype], c); - } - - // rjf: push task to walk dependency itypes - { - P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); - c->itype = lf->base_itype; - SLLQueuePush(first_walk_task, last_walk_task, c); - } - }break; - } - } - } - } - } - scratch_end(scratch); - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: UDT Conversion Tasks - -ASYNC_WORK_DEF(p2r_udt_convert_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - P2R_UDTConvertIn *in = (P2R_UDTConvertIn *)input; -#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) - RDIM_UDTChunkList *udts = push_array(arena, RDIM_UDTChunkList, 1); - RDI_U64 udts_chunk_cap = 1024; - ProfScope("convert UDT info") - { - for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) - { - //- rjf: skip basics - if(itype < in->tpi_leaf->itype_first) { continue; } - - //- rjf: grab type for this itype - skip if empty - RDIM_Type *dst_type = in->itype_type_ptrs[itype]; - if(dst_type == 0) { continue; } - - //- rjf: unpack itype leaf range - skip if out-of-range - CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[itype-in->tpi_leaf->itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - if(range->off+range->hdr.size > in->tpi_leaf->data.size || - range->off+2+header_struct_size > in->tpi_leaf->data.size || - range->hdr.size < 2) - { - continue; - } - - //- rjf: build UDT - CV_TypeId field_itype = 0; - switch(kind) - { - default:{}break; - - //////////////////////// - //- rjf: structs/unions/classes -> equip members - // - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - case CV_LeafKind_UNION: - { - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_members; - equip_members: - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < in->tpi_leaf->itype_first || in->tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[field_list_itype-in->tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > in->tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = in->tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_list_opl; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: MEMBER - case CV_LeafKind_MEMBER: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - U8 *name_ptr = offset_ptr + offset.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_DataField; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: STMEMBER - case CV_LeafKind_STMEMBER: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticData; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: METHOD - case CV_LeafKind_METHOD: - { - // rjf: unpack leaf - CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - //- rjf: method list itype -> range - CV_RecRange *method_list_range = &in->tpi_leaf->leaf_ranges.ranges[lf->list_itype-in->tpi_leaf->itype_first]; - - //- rjf: skip bad method lists - if(method_list_range->off+method_list_range->hdr.size > in->tpi_leaf->data.size || - method_list_range->hdr.size < 2 || - method_list_range->hdr.kind != CV_LeafKind_METHODLIST) - { - break; - } - - //- rjf: loop through all methods & emit members - U8 *method_list_first = in->tpi_leaf->data.str + method_list_range->off + 2; - U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; - for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; - method_read_ptr < method_list_opl; - method_read_ptr = next_method_read_ptr) - { - CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); - RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); - next_method_read_ptr = (U8 *)(method+1); - - // TODO(allen): PROBLEM - // We only get offsets for virtual functions (the "vbaseoff") from - // "Intro" and "PureIntro". In C++ inheritance, when we have a chain - // of inheritance (let's just talk single inheritance for now) the - // first class in the chain that introduces a new virtual function - // has this "Intro" method. If a later class in the chain redefines - // the virtual function it only has a "Virtual" method which does - // not update the offset. There is a "Virtual" and "PureVirtual" - // variant of "Virtual". The "Pure" in either case means there - // is no concrete procedure. When there is no "Pure" the method - // should have a corresponding procedure symbol id. - // - // The issue is we will want to mark all of our virtual methods as - // virtual and give them an offset, but that means we have to do - // some extra figuring to propogate offsets from "Intro" methods - // to "Virtual" methods in inheritance trees. That is - IF we want - // to start preserving the offsets of virtuals. There is room in - // the method struct to make this work, but for now I've just - // decided to drop this information. It is not urgently useful to - // us and greatly complicates matters. - - // rjf: read vbaseoff - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - if(next_method_read_ptr+4 <= method_list_opl) - { - vbaseoff = *(U32 *)next_method_read_ptr; - } - next_method_read_ptr += 4; - } - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - } - - }break; - - //- rjf: ONEMETHOD - case CV_LeafKind_ONEMETHOD: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); - U8 *vbaseoff_ptr = (U8 *)(lf+1); - U8 *vbaseoff_opl_ptr = vbaseoff_ptr; - U32 vbaseoff = 0; - if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) - { - vbaseoff = *(U32 *)(vbaseoff_ptr); - vbaseoff_opl_ptr += sizeof(U32); - } - U8 *name_ptr = vbaseoff_opl_ptr; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit method - switch(prop) - { - default: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Method; - mem->name = name; - mem->type = method_type; - }break; - - case CV_MethodProp_Static: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_StaticMethod; - mem->name = name; - mem->type = method_type; - }break; - - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualMethod; - mem->name = name; - mem->type = method_type; - }break; - } - }break; - - //- rjf: NESTTYPE - case CV_LeafKind_NESTTYPE: - { - // rjf: unpack leaf - CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: NESTTYPEEX - case CV_LeafKind_NESTTYPEEX: - { - // TODO(rjf): handle attribs - - // rjf: unpack leaf - CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; - U8 *name_ptr = (U8 *)(lf+1); - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_NestedType; - mem->name = name; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: BCLASS - case CV_LeafKind_BCLASS: - { - // TODO(rjf): log on bad offset - - // rjf: unpack leaf - CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; - U8 *offset_ptr = (U8 *)(lf+1); - CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); - U64 offset64 = cv_u64_from_numeric(&offset); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = offset_ptr+offset.encoded_size; - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_Base; - mem->type = p2r_type_ptr_from_itype(lf->itype); - mem->off = (U32)offset64; - }break; - - //- rjf: VBCLASS/IVBCLASS - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - { - // TODO(rjf): log on bad offsets - // TODO(rjf): handle attribs - // TODO(rjf): offsets? - - // rjf: unpack leaf - CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; - U8 *num1_ptr = (U8 *)(lf+1); - CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); - U8 *num2_ptr = num1_ptr + num1.encoded_size; - CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // rjf: emit member - RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); - mem->kind = RDI_MemberKind_VirtualBase; - mem->type = p2r_type_ptr_from_itype(lf->itype); - }break; - - //- rjf: VFUNCTAB - case CV_LeafKind_VFUNCTAB: - { - CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; - - // rjf: bump next read pointer past header - next_read_ptr = (U8 *)(lf+1); - - // NOTE(rjf): currently no-op this case - (void)lf; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - - //////////////////////// - //- rjf: enums -> equip enumerates - // - case CV_LeafKind_ENUM: - { - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - if(lf->props & CV_TypeProp_FwdRef) - { - break; - } - field_itype = lf->field_itype; - }goto equip_enum_vals; - equip_enum_vals:; - { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: grab UDT info - RDIM_UDT *dst_udt = dst_type->udt; - if(dst_udt == 0) - { - dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); - dst_udt->self_type = dst_type; - } - - //- rjf: gather all fields - typedef struct FieldListTask FieldListTask; - struct FieldListTask - { - FieldListTask *next; - CV_TypeId itype; - }; - FieldListTask start_fl_task = {0, field_itype}; - FieldListTask *fl_todo_stack = &start_fl_task; - FieldListTask *fl_done_stack = 0; - for(;fl_todo_stack != 0;) - { - //- rjf: take & unpack task - FieldListTask *fl_task = fl_todo_stack; - SLLStackPop(fl_todo_stack); - SLLStackPush(fl_done_stack, fl_task); - CV_TypeId field_list_itype = fl_task->itype; - - //- rjf: skip bad itypes - if(field_list_itype < in->tpi_leaf->itype_first || in->tpi_leaf->itype_opl <= field_list_itype) - { - continue; - } - - //- rjf: field list itype -> range - CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[field_list_itype-in->tpi_leaf->itype_first]; - - //- rjf: skip bad headers - if(range->off+range->hdr.size > in->tpi_leaf->data.size || - range->hdr.size < 2 || - range->hdr.kind != CV_LeafKind_FIELDLIST) - { - continue; - } - - //- rjf: loop over all fields - { - U8 *field_list_first = in->tpi_leaf->data.str+range->off+2; - U8 *field_list_opl = field_list_first+range->hdr.size-2; - for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; - read_ptr < field_list_opl; - read_ptr = next_read_ptr) - { - // rjf: unpack field - CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; - U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); - U8 *field_leaf_first = read_ptr+2; - U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; - next_read_ptr = field_leaf_opl; - - // rjf: skip out-of-bounds fields - if(field_leaf_first+field_leaf_header_size > field_list_opl) - { - continue; - } - - // rjf: process field - switch(field_kind) - { - //- rjf: unhandled/invalid cases - default: - { - // TODO(rjf): log - }break; - - //- rjf: INDEX - case CV_LeafKind_INDEX: - { - // rjf: unpack leaf - CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; - CV_TypeId new_itype = lf->itype; - - // rjf: determine if index itype is new - B32 is_new = 1; - for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) - { - if(t->itype == new_itype) - { - is_new = 0; - break; - } - } - - // rjf: if new -> push task to follow new itype - if(is_new) - { - FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); - SLLStackPush(fl_todo_stack, new_task); - new_task->itype = new_itype; - } - }break; - - //- rjf: ENUMERATE - case CV_LeafKind_ENUMERATE: - { - // TODO(rjf): attribs - - // rjf: unpack leaf - CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; - U8 *val_ptr = (U8 *)(lf+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); - - // rjf: bump next read pointer past variable length parts - next_read_ptr = name.str+name.size+1; - - // rjf: emit member - RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); - enum_val->name = name; - enum_val->val = val64; - }break; - } - - // rjf: align-up next field - next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); - } - } - } - - scratch_end(scratch); - }break; - } - } - } -#undef p2r_type_ptr_from_itype - ProfEnd(); - return udts; -} - -//////////////////////////////// -//~ rjf: Symbol Stream Conversion Path & Thread - -ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(p2r_async_root); - Temp scratch = scratch_begin(&arena, 1); - P2R_SymbolStreamConvertIn *in = (P2R_SymbolStreamConvertIn *)input; -#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (itype))]) : 0) - - ////////////////////////// - //- rjf: set up outputs for this sym stream - // - U64 sym_procedures_chunk_cap = 1024; - U64 sym_global_variables_chunk_cap = 1024; - U64 sym_thread_variables_chunk_cap = 1024; - U64 sym_constants_chunk_cap = 1024; - U64 sym_scopes_chunk_cap = 1024; - U64 sym_inline_sites_chunk_cap = 1024; - RDIM_SymbolChunkList sym_procedures = {0}; - RDIM_SymbolChunkList sym_global_variables = {0}; - RDIM_SymbolChunkList sym_thread_variables = {0}; - RDIM_SymbolChunkList sym_constants = {0}; - RDIM_ScopeChunkList sym_scopes = {0}; - RDIM_InlineSiteChunkList sym_inline_sites = {0}; - RDIM_TypeChunkList typedefs = {0}; - - ////////////////////////// - //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) - // - U64 procedure_frameprocs_count = 0; - U64 procedure_frameprocs_cap = (in->sym_ranges_opl - in->sym_ranges_first); - CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); - ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") - { - U64 procedure_num = 0; - CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges + in->sym_ranges_first; - CV_RecRange *rec_ranges_opl = in->sym->sym_ranges.ranges + in->sym_ranges_opl; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > in->sym->data.size || sym_off_first > in->sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = in->sym->data.str + sym_off_first; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; - - //- rjf: FRAMEPROC - case CV_SymKind_FRAMEPROC: - { - if(procedure_num == 0) { break; } - if(procedure_num > procedure_frameprocs_cap) { break; } - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; - procedure_frameprocs[procedure_num-1] = frameproc; - procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - procedure_num += 1; - }break; - } - } - U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); - arena_pop(scratch.arena, scratch_overkill); - } - - ////////////////////////// - //- rjf: symbols pass 2: construct all symbols, given procedure frame info map - // - ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") - { - RDIM_LocationSet *defrange_target = 0; - B32 defrange_target_is_param = 0; - U64 procedure_num = 0; - U64 procedure_base_voff = 0; - CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges + in->sym_ranges_first; - CV_RecRange *rec_ranges_opl = in->sym->sym_ranges.ranges + in->sym_ranges_opl; - typedef struct P2R_ScopeNode P2R_ScopeNode; - struct P2R_ScopeNode - { - P2R_ScopeNode *next; - RDIM_Scope *scope; - }; - P2R_ScopeNode *top_scope_node = 0; - P2R_ScopeNode *free_scope_node = 0; - RDIM_LineTable *inline_site_line_table = in->first_inline_site_line_table; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > in->sym->data.size || sym_off_first > in->sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = in->sym->data.str + sym_off_first; - void *sym_data_opl = in->sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; - - //- rjf: END - case CV_SymKind_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: BLOCK32 - case CV_SymKind_BLOCK32: - { - // rjf: unpack sym - CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; - - // rjf: build scope, insert into current parent scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); - { - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= in->coff_sections.count) ? &in->coff_sections.v[block32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + block32->off; - U64 voff_last = voff_first + block32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); - } - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - }break; - - //- rjf: LDATA32/GDATA32 - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - // rjf: unpack sym - CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(data32+1, sym_data_opl); - COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= in->coff_sections.count) ? &in->coff_sections.v[data32->sec-1] : 0; - U64 voff = (section ? section->voff : 0) + data32->off; - - // rjf: determine if this is an exact duplicate global - // - // PDB likes to have duplicates of these spread across different - // symbol streams so we deduplicate across the entire translation - // context. - // - B32 is_duplicate = 0; - { - // TODO(rjf): @important global symbol dedup - } - - // rjf: is not duplicate -> push new global - if(!is_duplicate) - { - // rjf: unpack global variable's type - RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); - - // rjf: unpack global's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack global's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, &sym_global_variables, sym_global_variables_chunk_cap); - symbol->is_extern = (kind == CV_SymKind_GDATA32); - symbol->name = name; - symbol->type = type; - symbol->offset = voff; - symbol->container_symbol = container_symbol; - symbol->container_type = container_type; - } - }break; - - //- rjf: UDT (typedefs) - case CV_SymKind_UDT: - if(in->parsing_global_stream && top_scope_node == 0) - { - CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; - String8 name = str8_cstring_capped(udt+1, sym_data_opl); - RDIM_Type *type = rdim_type_chunk_list_push(arena, &typedefs, 4096); - type->kind = RDI_TypeKind_Alias; - type->name = name; - type->direct_type = p2r_type_ptr_from_itype(udt->itype); - if(type->direct_type != 0) - { - type->byte_size = type->direct_type->byte_size; - } - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - // rjf: unpack sym - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(proc32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); - - // rjf: unpack proc's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2 && in->tpi_hash != 0 && in->tpi_leaf != 0) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack proc's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build procedure's root scope - // - // NOTE: even if there could be a containing scope at this point (which should be - // illegal in C/C++ but not necessarily in another language) we would not use - // it here because these scopes refer to the ranges of code that make up a - // procedure *not* the namespaces, so a procedure's root scope always has - // no parent. - RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); - { - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + proc32->off; - U64 voff_last = voff_first + proc32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, &sym_scopes, procedure_root_scope, voff_range); - procedure_base_voff = voff_first; - } - } - - // rjf: root scope voff minimum range -> link name - String8 link_name = {0}; - if(procedure_root_scope->voff_ranges.min != 0) - { - U64 voff = procedure_root_scope->voff_ranges.min; - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%in->link_name_map->buckets_count; - P2R_LinkNameNode *node = 0; - for(P2R_LinkNameNode *n = in->link_name_map->buckets[bucket_idx]; n != 0; n = n->next) - { - if(n->voff == voff) - { - link_name = n->name; - break; - } - } - } - - // rjf: build procedure symbol - RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, &sym_procedures, sym_procedures_chunk_cap); - procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); - procedure_symbol->name = name; - procedure_symbol->link_name = link_name; - procedure_symbol->type = type; - procedure_symbol->container_symbol = container_symbol; - procedure_symbol->container_type = container_type; - procedure_symbol->root_scope = procedure_root_scope; - - // rjf: fill root scope's symbol - procedure_root_scope->symbol = procedure_symbol; - - // rjf: push scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = procedure_root_scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: increment procedure counter - procedure_num += 1; - }break; - - //- rjf: REGREL32 - case CV_SymKind_REGREL32: - { - // TODO(rjf): apparently some of the information here may end up being - // redundant with "better" information from CV_SymKind_LOCAL record. - // we don't currently handle this, but if those cases arise then it - // will obviously be better to prefer the better information from both - // records. - - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); - CV_Reg cv_reg = regrel32->reg; - U32 var_off = regrel32->reg_off; - - // rjf: determine if this is a parameter - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - { - B32 is_stack_reg = 0; - switch(in->arch) - { - default:{}break; - case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; - case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; - } - if(is_stack_reg) - { - U32 frame_size = 0xFFFFFFFF; - if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) - { - CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; - frame_size = frameproc->frame_size; - } - if(var_off > frame_size) - { - local_kind = RDI_LocalKind_Parameter; - } - } - } - - // TODO(rjf): is this correct? - // rjf: redirect type, if 0, and if outside frame, to the return type of the - // containing procedure - if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && - top_scope_node->scope->symbol != 0 && - top_scope_node->scope->symbol->type != 0) - { - type = top_scope_node->scope->symbol->type->direct_type; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: add location info to local - if(type != 0) - { - // rjf: determine if we need an extra indirection to the value - B32 extra_indirection_to_value = 0; - switch(in->arch) - { - case RDI_Arch_X86: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); - }break; - case RDI_Arch_X64: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); - }break; - } - - // rjf: get raddbg register code - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); - // TODO(rjf): real byte_size & byte_pos from cv_reg goes here - U32 byte_size = 8; - U32 byte_pos = 0; - - // rjf: set location case - RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, in->arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, &sym_scopes, &local->locset, voff_range, loc); - } - }break; - - //- rjf: LTHREAD32/GTHREAD32 - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - // rjf: unpack sym - CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(thread32+1, sym_data_opl); - U32 tls_off = thread32->tls_off; - RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); - - // rjf: unpack thread variable's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack thread variable's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, &sym_thread_variables, sym_thread_variables_chunk_cap); - tvar->name = name; - tvar->type = type; - tvar->is_extern = (kind == CV_SymKind_GTHREAD32); - tvar->offset = tls_off; - tvar->container_type = container_type; - tvar->container_symbol = container_symbol; - }break; - - //- rjf: LOCAL - case CV_SymKind_LOCAL: - { - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; - String8 name = str8_cstring_capped(slocal+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); - - // rjf: determine if this symbol encodes the beginning of a global modification - B32 is_global_modification = 0; - if((slocal->flags & CV_LocalFlag_Global) || - (slocal->flags & CV_LocalFlag_Static)) - { - is_global_modification = 1; - } - - // rjf: is global modification -> emit global modification symbol - if(is_global_modification) - { - // TODO(rjf): add global modification symbols - defrange_target = 0; - defrange_target_is_param = 0; - } - - // rjf: is not a global modification -> emit a local variable - if(!is_global_modification) - { - // rjf: determine local kind - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - if(slocal->flags & CV_LocalFlag_Param) - { - local_kind = RDI_LocalKind_Parameter; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: save defrange target, for subsequent defrange symbols - defrange_target = &local->locset; - defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); - } - }break; - - //- rjf: DEFRANGE_REGISTESR - case CV_SymKind_DEFRANGE_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register->reg; - CV_LvarAddrRange *range = &defrange_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); - - // rjf: build location - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); - - // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; - CV_LvarAddrRange *range = &defrange_fprel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(in->arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(in->arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel->off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - - // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_SUBFIELD_REGISTER - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_subfield_register->reg; - CV_LvarAddrRange *range = &defrange_subfield_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); - - // rjf: skip "subfield" location info - currently not supported - if(defrange_subfield_register->field_offset != 0) - { - break; - } - - // rjf: build location - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); - - // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(in->arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(in->arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - - // rjf: emit location over ranges - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, &sym_scopes, defrange_target, voff_range, location); - }break; - - //- rjf: DEFRANGE_REGISTER_REL - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register_rel->reg; - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); - CV_LvarAddrRange *range = &defrange_register_rel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: build location - // TODO(rjf): offset & size from cv_reg code - U32 byte_size = rdi_addr_size_from_arch(in->arch); - U32 byte_pos = 0; - B32 extra_indirection_to_value = 0; - S64 var_off = defrange_register_rel->reg_off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - - // rjf: emit locations over ranges - p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: FILESTATIC - case CV_SymKind_FILESTATIC: - { - CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; - String8 name = str8_cstring_capped(file_static+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); - // TODO(rjf): emit a global modifier symbol - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: extract external info about inline site - String8 name = str8_zero(); - RDIM_Type *type = 0; - RDIM_Type *owner = 0; - if(in->ipi_leaf != 0 && in->ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < in->ipi_leaf->itype_opl) - { - CV_RecRange rec_range = in->ipi_leaf->leaf_ranges.ranges[sym->inlinee - in->ipi_leaf->itype_first]; - String8 rec_data = str8_substr(in->ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); - void *raw_leaf = rec_data.str + sizeof(U16); - - // rjf: extract method inline info - if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) - { - CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; - name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(mfunc_id->itype); - owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; - } - - // rjf: extract non-method function inline info - else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafFuncId)) - { - CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; - name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(func_id->itype); - owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; - } - } - - // rjf: build inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &sym_inline_sites, sym_inline_sites_chunk_cap); - inline_site->name = name; - inline_site->type = type; - inline_site->owner = owner; - inline_site->line_table = inline_site_line_table; - - // rjf: increment to next inline site line table in this unit - if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) - { - RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; - U64 current_idx = (U64)(inline_site_line_table - chunk->v); - if(current_idx+1 < chunk->count) - { - inline_site_line_table += 1; - } - else - { - chunk = chunk->next; - inline_site_line_table = 0; - if(chunk != 0) - { - inline_site_line_table = chunk->v; - } - } - } - - // rjf: build scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); - scope->inline_site = inline_site; - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: parse offset ranges of this inline site - attach to scope - { - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); - for(;;) - { - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) - { - // rjf: build new range & add to scope - RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; - rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); - } - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) - { - if(scope->voff_ranges.last != 0) - { - scope->voff_ranges.last->v.max = step.range.max; - } - } - - if(step.flags == 0) - { - break; - } - } - } - }break; - - //- rjf: INLINESITE_END - case CV_SymKind_INLINESITE_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: CONSTANT - case CV_SymKind_CONSTANT: - { - // rjf: unpack - CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; - RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); - U8 *val_ptr = (U8 *)(sym+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, sym_data_opl); - String8 val_data = str8_struct(&val64); - U64 container_name_opl = 0; - if(type != 0) - { - container_name_opl = p2r_end_of_cplusplus_container_name(type->name); - } - String8 name_qualified = name; - if(container_name_opl != 0) - { - name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); - } - - // rjf: build constant symbol - if(name_qualified.size != 0) - { - RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, &sym_constants, sym_constants_chunk_cap); - cnst->name = name_qualified; - cnst->type = type; - rdim_symbol_push_value_data(arena, &sym_constants, cnst, val_data); - } - }break; - } - } - } - - ////////////////////////// - //- rjf: allocate & fill output - // - P2R_SymbolStreamConvertOut *out = push_array(arena, P2R_SymbolStreamConvertOut, 1); - { - out->procedures = sym_procedures; - out->global_variables = sym_global_variables; - out->thread_variables = sym_thread_variables; - out->constants = sym_constants; - out->scopes = sym_scopes; - out->inline_sites = sym_inline_sites; - out->typedefs = typedefs; - } - -#undef p2r_type_ptr_from_itype - scratch_end(scratch); - ProfEnd(); - return out; -} - //////////////////////////////// //~ rjf: Top-Level Conversion Entry Point internal RDIM_BakeParams -p2r2_convert(Arena *arena, P2R_ConvertParams *params) +p2r_convert(Arena *arena, P2R_ConvertParams *params) { ////////////////////////////////////////////////////////////// //- rjf: do base MSF parse @@ -6125,8 +3285,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") { - RDIM_LocationSet *defrange_target = 0; - RDIM_Local *defrange_target2 = 0; + RDIM_Local *defrange_target = 0; B32 defrange_target_is_param = 0; U64 procedure_num = 0; U64 procedure_base_voff = 0; @@ -6182,7 +3341,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) SLLStackPush(free_scope_node, n); } defrange_target = 0; - defrange_target2 = 0; defrange_target_is_param = 0; }break; @@ -6477,13 +3635,9 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Location2 *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - rdim_local_push_location_case(arena, sym_scopes, local, loc2, (RDIM_Rng1U64){0, max_U64}); - - // rjf: set location case - RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Location *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, sym_scopes, &local->locset, voff_range, loc); + rdim_local_push_location_case(arena, sym_scopes, local, loc2, voff_range); } }break; @@ -6552,7 +3706,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { // TODO(rjf): add global modification symbols defrange_target = 0; - defrange_target2 = 0; defrange_target_is_param = 0; } @@ -6574,8 +3727,7 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) local->type = type; // rjf: save defrange target, for subsequent defrange symbols - defrange_target = &local->locset; - defrange_target2 = local; + defrange_target = local; defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); } }break; @@ -6589,10 +3741,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } - if(defrange_target2 == 0) - { - break; - } // rjf: unpack sym CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; @@ -6605,12 +3753,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL @@ -6622,10 +3768,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } - if(defrange_target2 == 0) - { - break; - } // rjf: find current procedure's frameproc CV_SymFrameproc *frameproc = 0; @@ -6658,11 +3800,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel->off; RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location2 *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); + RDIM_Location *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, location, range, range_section, gaps, gap_count); - // TODO(rjf): p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_SUBFIELD_REGISTER @@ -6674,10 +3815,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } - if(defrange_target2 == 0) - { - break; - } // rjf: unpack sym CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; @@ -6696,12 +3833,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) // rjf: build location RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE @@ -6713,10 +3848,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } - if(defrange_target2 == 0) - { - break; - } // rjf: find current procedure's frameproc CV_SymFrameproc *frameproc = 0; @@ -6742,14 +3873,12 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_size = rdi_addr_size_from_arch(arch); U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit location over ranges RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_location_set_push_case(arena, sym_scopes, defrange_target, voff_range, location); - rdim_local_push_location_case(arena, sym_scopes, defrange_target2, loc, voff_range); + rdim_local_push_location_case(arena, sym_scopes, defrange_target, loc, voff_range); }break; //- rjf: DEFRANGE_REGISTER_REL @@ -6761,10 +3890,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) { break; } - if(defrange_target2 == 0) - { - break; - } // rjf: unpack sym CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; @@ -6782,12 +3907,10 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) B32 extra_indirection_to_value = 0; S64 var_off = defrange_register_rel->reg_off; RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - RDIM_Location2 *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Location *location = p2r_location_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target2, loc, range, range_section, gaps, gap_count); - p2r_location_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: FILESTATIC @@ -6798,7 +3921,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); // TODO(rjf): emit a global modifier symbol defrange_target = 0; - defrange_target2 = 0; defrange_target_is_param = 0; }break; @@ -6931,7 +4053,6 @@ p2r2_convert(Arena *arena, P2R_ConvertParams *params) SLLStackPush(free_scope_node, n); } defrange_target = 0; - defrange_target2 = 0; defrange_target_is_param = 0; }break; diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index d3ef3fa3..3682e0f7 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -19,88 +19,7 @@ struct P2R_ConvertParams }; //////////////////////////////// -//~ rjf: Initial PDB Information Extraction & Conversion Preparation Task Types - -//- rjf: tpi hash parsing - -typedef struct P2R_TPIHashParseIn P2R_TPIHashParseIn; -struct P2R_TPIHashParseIn -{ - PDB_Strtbl *strtbl; - PDB_TpiParsed *tpi; - String8 hash_data; - String8 aux_data; -}; - -//- rjf: tpi leaves parsing - -typedef struct P2R_TPILeafParseIn P2R_TPILeafParseIn; -struct P2R_TPILeafParseIn -{ - String8 leaf_data; - CV_TypeId itype_first; -}; - -//- rjf: exe hashing - -typedef struct P2R_EXEHashIn P2R_EXEHashIn; -struct P2R_EXEHashIn -{ - String8 exe_data; -}; - -//- rjf: symbol stream parsing - -typedef struct P2R_SymbolStreamParseIn P2R_SymbolStreamParseIn; -struct P2R_SymbolStreamParseIn -{ - String8 data; -}; - -//- rjf: c13 line info stream parsing - -typedef struct P2R_C13StreamParseIn P2R_C13StreamParseIn; -struct P2R_C13StreamParseIn -{ - String8 data; - String8 strtbl; - COFF_SectionHeaderArray coff_sections; -}; - -//- rjf: comp unit parsing - -typedef struct P2R_CompUnitParseIn P2R_CompUnitParseIn; -struct P2R_CompUnitParseIn -{ - String8 data; -}; - -//- rjf: comp unit contribution table parsing - -typedef struct P2R_CompUnitContributionsParseIn P2R_CompUnitContributionsParseIn; -struct P2R_CompUnitContributionsParseIn -{ - String8 data; - COFF_SectionHeaderArray coff_sections; -}; - -//- rjf: comp unit contribution table bucketing by unit - -typedef struct P2R_CompUnitContributionsBucketIn P2R_CompUnitContributionsBucketIn; -struct P2R_CompUnitContributionsBucketIn -{ - U64 comp_unit_count; - PDB_CompUnitContributionArray contributions; -}; - -typedef struct P2R_CompUnitContributionsBucketOut P2R_CompUnitContributionsBucketOut; -struct P2R_CompUnitContributionsBucketOut -{ - RDIM_Rng1U64ChunkList *unit_ranges; -}; - -//////////////////////////////// -//~ rjf: Conversion Data Structure & Task Types +//~ rjf: Shared Conversion State //- rjf: link name map (voff -> string) @@ -137,79 +56,7 @@ struct P2R_SrcFileMap U64 slots_count; }; -//- rjf: per-unit source files conversion tasks - -typedef struct P2R_GatherUnitSrcFilesIn P2R_GatherUnitSrcFilesIn; -struct P2R_GatherUnitSrcFilesIn -{ - PDB_Strtbl *pdb_strtbl; - COFF_SectionHeaderArray coff_sections; - PDB_CompUnit *comp_unit; - CV_SymParsed *comp_unit_syms; - CV_C13Parsed *comp_unit_c13s; -}; - -typedef struct P2R_GatherUnitSrcFilesOut P2R_GatherUnitSrcFilesOut; -struct P2R_GatherUnitSrcFilesOut -{ - String8Array src_file_paths; -}; - -//- rjf: unit conversion tasks - -typedef struct P2R_UnitConvertIn P2R_UnitConvertIn; -struct P2R_UnitConvertIn -{ - U64 comp_unit_idx; - PDB_Strtbl *pdb_strtbl; - COFF_SectionHeaderArray coff_sections; - PDB_CompUnit *comp_unit; - RDIM_Rng1U64ChunkList comp_unit_ranges; - CV_SymParsed *comp_unit_syms; - CV_C13Parsed *comp_unit_c13s; - P2R_SrcFileMap *src_file_map; -}; - -typedef struct P2R_UnitConvertOut P2R_UnitConvertOut; -struct P2R_UnitConvertOut -{ - RDIM_UnitChunkList units; - RDIM_LineTableChunkList line_tables; - RDIM_LineTable *unit_first_inline_site_line_table; -}; - -//- rjf: src file sequence equipping task - -typedef struct P2R_SrcFileSeqEquipIn P2R_SrcFileSeqEquipIn; -struct P2R_SrcFileSeqEquipIn -{ - RDIM_SrcFileChunkList src_files; - RDIM_LineTableChunkList line_tables; -}; - -//- rjf: link name map building tasks - -typedef struct P2R_LinkNameMapBuildIn P2R_LinkNameMapBuildIn; -struct P2R_LinkNameMapBuildIn -{ - CV_SymParsed *sym; - COFF_SectionHeaderArray coff_sections; - P2R_LinkNameMap *link_name_map; -}; - -//- rjf: type forward resolution map build - -typedef struct P2R_ITypeFwdMapFillIn P2R_ITypeFwdMapFillIn; -struct P2R_ITypeFwdMapFillIn -{ - PDB_TpiHashParsed *tpi_hash; - CV_LeafParsed *tpi_leaf; - CV_TypeId itype_first; - CV_TypeId itype_opl; - CV_TypeId *itype_fwd_map; -}; - -//- rjf: itype chain build +//- rjf: itype chains typedef struct P2R_TypeIdChain P2R_TypeIdChain; struct P2R_TypeIdChain @@ -218,64 +65,101 @@ struct P2R_TypeIdChain CV_TypeId itype; }; -typedef struct P2R_ITypeChainBuildIn P2R_ITypeChainBuildIn; -struct P2R_ITypeChainBuildIn +//- rjf: main state bundle + +typedef struct P2R2_Shared P2R2_Shared; +struct P2R2_Shared { - CV_LeafParsed *tpi_leaf; - CV_TypeId itype_first; - CV_TypeId itype_opl; - CV_TypeId *itype_fwd_map; - P2R_TypeIdChain **itype_chains; -}; - -//- rjf: udt conversion - -typedef struct P2R_UDTConvertIn P2R_UDTConvertIn; -struct P2R_UDTConvertIn -{ - CV_LeafParsed *tpi_leaf; - CV_TypeId itype_first; - CV_TypeId itype_opl; - CV_TypeId *itype_fwd_map; - RDIM_Type **itype_type_ptrs; -}; - -//- rjf: symbol stream conversion - -typedef struct P2R_SymbolStreamConvertIn P2R_SymbolStreamConvertIn; -struct P2R_SymbolStreamConvertIn -{ - B32 parsing_global_stream; - RDI_Arch arch; + MSF_RawStreamTable *msf_raw_stream_table; + U64 msf_stream_lane_counter; + MSF_Parsed *msf; + + PDB_Info *pdb_info; + PDB_NamedStreamTable *named_streams; + + PDB_Strtbl *strtbl; + String8 raw_strtbl; + PDB_DbiParsed *dbi; + PDB_TpiParsed *tpi; + PDB_TpiParsed *ipi; + COFF_SectionHeaderArray coff_sections; + PDB_GsiParsed *gsi; + PDB_GsiParsed *psi_gsi_part; + + U64 exe_hash; PDB_TpiHashParsed *tpi_hash; CV_LeafParsed *tpi_leaf; + PDB_TpiHashParsed *ipi_hash; CV_LeafParsed *ipi_leaf; - CV_SymParsed *sym; - U64 sym_ranges_first; - U64 sym_ranges_opl; + PDB_CompUnitArray *comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions; + RDIM_Rng1U64ChunkList *unit_ranges; + + U64 sym_c13_unit_lane_counter; + U64 all_syms_count; + CV_SymParsed **all_syms; // [0] -> global; rest are unit nums + CV_C13Parsed **all_c13s; // [0] -> blank (global); rest are unit nums + + U64 exe_voff_max; + RDI_Arch arch; + U64 symbol_count_prediction; + + P2R_LinkNameMap link_name_map; + + U64 sym_lane_take_counter; + + String8Array *unit_file_paths; + U64Array *unit_file_paths_hashes; + + U64 total_path_count; + + RDIM_SrcFileChunkList all_src_files__sequenceless; + P2R_SrcFileMap src_file_map; + + RDIM_UnitChunkList all_units; + RDIM_LineTableChunkList *units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables; + + RDIM_LineTableChunkList all_line_tables; + CV_TypeId *itype_fwd_map; + CV_TypeId itype_first; + CV_TypeId itype_opl; + + P2R_TypeIdChain **itype_chains; + RDIM_Type **itype_type_ptrs; - P2R_LinkNameMap *link_name_map; - RDIM_LineTable *first_inline_site_line_table; -}; - -typedef struct P2R_SymbolStreamConvertOut P2R_SymbolStreamConvertOut; -struct P2R_SymbolStreamConvertOut -{ - RDIM_SymbolChunkList procedures; - RDIM_SymbolChunkList global_variables; - RDIM_SymbolChunkList thread_variables; - RDIM_SymbolChunkList constants; - RDIM_ScopeChunkList scopes; - RDIM_InlineSiteChunkList inline_sites; - RDIM_TypeChunkList typedefs; + RDIM_Type **basic_type_ptrs; + RDIM_TypeChunkList all_types__pre_typedefs; + + RDIM_UDTChunkList *lanes_udts; + + RDIM_UDTChunkList all_udts; + + RDIM_LocationChunkList *syms_locations; + RDIM_SymbolChunkList *syms_procedures; + RDIM_SymbolChunkList *syms_global_variables; + RDIM_SymbolChunkList *syms_thread_variables; + RDIM_SymbolChunkList *syms_constants; + RDIM_ScopeChunkList *syms_scopes; + RDIM_InlineSiteChunkList *syms_inline_sites; + RDIM_TypeChunkList *syms_typedefs; + + RDIM_LocationChunkList all_locations; + RDIM_SymbolChunkList all_procedures; + RDIM_SymbolChunkList all_global_variables; + RDIM_SymbolChunkList all_thread_variables; + RDIM_SymbolChunkList all_constants; + RDIM_ScopeChunkList all_scopes; + RDIM_InlineSiteChunkList all_inline_sites; + RDIM_TypeChunkList all_types; }; //////////////////////////////// //~ rjf: Globals -global ASYNC_Root *p2r_async_root = 0; +global P2R2_Shared *p2r2_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers @@ -299,64 +183,13 @@ internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_ty //////////////////////////////// //~ rjf: Location Info Building Helpers -internal RDIM_Location *p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); -internal void p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); - internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); -internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location2 *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); - -//////////////////////////////// -//~ rjf: Initial Parsing & Preparation Pass Tasks - -ASYNC_WORK_DEF(p2r_exe_hash_work); -ASYNC_WORK_DEF(p2r_tpi_hash_parse_work); -ASYNC_WORK_DEF(p2r_tpi_leaf_work); -ASYNC_WORK_DEF(p2r_symbol_stream_parse_work); -ASYNC_WORK_DEF(p2r_c13_stream_parse_work); -ASYNC_WORK_DEF(p2r_comp_unit_parse_work); -ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work); -ASYNC_WORK_DEF(p2r_comp_unit_contributions_bucket_work); - -//////////////////////////////// -//~ rjf: Unit Source File Gathering Tasks - -ASYNC_WORK_DEF(p2r_gather_unit_src_file_work); - -//////////////////////////////// -//~ rjf: Unit Conversion Tasks - -ASYNC_WORK_DEF(p2r_unit_convert_work); - -//////////////////////////////// -//~ rjf: Source File Sequence Equipping Task - -ASYNC_WORK_DEF(p2r_src_file_seq_equip_work); - -//////////////////////////////// -//~ rjf: Link Name Map Building Tasks - -ASYNC_WORK_DEF(p2r_link_name_map_build_work); - -//////////////////////////////// -//~ rjf: Type Parsing/Conversion Tasks - -ASYNC_WORK_DEF(p2r_itype_fwd_map_fill_work); -ASYNC_WORK_DEF(p2r_itype_chain_build_work); - -//////////////////////////////// -//~ rjf: UDT Conversion Tasks - -ASYNC_WORK_DEF(p2r_udt_convert_work); - -//////////////////////////////// -//~ rjf: Symbol Stream Conversion Tasks - -ASYNC_WORK_DEF(p2r_symbol_stream_convert_work); +internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); //////////////////////////////// //~ rjf: Top-Level Conversion Entry Point -internal RDIM_BakeParams p2r2_convert(Arena *arena, P2R_ConvertParams *params); +internal RDIM_BakeParams p2r_convert(Arena *arena, P2R_ConvertParams *params); #endif // RDI_FROM_PDB_H diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.c b/src/rdi_from_pdb/rdi_from_pdb_2.c deleted file mode 100644 index 29202cab..00000000 --- a/src/rdi_from_pdb/rdi_from_pdb_2.c +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/rdi_from_pdb/rdi_from_pdb_2.h b/src/rdi_from_pdb/rdi_from_pdb_2.h deleted file mode 100644 index 6ed82691..00000000 --- a/src/rdi_from_pdb/rdi_from_pdb_2.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_FROM_PDB_2_H -#define RDI_FROM_PDB_2_H - -typedef struct P2R2_ConvertThreadParams P2R2_ConvertThreadParams; -struct P2R2_ConvertThreadParams -{ - Arena *arena; - LaneCtx lane_ctx; - String8 input_exe_name; - String8 input_exe_data; - String8 input_pdb_name; - String8 input_pdb_data; - B32 deterministic; - RDIM_BakeParams *out_bake_params; -}; - -typedef struct P2R2_Shared P2R2_Shared; -struct P2R2_Shared -{ - MSF_RawStreamTable *msf_raw_stream_table; - U64 msf_stream_lane_counter; - MSF_Parsed *msf; - - PDB_Info *pdb_info; - PDB_NamedStreamTable *named_streams; - - PDB_Strtbl *strtbl; - String8 raw_strtbl; - PDB_DbiParsed *dbi; - PDB_TpiParsed *tpi; - PDB_TpiParsed *ipi; - - COFF_SectionHeaderArray coff_sections; - PDB_GsiParsed *gsi; - PDB_GsiParsed *psi_gsi_part; - - U64 exe_hash; - PDB_TpiHashParsed *tpi_hash; - CV_LeafParsed *tpi_leaf; - PDB_TpiHashParsed *ipi_hash; - CV_LeafParsed *ipi_leaf; - PDB_CompUnitArray *comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions; - RDIM_Rng1U64ChunkList *unit_ranges; - - U64 sym_c13_unit_lane_counter; - U64 all_syms_count; - CV_SymParsed **all_syms; // [0] -> global; rest are unit nums - CV_C13Parsed **all_c13s; // [0] -> blank (global); rest are unit nums - - U64 exe_voff_max; - RDI_Arch arch; - U64 symbol_count_prediction; - - P2R_LinkNameMap link_name_map; - - U64 sym_lane_take_counter; - - String8Array *unit_file_paths; - U64Array *unit_file_paths_hashes; - - U64 total_path_count; - - RDIM_SrcFileChunkList all_src_files__sequenceless; - P2R_SrcFileMap src_file_map; - - RDIM_UnitChunkList all_units; - RDIM_LineTableChunkList *units_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables; - - RDIM_LineTableChunkList all_line_tables; - - CV_TypeId *itype_fwd_map; - CV_TypeId itype_first; - CV_TypeId itype_opl; - - P2R_TypeIdChain **itype_chains; - - RDIM_Type **itype_type_ptrs; - RDIM_Type **basic_type_ptrs; - RDIM_TypeChunkList all_types__pre_typedefs; - - RDIM_UDTChunkList *lanes_udts; - - RDIM_UDTChunkList all_udts; - - RDIM_LocationChunkList *syms_locations; - RDIM_SymbolChunkList *syms_procedures; - RDIM_SymbolChunkList *syms_global_variables; - RDIM_SymbolChunkList *syms_thread_variables; - RDIM_SymbolChunkList *syms_constants; - RDIM_ScopeChunkList *syms_scopes; - RDIM_InlineSiteChunkList *syms_inline_sites; - RDIM_TypeChunkList *syms_typedefs; - - RDIM_LocationChunkList all_locations; - RDIM_SymbolChunkList all_procedures; - RDIM_SymbolChunkList all_global_variables; - RDIM_SymbolChunkList all_thread_variables; - RDIM_SymbolChunkList all_constants; - RDIM_ScopeChunkList all_scopes; - RDIM_InlineSiteChunkList all_inline_sites; - RDIM_TypeChunkList all_types; -}; - -global P2R2_Shared *p2r2_shared = 0; - -#endif // RDI_FROM_PDB_2_H diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index a751530b..14f1839d 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -3,8 +3,6 @@ #include "lib_rdi_make/rdi_make.c" -//////////////////////////////// - internal RDIM_DataModel rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch) { @@ -19,8 +17,6 @@ rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch) return data_model; } -//////////////////////////////// - internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections) { @@ -52,1085 +48,2828 @@ rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_Binar return top_level_info; } -//////////////////////////////// -//~ rjf: Baking Stage Tasks - -//- rjf: bake string map building - -#define rdim_make_string_map_if_needed() do {if(in->maps[thread_idx] == 0) ProfScope("make map") {in->maps[thread_idx] = rdim_bake_string_map_loose_make(arena, in->top);}} while(0) - -ASYNC_WORK_DEF(rdim_bake_src_files_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeSrcFilesStringsIn *in = (RDIM_BakeSrcFilesStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake src file strings") rdim_bake_string_map_loose_push_src_files(arena, in->top, in->maps[thread_idx], in->list); - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_units_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeUnitsStringsIn *in = (RDIM_BakeUnitsStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake unit strings") rdim_bake_string_map_loose_push_units(arena, in->top, in->maps[thread_idx], in->list); - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_types_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeTypesStringsIn *in = (RDIM_BakeTypesStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake type strings") - { - for(RDIM_BakeTypesStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_type_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_udts_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeUDTsStringsIn *in = (RDIM_BakeUDTsStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake udt strings") - { - for(RDIM_BakeUDTsStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_udt_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_symbols_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeSymbolsStringsIn *in = (RDIM_BakeSymbolsStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake symbol strings") - { - for(RDIM_BakeSymbolsStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_symbol_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_inline_site_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeInlineSiteStringsIn *in = input; - rdim_make_string_map_if_needed(); - ProfScope("bake inline site strings") - { - for(RDIM_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_scopes_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeScopesStringsIn *in = (RDIM_BakeScopesStringsIn *)input; - rdim_make_string_map_if_needed(); - ProfScope("bake scope strings") - { - for(RDIM_BakeScopesStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_scope_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(rdim_bake_line_tables_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeLineTablesIn *in = (RDIM_BakeLineTablesIn *)input; - RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); - ProfScope("bake line tables") *out = rdim_bake_line_tables(arena, in->line_tables); - ProfEnd(); - return out; -} - -#undef rdim_make_string_map_if_needed - -//- rjf: bake string map joining - -ASYNC_WORK_DEF(rdim_bake_string_map_join_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_JoinBakeStringMapSlotsIn *in = (RDIM_JoinBakeStringMapSlotsIn *)input; - ProfScope("join bake string maps") - { - for(U64 src_map_idx = 0; src_map_idx < in->src_maps_count; src_map_idx += 1) - { - for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1) - { - B32 src_slots_good = (in->src_maps[src_map_idx] != 0 && in->src_maps[src_map_idx]->slots != 0); - B32 dst_slot_is_zero = (in->dst_map->slots[slot_idx] == 0); - if(src_slots_good && dst_slot_is_zero) - { - in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx]; - } - else if(src_slots_good && in->src_maps[src_map_idx]->slots[slot_idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]); - } - } - } - } - ProfEnd(); - return 0; -} - -//- rjf: bake string map sorting - -ASYNC_WORK_DEF(rdim_bake_string_map_sort_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_SortBakeStringMapSlotsIn *in = (RDIM_SortBakeStringMapSlotsIn *)input; - ProfScope("sort bake string chunk list map range") - { - for(U64 slot_idx = in->slot_idx; - slot_idx < in->slot_idx+in->slot_count; - slot_idx += 1) - { - if(in->src_map->slots[slot_idx] != 0) - { - if(in->src_map->slots[slot_idx]->total_count > 1) - { - in->dst_map->slots[slot_idx] = push_array(arena, RDIM_BakeStringChunkList, 1); - *in->dst_map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, in->src_map->slots[slot_idx]); - } - else - { - in->dst_map->slots[slot_idx] = in->src_map->slots[slot_idx]; - } - } - } - } - ProfEnd(); - return 0; -} - -//- rjf: pass 1: interner/deduper map builds - -ASYNC_WORK_DEF(rdim_build_bake_name_map_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BuildBakeNameMapIn *in = (RDIM_BuildBakeNameMapIn *)input; - RDIM_BakeNameMap *name_map = 0; - ProfScope("build name map %i", in->k) name_map = rdim_bake_name_map_from_kind_params(arena, in->k, in->params); - ProfEnd(); - return name_map; -} - -//- rjf: pass 2: string-map-dependent debug info stream builds - -ASYNC_WORK_DEF(rdim_bake_units_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeUnitsIn *in = (RDIM_BakeUnitsIn *)input; - RDIM_UnitBakeResult *out = push_array(arena, RDIM_UnitBakeResult, 1); - ProfScope("bake units") *out = rdim_bake_units(arena, in->strings, in->path_tree, in->units); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_unit_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeUnitVMapIn *in = (RDIM_BakeUnitVMapIn *)input; - RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); - ProfScope("bake unit vmap") *out = rdim_bake_unit_vmap(arena, in->units); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_src_files_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeSrcFilesIn *in = (RDIM_BakeSrcFilesIn *)input; - RDIM_SrcFileBakeResult *out = push_array(arena, RDIM_SrcFileBakeResult, 1); - ProfScope("bake src files") *out = rdim_bake_src_files(arena, in->strings, in->path_tree, in->src_files); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_udts_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeUDTsIn *in = (RDIM_BakeUDTsIn *)input; - RDIM_UDTBakeResult *out = push_array(arena, RDIM_UDTBakeResult, 1); - ProfScope("bake udts") *out = rdim_bake_udts(arena, in->strings, in->udts); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_global_variables_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeGlobalVariablesIn *in = (RDIM_BakeGlobalVariablesIn *)input; - RDIM_GlobalVariableBakeResult *out = push_array(arena, RDIM_GlobalVariableBakeResult, 1); - ProfScope("bake global variables") *out = rdim_bake_global_variables(arena, in->strings, in->global_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_global_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeGlobalVMapIn *in = (RDIM_BakeGlobalVMapIn *)input; - RDIM_GlobalVMapBakeResult *out = push_array(arena, RDIM_GlobalVMapBakeResult, 1); - ProfScope("bake global vmap") *out = rdim_bake_global_vmap(arena, in->global_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_thread_variables_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeThreadVariablesIn *in = (RDIM_BakeThreadVariablesIn *)input; - RDIM_ThreadVariableBakeResult *out = push_array(arena, RDIM_ThreadVariableBakeResult, 1); - ProfScope("bake thread variables") *out = rdim_bake_thread_variables(arena, in->strings, in->thread_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_constants_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeConstantsIn *in = (RDIM_BakeConstantsIn *)input; - RDIM_ConstantsBakeResult *out = push_array(arena, RDIM_ConstantsBakeResult, 1); - ProfScope("bake constants") *out = rdim_bake_constants(arena, in->strings, in->constants); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_procedures_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeProceduresIn *in = (RDIM_BakeProceduresIn *)input; - RDIM_ProcedureBakeResult *out = push_array(arena, RDIM_ProcedureBakeResult, 1); - ProfScope("bake procedures") *out = rdim_bake_procedures(arena, in->strings, in->location_blocks, in->location_data_blobs, in->procedures); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_scopes_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeScopesIn *in = (RDIM_BakeScopesIn *)input; - RDIM_ScopeBakeResult *out = push_array(arena, RDIM_ScopeBakeResult, 1); - ProfScope("bake scopes") *out = rdim_bake_scopes(arena, in->strings, in->location_blocks, in->location_data_blobs, in->scopes); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_scope_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeScopeVMapIn *in = (RDIM_BakeScopeVMapIn *)input; - RDIM_ScopeVMapBakeResult *out = push_array(arena, RDIM_ScopeVMapBakeResult, 1); - ProfScope("bake scope vmap") *out = rdim_bake_scope_vmap(arena, in->scopes); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_inline_sites_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeInlineSitesIn *in = (RDIM_BakeInlineSitesIn *)input; - RDIM_InlineSiteBakeResult *out = push_array(arena, RDIM_InlineSiteBakeResult, 1); - ProfScope("bake inline sites") *out = rdim_bake_inline_sites(arena, in->strings, in->inline_sites); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_file_paths_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeFilePathsIn *in = (RDIM_BakeFilePathsIn *)input; - RDIM_FilePathBakeResult *out = push_array(arena, RDIM_FilePathBakeResult, 1); - ProfScope("bake file paths") *out = rdim_bake_file_paths(arena, in->strings, in->path_tree); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_strings_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeStringsIn *in = (RDIM_BakeStringsIn *)input; - RDIM_StringBakeResult *out = push_array(arena, RDIM_StringBakeResult, 1); - ProfScope("bake strings") *out = rdim_bake_strings(arena, in->strings); - ProfEnd(); - return out; -} - -//- rjf: pass 3: idx-run-map-dependent debug info stream builds - -ASYNC_WORK_DEF(rdim_bake_type_nodes_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeTypeNodesIn *in = (RDIM_BakeTypeNodesIn *)input; - RDIM_TypeNodeBakeResult *out = push_array(arena, RDIM_TypeNodeBakeResult, 1); - ProfScope("bake type nodes") *out = rdim_bake_types(arena, in->strings, in->idx_runs, in->types); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_name_map_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeNameMapIn *in = (RDIM_BakeNameMapIn *)input; - RDIM_NameMapBakeResult *out = push_array(arena, RDIM_NameMapBakeResult, 1); - ProfScope("bake name map %i", in->kind) *out = rdim_bake_name_map(arena, in->strings, in->idx_runs, in->map); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(rdim_bake_idx_runs_work) -{ - ProfBeginFunction(); - Arena *arena = async_root_thread_arena(rdim_local_async_root); - RDIM_BakeIdxRunsIn *in = (RDIM_BakeIdxRunsIn *)input; - RDIM_IndexRunBakeResult *out = push_array(arena, RDIM_IndexRunBakeResult, 1); - ProfScope("bake idx runs") *out = rdim_bake_index_runs(arena, in->idx_runs); - ProfEnd(); - return out; -} - -internal U64 -rdim_local_hash(RDIM_String8 string) -{ - U64 hash = 5381; - U8 *ptr = string.str; - U8 *opl = string.str + string.size; - for (;ptr < opl; ++ptr) { - hash = ((hash << 5) + hash) + (*ptr); - } - return hash; -} - -internal void -rdim_local_resolve_incomplete_types(RDIM_TypeChunkList *types, RDIM_UDTChunkList *udts) -{ - ProfBeginFunction(); - - Temp scratch = scratch_begin(0,0); - - U64 total_type_count = types->total_count + 1; - - ProfBegin("Build Hash Table"); - RDIM_Type **name_ht = rdim_push_array(scratch.arena, RDIM_Type *, total_type_count); - for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) - { - for(RDI_U64 i = 0; i < chunk->count; i += 1) - { - RDIM_Type *type = &chunk->v[i]; - if(RDI_TypeKind_FirstUserDefined <= type->kind && type->kind <= RDI_TypeKind_LastRecord) - { - RDIM_String8 name = type->link_name.size ? type->link_name : type->name; - RDI_U64 hash = rdim_local_hash(name); - - RDI_U64 best_slot = hash % types->total_count; - RDI_U64 slot = best_slot; - do - { - RDIM_Type *s = name_ht[slot]; - if(s == 0) - { - break; - } - - if(s->link_name.size) - { - if(str8_match(s->link_name, name, 0)) - { - break; - } - } - else if(s->name.size) - { - if(str8_match(s->name, type->name, 0)) - { - break; - } - } - - slot = (slot + 1) % total_type_count; - } while (slot != best_slot); - - if(name_ht[slot] == 0) - { - name_ht[slot] = type; - } - } - } - } - ProfEnd(); - - ProfBegin("Make Fwd Map"); - RDIM_Type **fwd_map = rdim_push_array(scratch.arena, RDIM_Type *, total_type_count); - for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) - { - for(RDI_U64 i = 0; i < chunk->count; i += 1) - { - RDIM_Type *type = &chunk->v[i]; - - if(RDI_TypeKind_FirstIncomplete <= type->kind && type->kind <= RDI_TypeKind_LastIncomplete) - { - RDIM_String8 name = type->link_name.size ? type->link_name : type->name; - RDI_U64 hash = rdim_local_hash(name); - RDI_U64 best_slot = hash % types->total_count; - RDI_U64 slot = best_slot; - - RDIM_Type *match = 0; - do - { - if(name_ht[slot] == 0) - { - break; - } - RDIM_Type *s = name_ht[slot]; - if(s->link_name.size) - { - if(str8_match(s->link_name, type->link_name, 0)) - { - match = s; - break; - } - } - else - { - if(str8_match(s->name, type->name, 0)) - { - match = s; - break; - } - } - - slot = (slot + 1) % total_type_count; - } while(slot != best_slot); - - if(match) - { - type->kind = RDI_TypeKind_NULL; - - RDI_U64 type_idx = rdim_idx_from_type(type); - fwd_map[type_idx] = match; - } - } - } - } - ProfEnd(); - - ProfBegin("Resolve Types"); - for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) - { - for(RDI_U64 i = 0; i < chunk->count; ++i) - { - RDIM_Type *t = &chunk->v[i]; - if(t->direct_type) - { - RDI_U64 direct_idx = rdim_idx_from_type(t->direct_type); - if(fwd_map[direct_idx]) - { - t->direct_type = fwd_map[direct_idx]; - } - } - if(t->param_types) - { - for(RDI_U64 param_idx = 0; param_idx < t->count; param_idx += 1) - { - RDI_U64 type_idx = rdim_idx_from_type(t->param_types[param_idx]); - if(fwd_map[type_idx]) - { - t->param_types[param_idx] = fwd_map[type_idx]; - } - } - } - } - } - for(RDIM_UDTChunkNode *chunk = udts->first; chunk != 0; chunk = chunk->next) - { - for(RDI_U64 i = 0; i < chunk->count; ++i) - { - RDIM_UDT *udt = &chunk->v[i]; - RDI_U64 self_idx = rdim_idx_from_type(udt->self_type); - if(fwd_map[self_idx]) - { - udt->self_type = fwd_map[self_idx]; - } - - for(RDIM_UDTMember *member = udt->first_member; member != 0; member = member->next) - { - RDI_U64 member_idx = rdim_idx_from_type(member->type); - if(fwd_map[member_idx]) - { - member->type = fwd_map[member_idx]; - } - } - } - } - ProfEnd(); - - scratch_end(scratch); - ProfEnd(); -} - internal RDIM_BakeResults -rdim_bake(Arena *arena, ASYNC_Root *async_root, RDIM_BakeParams *in_params) +rdim2_bake(Arena *arena, RDIM_BakeParams *params) { - Temp scratch = scratch_begin(0,0); - RDIM_BakeResults out = {0}; - rdim_local_async_root = async_root; - - ////////////////////////////// - //- rjf: kick off line tables baking + ////////////////////////////////////////////////////////////// + //- rjf: set up shared state // - ASYNC_Task *bake_line_tables_task = 0; + if(lane_idx() == 0) { - RDIM_BakeLineTablesIn *in = push_array(scratch.arena, RDIM_BakeLineTablesIn, 1); - in->line_tables = &in_params->line_tables; - bake_line_tables_task = async_task_launch(scratch.arena, rdim_bake_line_tables_work, .input = in); + rdim2_shared = push_array(arena, RDIM2_Shared, 1); } + lane_sync(); - ////////////////////////////// - //- rjf: build interned path tree + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers // - RDIM_BakePathTree *path_tree = 0; - ProfScope("build interned path tree") + ProfScope("gather unsorted vmap keys/markers") { - path_tree = rdim_bake_path_tree_from_params(arena, in_params); - } - - ////////////////////////////// - //- rjf: kick off string map building tasks - // - RDIM_BakeStringMapTopology bake_string_map_topology = {(64 + - in_params->procedures.total_count*1 + - in_params->global_variables.total_count*1 + - in_params->thread_variables.total_count*1 + - in_params->types.total_count/2)}; - RDIM_BakeStringMapLoose **bake_string_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringMapLoose *, async_thread_count()); - ASYNC_TaskList bake_string_map_build_tasks = {0}; - { - // rjf: src files - ProfScope("kick off src files string map build task") + //- rjf: gather scope vmap keys/markers + if(lane_idx() == lane_from_task_idx(0)) ProfScope("gather scope vmap keys/markers") { - RDIM_BakeSrcFilesStringsIn *in = push_array(scratch.arena, RDIM_BakeSrcFilesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - in->list = &in_params->src_files; - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_src_files_strings_work, .input = in)); - } - - // rjf: units - ProfScope("kick off units string map build task") - { - RDIM_BakeUnitsStringsIn *in = push_array(scratch.arena, RDIM_BakeUnitsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - in->list = &in_params->units; - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_units_strings_work, .input = in)); - } - - // rjf: types - ProfScope("kick off types string map build tasks") - { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->types.total_count+items_per_task-1)/items_per_task; - RDIM_TypeChunkNode *chunk = in_params->types.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; + rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); + rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); + ProfScope("fill keys/markers") { - RDIM_BakeTypesStringsIn *in = push_array(scratch.arena, RDIM_BakeTypesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) + RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; + RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; + for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - RDIM_BakeTypesStringsInNode *n = push_array(scratch.arena, RDIM_BakeTypesStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) + for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) { - chunk = chunk->next; - chunk_off = 0; + RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; + RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 + for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) + { + key_ptr->key = n->v.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = n->v.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } } } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_types_strings_work, .input = in)); } } - // rjf: UDTs - ProfScope("kick off udts string map build tasks") + //- rjf: gather unit vmap keys/markers + if(lane_idx() == lane_from_task_idx(1)) ProfScope("gather unit vmap keys/markers") { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->udts.total_count+items_per_task-1)/items_per_task; - RDIM_UDTChunkNode *chunk = in_params->udts.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + // rjf: count voff ranges + RDI_U64 voff_range_count = 0; + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) { - RDIM_BakeUDTsStringsIn *in = push_array(scratch.arena, RDIM_BakeUDTsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) + for(RDI_U64 idx = 0; idx < n->count; idx += 1) { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - RDIM_BakeUDTsStringsInNode *n = push_array(scratch.arena, RDIM_BakeUDTsStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) + RDIM_Unit *unit = &n->v[idx]; + voff_range_count += unit->voff_ranges.total_count; + } + } + + // rjf: count necessary markers + RDI_U64 marker_count = voff_range_count*2; + + // rjf: build keys/markers arrays + RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + RDI_U32 unit_idx = 1; + for(RDIM_UnitChunkNode *unit_chunk_n = params->units.first; + unit_chunk_n != 0; + unit_chunk_n = unit_chunk_n->next) + { + for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) { - chunk = chunk->next; - chunk_off = 0; + RDIM_Unit *unit = &unit_chunk_n->v[idx]; + for(RDIM_Rng1U64ChunkNode *n = unit->voff_ranges.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Rng1U64 range = n->v[chunk_idx]; + if(range.min < range.max) + { + key_ptr->key = range.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = range.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + } + unit_idx += 1; } } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_udts_strings_work, .input = in)); + } + + // rjf: store + rdim2_shared->unit_vmap_count = marker_count; + rdim2_shared->unit_vmap_keys = keys; + rdim2_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim2_shared->unit_vmap_markers = markers; + } + + //- rjf: gather global vmap keys/markers + if(lane_idx() == lane_from_task_idx(2)) ProfScope("gather global vmap keys/markers") + { + //- rjf: allocate keys/markers + RDI_U64 marker_count = params->global_variables.total_count*2 + 2; + RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); + + //- rjf: fill + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + + // rjf: fill actual globals + for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Symbol *global_var = &n->v[chunk_idx]; + RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 + RDI_U64 global_var_size = global_var->type ? global_var->type->byte_size : 1; + + RDI_U64 first = global_var->offset; + RDI_U64 opl = first + global_var_size; + + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + // rjf: fill nil global + { + RDI_U32 global_idx = 0; + RDI_U64 first = 0; + RDI_U64 opl = 0xffffffffffffffffull; + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + //- rjf: store + rdim2_shared->global_vmap_count = marker_count; + rdim2_shared->global_vmap_keys = keys; + rdim2_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim2_shared->global_vmap_markers = markers; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage sort all vmap keys + // + ProfScope("sort all vmap keys") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); + rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); + } + lane_sync(); + + // rjf: sort + struct + { + RDI_U64 vmap_count; + RDIM_SortKey *keys; + RDIM_SortKey *keys__swap; + } + sort_tasks[] = + { + {rdim2_shared->scope_vmap_count, rdim2_shared->scope_vmap_keys, rdim2_shared->scope_vmap_keys__swap}, + {rdim2_shared->unit_vmap_count, rdim2_shared->unit_vmap_keys, rdim2_shared->unit_vmap_keys__swap}, + {rdim2_shared->global_vmap_count, rdim2_shared->global_vmap_keys, rdim2_shared->global_vmap_keys__swap}, + }; + for EachElement(sort_task_idx, sort_tasks) ProfScope("sort %I64u", sort_task_idx) + { + RDI_U64 vmap_count = sort_tasks[sort_task_idx].vmap_count; + RDIM_SortKey *keys = sort_tasks[sort_task_idx].keys; + RDIM_SortKey *keys__swap = sort_tasks[sort_task_idx].keys__swap; + U64 bits_per_digit = 8; + U64 digits_count = 64 / bits_per_digit; + U64 num_possible_values_per_digit = 1 << bits_per_digit; + rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + RDIM_SortKey *src = keys; + RDIM_SortKey *dst = keys__swap; + U64 element_count = vmap_count; + for EachIndex(digit_idx, digits_count) + { + // rjf: count digit value occurrences per-lane + { + U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; + MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + RDIM_SortKey *sort_key = &src[idx]; + U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); + digit_counts[digit_value] += 1; + } + } + lane_sync(); + + // rjf: compute thread * digit value *relative* offset table + { + Rng1U64 range = lane_range(num_possible_values_per_digit); + for EachInRange(value_idx, range) + { + U64 layout_off = 0; + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; + } + } + } + lane_sync(); + + // rjf: convert relative offsets -> absolute offsets + if(lane_idx() == 0) + { + U64 last_off = 0; + U64 num_of_nonzero_digit = 0; + for EachIndex(value_idx, num_possible_values_per_digit) + { + for EachIndex(lane_idx, lane_count()) + { + rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; + } + last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; + } + // NOTE(rjf): required that: (last_off == element_count) + } + lane_sync(); + + // rjf: move + { + U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + RDIM_SortKey *src_key = &src[idx]; + U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); + U64 dst_off = lane_digit_offsets[digit_value]; + lane_digit_offsets[digit_value] += 1; + MemoryCopyStruct(&dst[dst_off], src_key); + } + } + lane_sync(); + + // rjf: swap + { + RDIM_SortKey *swap = src; + src = dst; + dst = swap; + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake all vmaps + // + ProfScope("bake all vmaps") + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct VMapBakeTask VMapBakeTask; + struct VMapBakeTask + { + VMapBakeTask *next; + String8 name; + RDI_U64 count; + RDIM_SortKey *keys; + RDIM_VMapMarker *markers; + RDIM_BakeVMap *bake_vmap_out; + }; + VMapBakeTask *first_task = 0; + VMapBakeTask *last_task = 0; + if(lane_idx() == lane_from_task_idx(0)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("scopes"); + task->count = rdim2_shared->scope_vmap_count; + task->keys = rdim2_shared->scope_vmap_keys; + task->markers = rdim2_shared->scope_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_scope_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + if(lane_idx() == lane_from_task_idx(1)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("units"); + task->count = rdim2_shared->unit_vmap_count; + task->keys = rdim2_shared->unit_vmap_keys; + task->markers = rdim2_shared->unit_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_unit_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + if(lane_idx() == lane_from_task_idx(2)) + { + VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); + task->name = str8_lit("globals"); + task->count = rdim2_shared->global_vmap_count; + task->keys = rdim2_shared->global_vmap_keys; + task->markers = rdim2_shared->global_vmap_markers; + task->bake_vmap_out = &rdim2_shared->baked_global_vmap.vmap; + SLLQueuePush(first_task, last_task, task); + } + for(VMapBakeTask *task = first_task; task != 0; task = task->next) ProfScope("vmap bake for %.*s", str8_varg(task->name)) + { + //- rjf: determine if an extra vmap entry for zero is needed + RDI_U32 extra_vmap_entry = 0; + if(task->count > 0 && task->keys[0].key != 0) + { + extra_vmap_entry = 1; + } + + //- rjf: fill output vmap entries + RDI_U32 vmap_count_raw = extra_vmap_entry + task->count; + RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw); + RDI_U32 vmap_entry_count_pass_1 = 0; + ProfScope("fill output vmap entries") + { + typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; + struct RDIM_VMapRangeTracker + { + RDIM_VMapRangeTracker *next; + RDI_U32 idx; + }; + RDI_VMapEntry *vmap_ptr = vmap; + if(extra_vmap_entry) + { + vmap_ptr->voff = 0; + vmap_ptr->idx = 0; + vmap_ptr += 1; + } + RDIM_VMapRangeTracker *tracker_stack = 0; + RDIM_VMapRangeTracker *tracker_free = 0; + RDIM_SortKey *key_ptr = task->keys; + RDIM_SortKey *key_opl = task->keys + task->count; + for(;key_ptr < key_opl;) + { + // rjf: get initial map state from tracker stack + RDI_U32 initial_idx = (RDI_U32)0xffffffff; + if(tracker_stack != 0) + { + initial_idx = tracker_stack->idx; + } + + // rjf: update tracker stack + // + // * we must process _all_ of the changes that apply at this voff before moving on + // + RDI_U64 voff = key_ptr->key; + + for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) + { + RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; + RDI_U32 idx = marker->idx; + + // rjf: range begin -> push to stack + if(marker->begin_range) + { + RDIM_VMapRangeTracker *new_tracker = tracker_free; + if(new_tracker != 0) + { + RDIM_SLLStackPop(tracker_free); + } + else + { + new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); + } + RDIM_SLLStackPush(tracker_stack, new_tracker); + new_tracker->idx = idx; + } + + // rjf: range ending -> pop matching node from stack (not always the top) + else + { + RDIM_VMapRangeTracker **ptr_in = &tracker_stack; + RDIM_VMapRangeTracker *match = 0; + for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) + { + if(node->idx == idx) + { + match = node; + break; + } + ptr_in = &node->next; + node = node->next; + } + if(match != 0) + { + *ptr_in = match->next; + RDIM_SLLStackPush(tracker_free, match); + } + } + } + + // rjf: get final map state from tracker stack + RDI_U32 final_idx = 0; + if(tracker_stack != 0) + { + final_idx = tracker_stack->idx; + } + + // rjf: if final is different from initial - emit new vmap entry + if(final_idx != initial_idx) + { + vmap_ptr->voff = voff; + vmap_ptr->idx = final_idx; + vmap_ptr += 1; + } + } + + vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: combine duplicate neighbors + RDI_U32 vmap_entry_count = 0; + ProfScope("combine duplicate neighbors") + { + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; + RDI_VMapEntry *vmap_out = vmap; + for(;vmap_ptr < vmap_opl;) + { + RDI_VMapEntry *vmap_range_first = vmap_ptr; + RDI_U64 idx = vmap_ptr->idx; + vmap_ptr += 1; + for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; + rdim_memcpy_struct(vmap_out, vmap_range_first); + vmap_out += 1; + } + vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill result + task->bake_vmap_out->vmap = vmap; + task->bake_vmap_out->count = vmap_entry_count; + } + scratch_end(scratch); + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage build interned path tree + // + if(lane_idx() == 0) ProfScope("build interned path tree") + { + //- rjf: set up tree + RDIM_BakePathTree *tree = rdim_push_array(arena, RDIM_BakePathTree, 1); + rdim_bake_path_tree_insert(arena, tree, rdim_str8_lit("")); + + //- rjf: bake unit file paths + RDIM_ProfScope("bake unit file paths") + { + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + rdim_bake_path_tree_insert(arena, tree, n->v[idx].source_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].object_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].archive_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].build_path); + } } } - // rjf: symbols - ProfScope("kick off symbols string map build tasks") + //- rjf: bake source file paths + RDIM_ProfScope("bake source file paths") { + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, tree, n->v[idx].path); + node->src_file = &n->v[idx]; + } + } + } + + rdim2_shared->path_tree = tree; + } + lane_sync(); + RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage gather all unsorted, joined, line table info; & sort + // + ProfScope("gather all unsorted, joined, line table info; & sort") + { + //- rjf: set up outputs + ProfScope("set up outputs") + { + // rjf: calculate header info + if(lane_idx() == 0) + { + rdim2_shared->line_tables_count = params->line_tables.total_count; + rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + ProfScope("flatten chunk list") + { + U64 joined_idx = 0; + for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) + { + for EachIndex(idx, n->count) + { + rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; + joined_idx += 1; + } + } + } + rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; + rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim2_shared->baked_line_tables.line_table_columns_count= 1; + rdim2_shared->line_table_block_take_counter = 0; + } + lane_sync(); + + // rjf: allocate outputs + ProfScope("allocate outputs") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); + ProfScope("lay out line tables") + { + U64 voffs_base_idx = 0; + U64 lines_base_idx = 0; + U64 cols_base_idx = 0; + for EachIndex(idx, rdim2_shared->line_tables_count) + { + U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil + RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; + RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; + dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 + dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 + dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 + voffs_base_idx += src->line_count + 2*src->seq_count; + lines_base_idx += src->line_count + 1*src->seq_count; + } + } + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); + } + if(lane_idx() == lane_from_task_idx(5)) + { + rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); + } + } + } + lane_sync(); + + //- rjf: wide bake + ProfScope("wide bake") + { + U64 line_table_block_size = 4096; + U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; + for(;;) + { + U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); + if(0 == line_table_block_num || line_table_block_count < line_table_block_num) + { + break; + } + U64 line_table_block_idx = line_table_block_num-1; + Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); + line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); + for EachInRange(line_table_idx, line_table_range) + { + RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + + //- rjf: gather + dst->line_count = src->line_count; + dst->seq_count = src->seq_count; + dst->key_count = dst->line_count + dst->seq_count; + dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); + dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); + { + RDIM_SortKey *key_ptr = dst->line_keys; + RDIM_LineRec *rec_ptr = dst->line_recs; + for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) + { + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + { + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + + //- rjf: sort + rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, + rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); + + //- rjf: fill + RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; + U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; + RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; + { + for EachIndex(idx, sorted_line_keys_count) + { + arranged_voffs[idx] = sorted_line_keys[idx].key; + } + arranged_voffs[sorted_line_keys_count] = ~0ull; + for EachIndex(idx, sorted_line_keys_count) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; + if(rec != 0) + { + arranged_lines[idx].file_idx = rec->file_id; + arranged_lines[idx].line_num = rec->line_num; + } + else + { + arranged_lines[idx].file_idx = 0; + arranged_lines[idx].line_num = 0; + } + } + } + } + } + } + } + lane_sync(); + RDI_U64 line_tables_count = rdim2_shared->line_tables_count; + RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; + RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage build string map + // + ProfScope("build string map") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") + { + rdim2_shared->bake_string_map_topology.slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + } + RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; + + //- rjf: push all strings into this lane's map + ProfScope("push all strings into this lane's map") + { + // rjf: push small top-level strings + if(lane_idx() == 0) ProfScope("push small top-level strings") + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.exe_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.producer_name); + for(RDIM_BinarySectionNode *n = params->binary_sections.first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->v.name); + } + for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->name); + } + } + + // rjf: push strings from source files + ProfScope("src files") + { + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[n_idx].path); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, normalized_path); + } + } + } + + // rjf: push strings from units + ProfScope("units") + { + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].unit_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].compiler_name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].source_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].object_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].archive_file); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].build_path); + } + } + } + + // rjf: push strings from types + ProfScope("types") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + } + } + } + + // rjf: push strings from udts + ProfScope("udts") + { + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(mem, RDIM_UDTMember, n->v[idx].first_member) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, mem->name); + } + for EachNode(enum_val, RDIM_UDTEnumVal, n->v[idx].first_enum_val) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, enum_val->name); + } + } + } + } + + // rjf: push strings from symbols RDIM_SymbolChunkList *symbol_lists[] = { - &in_params->global_variables, - &in_params->thread_variables, - &in_params->procedures, - &in_params->constants, + ¶ms->global_variables, + ¶ms->thread_variables, + ¶ms->procedures, + ¶ms->constants, }; - for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1) + ProfScope("symbols") { - U64 items_per_task = 4096; - U64 num_tasks = (symbol_lists[list_idx]->total_count+items_per_task-1)/items_per_task; - RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + for EachElement(list_idx, symbol_lists) { - RDIM_BakeSymbolsStringsIn *in = push_array(scratch.arena, RDIM_BakeSymbolsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) + for EachNode(n, RDIM_SymbolChunkNode, symbol_lists[list_idx]->first) { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - RDIM_BakeSymbolsStringsInNode *n = push_array(scratch.arena, RDIM_BakeSymbolsStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - chunk = chunk->next; - chunk_off = 0; + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].link_name); } } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_symbols_strings_work, .input = in)); } } - } - - // rjf: inline sites - ProfScope("kick off inline site string map build task") - { - U64 items_per_task = 4096; - U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task); - RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + + //- rjf: push strings from inline sites + ProfScope("inline sites") { - RDIM_BakeInlineSiteStringsIn *in = push_array(scratch.arena, RDIM_BakeInlineSiteStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - RDIM_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, RDIM_BakeInlineSiteStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - chunk = chunk->next; - chunk_off = 0; + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); } } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_inline_site_strings_work, .input = in)); } - } - - // rjf: scope chunks - ProfScope("kick off scope chunks string map build tasks") - { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->scopes.total_count+items_per_task-1)/items_per_task; - RDIM_ScopeChunkNode *chunk = in_params->scopes.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + + //- rjf: push strings from scopes + ProfScope("scopes") { - RDIM_BakeScopesStringsIn *in = push_array(scratch.arena, RDIM_BakeScopesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - RDIM_BakeScopesStringsInNode *n = push_array(scratch.arena, RDIM_BakeScopesStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) { - chunk = chunk->next; - chunk_off = 0; + for EachNode(local, RDIM_Local, n->v[n_idx].first_local) + { + rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, local->name); + } } } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_scopes_strings_work, .input = in)); } } - } - - ////////////////////////////// - //- rjf: kick off name map building tasks - // - RDIM_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0}; - ASYNC_Task *build_bake_name_map_task[RDI_NameMapKind_COUNT] = {0}; - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - build_bake_name_map_in[k].k = k; - build_bake_name_map_in[k].params = in_params; - build_bake_name_map_task[k] = async_task_launch(scratch.arena, rdim_build_bake_name_map_work, .input = &build_bake_name_map_in[k]); - } - - ////////////////////////////// - //- rjf: join string map building tasks - // - ProfScope("join string map building tasks") - { - for(ASYNC_TaskNode *n = bake_string_map_build_tasks.first; n != 0; n = n->next) - { - async_task_join(n->v); - } - } - - ////////////////////////////// - //- rjf: produce joined string map - // - RDIM_BakeStringMapLoose *unsorted_bake_string_map = rdim_bake_string_map_loose_make(arena, &bake_string_map_topology); - ProfScope("produce joined string map") - { - U64 slots_per_task = 16384; - U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, num_tasks); + lane_sync(); - // rjf: kickoff tasks - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + //- rjf: join + ProfScope("join") { - RDIM_JoinBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_JoinBakeStringMapSlotsIn, 1); - in->top = &bake_string_map_topology; - in->src_maps = bake_string_maps__in_progress; - in->src_maps_count = async_thread_count(); - in->dst_map = unsorted_bake_string_map; - in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task); - in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count); - tasks[task_idx] = async_task_launch(scratch.arena, rdim_bake_string_map_join_work, .input = in); - } - - // rjf: join tasks - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - async_task_join(tasks[task_idx]); - } - - // rjf: insert small top-level stuff - rdim_bake_string_map_loose_push_top_level_info(arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->top_level_info); - rdim_bake_string_map_loose_push_binary_sections(arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->binary_sections); - rdim_bake_string_map_loose_push_path_tree(arena, &bake_string_map_topology, unsorted_bake_string_map, path_tree); - } - - ////////////////////////////// - //- rjf: kick off string map sorting tasks - // - ASYNC_TaskList sort_bake_string_map_tasks = {0}; - RDIM_BakeStringMapLoose *sorted_bake_string_map__in_progress = rdim_bake_string_map_loose_make(arena, &bake_string_map_topology); - { - U64 slots_per_task = 256; - U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - RDIM_SortBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_SortBakeStringMapSlotsIn, 1); + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) { - in->top = &bake_string_map_topology; - in->src_map = unsorted_bake_string_map; - in->dst_map = sorted_bake_string_map__in_progress; - in->slot_idx = task_idx*slots_per_task; - in->slot_count = slots_per_task; - if(in->slot_idx+in->slot_count > bake_string_map_topology.slots_count) + for EachIndex(src_lane_idx, lane_count()) { - in->slot_count = bake_string_map_topology.slots_count - in->slot_idx; + RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } } } - async_task_list_push(scratch.arena, &sort_bake_string_map_tasks, async_task_launch(scratch.arena, rdim_bake_string_map_sort_work, .input = in)); } - } - - ////////////////////////////// - //- rjf: join string map sorting tasks - // - ProfScope("join string map sorting tasks") - { - for(ASYNC_TaskNode *n = sort_bake_string_map_tasks.first; n != 0; n = n->next) + lane_sync(); + + //- rjf: sort + ProfScope("sort") { - async_task_join(n->v); - } - } - RDIM_BakeStringMapLoose *sorted_bake_string_map = sorted_bake_string_map__in_progress; - - ////////////////////////////// - //- rjf: build finalized string map - // - ProfBegin("build finalized string map base indices"); - RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(arena, &bake_string_map_topology, sorted_bake_string_map); - ProfEnd(); - ProfBegin("build finalized string map"); - RDIM_BakeStringMapTight bake_strings = rdim_bake_string_map_tight_from_loose(arena, &bake_string_map_topology, &bake_string_map_base_idxes, sorted_bake_string_map); - ProfEnd(); - - ////////////////////////////// - //- rjf: kick off pass 2 tasks - // - RDIM_BakeUnitsIn bake_units_top_level_in = {&bake_strings, path_tree, &in_params->units}; - ASYNC_Task *bake_units_task = async_task_launch(scratch.arena, rdim_bake_units_work, .input = &bake_units_top_level_in); - RDIM_BakeUnitVMapIn bake_unit_vmap_in = {&in_params->units}; - ASYNC_Task *bake_unit_vmap_task = async_task_launch(scratch.arena, rdim_bake_unit_vmap_work, .input = &bake_unit_vmap_in); - RDIM_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, &in_params->src_files}; - ASYNC_Task *bake_src_files_task = async_task_launch(scratch.arena, rdim_bake_src_files_work, .input = &bake_src_files_in); - RDIM_BakeUDTsIn bake_udts_in = {&bake_strings, &in_params->udts}; - ASYNC_Task *bake_udts_task = async_task_launch(scratch.arena, rdim_bake_udts_work, .input = &bake_udts_in); - RDIM_BakeGlobalVMapIn bake_global_vmap_in = {&in_params->global_variables}; - ASYNC_Task *bake_global_vmap_task = async_task_launch(scratch.arena, rdim_bake_global_vmap_work, .input = &bake_global_vmap_in); - RDIM_BakeScopeVMapIn bake_scope_vmap_in = {&in_params->scopes}; - ASYNC_Task *bake_scope_vmap_task = async_task_launch(scratch.arena, rdim_bake_scope_vmap_work, .input = &bake_scope_vmap_in); - RDIM_BakeInlineSitesIn bake_inline_sites_in = {&bake_strings, &in_params->inline_sites}; - ASYNC_Task *bake_inline_sites_task = async_task_launch(scratch.arena, rdim_bake_inline_sites_work, .input = &bake_inline_sites_in); - RDIM_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; - ASYNC_Task *bake_file_paths_task = async_task_launch(scratch.arena, rdim_bake_file_paths_work, .input = &bake_file_paths_in); - RDIM_BakeStringsIn bake_strings_in = {&bake_strings}; - ASYNC_Task *bake_strings_task = async_task_launch(scratch.arena, rdim_bake_strings_work, .input = &bake_strings_in); - RDIM_BakeConstantsIn bake_constants_in = {&bake_strings, &in_params->constants}; - ASYNC_Task *bake_constants_task = async_task_launch(scratch.arena, rdim_bake_constants_work, .input = &bake_constants_in); - - ////////////////////////////// - //- rjf: (GIANT SERIAL DEPENDENCY CHAIN HACK OF LOCATION BLOCK BUILDING) - // - // TODO(rjf): // TODO(rjf): // TODO(rjf): { - // - // This needs to be majorly cleaned up. We are doing this giant - // serial-dependency chain of async tasks (thus removing all async - // properties) because each async task here is secretly mutating - // the same input parameter (something which breaks the rules & - // style used everywhere else in the converter). - // - // Location blocks for each category of symbol should be built - // & arranged in parallel, then joined via a very thin operation - // after the fact. We should not ever be secretly mutating input - // parameters to async tasks, we need to be only returning new - // stuff. - // - RDIM_String8List location_blocks = {0}; - RDIM_String8List location_data_blobs = {0}; - { - // reserve null location block for opl - rdim_location_block_chunk_list_push_array(arena, &location_blocks, 1); - - // TODO: export location instead of VOFF - RDIM_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, &in_params->global_variables}; - ASYNC_Task *bake_global_variables_task = async_task_launch(scratch.arena, rdim_bake_global_variables_work, .input = &bake_global_variables_in); - ProfScope("global variables") out.global_variables = *async_task_join_struct(bake_global_variables_task, RDIM_GlobalVariableBakeResult); - - // TODO: export location instead of VOFF - RDIM_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, &in_params->thread_variables}; - ASYNC_Task *bake_thread_variables_task = async_task_launch(scratch.arena, rdim_bake_thread_variables_work, .input = &bake_thread_variables_in); - ProfScope("thread variables") out.thread_variables = *async_task_join_struct(bake_thread_variables_task, RDIM_ThreadVariableBakeResult); - - RDIM_BakeScopesIn bake_scopes_in = {&bake_strings, &in_params->scopes, &location_blocks, &location_data_blobs}; - ASYNC_Task *bake_scopes_task = async_task_launch(scratch.arena, rdim_bake_scopes_work, .input = &bake_scopes_in); - ProfScope("scopes") out.scopes = *async_task_join_struct(bake_scopes_task, RDIM_ScopeBakeResult); - - RDIM_BakeProceduresIn bake_procedures_in = {&bake_strings, &in_params->procedures, &location_blocks, &location_data_blobs}; - ASYNC_Task *bake_procedures_task = async_task_launch(scratch.arena, rdim_bake_procedures_work, .input = &bake_procedures_in); - ProfScope("procedures") out.procedures = *async_task_join_struct(bake_procedures_task, RDIM_ProcedureBakeResult); - } - // - //- TODO(rjf): // TODO(rjf): // TODO(rjf): } - ////////////////////////////// - - ////////////////////////////// - //- rjf: join name map building tasks - // - RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT] = {0}; - ProfScope("join name map building tasks") - { - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - name_maps[k] = async_task_join_struct(build_bake_name_map_task[k], RDIM_BakeNameMap); - } - } - - ////////////////////////////// - //- rjf: build interned idx run map - // - RDIM_BakeIdxRunMap *idx_runs = 0; - ProfScope("build interned idx run map") - { - idx_runs = rdim_bake_idx_run_map_from_params(arena, name_maps, in_params); - } - - ////////////////////////////// - //- rjf: do small top-level bakes - // - ProfScope("top level info") out.top_level_info = rdim_bake_top_level_info(arena, &bake_strings, &in_params->top_level_info); - ProfScope("binary sections") out.binary_sections = rdim_bake_binary_sections(arena, &bake_strings, &in_params->binary_sections); - ProfScope("top level name maps section") out.top_level_name_maps = rdim_bake_name_maps_top_level(arena, &bake_strings, idx_runs, name_maps); - - ////////////////////////////// - //- rjf: kick off pass 3 tasks - // - RDIM_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, &in_params->types}; - ASYNC_Task *bake_type_nodes_task = async_task_launch(scratch.arena, rdim_bake_type_nodes_work, .input = &bake_type_nodes_in); - ASYNC_Task *bake_name_maps_tasks[RDI_NameMapKind_COUNT] = {0}; - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - if(name_maps[k] == 0 || name_maps[k]->name_count == 0) + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) { - continue; + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + lane_sync(); + + //- rjf: tighten string table + ProfScope("tighten string table") + { + RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; + RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); + rdim2_shared->bake_strings.slots_count = map_top->slots_count; + rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); + rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; + rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + for EachInRange(idx, slot_range) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + } + } } - RDIM_BakeNameMapIn *in = push_array(scratch.arena, RDIM_BakeNameMapIn, 1); - in->strings = &bake_strings; - in->idx_runs = idx_runs; - in->map = name_maps[k]; - in->kind = k; - bake_name_maps_tasks[k] = async_task_launch(scratch.arena, rdim_bake_name_map_work, .input = in); } } - RDIM_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; - ASYNC_Task *bake_idx_runs_task = async_task_launch(scratch.arena, rdim_bake_idx_runs_work, .input = &bake_idx_runs_in); + lane_sync(); + RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; - ////////////////////////////// - //- rjf: join remaining completed bakes + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage build name maps // - ProfScope("top-level units info") out.units = *async_task_join_struct(bake_units_task, RDIM_UnitBakeResult); - ProfScope("unit vmap") out.unit_vmap = *async_task_join_struct(bake_unit_vmap_task, RDIM_UnitVMapBakeResult); - ProfScope("source files") out.src_files = *async_task_join_struct(bake_src_files_task, RDIM_SrcFileBakeResult); - ProfScope("UDTs") out.udts = *async_task_join_struct(bake_udts_task, RDIM_UDTBakeResult); - ProfScope("global vmap") out.global_vmap = *async_task_join_struct(bake_global_vmap_task, RDIM_GlobalVMapBakeResult); - ProfScope("scope vmap") out.scope_vmap = *async_task_join_struct(bake_scope_vmap_task, RDIM_ScopeVMapBakeResult); - ProfScope("inline sites") out.inline_sites = *async_task_join_struct(bake_inline_sites_task, RDIM_InlineSiteBakeResult); - ProfScope("file paths") out.file_paths = *async_task_join_struct(bake_file_paths_task, RDIM_FilePathBakeResult); - ProfScope("strings") out.strings = *async_task_join_struct(bake_strings_task, RDIM_StringBakeResult); - ProfScope("constants") out.constants = *async_task_join_struct(bake_constants_task, RDIM_ConstantsBakeResult); - ProfScope("type nodes") out.type_nodes = *async_task_join_struct(bake_type_nodes_task, RDIM_TypeNodeBakeResult); - ProfScope("idx runs") out.idx_runs = *async_task_join_struct(bake_idx_runs_task, RDIM_IndexRunBakeResult); - ProfScope("line tables") out.line_tables = *async_task_join_struct(bake_line_tables_task, RDIM_LineTableBakeResult); - - ////////////////////////////// - //- rjf: join individual name map bakes - // - RDIM_NameMapBakeResult name_map_bakes[RDI_NameMapKind_COUNT] = {0}; - ProfScope("name maps") + ProfScope("build name maps") { - for EachNonZeroEnumVal(RDI_NameMapKind, k) + //- rjf: set up + if(lane_idx() == 0) { - RDIM_NameMapBakeResult *bake = async_task_join_struct(bake_name_maps_tasks[k], RDIM_NameMapBakeResult); - if(bake != 0) + for EachNonZeroEnumVal(RDI_NameMapKind, k) { - name_map_bakes[k] = *bake; + U64 slot_count = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; +#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break + Case(GlobalVariables, params->global_variables.total_count); + Case(ThreadVariables, params->thread_variables.total_count); + Case(Constants, params->constants.total_count); + Case(Procedures, params->procedures.total_count); + Case(LinkNameProcedures, params->procedures.total_count); + Case(Types, params->types.total_count); + Case(NormalSourcePaths, params->src_files.total_count); +#undef Case + } + rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); + rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; + } + } + lane_sync(); + + //- rjf: wide build + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_make(arena, top); + RDIM_BakeNameMap *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; + B32 link_names = 0; + RDIM_SymbolChunkList *symbols = 0; + switch((RDI_NameMapKindEnum)k) + { + case RDI_NameMapKind_NULL: + case RDI_NameMapKind_COUNT: + {}break; + case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; + case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; + case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; + case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; + symbol_name_map_build:; + { + for EachNode(n, RDIM_SymbolChunkNode, symbols->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Symbol *symbol = &n->v[n_idx]; + rdim_bake_name_map_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); + } + } + }break; + case RDI_NameMapKind_Types: + { + RDIM_TypeChunkList *types = ¶ms->types; + for EachNode(n, RDIM_TypeChunkNode, types->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_Type *type = &n->v[n_idx]; + rdim_bake_name_map_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); + } + } + }break; + case RDI_NameMapKind_NormalSourcePaths: + { + RDIM_SrcFileChunkList *src_files = ¶ms->src_files; + for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) + { + Rng1U64 n_range = lane_range(n->count); + for EachInRange(n_idx, n_range) + { + RDIM_SrcFile *src_file = &n->v[n_idx]; + RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); + rdim_bake_name_map_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); + } + } + }break; + } + } + lane_sync(); + + //- rjf: join & sort + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_make(arena, &rdim2_shared->bake_name_map_topology[k]); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeNameMap *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap *dst_map = map; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + + //- rjf: sort + ProfScope("sort") + { + Rng1U64 slot_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage build index runs + // + ProfScope("build index runs") + { + //- rjf: set up per-lane outputs + if(lane_idx() == 0) ProfScope("set up per-lane outputs") + { + rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + + params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->types.total_count); + rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + lane_sync(); + + //- rjf: set up this lane's map + ProfScope("set up this lane's map") + { + rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + } + RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + + //- rjf: wide fill of all index runs + ProfScope("fill all lane index run maps") + { + //- rjf: bake runs of function-type parameter lists + ProfScope("bake runs of function-type parameter lists") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) + { + RDIM_Type *type = &n->v[n_idx]; + if(type->count == 0) + { + continue; + } + if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = type->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); + } + } + } + } + + //- rjf: bake runs of name map match lists + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 slot_idx_range = lane_range(top->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; + if(slot != 0) + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + String8 active_string = {0}; + RDIM_BakeNameChunkNode *n = slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + String8 string = {0}; + U64 idx = 0; + if(n != 0) + { + string = n->v[n_idx].string; + idx = n->v[n_idx].idx; + } + + // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list + if(!str8_match(string, active_string, 0)) + { + if(active_idx_count > 1) + { + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); + } + active_string = string; + first_idx_run_node = 0; + last_idx_run_node = 0; + active_idx_count = 0; + temp_end(scratch); + } + + // rjf: new element matches the active list -> push + if(active_string.size != 0 && str8_match(string, active_string, 0)) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); + } + } + } + } + lane_sync(); + + //- rjf: join + ProfScope("join") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + for EachIndex(src_lane_idx, lane_count()) + { + RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; + if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) + { + dst_map->slots[slot_idx] = src_map->slots[slot_idx]; + } + else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) + { + rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); + } + } + } + } + lane_sync(); + + //- rjf: sort + ProfScope("sort") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + for EachInRange(slot_idx, slot_range) + { + if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) + { + *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); + map->slots_idx_counts[slot_idx] = 0; + for EachNode(n, RDIM_BakeIdxRunChunkNode, map->slots[slot_idx]->first) + { + for EachIndex(idx, n->count) + { + map->slots_idx_counts[slot_idx] += n->v[idx].count; + } + } + } + } + } + lane_sync(); + + //- rjf: tighten idx run table + ProfScope("tighten idx run table") + { + RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; + if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") + { + rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); + rdim2_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim2_shared->bake_idx_runs.slots_count+1); + RDI_U64 encoding_idx_off = 0; + for(RDI_U64 slot_idx = 0; slot_idx < map_top->slots_count; slot_idx += 1) + { + rdim2_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; + if(map->slots[slot_idx] != 0) + { + encoding_idx_off += map->slots_idx_counts[slot_idx]; + } + } + rdim2_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; + } + lane_sync(); + ProfScope("fill tight map") + { + Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); + for EachInRange(idx, slot_range) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); + } + } + } + } + } + lane_sync(); + RDIM_BakeIdxRunMap *bake_idx_runs = &rdim2_shared->bake_idx_runs; + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake strings + // + ProfScope("bake strings") + { + // rjf: set up + if(lane_idx() == 0) ProfScope("set up; lay out strings") + { + rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; + rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); + RDI_U64 off_cursor = 0; + for EachIndex(slot_idx, bake_strings->slots_count) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; + off_cursor += src->string.size; + } + } + } + rdim2_shared->baked_strings.string_data_size = off_cursor; + rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); + } + lane_sync(); + + // rjf: wide fill string data + ProfScope("wide fill") + { + Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); + for EachInRange(slot_idx, slot_idx_range) + { + for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) + { + for EachIndex(n_idx, n->count) + { + RDIM_BakeString *src = &n->v[n_idx]; + U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; + U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; + rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); + } + } + } + } + } + lane_sync(); + RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake idx runs + // + ProfScope("bake idx runs") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; + rdim2_shared->baked_idx_runs.idx_runs = push_array(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); + } + lane_sync(); + + // rjf: wide fill + { + Rng1U64 range = lane_range(bake_idx_runs->slots_count); + for EachInRange(slot_idx, range) + { + RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; + for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) + { + StaticAssert(sizeof(rdim2_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); + for EachIndex(n_idx, n->count) + { + rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); + off += n->v[n_idx].count; + } + } + } + } + } + lane_sync(); + RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake name maps + // + ProfScope("bake name maps") + { + // rjf: count unique names in all name maps; lay out baked nodes + ProfScope("count unique names in all name maps; lay out baked nodes") + { + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->lane_name_map_node_counts[k] = push_array(arena, U64, lane_count()); + rdim2_shared->lane_name_map_node_offs[k] = push_array(arena, U64, lane_count()); + } + } + lane_sync(); + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + Rng1U64 range = lane_range(top->slots_count); + for EachInRange(idx, range) + { + if(map->slots[idx] != 0) + { + U64 total_unique_name_count = 0; + U64 last_hash = 0; + for EachNode(n, RDIM_BakeNameChunkNode, map->slots[idx]->first) + { + for EachIndex(n_idx, n->count) + { + if(n->v[n_idx].hash != last_hash) + { + total_unique_name_count += 1; + last_hash = n->v[n_idx].hash; + } + } + } + rdim2_shared->lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; + } + } + } + lane_sync(); + if(lane_idx() == 0) + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDI_U64 node_off = 0; + for EachIndex(l_idx, lane_count()) + { + rdim2_shared->name_map_node_counts[k] += rdim2_shared->lane_name_map_node_counts[k][l_idx]; + rdim2_shared->lane_name_map_node_offs[k][l_idx] = node_off; + node_off += rdim2_shared->lane_name_map_node_counts[k][l_idx]; + } + rdim2_shared->total_name_map_node_count += rdim2_shared->name_map_node_counts[k]; + } + } + } + lane_sync(); + + // rjf: setup + ProfScope("setup") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_top_level_name_maps.name_maps_count = RDI_NameMapKind_COUNT; + rdim2_shared->baked_top_level_name_maps.name_maps = push_array(arena, RDI_NameMap, rdim2_shared->baked_top_level_name_maps.name_maps_count); + RDI_U32 bucket_off = 0; + RDI_U32 node_off = 0; + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; + rdim2_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; + rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim2_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 + rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim2_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 + bucket_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count; + node_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count; + } + rdim2_shared->baked_name_maps.buckets_count = bucket_off; + rdim2_shared->baked_name_maps.buckets = push_array(arena, RDI_NameMapBucket, rdim2_shared->baked_name_maps.buckets_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_name_maps.nodes_count = rdim2_shared->total_name_map_node_count; + rdim2_shared->baked_name_maps.nodes = push_array(arena, RDI_NameMapNode, rdim2_shared->baked_name_maps.nodes_count); + } + } + lane_sync(); + + // rjf: wide fill baked name maps + ProfScope("wide fill baked name maps") + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) + { + RDI_U64 write_node_off = rdim2_shared->lane_name_map_node_offs[k][lane_idx()]; + RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + U64 slots_count = top->slots_count; + RDIM_BakeNameMap *src_map = rdim2_shared->bake_name_maps[k]; + RDI_NameMap *dst_map = &rdim2_shared->baked_top_level_name_maps.name_maps[k]; + RDI_NameMapBucket *dst_buckets = rdim2_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; + RDI_NameMapNode *dst_nodes = rdim2_shared->baked_name_maps.nodes + dst_map->node_base_idx; + Rng1U64 slot_range = lane_range(slots_count); + for EachInRange(slot_idx, slot_range) + { + RDIM_BakeNameChunkList *src_slot = src_map->slots[slot_idx]; + if(src_slot == 0) { continue; } + RDI_NameMapBucket *dst_bucket = &dst_buckets[slot_idx]; + dst_bucket->first_node = write_node_off; + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct IdxRunNode IdxRunNode; + struct IdxRunNode + { + IdxRunNode *next; + RDI_U64 idx; + }; + IdxRunNode *first_idx_run_node = 0; + IdxRunNode *last_idx_run_node = 0; + U64 active_idx_count = 0; + String8 active_string = {0}; + RDIM_BakeNameChunkNode *n = src_slot->first; + U64 n_idx = 0; + for(;;) + { + // rjf: advance chunk + if(n != 0 && n_idx >= n->count) + { + n = n->next; + n_idx = 0; + } + + // rjf: grab next element + U64 idx = 0; + String8 string = {0}; + if(n != 0) + { + idx = n->v[n_idx].idx; + string = n->v[n_idx].string; + } + + // rjf: next element doesn't match the active list? -> push index run, clear active list, start new list + if(!str8_match(active_string, string, 0)) + { + // rjf: has active run -> flatten & serialize + if(active_string.size != 0) + { + // rjf: flatten idxes + RDI_U64 idxs_count = active_idx_count; + RDI_U32 *idxs = rdim_push_array(scratch.arena, RDI_U32, idxs_count); + { + U64 write_idx = 0; + for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) + { + idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 + write_idx += 1; + } + } + + // rjf: serialize node + RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; + dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); + dst_node->match_count = idxs_count; + if(dst_node->match_count == 1) + { + dst_node->match_idx_or_idx_run_first = idxs[0]; + } + else if(dst_node->match_count > 1) + { + dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run(bake_idx_runs, idxs, idxs_count); + } + dst_bucket->node_count += 1; + write_node_off += 1; + } + + // rjf: start new list + active_string = string; + first_idx_run_node = 0; + last_idx_run_node = 0; + active_idx_count = 0; + temp_end(scratch); + } + + // rjf: hash matches the active list -> push + if(active_string.size != 0 && str8_match(active_string, string, 0)) + { + IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); + idx_run_n->idx = idx; + SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); + active_idx_count += 1; + } + + // rjf: advance index + n_idx += 1; + + // rjf: end on zero node + if(n == 0) + { + break; + } + } + scratch_end(scratch); + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage gather line-bucketed src line map data + // + ProfScope("gather line-bucketed src line map data") + { + if(lane_idx() == 0) + { + rdim2_shared->bake_src_line_maps = push_array(arena, RDIM_BakeSrcLineMap, params->src_files.total_count); + } + lane_sync(); + { + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + U64 file_idx = n->base_idx + n_idx; + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[file_idx]; + + // rjf: set up map + map->slots_count = n->v[n_idx].total_line_count; + map->slots = push_array(arena, RDIM_BakeSrcLineMapSlot, map->slots_count); + + // rjf: gather line-bucketed info + for EachNode(frag, RDIM_SrcFileLineMapFragment, n->v[n_idx].first_line_map_fragment) + { + RDIM_LineSequence *seq = frag->seq; + for EachIndex(idx, seq->line_count) + { + RDI_U32 line_num = seq->line_nums[idx]; + RDI_U64 voff_first = seq->voffs[idx]; + RDI_U64 voff_opl = seq->voffs[idx+1]; + RDI_U64 slot_idx = line_num%map->slots_count; + + // rjf: find existing line node + RDIM_BakeSrcLineMapNode *line_node = 0; + { + for EachNode(line_n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) + { + if(line_n->line_num == line_num) + { + line_node = line_n; + break; + } + } + } + + // rjf: construct new node if unseen + if(line_node == 0) + { + line_node = push_array(arena, RDIM_BakeSrcLineMapNode, 1); + SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, line_node); + line_node->line_num = line_num; + map->line_count += 1; + } + + // rjf: push this voff range + RDIM_Rng1U64 voff_range = {voff_first, voff_opl}; + rdim_rng1u64_list_push(arena, &line_node->voff_ranges, voff_range); + map->voff_range_count += 1; + } + } + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage sort line-bucketed src line map data + // + ProfScope("sort line-bucketed src line map data") + { + U64 map_count = params->src_files.total_count; + if(lane_idx() == 0) + { + rdim2_shared->bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); + } + lane_sync(); + for(;;) + { + U64 map_num = ins_atomic_u64_inc_eval(&rdim2_shared->bake_src_line_map_take_counter); + if(map_num < 1 || map_count < map_num) + { + break; + } + U64 map_idx = map_num-1; + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[map_idx]; + + // rjf: gather keys + rdim2_shared->bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); + RDIM_SortKey *keys = rdim2_shared->bake_src_line_map_keys[map_idx]; + { + U64 key_idx = 0; + for EachIndex(slot_idx, map->slots_count) + { + for EachNode(n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) + { + keys[key_idx].key = n->line_num; + keys[key_idx].val = n; + key_idx += 1; + } + } + } + + // rjf: sort keys + { + radsort(keys, map->line_count, rdim_sort_key_is_before); } } } - ////////////////////////////// - //- rjf: join all individual name map bakes + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute src file / src file line map layout // - ProfScope("join all name map bakes into final name map bake") + ProfScope("compute src file / src file line map layout") { - out.name_maps = rdim_name_map_bake_results_combine(arena, name_map_bakes, ArrayCount(name_map_bakes)); + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim2_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + } + lane_sync(); + + // rjf: wide count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + for EachInRange(idx, range) + { + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; + rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; + rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; + rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 num_layout_off = 0; + U64 voff_layout_off = 0; + U64 map_layout_off = 1; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; + rdim2_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; + rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; + rdim2_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; + num_layout_off += rdim2_shared->lane_chunk_src_file_num_counts[slot_idx]; + voff_layout_off += rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx]; + map_layout_off += rdim2_shared->lane_chunk_src_file_map_counts[slot_idx]; + } + chunk_idx += 1; + } + rdim2_shared->total_src_map_line_count = num_layout_off; + rdim2_shared->total_src_map_voff_count = voff_layout_off; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake src files + // + ProfScope("bake src files") + { + //- rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); + rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); + rdim2_shared->baked_src_files.source_line_map_nums_count = rdim2_shared->total_src_map_line_count; + rdim2_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_nums_count); + rdim2_shared->baked_src_files.source_line_map_rngs_count = rdim2_shared->total_src_map_line_count + rdim2_shared->baked_src_files.source_line_maps_count; + rdim2_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_rngs_count); + rdim2_shared->baked_src_files.source_line_map_voffs_count = rdim2_shared->total_src_map_voff_count; + rdim2_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_src_files.source_line_map_voffs_count); + } + lane_sync(); + + //- rjf: bake + U64 chunk_idx = 0; + for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) + { + Rng1U64 range = lane_range(n->count); + U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; + U64 dst_num_off = rdim2_shared->lane_chunk_src_file_num_offs[slot_idx]; + U64 dst_map_off = rdim2_shared->lane_chunk_src_file_map_offs[slot_idx]; + U64 dst_voff_off = rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx]; + U64 dst_rng_off = dst_num_off + dst_map_off; + for EachInRange(idx, range) + { + RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; + RDIM_SortKey *sorted_map_keys = rdim2_shared->bake_src_line_map_keys[n->base_idx + idx]; + RDIM_SrcFile *src = &n->v[idx]; + RDI_SourceFile *dst = &rdim2_shared->baked_src_files.source_files[n->base_idx + idx + 1]; + RDI_SourceLineMap *dst_map = &rdim2_shared->baked_src_files.source_line_maps[dst_map_off]; + RDI_U32 *dst_nums = &rdim2_shared->baked_src_files.source_line_map_nums[dst_num_off]; + RDI_U32 *dst_rngs = &rdim2_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; + RDI_U64 *dst_voffs = &rdim2_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; + + //- rjf: fill file info + Temp scratch = scratch_begin(&arena, 1); + String8 normalized_path = rdim_lower_from_str8(scratch.arena, src->path); + dst->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src->path); + dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); + dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; + scratch_end(scratch); + + //- rjf: fill map info + if(src->total_line_count != 0) + { + dst_map->line_count = (RDI_U32)map->line_count; // TODO(rjf): @u64_to_u32 + dst_map->voff_count = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 + dst_map->line_map_nums_base_idx = (RDI_U32)dst_num_off; // TODO(rjf): @u64_to_u32 + dst_map->line_map_range_base_idx = (RDI_U32)dst_rng_off; // TODO(rjf): @u64_to_u32 + dst_map->line_map_voff_base_idx = (RDI_U32)dst_voff_off; // TODO(rjf): @u64_to_u32 + dst_map_off += 1; + } + + //- rjf: fill nums/ranges/voffs info + if(src->total_line_count != 0) + { + U64 *dst_voff_ptr = dst_voffs; + for EachIndex(line_num_idx, map->line_count) + { + dst_nums[line_num_idx] = (RDI_U32)sorted_map_keys[line_num_idx].key; // TODO(rjf): @u64_to_u32 + dst_rngs[line_num_idx] = (RDI_U32)(dst_voff_ptr - dst_voffs); // TODO(rjf): @u64_to_u32 + RDIM_BakeSrcLineMapNode *node = (RDIM_BakeSrcLineMapNode *)sorted_map_keys[line_num_idx].val; + for EachNode(rng_n, RDIM_Rng1U64Node, node->voff_ranges.first) + { + dst_voff_ptr[0] = rng_n->v.min; + dst_voff_ptr += 1; + } + } + dst_rngs[map->line_count] = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 + dst_num_off += map->line_count; + dst_rng_off += map->line_count+1; + dst_voff_off += map->voff_range_count; + } + } + chunk_idx += 1; + } } - //////////////////////////////// + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts + // + ProfScope("compute lane UDT member/enum-val layouts") + { + // rjf: allocate + if(lane_idx() == 0) + { + rdim2_shared->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim2_shared->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + } + lane_sync(); + + // rjf: count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + U64 slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; + rdim2_shared->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; + rdim2_shared->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 member_layout_off = 1; + U64 enum_val_layout_off = 1; + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->udts.chunk_count + chunk_idx; + rdim2_shared->member_chunk_lane_offs[slot_idx] = member_layout_off; + rdim2_shared->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; + member_layout_off += rdim2_shared->member_chunk_lane_counts[slot_idx]; + enum_val_layout_off += rdim2_shared->enum_val_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + } + lane_sync(); - out.location_blocks = rdim_str8_list_join(arena, &location_blocks, rdim_str8(0,0)); - out.location_data = rdim_str8_list_join(arena, &location_data_blobs, rdim_str8(0,0)); + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake UDTs + // + ProfScope("bake UDTs") + { + //- rjf: set up + ProfScope("set up") + { + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; + rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; + rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + } + } + lane_sync(); + + //- rjf: bake UDTs + ProfScope("bake UDTs") + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_UDTChunkNode, params->udts.first) + { + Rng1U64 range = lane_range(n->count); + U64 layout_slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; + U64 member_layout_off = rdim2_shared->member_chunk_lane_offs[layout_slot_idx]; + U64 enum_val_layout_off = rdim2_shared->enum_val_chunk_lane_offs[layout_slot_idx]; + for EachInRange(n_idx, range) + { + RDIM_UDT *src_udt = &n->v[n_idx]; + RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + + //- rjf: fill member info + if(src_udt->first_member != 0) + { + U64 member_off_first = member_layout_off; + for EachNode(src_member, RDIM_UDTMember, src_udt->first_member) + { + RDI_Member *dst_member = &rdim2_shared->baked_udts.members[member_layout_off]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + member_layout_off += 1; + } + U64 member_off_opl = member_layout_off; + dst_udt->member_first = (RDI_U32)member_off_first; // TODO(rjf): @u64_to_u32 + dst_udt->member_count = (RDI_U32)(member_off_opl - member_off_first); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill enum val info + else if(src_udt->first_enum_val != 0) + { + U64 enum_val_off_first = enum_val_layout_off; + for EachNode(src_enum_val, RDIM_UDTEnumVal, src_udt->first_enum_val) + { + RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[enum_val_layout_off]; + dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_enum_val->name); + dst_member->val = src_enum_val->val; + enum_val_layout_off += 1; + } + U64 enum_val_off_opl = enum_val_layout_off; + dst_udt->flags |= RDI_UDTFlag_EnumMembers; + dst_udt->member_first = (RDI_U32)enum_val_off_first; // TODO(rjf): @u64_to_u32 + dst_udt->member_count = (RDI_U32)(enum_val_off_opl - enum_val_off_first); // TODO(rjf): @u64_to_u32 + } + } + chunk_idx += 1; + } + } + } + lane_sync(); - rdim_local_async_root = 0; - scratch_end(scratch); - return out; + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute lane location block layout + // + U64 total_location_case_chunk_count = (params->scopes.chunk_count + params->procedures.chunk_count); + ProfScope("compute lane location block layout") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->location_case_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + rdim2_shared->location_case_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + } + lane_sync(); + + // rjf: per-chunk-lane count of location cases + { + // rjf: count location cases in scopes + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(local, RDIM_Local, n->v[idx].first_local) + { + rdim2_shared->location_case_chunk_lane_counts[slot_idx] += local->location_cases.count; + } + } + chunk_idx += 1; + } + + // rjf: count location cases in procedures + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + rdim2_shared->location_case_chunk_lane_counts[slot_idx] += n->v[idx].location_cases.count; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out location case offsets + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 location_case_layout_off = 1; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; + rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; + rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + rdim2_shared->total_location_case_count = location_case_layout_off; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake location blocks + // + ProfScope("bake location blocks") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_location_blocks.location_blocks_count = rdim2_shared->total_location_case_count; + rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + } + lane_sync(); + + // rjf: wide fill from scopes + U64 chunk_idx = 0; + ProfScope("wide fill from scopes") + { + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(local, RDIM_Local, n->v[idx].first_local) + { + for EachNode(src, RDIM_LocationCase, local->location_cases.first) + { + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 + layout_off += 1; + } + } + } + chunk_idx += 1; + } + } + + // rjf: wide fill from procedures + ProfScope("wide fill from procedures") + { + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + for EachNode(src, RDIM_LocationCase, n->v[idx].location_cases.first) + { + RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 + dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 + dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 + layout_off += 1; + } + } + chunk_idx += 1; + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake locations + // + ProfScope("bake locations") + { + if(lane_idx() == 0) + { + rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + } + lane_sync(); + for EachNode(n, RDIM_LocationChunkNode, params->locations.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Location *loc = &n->v[n_idx]; + RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + switch((RDI_LocationKindEnum)loc->info.kind) + { + case RDI_LocationKind_NULL:{}break; + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); + RDI_U64 write_off = sizeof(loc->info.kind); + for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) + { + MemoryCopy(dst + write_off, &op_node->op, 1); + write_off += 1; + MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); + write_off += op_node->p_size; + } + dst[write_off] = 0; + }break; + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + case RDI_LocationKind_ValReg: + { + RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; + MemoryCopy(dst, &baked, sizeof(baked)); + }break; + } + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) + // + ProfScope("compute layout for scope sub-lists (locals / voffs)") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + } + lane_sync(); + + // rjf: count per-lane-chunk + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + U64 num_locals_in_this_lane_and_node = 0; + U64 num_voffs_in_this_lane_and_node = 0; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + num_locals_in_this_lane_and_node += n->v[n_idx].local_count; + num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; + } + rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; + rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: lay out each lane's range + if(lane_idx() == 0) + { + U64 local_layout_off = 1; + U64 voff_layout_off = 1; + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; + rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; + rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; + local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; + voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + lane_sync(); + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake scopes + // + ProfScope("bake scopes") + { + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; + rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; + rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; + rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); + } + lane_sync(); + + //- rjf: wide fill + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) + { + Rng1U64 range = lane_range(n->count); + U64 scope_chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; + U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 location_block_chunk_lane_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; + U64 chunk_location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_chunk_lane_slot_idx]; + for EachInRange(n_idx, range) + { + U64 dst_idx = 1 + n->base_idx + n_idx; + RDIM_Scope *src_scope = &n->v[n_idx]; + RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; + + //- rjf: fill voff ranges + U64 voff_idx_first = chunk_voff_off; + for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) + { + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; + rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; + chunk_voff_off += 2; + } + U64 voff_idx_opl = chunk_voff_off; + + //- rjf: fill locals + U64 local_idx_first = chunk_local_off; + for EachNode(src_local, RDIM_Local, src_scope->first_local) + { + RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; + dst_local->kind = src_local->kind; + dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); + dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 + if(src_local->location_cases.count != 0) + { + dst_local->location_first = chunk_location_block_off; + dst_local->location_opl = chunk_location_block_off + src_local->location_cases.count; + chunk_location_block_off += src_local->location_cases.count; + } + chunk_local_off += 1; + } + U64 local_idx_opl = chunk_local_off; + + //- rjf: fill scope + dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 + dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 + dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 + dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 + dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 + dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake procedures + // + ProfScope("bake procedures") + { + if(lane_idx() == 0) + { + rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + } + lane_sync(); + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) + { + U64 location_block_layout_slot_idx = lane_idx()*total_location_case_chunk_count + params->scopes.chunk_count + chunk_idx; + U64 location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_layout_slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_Procedure *dst = &rdim2_shared->baked_procedures.procedures[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 + if(src->location_cases.count != 0) + { + dst->frame_base_location_first = location_block_off; + dst->frame_base_location_opl = location_block_off + src->location_cases.count; + location_block_off += src->location_cases.count; + } + } + chunk_idx += 1; + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage compute layout for constant data + // + ProfScope("compute layout for constant data") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); + rdim2_shared->constant_data_chunk_lane_offs = push_array(arena, U64, lane_count() * params->constants.chunk_count); + } + lane_sync(); + + // rjf: count + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; + Rng1U64 range = lane_range(n->count); + for EachInRange(idx, range) + { + rdim2_shared->constant_data_chunk_lane_counts[slot_idx] += n->v[idx].value_data.size; + } + chunk_idx += 1; + } + } + lane_sync(); + + // rjf: layout + if(lane_idx() == 0) + { + U64 chunk_idx = 0; + U64 layout_off = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + for EachIndex(l_idx, lane_count()) + { + U64 slot_idx = l_idx*params->constants.chunk_count + chunk_idx; + rdim2_shared->constant_data_chunk_lane_offs[slot_idx] = layout_off; + layout_off += rdim2_shared->constant_data_chunk_lane_counts[slot_idx]; + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake constants + // + ProfScope("bake constants") + { + // rjf: set up + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + } + lane_sync(); + + // rjf: wide bake + { + U64 chunk_idx = 0; + for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) + { + U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; + U64 value_data_off = rdim2_shared->constant_data_chunk_lane_offs[slot_idx]; + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_Constant *dst = &rdim2_shared->baked_constants.constants[1 + n->base_idx + n_idx]; + RDI_U32 *dst_value_off = &rdim2_shared->baked_constants.constant_values[1 + n->base_idx + n_idx]; + RDI_U8 *dst_value_data = rdim2_shared->baked_constants.constant_value_data + value_data_off; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->constant_value_idx = 1 + n->base_idx + n_idx; + dst_value_off[0] = (RDI_U32)value_data_off; // TODO(rjf): @u64_to_u32 + rdim_memcpy(dst_value_data, src->value_data.str, src->value_data.size); + value_data_off += src->value_data.size; + } + chunk_idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs + // + { + //- rjf: setup outputs + if(lane_idx() == lane_from_task_idx(0)) + { + rdim2_shared->baked_units.units_count = params->units.total_count+1; + rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); + } + if(lane_idx() == lane_from_task_idx(1)) + { + rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; + rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); + } + if(lane_idx() == lane_from_task_idx(2)) + { + rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; + rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); + } + if(lane_idx() == lane_from_task_idx(3)) + { + rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; + rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); + } + if(lane_idx() == lane_from_task_idx(4)) + { + rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; + rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + } + lane_sync(); + + //- rjf: bake units + ProfScope("bake units") + { + for EachNode(n, RDIM_UnitChunkNode, params->units.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Unit *src = &n->v[n_idx]; + RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; + dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); + dst->language = src->language; + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + + //- rjf: bake type nodes + ProfScope("bake type nodes") + { + for EachNode(n, RDIM_TypeChunkNode, params->types.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Type *src = &n->v[n_idx]; + RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; + + //- rjf: fill shared type node info + dst->kind = src->kind; + dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 + dst->byte_size = src->byte_size; + + //- rjf: fill built-in-only type node info + if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) + { + dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + } + + //- rjf: fill array sizes + else if(dst->kind == RDI_TypeKind_Array) + { + U64 direct_byte_size = 1; + if(src->direct_type && src->direct_type->byte_size > 0) + { + direct_byte_size = src->direct_type->byte_size; + } + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); + dst->constructed.count = src->byte_size / direct_byte_size; + } + + //- rjf: fill constructed type node info + else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) + { + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->constructed.count = src->count; + if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = src->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run(bake_idx_runs, param_idx_run, param_idx_run_count); + } + else if(dst->kind == RDI_TypeKind_MemberPtr) + { + // TODO(rjf): member pointers not currently supported. + } + } + + //- rjf: fill user-defined-type info + else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) + { + dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 + dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill bitfield info + else if(dst->kind == RDI_TypeKind_Bitfield) + { + dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->bitfield.off = src->off; + dst->bitfield.size = src->count; + } + } + } + } + + //- rjf: bake global variables + ProfScope("bake global variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->voff = src->offset; + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake thread variables + ProfScope("bake thread variables") + { + for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDIM_Symbol *src = &n->v[n_idx]; + RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: bake inline sites + ProfScope("bake inline sites") + { + for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) + { + Rng1U64 range = lane_range(n->count); + for EachInRange(n_idx, range) + { + RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; + RDIM_InlineSite *src = &n->v[n_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 + dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage bake file paths + // + ProfScope("bake file paths") + { + // rjf: set up + if(lane_idx() == 0) + { + rdim2_shared->baked_file_paths.nodes_count = path_tree->count; + rdim2_shared->baked_file_paths.nodes = push_array(arena, RDI_FilePathNode, rdim2_shared->baked_file_paths.nodes_count); + rdim2_shared->baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, rdim2_shared->baked_file_paths.nodes_count); + { + U64 idx = 0; + for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) + { + rdim2_shared->baked_file_path_src_nodes[idx] = n; + idx += 1; + } + } + } + lane_sync(); + + // rjf: fill + { + Rng1U64 range = lane_range(rdim2_shared->baked_file_paths.nodes_count); + for EachInRange(idx, range) + { + RDIM_BakePathNode *src = rdim2_shared->baked_file_path_src_nodes[idx]; + RDI_FilePathNode *dst = &rdim2_shared->baked_file_paths.nodes[idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->source_file_idx = rdim_idx_from_src_file(src->src_file); + if(src->parent != 0) + { + dst->parent_path_node = src->parent->idx; + } + if(src->first_child != 0) + { + dst->first_child = src->first_child->idx; + } + if(src->next_sibling != 0) + { + dst->next_sibling = src->next_sibling->idx; + } + } + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage do small final baking tasks + // + ProfScope("do small final baking tasks") + { + if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") + { + rdim2_shared->baked_top_level_info.top_level_info.arch = params->top_level_info.arch; + rdim2_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); + rdim2_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; + rdim2_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; + rdim2_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); + } + if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") + { + RDIM_BinarySectionList *src = ¶ms->binary_sections; + RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src->count+1); + U64 dst_idx = 1; + for(RDIM_BinarySectionNode *src_n = src->first; src_n != 0; src_n = src_n->next, dst_idx += 1) + { + RDIM_BinarySection *src = &src_n->v; + RDI_BinarySection *dst = &dst_base[dst_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); + dst->flags = src->flags; + dst->voff_first = src->voff_first; + dst->voff_opl = src->voff_opl; + dst->foff_first = src->foff_first; + dst->foff_opl = src->foff_opl; + } + rdim2_shared->baked_binary_sections.binary_sections = dst_base; + rdim2_shared->baked_binary_sections.binary_sections_count = dst_idx; + } + } + lane_sync(); + + ////////////////////////////////////////////////////////////// + //- rjf: @rdim_bake_stage package results + // + RDIM_BakeResults result = {0}; + { + result.top_level_info = rdim2_shared->baked_top_level_info; + result.binary_sections = rdim2_shared->baked_binary_sections; + result.units = rdim2_shared->baked_units; + result.unit_vmap = rdim2_shared->baked_unit_vmap; + result.src_files = rdim2_shared->baked_src_files; + result.line_tables = rdim2_shared->baked_line_tables; + result.type_nodes = rdim2_shared->baked_type_nodes; + result.udts = rdim2_shared->baked_udts; + result.global_variables = rdim2_shared->baked_global_variables; + result.global_vmap = rdim2_shared->baked_global_vmap; + result.thread_variables = rdim2_shared->baked_thread_variables; + result.constants = rdim2_shared->baked_constants; + result.procedures = rdim2_shared->baked_procedures; + result.scopes = rdim2_shared->baked_scopes; + result.inline_sites = rdim2_shared->baked_inline_sites; + result.scope_vmap = rdim2_shared->baked_scope_vmap; + result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; + result.name_maps = rdim2_shared->baked_name_maps; + result.file_paths = rdim2_shared->baked_file_paths; + result.strings = rdim2_shared->baked_strings; + result.idx_runs = rdim2_shared->baked_idx_runs; + result.locations = rdim2_shared->baked_locations; + result.location_blocks2 = rdim2_shared->baked_location_blocks; + } + + return result; } internal RDIM_SerializedSectionBundle @@ -1166,4 +2905,3 @@ rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) return out; } - diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index 437f7bce..e5b03675 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -48,340 +48,141 @@ //- rjf: main library #include "lib_rdi_make/rdi_make.h" -//- rjf: line table baking task types +//- rjf: unsorted joined line table info -typedef struct RDIM_BakeLineTablesIn RDIM_BakeLineTablesIn; -struct RDIM_BakeLineTablesIn +typedef struct RDIM_UnsortedJoinedLineTable RDIM_UnsortedJoinedLineTable; +struct RDIM_UnsortedJoinedLineTable { - RDIM_LineTableChunkList *line_tables; + RDI_U64 line_count; + RDI_U64 seq_count; + RDI_U64 key_count; + RDIM_SortKey *line_keys; + RDIM_LineRec *line_recs; }; -//- rjf: string map baking task types +//- rjf: shared state bundle -typedef struct RDIM_BakeSrcFilesStringsIn RDIM_BakeSrcFilesStringsIn; -struct RDIM_BakeSrcFilesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_SrcFileChunkList *list; -}; - -typedef struct RDIM_BakeUnitsStringsIn RDIM_BakeUnitsStringsIn; -struct RDIM_BakeUnitsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_UnitChunkList *list; -}; - -typedef struct RDIM_BakeUDTsStringsInNode RDIM_BakeUDTsStringsInNode; -struct RDIM_BakeUDTsStringsInNode -{ - RDIM_BakeUDTsStringsInNode *next; - RDIM_UDT *v; - RDI_U64 count; -}; - -typedef struct RDIM_BakeTypesStringsInNode RDIM_BakeTypesStringsInNode; -struct RDIM_BakeTypesStringsInNode -{ - RDIM_BakeTypesStringsInNode *next; - RDIM_Type *v; - RDI_U64 count; -}; - -typedef struct RDIM_BakeTypesStringsIn RDIM_BakeTypesStringsIn; -struct RDIM_BakeTypesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_BakeTypesStringsInNode *first; - RDIM_BakeTypesStringsInNode *last; -}; - -typedef struct RDIM_BakeUDTsStringsIn RDIM_BakeUDTsStringsIn; -struct RDIM_BakeUDTsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_BakeUDTsStringsInNode *first; - RDIM_BakeUDTsStringsInNode *last; -}; - -typedef struct RDIM_BakeSymbolsStringsInNode RDIM_BakeSymbolsStringsInNode; -struct RDIM_BakeSymbolsStringsInNode -{ - RDIM_BakeSymbolsStringsInNode *next; - RDIM_Symbol *v; - RDI_U64 count; -}; - -typedef struct RDIM_BakeSymbolsStringsIn RDIM_BakeSymbolsStringsIn; -struct RDIM_BakeSymbolsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_BakeSymbolsStringsInNode *first; - RDIM_BakeSymbolsStringsInNode *last; -}; - -typedef struct RDIM_BakeInlineSiteStringsInNode RDIM_BakeInlineSiteStringsInNode; -struct RDIM_BakeInlineSiteStringsInNode -{ - RDIM_BakeInlineSiteStringsInNode *next; - RDIM_InlineSite *v; - RDI_U64 count; -}; - -typedef struct RDIM_BakeInlineSiteStringsIn RDIM_BakeInlineSiteStringsIn; -struct RDIM_BakeInlineSiteStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_BakeInlineSiteStringsInNode *first; - RDIM_BakeInlineSiteStringsInNode *last; -}; - -typedef struct RDIM_BakeScopesStringsInNode RDIM_BakeScopesStringsInNode; -struct RDIM_BakeScopesStringsInNode -{ - RDIM_BakeScopesStringsInNode *next; - RDIM_Scope *v; - RDI_U64 count; -}; - -typedef struct RDIM_BakeScopesStringsIn RDIM_BakeScopesStringsIn; -struct RDIM_BakeScopesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_BakeScopesStringsInNode *first; - RDIM_BakeScopesStringsInNode *last; -}; - -//- rjf: OLD string map baking types - -typedef struct RDIM_BuildBakeStringMapIn RDIM_BuildBakeStringMapIn; -struct RDIM_BuildBakeStringMapIn +typedef struct RDIM2_Shared RDIM2_Shared; +struct RDIM2_Shared { + RDI_U64 scope_vmap_count; + RDIM_SortKey *scope_vmap_keys; + RDIM_SortKey *scope_vmap_keys__swap; + RDIM_VMapMarker *scope_vmap_markers; + RDI_U64 unit_vmap_count; + RDIM_SortKey *unit_vmap_keys; + RDIM_SortKey *unit_vmap_keys__swap; + RDIM_VMapMarker *unit_vmap_markers; + RDI_U64 global_vmap_count; + RDIM_SortKey *global_vmap_keys; + RDIM_SortKey *global_vmap_keys__swap; + RDIM_VMapMarker *global_vmap_markers; + U32 **lane_digit_counts; + U32 **lane_digit_offsets; + + RDIM_ScopeVMapBakeResult baked_scope_vmap; + RDIM_UnitVMapBakeResult baked_unit_vmap; + RDIM_GlobalVMapBakeResult baked_global_vmap; + RDIM_BakePathTree *path_tree; - RDIM_BakeParams *params; + + RDI_U64 line_tables_count; + RDI_U64 line_table_block_take_counter; + RDIM_LineTable **src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables; + + RDIM_SortKey **sorted_line_table_keys; + + RDIM_LineTableBakeResult baked_line_tables; + + RDIM_BakeStringMapTopology bake_string_map_topology; + RDIM_BakeStringMapLoose **lane_bake_string_maps__loose; + RDIM_BakeStringMapLoose *bake_string_map__loose; + RDIM_BakeStringMapTight bake_strings; + + RDIM_BakeNameMapTopology bake_name_map_topology[RDI_NameMapKind_COUNT]; + RDIM_BakeNameMap **lane_bake_name_maps[RDI_NameMapKind_COUNT]; + RDIM_BakeNameMap *bake_name_maps[RDI_NameMapKind_COUNT]; + + RDIM_BakeIdxRunMapTopology bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose **lane_bake_idx_run_maps__loose; + RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; + RDIM_BakeIdxRunMap bake_idx_runs; + + RDIM_StringBakeResult baked_strings; + + RDIM_IndexRunBakeResult baked_idx_runs; + + RDI_U64 *lane_name_map_node_counts[RDI_NameMapKind_COUNT]; + RDI_U64 *lane_name_map_node_offs[RDI_NameMapKind_COUNT]; + RDI_U64 name_map_node_counts[RDI_NameMapKind_COUNT]; + RDI_U64 total_name_map_node_count; + RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; + RDIM_NameMapBakeResult baked_name_maps; + + RDIM_BakeSrcLineMap *bake_src_line_maps; + + RDI_U64 bake_src_line_map_take_counter; + RDIM_SortKey **bake_src_line_map_keys; + + RDI_U64 *lane_chunk_src_file_num_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_voff_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_map_counts; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_voff_offs; // [lane_count * src_file_chunk_count] + RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] + RDI_U64 total_src_map_line_count; + RDI_U64 total_src_map_voff_count; + + RDIM_SrcFileBakeResult baked_src_files; + + RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] + RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] + RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] + RDI_U64 *enum_val_chunk_lane_offs; // [lane_count * udt_chunk_count] + + RDIM_UDTBakeResult baked_udts; + + RDI_U64 *location_case_chunk_lane_counts; // [lane_count * (scope_chunk_count + procedure_chunk_count) + RDI_U64 *location_case_chunk_lane_offs; // [lane_count * (scope_chunk_count + procedure_chunk_count) + RDI_U64 total_location_case_count; + + RDIM_LocationBlockBakeResult baked_location_blocks; + + RDIM_LocationBakeResult baked_locations; + + RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] + RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] + + RDIM_ScopeBakeResult baked_scopes; + + RDIM_ProcedureBakeResult baked_procedures; + + RDI_U64 *constant_data_chunk_lane_counts; // [lane_count * constant_chunk_count] + RDI_U64 *constant_data_chunk_lane_offs; // [lane_count * constant_chunk_count] + + RDIM_ConstantsBakeResult baked_constants; + + RDIM_UnitBakeResult baked_units; + RDIM_TypeNodeBakeResult baked_type_nodes; + RDIM_GlobalVariableBakeResult baked_global_variables; + RDIM_ThreadVariableBakeResult baked_thread_variables; + RDIM_InlineSiteBakeResult baked_inline_sites; + + RDIM_BakePathNode **baked_file_path_src_nodes; + RDIM_FilePathBakeResult baked_file_paths; + + RDIM_TopLevelInfoBakeResult baked_top_level_info; + RDIM_BinarySectionBakeResult baked_binary_sections; }; -typedef struct RDIM_BuildBakeNameMapIn RDIM_BuildBakeNameMapIn; -struct RDIM_BuildBakeNameMapIn -{ - RDI_NameMapKind k; - RDIM_BakeParams *params; -}; - -//- rjf: string map joining task types - -typedef struct RDIM_JoinBakeStringMapSlotsIn RDIM_JoinBakeStringMapSlotsIn; -struct RDIM_JoinBakeStringMapSlotsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **src_maps; - U64 src_maps_count; - RDIM_BakeStringMapLoose *dst_map; - Rng1U64 slot_idx_range; -}; - -//- rjf: string map sorting task types - -typedef struct RDIM_SortBakeStringMapSlotsIn RDIM_SortBakeStringMapSlotsIn; -struct RDIM_SortBakeStringMapSlotsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose *src_map; - RDIM_BakeStringMapLoose *dst_map; - U64 slot_idx; - U64 slot_count; -}; - -//- rjf: debug info baking task types - -typedef struct RDIM_BakeUnitsIn RDIM_BakeUnitsIn; -struct RDIM_BakeUnitsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; - RDIM_UnitChunkList *units; -}; - -typedef struct RDIM_BakeUnitVMapIn RDIM_BakeUnitVMapIn; -struct RDIM_BakeUnitVMapIn -{ - RDIM_UnitChunkList *units; -}; - -typedef struct RDIM_BakeSrcFilesIn RDIM_BakeSrcFilesIn; -struct RDIM_BakeSrcFilesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; - RDIM_SrcFileChunkList *src_files; -}; - -typedef struct RDIM_BakeUDTsIn RDIM_BakeUDTsIn; -struct RDIM_BakeUDTsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_UDTChunkList *udts; -}; - -typedef struct RDIM_BakeGlobalVariablesIn RDIM_BakeGlobalVariablesIn; -struct RDIM_BakeGlobalVariablesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *global_variables; -}; - -typedef struct RDIM_BakeConstantsIn RDIM_BakeConstantsIn; -struct RDIM_BakeConstantsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *constants; -}; - -typedef struct RDIM_BakeGlobalVMapIn RDIM_BakeGlobalVMapIn; -struct RDIM_BakeGlobalVMapIn -{ - RDIM_SymbolChunkList *global_variables; -}; - -typedef struct RDIM_BakeThreadVariablesIn RDIM_BakeThreadVariablesIn; -struct RDIM_BakeThreadVariablesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *thread_variables; -}; - -typedef struct RDIM_BakeProceduresIn RDIM_BakeProceduresIn; -struct RDIM_BakeProceduresIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *procedures; - RDIM_String8List *location_blocks; - RDIM_String8List *location_data_blobs; -}; - -typedef struct RDIM_BakeScopesIn RDIM_BakeScopesIn; -struct RDIM_BakeScopesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_ScopeChunkList *scopes; - RDIM_String8List *location_blocks; - RDIM_String8List *location_data_blobs; -}; - -typedef struct RDIM_BakeScopeVMapIn RDIM_BakeScopeVMapIn; -struct RDIM_BakeScopeVMapIn -{ - RDIM_ScopeChunkList *scopes; -}; - -typedef struct RDIM_BakeInlineSitesIn RDIM_BakeInlineSitesIn; -struct RDIM_BakeInlineSitesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_InlineSiteChunkList *inline_sites; -}; - -typedef struct RDIM_BakeFilePathsIn RDIM_BakeFilePathsIn; -struct RDIM_BakeFilePathsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; -}; - -typedef struct RDIM_BakeStringsIn RDIM_BakeStringsIn; -struct RDIM_BakeStringsIn -{ - RDIM_BakeStringMapTight *strings; -}; - -typedef struct RDIM_BakeTypeNodesIn RDIM_BakeTypeNodesIn; -struct RDIM_BakeTypeNodesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakeIdxRunMap *idx_runs; - RDIM_TypeChunkList *types; -}; - -typedef struct RDIM_BakeNameMapIn RDIM_BakeNameMapIn; -struct RDIM_BakeNameMapIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakeIdxRunMap *idx_runs; - RDIM_BakeNameMap *map; - RDI_NameMapKind kind; -}; - -typedef struct RDIM_BakeIdxRunsIn RDIM_BakeIdxRunsIn; -struct RDIM_BakeIdxRunsIn -{ - RDIM_BakeIdxRunMap *idx_runs; -}; - -//////////////////////////////// +global RDIM2_Shared *rdim2_shared = 0; internal RDIM_DataModel rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch); - -//////////////////////////////// -//~ rjf: Baking Stage Tasks - -//- rjf: unsorted bake string map building -ASYNC_WORK_DEF(rdim_bake_src_files_strings_work); -ASYNC_WORK_DEF(rdim_bake_units_strings_work); -ASYNC_WORK_DEF(rdim_bake_types_strings_work); -ASYNC_WORK_DEF(rdim_bake_udts_strings_work); -ASYNC_WORK_DEF(rdim_bake_symbols_strings_work); -ASYNC_WORK_DEF(rdim_bake_scopes_strings_work); -ASYNC_WORK_DEF(rdim_bake_line_tables_work); - -//- rjf: bake string map joining -ASYNC_WORK_DEF(rdim_bake_string_map_join_work); - -//- rjf: bake string map sorting -ASYNC_WORK_DEF(rdim_bake_string_map_sort_work); - -//- rjf: pass 1: interner/deduper map builds -ASYNC_WORK_DEF(rdim_build_bake_name_map_work); - -//- rjf: pass 2: string-map-dependent debug info stream builds -ASYNC_WORK_DEF(rdim_bake_units_work); -ASYNC_WORK_DEF(rdim_bake_unit_vmap_work); -ASYNC_WORK_DEF(rdim_bake_src_files_work); -ASYNC_WORK_DEF(rdim_bake_udts_work); -ASYNC_WORK_DEF(rdim_bake_global_variables_work); -ASYNC_WORK_DEF(rdim_bake_global_vmap_work); -ASYNC_WORK_DEF(rdim_bake_thread_variables_work); -ASYNC_WORK_DEF(rdim_bake_constants_work); -ASYNC_WORK_DEF(rdim_bake_procedures_work); -ASYNC_WORK_DEF(rdim_bake_scopes_work); -ASYNC_WORK_DEF(rdim_bake_scope_vmap_work); -ASYNC_WORK_DEF(rdim_bake_file_paths_work); -ASYNC_WORK_DEF(rdim_bake_strings_work); - -//- rjf: pass 3: idx-run-map-dependent debug info stream builds -ASYNC_WORK_DEF(rdim_bake_type_nodes_work); -ASYNC_WORK_DEF(rdim_bake_name_map_work); -ASYNC_WORK_DEF(rdim_bake_idx_runs_work); - -//////////////////////////////// -//~ rjf: Globals - -global ASYNC_Root *rdim_local_async_root = 0; - -//////////////////////////////// - -internal RDIM_DataModel rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch); internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections); - -//////////////////////////////// - -internal RDIM_BakeResults rdim_bake(Arena *arena, ASYNC_Root *async_root, RDIM_BakeParams *in); +internal RDIM_BakeResults rdim2_bake(Arena *arena, RDIM_BakeParams *params); internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in); #endif // RDI_MAKE_LOCAL_H diff --git a/src/rdi_make/rdi_make_local_2.c b/src/rdi_make/rdi_make_local_2.c deleted file mode 100644 index 28a244d7..00000000 --- a/src/rdi_make/rdi_make_local_2.c +++ /dev/null @@ -1,2794 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal RDIM_BakeResults -rdim2_bake(Arena *arena, RDIM_BakeParams *params) -{ - ////////////////////////////////////////////////////////////// - //- rjf: set up shared state - // - if(lane_idx() == 0) - { - rdim2_shared = push_array(arena, RDIM2_Shared, 1); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage gather unsorted vmap keys/markers - // - ProfScope("gather unsorted vmap keys/markers") - { - //- rjf: gather scope vmap keys/markers - if(lane_idx() == lane_from_task_idx(0)) ProfScope("gather scope vmap keys/markers") - { - rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; - rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); - ProfScope("fill keys/markers") - { - RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; - RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; - for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) - { - RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 - for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) - { - key_ptr->key = n->v.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = n->v.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - } - } - - //- rjf: gather unit vmap keys/markers - if(lane_idx() == lane_from_task_idx(1)) ProfScope("gather unit vmap keys/markers") - { - // rjf: count voff ranges - RDI_U64 voff_range_count = 0; - for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) - { - for(RDI_U64 idx = 0; idx < n->count; idx += 1) - { - RDIM_Unit *unit = &n->v[idx]; - voff_range_count += unit->voff_ranges.total_count; - } - } - - // rjf: count necessary markers - RDI_U64 marker_count = voff_range_count*2; - - // rjf: build keys/markers arrays - RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - RDI_U32 unit_idx = 1; - for(RDIM_UnitChunkNode *unit_chunk_n = params->units.first; - unit_chunk_n != 0; - unit_chunk_n = unit_chunk_n->next) - { - for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) - { - RDIM_Unit *unit = &unit_chunk_n->v[idx]; - for(RDIM_Rng1U64ChunkNode *n = unit->voff_ranges.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Rng1U64 range = n->v[chunk_idx]; - if(range.min < range.max) - { - key_ptr->key = range.min; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = range.max; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - unit_idx += 1; - } - } - } - - // rjf: store - rdim2_shared->unit_vmap_count = marker_count; - rdim2_shared->unit_vmap_keys = keys; - rdim2_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim2_shared->unit_vmap_markers = markers; - } - - //- rjf: gather global vmap keys/markers - if(lane_idx() == lane_from_task_idx(2)) ProfScope("gather global vmap keys/markers") - { - //- rjf: allocate keys/markers - RDI_U64 marker_count = params->global_variables.total_count*2 + 2; - RDIM_SortKey *keys = rdim_push_array_no_zero(arena, RDIM_SortKey, marker_count); - RDIM_VMapMarker *markers = rdim_push_array_no_zero(arena, RDIM_VMapMarker, marker_count); - - //- rjf: fill - { - RDIM_SortKey *key_ptr = keys; - RDIM_VMapMarker *marker_ptr = markers; - - // rjf: fill actual globals - for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) - { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) - { - RDIM_Symbol *global_var = &n->v[chunk_idx]; - RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 - RDI_U64 global_var_size = global_var->type ? global_var->type->byte_size : 1; - - RDI_U64 first = global_var->offset; - RDI_U64 opl = first + global_var_size; - - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_var_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - // rjf: fill nil global - { - RDI_U32 global_idx = 0; - RDI_U64 first = 0; - RDI_U64 opl = 0xffffffffffffffffull; - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - //- rjf: store - rdim2_shared->global_vmap_count = marker_count; - rdim2_shared->global_vmap_keys = keys; - rdim2_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim2_shared->global_vmap_markers = markers; - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage sort all vmap keys - // - ProfScope("sort all vmap keys") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); - rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); - } - lane_sync(); - - // rjf: sort - struct - { - RDI_U64 vmap_count; - RDIM_SortKey *keys; - RDIM_SortKey *keys__swap; - } - sort_tasks[] = - { - {rdim2_shared->scope_vmap_count, rdim2_shared->scope_vmap_keys, rdim2_shared->scope_vmap_keys__swap}, - {rdim2_shared->unit_vmap_count, rdim2_shared->unit_vmap_keys, rdim2_shared->unit_vmap_keys__swap}, - {rdim2_shared->global_vmap_count, rdim2_shared->global_vmap_keys, rdim2_shared->global_vmap_keys__swap}, - }; - for EachElement(sort_task_idx, sort_tasks) ProfScope("sort %I64u", sort_task_idx) - { - RDI_U64 vmap_count = sort_tasks[sort_task_idx].vmap_count; - RDIM_SortKey *keys = sort_tasks[sort_task_idx].keys; - RDIM_SortKey *keys__swap = sort_tasks[sort_task_idx].keys__swap; - U64 bits_per_digit = 8; - U64 digits_count = 64 / bits_per_digit; - U64 num_possible_values_per_digit = 1 << bits_per_digit; - rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - RDIM_SortKey *src = keys; - RDIM_SortKey *dst = keys__swap; - U64 element_count = vmap_count; - for EachIndex(digit_idx, digits_count) - { - // rjf: count digit value occurrences per-lane - { - U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; - MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *sort_key = &src[idx]; - U16 digit_value = (U16)(U8)(sort_key->key >> (digit_idx*bits_per_digit)); - digit_counts[digit_value] += 1; - } - } - lane_sync(); - - // rjf: compute thread * digit value *relative* offset table - { - Rng1U64 range = lane_range(num_possible_values_per_digit); - for EachInRange(value_idx, range) - { - U64 layout_off = 0; - for EachIndex(lane_idx, lane_count()) - { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; - layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; - } - } - } - lane_sync(); - - // rjf: convert relative offsets -> absolute offsets - if(lane_idx() == 0) - { - U64 last_off = 0; - U64 num_of_nonzero_digit = 0; - for EachIndex(value_idx, num_possible_values_per_digit) - { - for EachIndex(lane_idx, lane_count()) - { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; - } - last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; - } - // NOTE(rjf): required that: (last_off == element_count) - } - lane_sync(); - - // rjf: move - { - U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - RDIM_SortKey *src_key = &src[idx]; - U16 digit_value = (U16)(U8)(src_key->key >> (digit_idx*bits_per_digit)); - U64 dst_off = lane_digit_offsets[digit_value]; - lane_digit_offsets[digit_value] += 1; - MemoryCopyStruct(&dst[dst_off], src_key); - } - } - lane_sync(); - - // rjf: swap - { - RDIM_SortKey *swap = src; - src = dst; - dst = swap; - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake all vmaps - // - ProfScope("bake all vmaps") - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct VMapBakeTask VMapBakeTask; - struct VMapBakeTask - { - VMapBakeTask *next; - String8 name; - RDI_U64 count; - RDIM_SortKey *keys; - RDIM_VMapMarker *markers; - RDIM_BakeVMap *bake_vmap_out; - }; - VMapBakeTask *first_task = 0; - VMapBakeTask *last_task = 0; - if(lane_idx() == lane_from_task_idx(0)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("scopes"); - task->count = rdim2_shared->scope_vmap_count; - task->keys = rdim2_shared->scope_vmap_keys; - task->markers = rdim2_shared->scope_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_scope_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - if(lane_idx() == lane_from_task_idx(1)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("units"); - task->count = rdim2_shared->unit_vmap_count; - task->keys = rdim2_shared->unit_vmap_keys; - task->markers = rdim2_shared->unit_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_unit_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - if(lane_idx() == lane_from_task_idx(2)) - { - VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); - task->name = str8_lit("globals"); - task->count = rdim2_shared->global_vmap_count; - task->keys = rdim2_shared->global_vmap_keys; - task->markers = rdim2_shared->global_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_global_vmap.vmap; - SLLQueuePush(first_task, last_task, task); - } - for(VMapBakeTask *task = first_task; task != 0; task = task->next) ProfScope("vmap bake for %.*s", str8_varg(task->name)) - { - //- rjf: determine if an extra vmap entry for zero is needed - RDI_U32 extra_vmap_entry = 0; - if(task->count > 0 && task->keys[0].key != 0) - { - extra_vmap_entry = 1; - } - - //- rjf: fill output vmap entries - RDI_U32 vmap_count_raw = extra_vmap_entry + task->count; - RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw); - RDI_U32 vmap_entry_count_pass_1 = 0; - ProfScope("fill output vmap entries") - { - typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; - struct RDIM_VMapRangeTracker - { - RDIM_VMapRangeTracker *next; - RDI_U32 idx; - }; - RDI_VMapEntry *vmap_ptr = vmap; - if(extra_vmap_entry) - { - vmap_ptr->voff = 0; - vmap_ptr->idx = 0; - vmap_ptr += 1; - } - RDIM_VMapRangeTracker *tracker_stack = 0; - RDIM_VMapRangeTracker *tracker_free = 0; - RDIM_SortKey *key_ptr = task->keys; - RDIM_SortKey *key_opl = task->keys + task->count; - for(;key_ptr < key_opl;) - { - // rjf: get initial map state from tracker stack - RDI_U32 initial_idx = (RDI_U32)0xffffffff; - if(tracker_stack != 0) - { - initial_idx = tracker_stack->idx; - } - - // rjf: update tracker stack - // - // * we must process _all_ of the changes that apply at this voff before moving on - // - RDI_U64 voff = key_ptr->key; - - for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) - { - RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; - RDI_U32 idx = marker->idx; - - // rjf: range begin -> push to stack - if(marker->begin_range) - { - RDIM_VMapRangeTracker *new_tracker = tracker_free; - if(new_tracker != 0) - { - RDIM_SLLStackPop(tracker_free); - } - else - { - new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); - } - RDIM_SLLStackPush(tracker_stack, new_tracker); - new_tracker->idx = idx; - } - - // rjf: range ending -> pop matching node from stack (not always the top) - else - { - RDIM_VMapRangeTracker **ptr_in = &tracker_stack; - RDIM_VMapRangeTracker *match = 0; - for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) - { - if(node->idx == idx) - { - match = node; - break; - } - ptr_in = &node->next; - node = node->next; - } - if(match != 0) - { - *ptr_in = match->next; - RDIM_SLLStackPush(tracker_free, match); - } - } - } - - // rjf: get final map state from tracker stack - RDI_U32 final_idx = 0; - if(tracker_stack != 0) - { - final_idx = tracker_stack->idx; - } - - // rjf: if final is different from initial - emit new vmap entry - if(final_idx != initial_idx) - { - vmap_ptr->voff = voff; - vmap_ptr->idx = final_idx; - vmap_ptr += 1; - } - } - - vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: combine duplicate neighbors - RDI_U32 vmap_entry_count = 0; - ProfScope("combine duplicate neighbors") - { - RDI_VMapEntry *vmap_ptr = vmap; - RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; - RDI_VMapEntry *vmap_out = vmap; - for(;vmap_ptr < vmap_opl;) - { - RDI_VMapEntry *vmap_range_first = vmap_ptr; - RDI_U64 idx = vmap_ptr->idx; - vmap_ptr += 1; - for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; - rdim_memcpy_struct(vmap_out, vmap_range_first); - vmap_out += 1; - } - vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill result - task->bake_vmap_out->vmap = vmap; - task->bake_vmap_out->count = vmap_entry_count; - } - scratch_end(scratch); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage build interned path tree - // - if(lane_idx() == 0) ProfScope("build interned path tree") - { - rdim2_shared->path_tree = rdim_bake_path_tree_from_params(arena, params); - } - lane_sync(); - RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage gather all unsorted, joined, line table info; & sort - // - ProfScope("gather all unsorted, joined, line table info; & sort") - { - //- rjf: set up outputs - ProfScope("set up outputs") - { - // rjf: calculate header info - if(lane_idx() == 0) - { - rdim2_shared->line_tables_count = params->line_tables.total_count; - rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); - ProfScope("flatten chunk list") - { - U64 joined_idx = 0; - for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) - { - for EachIndex(idx, n->count) - { - rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; - joined_idx += 1; - } - } - } - rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; - rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_columns_count= 1; - rdim2_shared->line_table_block_take_counter = 0; - } - lane_sync(); - - // rjf: allocate outputs - ProfScope("allocate outputs") - { - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); - ProfScope("lay out line tables") - { - U64 voffs_base_idx = 0; - U64 lines_base_idx = 0; - U64 cols_base_idx = 0; - for EachIndex(idx, rdim2_shared->line_tables_count) - { - U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil - RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; - RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; - dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 - dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 - dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 - voffs_base_idx += src->line_count + 2*src->seq_count; - lines_base_idx += src->line_count + 1*src->seq_count; - } - } - } - if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); - } - if(lane_idx() == lane_from_task_idx(4)) - { - rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); - } - if(lane_idx() == lane_from_task_idx(5)) - { - rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); - } - } - } - lane_sync(); - - //- rjf: wide bake - ProfScope("wide bake") - { - U64 line_table_block_size = 4096; - U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; - for(;;) - { - U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); - if(0 == line_table_block_num || line_table_block_count < line_table_block_num) - { - break; - } - U64 line_table_block_idx = line_table_block_num-1; - Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); - line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); - for EachInRange(line_table_idx, line_table_range) - { - RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; - RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; - - //- rjf: gather - dst->line_count = src->line_count; - dst->seq_count = src->seq_count; - dst->key_count = dst->line_count + dst->seq_count; - dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); - dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); - { - RDIM_SortKey *key_ptr = dst->line_keys; - RDIM_LineRec *rec_ptr = dst->line_recs; - for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) - { - RDIM_LineSequence *seq = &seq_n->v; - for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) - { - key_ptr->key = seq->voffs[line_idx]; - key_ptr->val = rec_ptr; - key_ptr += 1; - rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 - rec_ptr->line_num = seq->line_nums[line_idx]; - if(seq->col_nums != 0) - { - rec_ptr->col_first = seq->col_nums[line_idx*2]; - rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; - } - rec_ptr += 1; - } - key_ptr->key = seq->voffs[seq->line_count]; - key_ptr->val = 0; - key_ptr += 1; - } - } - - //- rjf: sort - rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); - - //- rjf: fill - RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; - U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; - RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; - U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; - RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; - RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; - { - for EachIndex(idx, sorted_line_keys_count) - { - arranged_voffs[idx] = sorted_line_keys[idx].key; - } - arranged_voffs[sorted_line_keys_count] = ~0ull; - for EachIndex(idx, sorted_line_keys_count) - { - RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; - if(rec != 0) - { - arranged_lines[idx].file_idx = rec->file_id; - arranged_lines[idx].line_num = rec->line_num; - } - else - { - arranged_lines[idx].file_idx = 0; - arranged_lines[idx].line_num = 0; - } - } - } - } - } - } - } - lane_sync(); - RDI_U64 line_tables_count = rdim2_shared->line_tables_count; - RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; - RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; - RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage build string map - // - ProfScope("build string map") - { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") - { - rdim2_shared->bake_string_map_topology.slots_count = (64 + - params->procedures.total_count*1 + - params->global_variables.total_count*1 + - params->thread_variables.total_count*1 + - params->types.total_count/2); - rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); - rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); - } - lane_sync(); - - //- rjf: set up this lane's map - ProfScope("set up this lane's map") - { - rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); - } - RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; - RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; - - //- rjf: push all strings into this lane's map - ProfScope("push all strings into this lane's map") - { - // rjf: push small top-level strings - if(lane_idx() == 0) ProfScope("push small top-level strings") - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.exe_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, params->top_level_info.producer_name); - for(RDIM_BinarySectionNode *n = params->binary_sections.first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->v.name); - } - for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, n->name); - } - } - - // rjf: push strings from source files - ProfScope("src files") - { - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, n->v[n_idx].path); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 1, normalized_path); - } - } - } - - // rjf: push strings from units - ProfScope("units") - { - for EachNode(n, RDIM_UnitChunkNode, params->units.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].unit_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].compiler_name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].source_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].object_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].archive_file); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].build_path); - } - } - } - - // rjf: push strings from types - ProfScope("types") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); - } - } - } - - // rjf: push strings from udts - ProfScope("udts") - { - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - for EachNode(mem, RDIM_UDTMember, n->v[idx].first_member) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, mem->name); - } - for EachNode(enum_val, RDIM_UDTEnumVal, n->v[idx].first_enum_val) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, enum_val->name); - } - } - } - } - - // rjf: push strings from symbols - RDIM_SymbolChunkList *symbol_lists[] = - { - ¶ms->global_variables, - ¶ms->thread_variables, - ¶ms->procedures, - ¶ms->constants, - }; - ProfScope("symbols") - { - for EachElement(list_idx, symbol_lists) - { - for EachNode(n, RDIM_SymbolChunkNode, symbol_lists[list_idx]->first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].link_name); - } - } - } - } - - //- rjf: push strings from inline sites - ProfScope("inline sites") - { - for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, n->v[n_idx].name); - } - } - } - - //- rjf: push strings from scopes - ProfScope("scopes") - { - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - for EachNode(local, RDIM_Local, n->v[n_idx].first_local) - { - rdim_bake_string_map_loose_insert(arena, lane_map_top, lane_map, 4, local->name); - } - } - } - } - } - lane_sync(); - - //- rjf: join - ProfScope("join") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } - } - lane_sync(); - - //- rjf: sort - ProfScope("sort") - { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } - } - } - lane_sync(); - - //- rjf: tighten string table - ProfScope("tighten string table") - { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; - if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") - { - RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_strings.slots_count = map_top->slots_count; - rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); - rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; - rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; - } - lane_sync(); - ProfScope("fill tight map") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); - for EachInRange(idx, slot_range) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); - } - } - } - } - } - lane_sync(); - RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage build name maps - // - ProfScope("build name maps") - { - //- rjf: set up - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - U64 slot_count = 0; - switch((RDI_NameMapKindEnum)k) - { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; -#define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break - Case(GlobalVariables, params->global_variables.total_count); - Case(ThreadVariables, params->thread_variables.total_count); - Case(Constants, params->constants.total_count); - Case(Procedures, params->procedures.total_count); - Case(LinkNameProcedures, params->procedures.total_count); - Case(Types, params->types.total_count); - Case(NormalSourcePaths, params->src_files.total_count); -#undef Case - } - rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap2 *, lane_count()); - rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; - } - } - lane_sync(); - - //- rjf: wide build - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_2_make(arena, top); - RDIM_BakeNameMap2 *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; - B32 link_names = 0; - RDIM_SymbolChunkList *symbols = 0; - switch((RDI_NameMapKindEnum)k) - { - case RDI_NameMapKind_NULL: - case RDI_NameMapKind_COUNT: - {}break; - case RDI_NameMapKind_GlobalVariables: {symbols = ¶ms->global_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_ThreadVariables: {symbols = ¶ms->thread_variables;}goto symbol_name_map_build; - case RDI_NameMapKind_Constants: {symbols = ¶ms->constants;}goto symbol_name_map_build; - case RDI_NameMapKind_Procedures: {symbols = ¶ms->procedures;}goto symbol_name_map_build; - case RDI_NameMapKind_LinkNameProcedures:{symbols = ¶ms->procedures; link_names = 1;}goto symbol_name_map_build; - symbol_name_map_build:; - { - for EachNode(n, RDIM_SymbolChunkNode, symbols->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Symbol *symbol = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); - } - } - }break; - case RDI_NameMapKind_Types: - { - RDIM_TypeChunkList *types = ¶ms->types; - for EachNode(n, RDIM_TypeChunkNode, types->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_Type *type = &n->v[n_idx]; - rdim_bake_name_map_2_insert(arena, top, map, 4, type->name, rdim_idx_from_type(type)); - } - } - }break; - case RDI_NameMapKind_NormalSourcePaths: - { - RDIM_SrcFileChunkList *src_files = ¶ms->src_files; - for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) - { - Rng1U64 n_range = lane_range(n->count); - for EachInRange(n_idx, n_range) - { - RDIM_SrcFile *src_file = &n->v[n_idx]; - RDIM_String8 normalized_path = rdim_lower_from_str8(arena, src_file->path); - rdim_bake_name_map_2_insert(arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); - } - } - }break; - } - } - lane_sync(); - - //- rjf: join & sort - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_2_make(arena, &rdim2_shared->bake_name_map_topology[k]); - } - } - lane_sync(); - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - - //- rjf: join - ProfScope("join") - { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeNameMap2 *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; - RDIM_BakeNameMap2 *dst_map = map; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } - } - - //- rjf: sort - ProfScope("sort") - { - Rng1U64 slot_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - } - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage build index runs - // - ProfScope("build index runs") - { - //- rjf: set up per-lane outputs - if(lane_idx() == 0) ProfScope("set up per-lane outputs") - { - rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + - params->procedures.total_count + - params->global_variables.total_count + - params->thread_variables.total_count + - params->types.total_count); - rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); - rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - lane_sync(); - - //- rjf: set up this lane's map - ProfScope("set up this lane's map") - { - rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); - } - RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; - - //- rjf: wide fill of all index runs - ProfScope("fill all lane index run maps") - { - //- rjf: bake runs of function-type parameter lists - ProfScope("bake runs of function-type parameter lists") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) - { - RDIM_Type *type = &n->v[n_idx]; - if(type->count == 0) - { - continue; - } - if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = type->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, param_idx_run, param_idx_run_count); - } - } - } - } - - //- rjf: bake runs of name map match lists - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - Rng1U64 slot_idx_range = lane_range(top->slots_count); - for EachInRange(slot_idx, slot_idx_range) - { - RDIM_BakeNameChunkList *slot = map->slots[slot_idx]; - if(slot != 0) - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct IdxRunNode IdxRunNode; - struct IdxRunNode - { - IdxRunNode *next; - RDI_U64 idx; - }; - IdxRunNode *first_idx_run_node = 0; - IdxRunNode *last_idx_run_node = 0; - U64 active_idx_count = 0; - String8 active_string = {0}; - RDIM_BakeNameChunkNode *n = slot->first; - U64 n_idx = 0; - for(;;) - { - // rjf: advance chunk - if(n != 0 && n_idx >= n->count) - { - n = n->next; - n_idx = 0; - } - - // rjf: grab next element - String8 string = {0}; - U64 idx = 0; - if(n != 0) - { - string = n->v[n_idx].string; - idx = n->v[n_idx].idx; - } - - // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list - if(!str8_match(string, active_string, 0)) - { - if(active_idx_count > 1) - { - RDI_U64 idxs_count = active_idx_count; - RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); - { - U64 write_idx = 0; - for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) - { - idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 - write_idx += 1; - } - } - rdim_bake_idx_run_map_loose_insert(arena, lane_map_top, lane_map, 4, idxs, idxs_count); - } - active_string = string; - first_idx_run_node = 0; - last_idx_run_node = 0; - active_idx_count = 0; - temp_end(scratch); - } - - // rjf: new element matches the active list -> push - if(active_string.size != 0 && str8_match(string, active_string, 0)) - { - IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); - idx_run_n->idx = idx; - SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); - active_idx_count += 1; - } - - // rjf: advance index - n_idx += 1; - - // rjf: end on zero node - if(n == 0) - { - break; - } - } - scratch_end(scratch); - } - } - } - } - lane_sync(); - - //- rjf: join - ProfScope("join") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - for EachIndex(src_lane_idx, lane_count()) - { - RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; - dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; - if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) - { - dst_map->slots[slot_idx] = src_map->slots[slot_idx]; - } - else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) - { - rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); - } - } - } - } - lane_sync(); - - //- rjf: sort - ProfScope("sort") - { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); - for EachInRange(slot_idx, slot_range) - { - if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) - { - *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); - map->slots_idx_counts[slot_idx] = 0; - for EachNode(n, RDIM_BakeIdxRunChunkNode, map->slots[slot_idx]->first) - { - for EachIndex(idx, n->count) - { - map->slots_idx_counts[slot_idx] += n->v[idx].count; - } - } - } - } - } - lane_sync(); - - //- rjf: tighten idx run table - ProfScope("tighten idx run table") - { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; - if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") - { - rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; - rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); - rdim2_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim2_shared->bake_idx_runs.slots_count+1); - RDI_U64 encoding_idx_off = 0; - for(RDI_U64 slot_idx = 0; slot_idx < map_top->slots_count; slot_idx += 1) - { - rdim2_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; - if(map->slots[slot_idx] != 0) - { - encoding_idx_off += map->slots_idx_counts[slot_idx]; - } - } - rdim2_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; - } - lane_sync(); - ProfScope("fill tight map") - { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); - for EachInRange(idx, slot_range) - { - if(map->slots[idx] != 0) - { - rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); - } - } - } - } - } - lane_sync(); - RDIM_BakeIdxRunMap2 *bake_idx_runs = &rdim2_shared->bake_idx_runs; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake strings - // - ProfScope("bake strings") - { - // rjf: set up - if(lane_idx() == 0) ProfScope("set up; lay out strings") - { - rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; - rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); - RDI_U64 off_cursor = 0; - for EachIndex(slot_idx, bake_strings->slots_count) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) - { - for EachIndex(n_idx, n->count) - { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; - off_cursor += src->string.size; - } - } - } - rdim2_shared->baked_strings.string_data_size = off_cursor; - rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); - } - lane_sync(); - - // rjf: wide fill string data - ProfScope("wide fill") - { - Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); - for EachInRange(slot_idx, slot_idx_range) - { - for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) - { - for EachIndex(n_idx, n->count) - { - RDIM_BakeString *src = &n->v[n_idx]; - U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; - rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); - } - } - } - } - } - lane_sync(); - RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake idx runs - // - ProfScope("bake idx runs") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; - rdim2_shared->baked_idx_runs.idx_runs = push_array(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); - } - lane_sync(); - - // rjf: wide fill - { - Rng1U64 range = lane_range(bake_idx_runs->slots_count); - for EachInRange(slot_idx, range) - { - RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; - for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) - { - StaticAssert(sizeof(rdim2_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); - for EachIndex(n_idx, n->count) - { - rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); - off += n->v[n_idx].count; - } - } - } - } - } - lane_sync(); - RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake name maps - // - ProfScope("bake name maps") - { - // rjf: count unique names in all name maps; lay out baked nodes - ProfScope("count unique names in all name maps; lay out baked nodes") - { - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - rdim2_shared->lane_name_map_node_counts[k] = push_array(arena, U64, lane_count()); - rdim2_shared->lane_name_map_node_offs[k] = push_array(arena, U64, lane_count()); - } - } - lane_sync(); - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap2 *map = rdim2_shared->bake_name_maps[k]; - Rng1U64 range = lane_range(top->slots_count); - for EachInRange(idx, range) - { - if(map->slots[idx] != 0) - { - U64 total_unique_name_count = 0; - U64 last_hash = 0; - for EachNode(n, RDIM_BakeNameChunkNode, map->slots[idx]->first) - { - for EachIndex(n_idx, n->count) - { - if(n->v[n_idx].hash != last_hash) - { - total_unique_name_count += 1; - last_hash = n->v[n_idx].hash; - } - } - } - rdim2_shared->lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; - } - } - } - lane_sync(); - if(lane_idx() == 0) - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - RDI_U64 node_off = 0; - for EachIndex(l_idx, lane_count()) - { - rdim2_shared->name_map_node_counts[k] += rdim2_shared->lane_name_map_node_counts[k][l_idx]; - rdim2_shared->lane_name_map_node_offs[k][l_idx] = node_off; - node_off += rdim2_shared->lane_name_map_node_counts[k][l_idx]; - } - rdim2_shared->total_name_map_node_count += rdim2_shared->name_map_node_counts[k]; - } - } - } - lane_sync(); - - // rjf: setup - ProfScope("setup") - { - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_top_level_name_maps.name_maps_count = RDI_NameMapKind_COUNT; - rdim2_shared->baked_top_level_name_maps.name_maps = push_array(arena, RDI_NameMap, rdim2_shared->baked_top_level_name_maps.name_maps_count); - RDI_U32 bucket_off = 0; - RDI_U32 node_off = 0; - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; - rdim2_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; - rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim2_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 - rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim2_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 - bucket_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count; - node_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count; - } - rdim2_shared->baked_name_maps.buckets_count = bucket_off; - rdim2_shared->baked_name_maps.buckets = push_array(arena, RDI_NameMapBucket, rdim2_shared->baked_name_maps.buckets_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_name_maps.nodes_count = rdim2_shared->total_name_map_node_count; - rdim2_shared->baked_name_maps.nodes = push_array(arena, RDI_NameMapNode, rdim2_shared->baked_name_maps.nodes_count); - } - } - lane_sync(); - - // rjf: wide fill baked name maps - ProfScope("wide fill baked name maps") - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) - { - RDI_U64 write_node_off = rdim2_shared->lane_name_map_node_offs[k][lane_idx()]; - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - U64 slots_count = top->slots_count; - RDIM_BakeNameMap2 *src_map = rdim2_shared->bake_name_maps[k]; - RDI_NameMap *dst_map = &rdim2_shared->baked_top_level_name_maps.name_maps[k]; - RDI_NameMapBucket *dst_buckets = rdim2_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; - RDI_NameMapNode *dst_nodes = rdim2_shared->baked_name_maps.nodes + dst_map->node_base_idx; - Rng1U64 slot_range = lane_range(slots_count); - for EachInRange(slot_idx, slot_range) - { - RDIM_BakeNameChunkList *src_slot = src_map->slots[slot_idx]; - if(src_slot == 0) { continue; } - RDI_NameMapBucket *dst_bucket = &dst_buckets[slot_idx]; - dst_bucket->first_node = write_node_off; - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct IdxRunNode IdxRunNode; - struct IdxRunNode - { - IdxRunNode *next; - RDI_U64 idx; - }; - IdxRunNode *first_idx_run_node = 0; - IdxRunNode *last_idx_run_node = 0; - U64 active_idx_count = 0; - String8 active_string = {0}; - RDIM_BakeNameChunkNode *n = src_slot->first; - U64 n_idx = 0; - for(;;) - { - // rjf: advance chunk - if(n != 0 && n_idx >= n->count) - { - n = n->next; - n_idx = 0; - } - - // rjf: grab next element - U64 idx = 0; - String8 string = {0}; - if(n != 0) - { - idx = n->v[n_idx].idx; - string = n->v[n_idx].string; - } - - // rjf: next element doesn't match the active list? -> push index run, clear active list, start new list - if(!str8_match(active_string, string, 0)) - { - // rjf: has active run -> flatten & serialize - if(active_string.size != 0) - { - // rjf: flatten idxes - RDI_U64 idxs_count = active_idx_count; - RDI_U32 *idxs = rdim_push_array(scratch.arena, RDI_U32, idxs_count); - { - U64 write_idx = 0; - for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) - { - idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 - write_idx += 1; - } - } - - // rjf: serialize node - RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; - dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); - dst_node->match_count = idxs_count; - if(dst_node->match_count == 1) - { - dst_node->match_idx_or_idx_run_first = idxs[0]; - } - else if(dst_node->match_count > 1) - { - dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, idxs, idxs_count); - } - dst_bucket->node_count += 1; - write_node_off += 1; - } - - // rjf: start new list - active_string = string; - first_idx_run_node = 0; - last_idx_run_node = 0; - active_idx_count = 0; - temp_end(scratch); - } - - // rjf: hash matches the active list -> push - if(active_string.size != 0 && str8_match(active_string, string, 0)) - { - IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); - idx_run_n->idx = idx; - SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); - active_idx_count += 1; - } - - // rjf: advance index - n_idx += 1; - - // rjf: end on zero node - if(n == 0) - { - break; - } - } - scratch_end(scratch); - } - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage gather line-bucketed src line map data - // - ProfScope("gather line-bucketed src line map data") - { - if(lane_idx() == 0) - { - rdim2_shared->bake_src_line_maps = push_array(arena, RDIM_BakeSrcLineMap, params->src_files.total_count); - } - lane_sync(); - { - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - U64 file_idx = n->base_idx + n_idx; - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[file_idx]; - - // rjf: set up map - map->slots_count = n->v[n_idx].total_line_count; - map->slots = push_array(arena, RDIM_BakeSrcLineMapSlot, map->slots_count); - - // rjf: gather line-bucketed info - for EachNode(frag, RDIM_SrcFileLineMapFragment, n->v[n_idx].first_line_map_fragment) - { - RDIM_LineSequence *seq = frag->seq; - for EachIndex(idx, seq->line_count) - { - RDI_U32 line_num = seq->line_nums[idx]; - RDI_U64 voff_first = seq->voffs[idx]; - RDI_U64 voff_opl = seq->voffs[idx+1]; - RDI_U64 slot_idx = line_num%map->slots_count; - - // rjf: find existing line node - RDIM_BakeSrcLineMapNode *line_node = 0; - { - for EachNode(line_n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) - { - if(line_n->line_num == line_num) - { - line_node = line_n; - break; - } - } - } - - // rjf: construct new node if unseen - if(line_node == 0) - { - line_node = push_array(arena, RDIM_BakeSrcLineMapNode, 1); - SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, line_node); - line_node->line_num = line_num; - map->line_count += 1; - } - - // rjf: push this voff range - RDIM_Rng1U64 voff_range = {voff_first, voff_opl}; - rdim_rng1u64_list_push(arena, &line_node->voff_ranges, voff_range); - map->voff_range_count += 1; - } - } - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage sort line-bucketed src line map data - // - ProfScope("sort line-bucketed src line map data") - { - U64 map_count = params->src_files.total_count; - if(lane_idx() == 0) - { - rdim2_shared->bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); - } - lane_sync(); - for(;;) - { - U64 map_num = ins_atomic_u64_inc_eval(&rdim2_shared->bake_src_line_map_take_counter); - if(map_num < 1 || map_count < map_num) - { - break; - } - U64 map_idx = map_num-1; - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[map_idx]; - - // rjf: gather keys - rdim2_shared->bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); - RDIM_SortKey *keys = rdim2_shared->bake_src_line_map_keys[map_idx]; - { - U64 key_idx = 0; - for EachIndex(slot_idx, map->slots_count) - { - for EachNode(n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) - { - keys[key_idx].key = n->line_num; - keys[key_idx].val = n; - key_idx += 1; - } - } - } - - // rjf: sort keys - { - radsort(keys, map->line_count, rdim_sort_key_is_before); - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute src file / src file line map layout - // - ProfScope("compute src file / src file line map layout") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - } - lane_sync(); - - // rjf: wide count - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; - for EachInRange(idx, range) - { - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; - rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; - rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; - rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; - } - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: layout - if(lane_idx() == 0) - { - U64 chunk_idx = 0; - U64 num_layout_off = 0; - U64 voff_layout_off = 0; - U64 map_layout_off = 1; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; - rdim2_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; - rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; - rdim2_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; - num_layout_off += rdim2_shared->lane_chunk_src_file_num_counts[slot_idx]; - voff_layout_off += rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx]; - map_layout_off += rdim2_shared->lane_chunk_src_file_map_counts[slot_idx]; - } - chunk_idx += 1; - } - rdim2_shared->total_src_map_line_count = num_layout_off; - rdim2_shared->total_src_map_voff_count = voff_layout_off; - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake src files - // - ProfScope("bake src files") - { - //- rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - rdim2_shared->baked_src_files.source_line_map_nums_count = rdim2_shared->total_src_map_line_count; - rdim2_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_nums_count); - rdim2_shared->baked_src_files.source_line_map_rngs_count = rdim2_shared->total_src_map_line_count + rdim2_shared->baked_src_files.source_line_maps_count; - rdim2_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_rngs_count); - rdim2_shared->baked_src_files.source_line_map_voffs_count = rdim2_shared->total_src_map_voff_count; - rdim2_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_src_files.source_line_map_voffs_count); - } - lane_sync(); - - //- rjf: bake - U64 chunk_idx = 0; - for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) - { - Rng1U64 range = lane_range(n->count); - U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; - U64 dst_num_off = rdim2_shared->lane_chunk_src_file_num_offs[slot_idx]; - U64 dst_map_off = rdim2_shared->lane_chunk_src_file_map_offs[slot_idx]; - U64 dst_voff_off = rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx]; - U64 dst_rng_off = dst_num_off + dst_map_off; - for EachInRange(idx, range) - { - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; - RDIM_SortKey *sorted_map_keys = rdim2_shared->bake_src_line_map_keys[n->base_idx + idx]; - RDIM_SrcFile *src = &n->v[idx]; - RDI_SourceFile *dst = &rdim2_shared->baked_src_files.source_files[n->base_idx + idx + 1]; - RDI_SourceLineMap *dst_map = &rdim2_shared->baked_src_files.source_line_maps[dst_map_off]; - RDI_U32 *dst_nums = &rdim2_shared->baked_src_files.source_line_map_nums[dst_num_off]; - RDI_U32 *dst_rngs = &rdim2_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; - RDI_U64 *dst_voffs = &rdim2_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; - - //- rjf: fill file info - Temp scratch = scratch_begin(&arena, 1); - String8 normalized_path = rdim_lower_from_str8(scratch.arena, src->path); - dst->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src->path); - dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); - dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; - scratch_end(scratch); - - //- rjf: fill map info - if(src->total_line_count != 0) - { - dst_map->line_count = (RDI_U32)map->line_count; // TODO(rjf): @u64_to_u32 - dst_map->voff_count = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 - dst_map->line_map_nums_base_idx = (RDI_U32)dst_num_off; // TODO(rjf): @u64_to_u32 - dst_map->line_map_range_base_idx = (RDI_U32)dst_rng_off; // TODO(rjf): @u64_to_u32 - dst_map->line_map_voff_base_idx = (RDI_U32)dst_voff_off; // TODO(rjf): @u64_to_u32 - dst_map_off += 1; - } - - //- rjf: fill nums/ranges/voffs info - if(src->total_line_count != 0) - { - U64 *dst_voff_ptr = dst_voffs; - for EachIndex(line_num_idx, map->line_count) - { - dst_nums[line_num_idx] = (RDI_U32)sorted_map_keys[line_num_idx].key; // TODO(rjf): @u64_to_u32 - dst_rngs[line_num_idx] = (RDI_U32)(dst_voff_ptr - dst_voffs); // TODO(rjf): @u64_to_u32 - RDIM_BakeSrcLineMapNode *node = (RDIM_BakeSrcLineMapNode *)sorted_map_keys[line_num_idx].val; - for EachNode(rng_n, RDIM_Rng1U64Node, node->voff_ranges.first) - { - dst_voff_ptr[0] = rng_n->v.min; - dst_voff_ptr += 1; - } - } - dst_rngs[map->line_count] = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 - dst_num_off += map->line_count; - dst_rng_off += map->line_count+1; - dst_voff_off += map->voff_range_count; - } - } - chunk_idx += 1; - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts - // - ProfScope("compute lane UDT member/enum-val layouts") - { - // rjf: allocate - if(lane_idx() == 0) - { - rdim2_shared->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); - } - lane_sync(); - - // rjf: count - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - U64 slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; - rdim2_shared->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; - rdim2_shared->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; - } - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: layout - if(lane_idx() == 0) - { - U64 member_layout_off = 1; - U64 enum_val_layout_off = 1; - U64 chunk_idx = 0; - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->udts.chunk_count + chunk_idx; - rdim2_shared->member_chunk_lane_offs[slot_idx] = member_layout_off; - rdim2_shared->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; - member_layout_off += rdim2_shared->member_chunk_lane_counts[slot_idx]; - enum_val_layout_off += rdim2_shared->enum_val_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake UDTs - // - ProfScope("bake UDTs") - { - //- rjf: set up - ProfScope("set up") - { - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; - rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; - rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; - rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); - } - } - lane_sync(); - - //- rjf: bake UDTs - ProfScope("bake UDTs") - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_UDTChunkNode, params->udts.first) - { - Rng1U64 range = lane_range(n->count); - U64 layout_slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; - U64 member_layout_off = rdim2_shared->member_chunk_lane_offs[layout_slot_idx]; - U64 enum_val_layout_off = rdim2_shared->enum_val_chunk_lane_offs[layout_slot_idx]; - for EachInRange(n_idx, range) - { - RDIM_UDT *src_udt = &n->v[n_idx]; - RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; - - //- rjf: fill basics - dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 - dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 - dst_udt->line = src_udt->line; - dst_udt->col = src_udt->col; - - //- rjf: fill member info - if(src_udt->first_member != 0) - { - U64 member_off_first = member_layout_off; - for EachNode(src_member, RDIM_UDTMember, src_udt->first_member) - { - RDI_Member *dst_member = &rdim2_shared->baked_udts.members[member_layout_off]; - dst_member->kind = src_member->kind; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); - dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 - dst_member->off = src_member->off; - member_layout_off += 1; - } - U64 member_off_opl = member_layout_off; - dst_udt->member_first = (RDI_U32)member_off_first; // TODO(rjf): @u64_to_u32 - dst_udt->member_count = (RDI_U32)(member_off_opl - member_off_first); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill enum val info - else if(src_udt->first_enum_val != 0) - { - U64 enum_val_off_first = enum_val_layout_off; - for EachNode(src_enum_val, RDIM_UDTEnumVal, src_udt->first_enum_val) - { - RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[enum_val_layout_off]; - dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_enum_val->name); - dst_member->val = src_enum_val->val; - enum_val_layout_off += 1; - } - U64 enum_val_off_opl = enum_val_layout_off; - dst_udt->flags |= RDI_UDTFlag_EnumMembers; - dst_udt->member_first = (RDI_U32)enum_val_off_first; // TODO(rjf): @u64_to_u32 - dst_udt->member_count = (RDI_U32)(enum_val_off_opl - enum_val_off_first); // TODO(rjf): @u64_to_u32 - } - } - chunk_idx += 1; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute lane location block layout - // - U64 total_location_case_chunk_count = (params->scopes.chunk_count + params->procedures.chunk_count); - ProfScope("compute lane location block layout") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->location_case_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); - rdim2_shared->location_case_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); - } - lane_sync(); - - // rjf: per-chunk-lane count of location cases - { - // rjf: count location cases in scopes - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - for EachNode(local, RDIM_Local, n->v[idx].first_local) - { - rdim2_shared->location_case_chunk_lane_counts[slot_idx] += local->location_cases.count; - } - } - chunk_idx += 1; - } - - // rjf: count location cases in procedures - for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) - { - U64 slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - rdim2_shared->location_case_chunk_lane_counts[slot_idx] += n->v[idx].location_cases.count; - } - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: lay out location case offsets - if(lane_idx() == 0) - { - U64 chunk_idx = 0; - U64 location_case_layout_off = 1; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; - rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; - location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; - rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; - location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - rdim2_shared->total_location_case_count = location_case_layout_off; - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake location blocks - // - ProfScope("bake location blocks") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->baked_location_blocks.location_blocks_count = rdim2_shared->total_location_case_count; - rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); - } - lane_sync(); - - // rjf: wide fill from scopes - U64 chunk_idx = 0; - ProfScope("wide fill from scopes") - { - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - for EachNode(local, RDIM_Local, n->v[idx].first_local) - { - for EachNode(src, RDIM_LocationCase2, local->location_cases.first) - { - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; - dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 - dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 - dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 - layout_off += 1; - } - } - } - chunk_idx += 1; - } - } - - // rjf: wide fill from procedures - ProfScope("wide fill from procedures") - { - for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) - { - U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - for EachNode(src, RDIM_LocationCase2, n->v[idx].location_cases.first) - { - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; - dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 - dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 - dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 - layout_off += 1; - } - } - chunk_idx += 1; - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake locations - // - ProfScope("bake locations") - { - if(lane_idx() == 0) - { - rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; - rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); - } - lane_sync(); - for EachNode(n, RDIM_LocationChunkNode, params->locations.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Location2 *loc = &n->v[n_idx]; - RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; - switch((RDI_LocationKindEnum)loc->info.kind) - { - case RDI_LocationKind_NULL:{}break; - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - MemoryCopy(dst+0, &loc->info.kind, sizeof(loc->info.kind)); - RDI_U64 write_off = sizeof(loc->info.kind); - for EachNode(op_node, RDIM_EvalBytecodeOp, loc->info.bytecode.first_op) - { - MemoryCopy(dst + write_off, &op_node->op, 1); - write_off += 1; - MemoryCopy(dst + write_off, &op_node->p, op_node->p_size); - write_off += op_node->p_size; - } - dst[write_off] = 0; - }break; - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 baked = {loc->info.kind, loc->info.reg_code, loc->info.offset}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - case RDI_LocationKind_ValReg: - { - RDI_LocationReg baked = {loc->info.kind, loc->info.reg_code}; - MemoryCopy(dst, &baked, sizeof(baked)); - }break; - } - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) - // - ProfScope("compute layout for scope sub-lists (locals / voffs)") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - } - lane_sync(); - - // rjf: count per-lane-chunk - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - U64 num_locals_in_this_lane_and_node = 0; - U64 num_voffs_in_this_lane_and_node = 0; - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - num_locals_in_this_lane_and_node += n->v[n_idx].local_count; - num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; - } - rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; - rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: lay out each lane's range - if(lane_idx() == 0) - { - U64 local_layout_off = 1; - U64 voff_layout_off = 1; - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; - rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; - rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; - local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; - voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - } - lane_sync(); - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake scopes - // - ProfScope("bake scopes") - { - //- rjf: setup outputs - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; - rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; - rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; - rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); - } - lane_sync(); - - //- rjf: wide fill - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) - { - Rng1U64 range = lane_range(n->count); - U64 scope_chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; - U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; - U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; - U64 location_block_chunk_lane_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 chunk_location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_chunk_lane_slot_idx]; - for EachInRange(n_idx, range) - { - U64 dst_idx = 1 + n->base_idx + n_idx; - RDIM_Scope *src_scope = &n->v[n_idx]; - RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; - - //- rjf: fill voff ranges - U64 voff_idx_first = chunk_voff_off; - for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) - { - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; - chunk_voff_off += 2; - } - U64 voff_idx_opl = chunk_voff_off; - - //- rjf: fill locals - U64 local_idx_first = chunk_local_off; - for EachNode(src_local, RDIM_Local, src_scope->first_local) - { - RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; - dst_local->kind = src_local->kind; - dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); - dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 - if(src_local->location_cases.count != 0) - { - dst_local->location_first = chunk_location_block_off; - dst_local->location_opl = chunk_location_block_off + src_local->location_cases.count; - chunk_location_block_off += src_local->location_cases.count; - } - chunk_local_off += 1; - } - U64 local_idx_opl = chunk_local_off; - - //- rjf: fill scope - dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 - dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 - dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 - dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 - dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 - dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 - dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 - } - chunk_idx += 1; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake procedures - // - ProfScope("bake procedures") - { - if(lane_idx() == 0) - { - rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; - rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); - } - lane_sync(); - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) - { - U64 location_block_layout_slot_idx = lane_idx()*total_location_case_chunk_count + params->scopes.chunk_count + chunk_idx; - U64 location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_layout_slot_idx]; - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_Procedure *dst = &rdim2_shared->baked_procedures.procedures[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 - if(src->location_cases.count != 0) - { - dst->frame_base_location_first = location_block_off; - dst->frame_base_location_opl = location_block_off + src->location_cases.count; - location_block_off += src->location_cases.count; - } - } - chunk_idx += 1; - } - } - } - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage compute layout for constant data - // - ProfScope("compute layout for constant data") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); - rdim2_shared->constant_data_chunk_lane_offs = push_array(arena, U64, lane_count() * params->constants.chunk_count); - } - lane_sync(); - - // rjf: count - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) - { - U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; - Rng1U64 range = lane_range(n->count); - for EachInRange(idx, range) - { - rdim2_shared->constant_data_chunk_lane_counts[slot_idx] += n->v[idx].value_data.size; - } - chunk_idx += 1; - } - } - lane_sync(); - - // rjf: layout - if(lane_idx() == 0) - { - U64 chunk_idx = 0; - U64 layout_off = 0; - for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) - { - for EachIndex(l_idx, lane_count()) - { - U64 slot_idx = l_idx*params->constants.chunk_count + chunk_idx; - rdim2_shared->constant_data_chunk_lane_offs[slot_idx] = layout_off; - layout_off += rdim2_shared->constant_data_chunk_lane_counts[slot_idx]; - } - chunk_idx += 1; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake constants - // - ProfScope("bake constants") - { - // rjf: set up - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; - rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); - } - lane_sync(); - - // rjf: wide bake - { - U64 chunk_idx = 0; - for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) - { - U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; - U64 value_data_off = rdim2_shared->constant_data_chunk_lane_offs[slot_idx]; - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_Constant *dst = &rdim2_shared->baked_constants.constants[1 + n->base_idx + n_idx]; - RDI_U32 *dst_value_off = &rdim2_shared->baked_constants.constant_values[1 + n->base_idx + n_idx]; - RDI_U8 *dst_value_data = rdim2_shared->baked_constants.constant_value_data + value_data_off; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->constant_value_idx = 1 + n->base_idx + n_idx; - dst_value_off[0] = (RDI_U32)value_data_off; // TODO(rjf): @u64_to_u32 - rdim_memcpy(dst_value_data, src->value_data.str, src->value_data.size); - value_data_off += src->value_data.size; - } - chunk_idx += 1; - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake units, symbols, types, UDTs - // - { - //- rjf: setup outputs - if(lane_idx() == lane_from_task_idx(0)) - { - rdim2_shared->baked_units.units_count = params->units.total_count+1; - rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); - } - if(lane_idx() == lane_from_task_idx(1)) - { - rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; - rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); - } - if(lane_idx() == lane_from_task_idx(2)) - { - rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; - rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); - } - if(lane_idx() == lane_from_task_idx(3)) - { - rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; - rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); - } - if(lane_idx() == lane_from_task_idx(4)) - { - rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; - rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); - } - lane_sync(); - - //- rjf: bake units - ProfScope("bake units") - { - for EachNode(n, RDIM_UnitChunkNode, params->units.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Unit *src = &n->v[n_idx]; - RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; - dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); - dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); - dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); - dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); - dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); - dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); - dst->language = src->language; - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - - //- rjf: bake type nodes - ProfScope("bake type nodes") - { - for EachNode(n, RDIM_TypeChunkNode, params->types.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Type *src = &n->v[n_idx]; - RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; - - //- rjf: fill shared type node info - dst->kind = src->kind; - dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 - dst->byte_size = src->byte_size; - - //- rjf: fill built-in-only type node info - if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) - { - dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - } - - //- rjf: fill array sizes - else if(dst->kind == RDI_TypeKind_Array) - { - U64 direct_byte_size = 1; - if(src->direct_type && src->direct_type->byte_size > 0) - { - direct_byte_size = src->direct_type->byte_size; - } - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); - dst->constructed.count = src->byte_size / direct_byte_size; - } - - //- rjf: fill constructed type node info - else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) - { - dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->constructed.count = src->count; - if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) - { - RDI_U32 param_idx_run_count = src->count; - RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); - for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) - { - param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 - } - dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run_2(bake_idx_runs, param_idx_run, param_idx_run_count); - } - else if(dst->kind == RDI_TypeKind_MemberPtr) - { - // TODO(rjf): member pointers not currently supported. - } - } - - //- rjf: fill user-defined-type info - else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) - { - dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 - dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - } - - //- rjf: fill bitfield info - else if(dst->kind == RDI_TypeKind_Bitfield) - { - dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 - dst->bitfield.off = src->off; - dst->bitfield.size = src->count; - } - } - } - } - - //- rjf: bake global variables - ProfScope("bake global variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->global_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->voff = src->offset; - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake thread variables - ProfScope("bake thread variables") - { - for EachNode(n, RDIM_SymbolChunkNode, params->thread_variables.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDIM_Symbol *src = &n->v[n_idx]; - RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); - if(src->is_extern) - { - dst->link_flags |= RDI_LinkFlag_External; - } - if(src->container_type != 0) - { - dst->link_flags |= RDI_LinkFlag_TypeScoped; - dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 - } - else if(src->container_symbol != 0) - { - dst->link_flags |= RDI_LinkFlag_ProcScoped; - dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 - } - } - } - } - - //- rjf: bake inline sites - ProfScope("bake inline sites") - { - for EachNode(n, RDIM_InlineSiteChunkNode, params->inline_sites.first) - { - Rng1U64 range = lane_range(n->count); - for EachInRange(n_idx, range) - { - RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; - RDIM_InlineSite *src = &n->v[n_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 - dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage bake file paths - // - ProfScope("bake file paths") - { - // rjf: set up - if(lane_idx() == 0) - { - rdim2_shared->baked_file_paths.nodes_count = path_tree->count; - rdim2_shared->baked_file_paths.nodes = push_array(arena, RDI_FilePathNode, rdim2_shared->baked_file_paths.nodes_count); - rdim2_shared->baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, rdim2_shared->baked_file_paths.nodes_count); - { - U64 idx = 0; - for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) - { - rdim2_shared->baked_file_path_src_nodes[idx] = n; - idx += 1; - } - } - } - lane_sync(); - - // rjf: fill - { - Rng1U64 range = lane_range(rdim2_shared->baked_file_paths.nodes_count); - for EachInRange(idx, range) - { - RDIM_BakePathNode *src = rdim2_shared->baked_file_path_src_nodes[idx]; - RDI_FilePathNode *dst = &rdim2_shared->baked_file_paths.nodes[idx]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->source_file_idx = rdim_idx_from_src_file(src->src_file); - if(src->parent != 0) - { - dst->parent_path_node = src->parent->idx; - } - if(src->first_child != 0) - { - dst->first_child = src->first_child->idx; - } - if(src->next_sibling != 0) - { - dst->next_sibling = src->next_sibling->idx; - } - } - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage do small final baking tasks - // - ProfScope("do small final baking tasks") - { - if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") - { - rdim2_shared->baked_top_level_info.top_level_info.arch = params->top_level_info.arch; - rdim2_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); - rdim2_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; - rdim2_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; - rdim2_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); - } - if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") - { - RDIM_BinarySectionList *src = ¶ms->binary_sections; - RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src->count+1); - U64 dst_idx = 1; - for(RDIM_BinarySectionNode *src_n = src->first; src_n != 0; src_n = src_n->next, dst_idx += 1) - { - RDIM_BinarySection *src = &src_n->v; - RDI_BinarySection *dst = &dst_base[dst_idx]; - dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); - dst->flags = src->flags; - dst->voff_first = src->voff_first; - dst->voff_opl = src->voff_opl; - dst->foff_first = src->foff_first; - dst->foff_opl = src->foff_opl; - } - rdim2_shared->baked_binary_sections.binary_sections = dst_base; - rdim2_shared->baked_binary_sections.binary_sections_count = dst_idx; - } - } - lane_sync(); - - ////////////////////////////////////////////////////////////// - //- rjf: @rdim_bake_stage package results - // - RDIM_BakeResults result = {0}; - { - result.top_level_info = rdim2_shared->baked_top_level_info; - result.binary_sections = rdim2_shared->baked_binary_sections; - result.units = rdim2_shared->baked_units; - result.unit_vmap = rdim2_shared->baked_unit_vmap; - result.src_files = rdim2_shared->baked_src_files; - result.line_tables = rdim2_shared->baked_line_tables; - result.type_nodes = rdim2_shared->baked_type_nodes; - result.udts = rdim2_shared->baked_udts; - result.global_variables = rdim2_shared->baked_global_variables; - result.global_vmap = rdim2_shared->baked_global_vmap; - result.thread_variables = rdim2_shared->baked_thread_variables; - result.constants = rdim2_shared->baked_constants; - result.procedures = rdim2_shared->baked_procedures; - result.scopes = rdim2_shared->baked_scopes; - result.inline_sites = rdim2_shared->baked_inline_sites; - result.scope_vmap = rdim2_shared->baked_scope_vmap; - result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; - result.name_maps = rdim2_shared->baked_name_maps; - result.file_paths = rdim2_shared->baked_file_paths; - result.strings = rdim2_shared->baked_strings; - result.idx_runs = rdim2_shared->baked_idx_runs; - result.locations = rdim2_shared->baked_locations; - result.location_blocks2 = rdim2_shared->baked_location_blocks; - } - - return result; -} diff --git a/src/rdi_make/rdi_make_local_2.h b/src/rdi_make/rdi_make_local_2.h deleted file mode 100644 index 7b43b9be..00000000 --- a/src/rdi_make/rdi_make_local_2.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_MAKE_LOCAL_2_H -#define RDI_MAKE_LOCAL_2_H - -//- rjf: unsorted joined line table info - -typedef struct RDIM_UnsortedJoinedLineTable RDIM_UnsortedJoinedLineTable; -struct RDIM_UnsortedJoinedLineTable -{ - RDI_U64 line_count; - RDI_U64 seq_count; - RDI_U64 key_count; - RDIM_SortKey *line_keys; - RDIM_LineRec *line_recs; -}; - -//- rjf: shared state bundle - -typedef struct RDIM2_Shared RDIM2_Shared; -struct RDIM2_Shared -{ - RDI_U64 scope_vmap_count; - RDIM_SortKey *scope_vmap_keys; - RDIM_SortKey *scope_vmap_keys__swap; - RDIM_VMapMarker *scope_vmap_markers; - RDI_U64 unit_vmap_count; - RDIM_SortKey *unit_vmap_keys; - RDIM_SortKey *unit_vmap_keys__swap; - RDIM_VMapMarker *unit_vmap_markers; - RDI_U64 global_vmap_count; - RDIM_SortKey *global_vmap_keys; - RDIM_SortKey *global_vmap_keys__swap; - RDIM_VMapMarker *global_vmap_markers; - U32 **lane_digit_counts; - U32 **lane_digit_offsets; - - RDIM_ScopeVMapBakeResult baked_scope_vmap; - RDIM_UnitVMapBakeResult baked_unit_vmap; - RDIM_GlobalVMapBakeResult baked_global_vmap; - - RDIM_BakePathTree *path_tree; - - RDI_U64 line_tables_count; - RDI_U64 line_table_block_take_counter; - RDIM_LineTable **src_line_tables; - RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables; - - RDIM_SortKey **sorted_line_table_keys; - - RDIM_LineTableBakeResult baked_line_tables; - - RDIM_BakeStringMapTopology bake_string_map_topology; - RDIM_BakeStringMapLoose **lane_bake_string_maps__loose; - RDIM_BakeStringMapLoose *bake_string_map__loose; - RDIM_BakeStringMapTight bake_strings; - - RDIM_BakeNameMapTopology bake_name_map_topology[RDI_NameMapKind_COUNT]; - RDIM_BakeNameMap2 **lane_bake_name_maps[RDI_NameMapKind_COUNT]; - RDIM_BakeNameMap2 *bake_name_maps[RDI_NameMapKind_COUNT]; - - RDIM_BakeIdxRunMapTopology bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose **lane_bake_idx_run_maps__loose; - RDIM_BakeIdxRunMapLoose *bake_idx_run_map__loose; - RDIM_BakeIdxRunMap2 bake_idx_runs; - - RDIM_StringBakeResult baked_strings; - - RDIM_IndexRunBakeResult baked_idx_runs; - - RDI_U64 *lane_name_map_node_counts[RDI_NameMapKind_COUNT]; - RDI_U64 *lane_name_map_node_offs[RDI_NameMapKind_COUNT]; - RDI_U64 name_map_node_counts[RDI_NameMapKind_COUNT]; - RDI_U64 total_name_map_node_count; - RDIM_TopLevelNameMapBakeResult baked_top_level_name_maps; - RDIM_NameMapBakeResult baked_name_maps; - - RDIM_BakeSrcLineMap *bake_src_line_maps; - - RDI_U64 bake_src_line_map_take_counter; - RDIM_SortKey **bake_src_line_map_keys; - - RDI_U64 *lane_chunk_src_file_num_counts; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_voff_counts; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_map_counts; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_voff_offs; // [lane_count * src_file_chunk_count] - RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] - RDI_U64 total_src_map_line_count; - RDI_U64 total_src_map_voff_count; - - RDIM_SrcFileBakeResult baked_src_files; - - RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] - RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] - RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] - RDI_U64 *enum_val_chunk_lane_offs; // [lane_count * udt_chunk_count] - - RDIM_UDTBakeResult baked_udts; - - RDI_U64 *location_case_chunk_lane_counts; // [lane_count * (scope_chunk_count + procedure_chunk_count) - RDI_U64 *location_case_chunk_lane_offs; // [lane_count * (scope_chunk_count + procedure_chunk_count) - RDI_U64 total_location_case_count; - - RDIM_LocationBlockBakeResult baked_location_blocks; - - RDIM_LocationBakeResult baked_locations; - - RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] - RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] - RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] - RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] - - RDIM_ScopeBakeResult baked_scopes; - - RDIM_ProcedureBakeResult baked_procedures; - - RDI_U64 *constant_data_chunk_lane_counts; // [lane_count * constant_chunk_count] - RDI_U64 *constant_data_chunk_lane_offs; // [lane_count * constant_chunk_count] - - RDIM_ConstantsBakeResult baked_constants; - - RDIM_UnitBakeResult baked_units; - RDIM_TypeNodeBakeResult baked_type_nodes; - RDIM_GlobalVariableBakeResult baked_global_variables; - RDIM_ThreadVariableBakeResult baked_thread_variables; - RDIM_InlineSiteBakeResult baked_inline_sites; - - RDIM_BakePathNode **baked_file_path_src_nodes; - RDIM_FilePathBakeResult baked_file_paths; - - RDIM_TopLevelInfoBakeResult baked_top_level_info; - RDIM_BinarySectionBakeResult baked_binary_sections; -}; - -global RDIM2_Shared *rdim2_shared = 0; - -internal RDIM_BakeResults rdim2_bake(Arena *arena, RDIM_BakeParams *params); - -#endif // RDI_MAKE_LOCAL_2_H From 23a68faadd359a4583128d7d43187a3ab61d77c5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 17:06:19 -0700 Subject: [PATCH 138/302] rdim2 -> rdim; p2r2 -> p2r --- src/radbin/radbin.c | 2 +- src/rdi_from_pdb/rdi_from_pdb.c | 390 ++++++++--------- src/rdi_from_pdb/rdi_from_pdb.h | 10 +- src/rdi_make/rdi_make_local.c | 712 ++++++++++++++++---------------- src/rdi_make/rdi_make_local.h | 8 +- 5 files changed, 561 insertions(+), 561 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 132e821f..c54468bb 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -755,7 +755,7 @@ rb_thread_entry_point(void *p) RDIM_BakeResults bake_results = {0}; if(convert_done) ProfScope("bake") { - bake_results = rdim2_bake(arena, &bake_params); + bake_results = rdim_bake(arena, &bake_params); } //- rjf: convert done => generate output diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index a42616c5..8f4a88f6 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -315,7 +315,7 @@ p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encod } internal RDIM_LocationInfo -p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) +p2r_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) { RDIM_LocationInfo result = {0}; if(0 <= offset && offset <= (S64)max_U16) @@ -352,7 +352,7 @@ p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode re } internal void -p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +p2r_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) { //- rjf: extract range info U64 voff_first = 0; @@ -399,14 +399,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: setup output buckets if(lane_idx() == 0) { - p2r2_shared = push_array(arena, P2R2_Shared, 1); - p2r2_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); - p2r2_shared->msf = push_array(arena, MSF_Parsed, 1); - p2r2_shared->msf->page_size = p2r2_shared->msf_raw_stream_table->page_size; - p2r2_shared->msf->page_count = p2r2_shared->msf_raw_stream_table->total_page_count; - p2r2_shared->msf->stream_count = p2r2_shared->msf_raw_stream_table->stream_count; - p2r2_shared->msf->streams = push_array(arena, String8, p2r2_shared->msf->stream_count); - p2r2_shared->msf_stream_lane_counter = 0; + p2r_shared = push_array(arena, P2R_Shared, 1); + p2r_shared->msf_raw_stream_table = msf_raw_stream_table_from_data(arena, params->input_pdb_data); + p2r_shared->msf = push_array(arena, MSF_Parsed, 1); + p2r_shared->msf->page_size = p2r_shared->msf_raw_stream_table->page_size; + p2r_shared->msf->page_count = p2r_shared->msf_raw_stream_table->total_page_count; + p2r_shared->msf->stream_count = p2r_shared->msf_raw_stream_table->stream_count; + p2r_shared->msf->streams = push_array(arena, String8, p2r_shared->msf->stream_count); + p2r_shared->msf_stream_lane_counter = 0; } lane_sync(); @@ -414,18 +414,18 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for(;;) { - U64 stream_num = ins_atomic_u64_inc_eval(&p2r2_shared->msf_stream_lane_counter); - if(stream_num < 1 || p2r2_shared->msf->stream_count < stream_num) + U64 stream_num = ins_atomic_u64_inc_eval(&p2r_shared->msf_stream_lane_counter); + if(stream_num < 1 || p2r_shared->msf->stream_count < stream_num) { break; } U64 stream_idx = stream_num-1; - p2r2_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r2_shared->msf_raw_stream_table, stream_idx); + p2r_shared->msf->streams[stream_idx] = msf_data_from_stream_number(arena, params->input_pdb_data, p2r_shared->msf_raw_stream_table, stream_idx); } } } lane_sync(); - MSF_Parsed *msf = p2r2_shared->msf; + MSF_Parsed *msf = p2r_shared->msf; ////////////////////////////////////////////////////////////// //- rjf: do top-level MSF/PDB extraction @@ -435,20 +435,20 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) ProfScope("parse PDB info") { String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); - p2r2_shared->pdb_info = pdb_info_from_data(arena, info_data); - if(p2r2_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) + p2r_shared->pdb_info = pdb_info_from_data(arena, info_data); + if(p2r_shared->pdb_info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { log_user_error(str8_lit("PDB was linked with /DEBUG:FASTLINK; partial debug info is not supported. Please relink using /DEBUG:FULL.")); } } ProfScope("parse named streams table") { - p2r2_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r2_shared->pdb_info); + p2r_shared->named_streams = pdb_named_stream_table_from_info(arena, p2r_shared->pdb_info); } } lane_sync(); - PDB_Info *pdb_info = p2r2_shared->pdb_info; - PDB_NamedStreamTable *named_streams = p2r2_shared->named_streams; + PDB_Info *pdb_info = p2r_shared->pdb_info; + PDB_NamedStreamTable *named_streams = p2r_shared->named_streams; ////////////////////////////////////////////////////////////// //- rjf: parse PDB strtbl & top-level streams @@ -459,31 +459,31 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - p2r2_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); - p2r2_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r2_shared->strtbl->strblock_min, p2r2_shared->strtbl->strblock_max)); + p2r_shared->strtbl = pdb_strtbl_from_data(arena, strtbl_data); + p2r_shared->raw_strtbl = str8_substr(strtbl_data, rng_1u64(p2r_shared->strtbl->strblock_min, p2r_shared->strtbl->strblock_max)); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse DBI") { String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); - p2r2_shared->dbi = pdb_dbi_from_data(arena, dbi_data); + p2r_shared->dbi = pdb_dbi_from_data(arena, dbi_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI") { String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); - p2r2_shared->tpi = pdb_tpi_from_data(arena, tpi_data); + p2r_shared->tpi = pdb_tpi_from_data(arena, tpi_data); } if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI") { String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); - p2r2_shared->ipi = pdb_tpi_from_data(arena, ipi_data); + p2r_shared->ipi = pdb_tpi_from_data(arena, ipi_data); } } lane_sync(); - PDB_Strtbl *strtbl = p2r2_shared->strtbl; - String8 raw_strtbl = p2r2_shared->raw_strtbl; - PDB_DbiParsed *dbi = p2r2_shared->dbi; - PDB_TpiParsed *tpi = p2r2_shared->tpi; - PDB_TpiParsed *ipi = p2r2_shared->ipi; + PDB_Strtbl *strtbl = p2r_shared->strtbl; + String8 raw_strtbl = p2r_shared->raw_strtbl; + PDB_DbiParsed *dbi = p2r_shared->dbi; + PDB_TpiParsed *tpi = p2r_shared->tpi; + PDB_TpiParsed *ipi = p2r_shared->ipi; ////////////////////////////////////////////////////////////// //- rjf: unpack DBI @@ -494,24 +494,24 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; String8 section_data = msf_data_from_stream(msf, section_stream); - p2r2_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); + p2r_shared->coff_sections = pdb_coff_section_array_from_data(arena, section_data); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse GSI") { String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); - p2r2_shared->gsi = pdb_gsi_from_data(arena, gsi_data); + p2r_shared->gsi = pdb_gsi_from_data(arena, gsi_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse GSI part of PSI") { String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); - p2r2_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + p2r_shared->psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); } } lane_sync(); - COFF_SectionHeaderArray coff_sections = p2r2_shared->coff_sections; - PDB_GsiParsed *gsi = p2r2_shared->gsi; - PDB_GsiParsed *psi_gsi_part = p2r2_shared->psi_gsi_part; + COFF_SectionHeaderArray coff_sections = p2r_shared->coff_sections; + PDB_GsiParsed *gsi = p2r_shared->gsi; + PDB_GsiParsed *psi_gsi_part = p2r_shared->psi_gsi_part; ////////////////////////////////////////////////////////////// //- rjf: hash EXE, parse TPI/IPI hash/leaf & global symbol stream & comp units @@ -520,68 +520,68 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { if(lane_idx() == lane_from_task_idx(0)) ProfScope("hash EXE") { - p2r2_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); + p2r_shared->exe_hash = rdi_hash(params->input_exe_data.str, params->input_exe_data.size); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("parse TPI hash") { String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); - p2r2_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); + p2r_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") { String8 leaf_data = pdb_leaf_data_from_tpi(tpi); - p2r2_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); + p2r_shared->tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); } if(lane_idx() == lane_from_task_idx(3)) ProfScope("parse IPI hash") { String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); - p2r2_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); + p2r_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") { String8 leaf_data = pdb_leaf_data_from_tpi(ipi); - p2r2_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); + p2r_shared->ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); } if(lane_idx() == lane_from_task_idx(5)) ProfScope("parse compilation units") { String8 comp_units_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); - p2r2_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); + p2r_shared->comp_units = pdb_comp_unit_array_from_data(arena, comp_units_data); } if(lane_idx() == lane_from_task_idx(6)) ProfScope("parse compilation unit contributions") { String8 contribs_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); - p2r2_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); + p2r_shared->comp_unit_contributions = pdb_comp_unit_contribution_array_from_data(arena, contribs_data, coff_sections); } } lane_sync(); - U64 exe_hash = p2r2_shared->exe_hash; - PDB_TpiHashParsed *tpi_hash = p2r2_shared->tpi_hash; - CV_LeafParsed *tpi_leaf = p2r2_shared->tpi_leaf; - PDB_TpiHashParsed *ipi_hash = p2r2_shared->ipi_hash; - CV_LeafParsed *ipi_leaf = p2r2_shared->ipi_leaf; - PDB_CompUnitArray *comp_units = p2r2_shared->comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions = p2r2_shared->comp_unit_contributions; + U64 exe_hash = p2r_shared->exe_hash; + PDB_TpiHashParsed *tpi_hash = p2r_shared->tpi_hash; + CV_LeafParsed *tpi_leaf = p2r_shared->tpi_leaf; + PDB_TpiHashParsed *ipi_hash = p2r_shared->ipi_hash; + CV_LeafParsed *ipi_leaf = p2r_shared->ipi_leaf; + PDB_CompUnitArray *comp_units = p2r_shared->comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions = p2r_shared->comp_unit_contributions; ////////////////////////////////////////////////////////////// //- rjf: bucket compilation unit contributions // ProfScope("bucket compilation unit contributions") if(lane_idx() == 0) { - p2r2_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); + p2r_shared->unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, comp_units->count); for(U64 idx = 0; idx < comp_unit_contributions->count; idx += 1) { PDB_CompUnitContribution *contribution = &comp_unit_contributions->contributions[idx]; if(contribution->mod < comp_units->count) { RDIM_Rng1U64 r = {contribution->voff_first, contribution->voff_opl}; - rdim_rng1u64_chunk_list_push(arena, &p2r2_shared->unit_ranges[contribution->mod], 256, r); + rdim_rng1u64_chunk_list_push(arena, &p2r_shared->unit_ranges[contribution->mod], 256, r); } } } lane_sync(); - RDIM_Rng1U64ChunkList *unit_ranges = p2r2_shared->unit_ranges; + RDIM_Rng1U64ChunkList *unit_ranges = p2r_shared->unit_ranges; ////////////////////////////////////////////////////////////// //- rjf: parse all syms & c13 line info streams @@ -591,19 +591,19 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: setup outputs if(lane_idx() == 0) { - p2r2_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI - p2r2_shared->all_syms = push_array(arena, CV_SymParsed *, p2r2_shared->all_syms_count); - p2r2_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r2_shared->all_syms_count); - p2r2_shared->sym_c13_unit_lane_counter = 0; + p2r_shared->all_syms_count = comp_units->count+1; // +1 for global symbol stream from DBI + p2r_shared->all_syms = push_array(arena, CV_SymParsed *, p2r_shared->all_syms_count); + p2r_shared->all_c13s = push_array(arena, CV_C13Parsed *, p2r_shared->all_syms_count); + p2r_shared->sym_c13_unit_lane_counter = 0; } lane_sync(); //- rjf: wide fill { - U64 task_count = p2r2_shared->all_syms_count; + U64 task_count = p2r_shared->all_syms_count; for(;;) { - U64 task_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_c13_unit_lane_counter); + U64 task_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_c13_unit_lane_counter); if(task_num == 0 || task_count < task_num) { break; @@ -614,21 +614,21 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) PDB_CompUnit *unit = comp_units->units[task_idx-1]; String8 unit_sym_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); String8 unit_c13_data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); - p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); - p2r2_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); + p2r_shared->all_syms[task_idx] = cv_sym_from_data(arena, unit_sym_data, 4); + p2r_shared->all_c13s[task_idx] = cv_c13_parsed_from_data(arena, unit_c13_data, raw_strtbl, coff_sections); } else { String8 global_sym_data = msf_data_from_stream(msf, dbi->sym_sn); - p2r2_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); + p2r_shared->all_syms[task_idx] = cv_sym_from_data(arena, global_sym_data, 4); } } } } lane_sync(); - U64 all_syms_count = p2r2_shared->all_syms_count; - CV_SymParsed **all_syms = p2r2_shared->all_syms; - CV_C13Parsed **all_c13s = p2r2_shared->all_c13s; + U64 all_syms_count = p2r_shared->all_syms_count; + CV_SymParsed **all_syms = p2r_shared->all_syms; + CV_C13Parsed **all_c13s = p2r_shared->all_c13s; ////////////////////////////////////////////////////////////// //- rjf: calculate EXE's max voff @@ -640,11 +640,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) { U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; - p2r2_shared->exe_voff_max = Max(p2r2_shared->exe_voff_max, sec_voff_max); + p2r_shared->exe_voff_max = Max(p2r_shared->exe_voff_max, sec_voff_max); } } lane_sync(); - U64 exe_voff_max = p2r2_shared->exe_voff_max; + U64 exe_voff_max = p2r_shared->exe_voff_max; ////////////////////////////////////////////////////////////// //- rjf: determine architecture @@ -667,15 +667,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // for EachIndex(idx, all_syms_count) { - p2r2_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); - if(p2r2_shared->arch != RDI_Arch_NULL) + p2r_shared->arch = p2r_rdi_arch_from_cv_arch(all_syms[idx]->info.arch); + if(p2r_shared->arch != RDI_Arch_NULL) { break; } } } lane_sync(); - RDI_Arch arch = p2r2_shared->arch; + RDI_Arch arch = p2r_shared->arch; U64 arch_addr_size = rdi_addr_size_from_arch(arch); ////////////////////////////////////////////////////////////// @@ -688,11 +688,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { rec_range_count += all_syms[idx]->sym_ranges.count; } - p2r2_shared->symbol_count_prediction = rec_range_count/8; - p2r2_shared->symbol_count_prediction = Max(p2r2_shared->symbol_count_prediction, 256); + p2r_shared->symbol_count_prediction = rec_range_count/8; + p2r_shared->symbol_count_prediction = Max(p2r_shared->symbol_count_prediction, 256); } lane_sync(); - U64 symbol_count_prediction = p2r2_shared->symbol_count_prediction; + U64 symbol_count_prediction = p2r_shared->symbol_count_prediction; ////////////////////////////////////////////////////////////// //- rjf: build link name map @@ -701,8 +701,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { // rjf: set up { - p2r2_shared->link_name_map.buckets_count = symbol_count_prediction; - p2r2_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r2_shared->link_name_map.buckets_count); + p2r_shared->link_name_map.buckets_count = symbol_count_prediction; + p2r_shared->link_name_map.buckets = push_array(arena, P2R_LinkNameNode *, p2r_shared->link_name_map.buckets_count); } // rjf: fill @@ -744,9 +744,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: commit to link name map U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%p2r2_shared->link_name_map.buckets_count; + U64 bucket_idx = hash%p2r_shared->link_name_map.buckets_count; P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); - SLLStackPush(p2r2_shared->link_name_map.buckets[bucket_idx], node); + SLLStackPush(p2r_shared->link_name_map.buckets[bucket_idx], node); node->voff = voff; node->name = name; }break; @@ -755,7 +755,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - P2R_LinkNameMap link_name_map = p2r2_shared->link_name_map; + P2R_LinkNameMap link_name_map = p2r_shared->link_name_map; ////////////////////////////////////////////////////////////// //- rjf: gather all file paths @@ -765,9 +765,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: prep outputs ProfScope("prep outputs") if(lane_idx() == 0) { - p2r2_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); - p2r2_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); - p2r2_shared->sym_lane_take_counter = 0; + p2r_shared->unit_file_paths = push_array(arena, String8Array, comp_units->count); + p2r_shared->unit_file_paths_hashes = push_array(arena, U64Array, comp_units->count); + p2r_shared->sym_lane_take_counter = 0; } lane_sync(); @@ -785,7 +785,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for(;;) { //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); if(unit_num > comp_units->count) { break; @@ -1024,24 +1024,24 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } //- rjf: merge into array for this unit - p2r2_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); + p2r_shared->unit_file_paths[unit_idx] = str8_array_from_list(arena, &src_file_paths); //- rjf: hash this unit's file paths U64Array hashes = {0}; - hashes.count = p2r2_shared->unit_file_paths[unit_idx].count; + hashes.count = p2r_shared->unit_file_paths[unit_idx].count; hashes.v = push_array(arena, U64, hashes.count); - for EachIndex(idx, p2r2_shared->unit_file_paths[unit_idx].count) + for EachIndex(idx, p2r_shared->unit_file_paths[unit_idx].count) { - hashes.v[idx] = rdi_hash(p2r2_shared->unit_file_paths[unit_idx].v[idx].str, p2r2_shared->unit_file_paths[unit_idx].v[idx].size); + hashes.v[idx] = rdi_hash(p2r_shared->unit_file_paths[unit_idx].v[idx].str, p2r_shared->unit_file_paths[unit_idx].v[idx].size); } - p2r2_shared->unit_file_paths_hashes[unit_idx] = hashes; + p2r_shared->unit_file_paths_hashes[unit_idx] = hashes; } scratch_end(scratch); } } lane_sync(); - String8Array *unit_file_paths = p2r2_shared->unit_file_paths; - U64Array *unit_file_paths_hashes = p2r2_shared->unit_file_paths_hashes; + String8Array *unit_file_paths = p2r_shared->unit_file_paths; + U64Array *unit_file_paths_hashes = p2r_shared->unit_file_paths_hashes; ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files @@ -1050,13 +1050,13 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: set up table ProfScope("set up table") if(lane_idx() == 0) { - p2r2_shared->total_path_count = 0; + p2r_shared->total_path_count = 0; for EachIndex(idx, comp_units->count) { - p2r2_shared->total_path_count += unit_file_paths[idx].count; + p2r_shared->total_path_count += unit_file_paths[idx].count; } - p2r2_shared->src_file_map.slots_count = p2r2_shared->total_path_count + p2r2_shared->total_path_count/2 + 1; - p2r2_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r2_shared->src_file_map.slots_count); + p2r_shared->src_file_map.slots_count = p2r_shared->total_path_count + p2r_shared->total_path_count/2 + 1; + p2r_shared->src_file_map.slots = push_array(arena, P2R_SrcFileNode *, p2r_shared->src_file_map.slots_count); } lane_sync(); @@ -1071,9 +1071,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { String8 file_path_sanitized = paths.v[path_idx]; U64 file_path_sanitized_hash = hashes.v[path_idx]; - U64 src_file_slot = file_path_sanitized_hash%p2r2_shared->src_file_map.slots_count; + U64 src_file_slot = file_path_sanitized_hash%p2r_shared->src_file_map.slots_count; P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = p2r2_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) + for(P2R_SrcFileNode *n = p2r_shared->src_file_map.slots[src_file_slot]; n != 0; n = n->next) { if(str8_match(n->src_file->path, file_path_sanitized, 0)) { @@ -1084,8 +1084,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(src_file_node == 0) { src_file_node = push_array(arena, P2R_SrcFileNode, 1); - SLLStackPush(p2r2_shared->src_file_map.slots[src_file_slot], src_file_node); - src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r2_shared->all_src_files__sequenceless, p2r2_shared->total_path_count); + SLLStackPush(p2r_shared->src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &p2r_shared->all_src_files__sequenceless, p2r_shared->total_path_count); src_file_node->src_file->path = push_str8_copy(arena, file_path_sanitized); } } @@ -1093,8 +1093,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - RDIM_SrcFileChunkList all_src_files__sequenceless = p2r2_shared->all_src_files__sequenceless; - P2R_SrcFileMap src_file_map = p2r2_shared->src_file_map; + RDIM_SrcFileChunkList all_src_files__sequenceless = p2r_shared->all_src_files__sequenceless; + P2R_SrcFileMap src_file_map = p2r_shared->src_file_map; ////////////////////////////////////////////////////////////// //- rjf: convert unit info @@ -1106,23 +1106,23 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, comp_units->count) { - rdim_unit_chunk_list_push(arena, &p2r2_shared->all_units, comp_units->count); + rdim_unit_chunk_list_push(arena, &p2r_shared->all_units, comp_units->count); } - p2r2_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); - p2r2_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); - p2r2_shared->sym_lane_take_counter = 0; + p2r_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); + p2r_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); + p2r_shared->sym_lane_take_counter = 0; } lane_sync(); - RDIM_Unit *units = p2r2_shared->all_units.first->v; - U64 units_count = p2r2_shared->all_units.first->count; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; + RDIM_Unit *units = p2r_shared->all_units.first->v; + U64 units_count = p2r_shared->all_units.first->count; + RDIM_LineTableChunkList *units_line_tables = p2r_shared->units_line_tables; Assert(units_count == comp_units->count); //- rjf: do per-lane work ProfScope("wide fill") for(;;) { //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); if(unit_num > comp_units->count) { break; @@ -1403,9 +1403,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(line_table == 0) { line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(p2r2_shared->units_first_inline_site_line_tables[unit_idx] == 0) + if(p2r_shared->units_first_inline_site_line_tables[unit_idx] == 0) { - p2r2_shared->units_first_inline_site_line_tables[unit_idx] = line_table; + p2r_shared->units_first_inline_site_line_tables[unit_idx] = line_table; } } rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); @@ -1451,9 +1451,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - RDIM_UnitChunkList all_units = p2r2_shared->all_units; - RDIM_LineTableChunkList *units_line_tables = p2r2_shared->units_line_tables; - RDIM_LineTable **units_first_inline_site_line_tables = p2r2_shared->units_first_inline_site_line_tables; + RDIM_UnitChunkList all_units = p2r_shared->all_units; + RDIM_LineTableChunkList *units_line_tables = p2r_shared->units_line_tables; + RDIM_LineTable **units_first_inline_site_line_tables = p2r_shared->units_first_inline_site_line_tables; ////////////////////////////////////////////////////////////// //- rjf: join all line tables @@ -1462,11 +1462,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, comp_units->count) { - rdim_line_table_chunk_list_concat_in_place(&p2r2_shared->all_line_tables, &units_line_tables[idx]); + rdim_line_table_chunk_list_concat_in_place(&p2r_shared->all_line_tables, &units_line_tables[idx]); } } lane_sync(); - RDIM_LineTableChunkList all_line_tables = p2r2_shared->all_line_tables; + RDIM_LineTableChunkList all_line_tables = p2r_shared->all_line_tables; ////////////////////////////////////////////////////////////// //- rjf: equip source files with line sequences @@ -1482,13 +1482,13 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_LineTable *line_table = &line_table_chunk_n->v[chunk_line_table_idx]; for(RDIM_LineSequenceNode *s = line_table->first_seq; s != 0; s = s->next) { - rdim_src_file_push_line_sequence(arena, &p2r2_shared->all_src_files__sequenceless, s->v.src_file, &s->v); + rdim_src_file_push_line_sequence(arena, &p2r_shared->all_src_files__sequenceless, s->v.src_file, &s->v); } } } } lane_sync(); - RDIM_SrcFileChunkList all_src_files = p2r2_shared->all_src_files__sequenceless; + RDIM_SrcFileChunkList all_src_files = p2r_shared->all_src_files__sequenceless; ////////////////////////////////////////////////////////////// //- rjf: types pass 1: produce type forward resolution map @@ -1504,19 +1504,19 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: allocate forward resolution map if(lane_idx() == 0) { - p2r2_shared->itype_first = tpi_leaf->itype_first; - p2r2_shared->itype_opl = tpi_leaf->itype_opl; - p2r2_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r2_shared->itype_opl); + p2r_shared->itype_first = tpi_leaf->itype_first; + p2r_shared->itype_opl = tpi_leaf->itype_opl; + p2r_shared->itype_fwd_map = push_array(arena, CV_TypeId, (U64)p2r_shared->itype_opl); } lane_sync(); //- rjf: do wide fill { - Rng1U64 range = lane_range(p2r2_shared->itype_opl); + Rng1U64 range = lane_range(p2r_shared->itype_opl); for EachInRange(idx, range) { CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r2_shared->itype_first) { continue; } + if(itype < p2r_shared->itype_first) { continue; } //- rjf: determine if this itype resolves to another CV_TypeId itype_fwd = 0; @@ -1628,15 +1628,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map if(itype_fwd != 0 && itype_fwd < tpi_leaf->itype_opl) { - p2r2_shared->itype_fwd_map[itype] = itype_fwd; + p2r_shared->itype_fwd_map[itype] = itype_fwd; } } } } lane_sync(); - CV_TypeId *itype_fwd_map = p2r2_shared->itype_fwd_map; - CV_TypeId itype_first = p2r2_shared->itype_first; - CV_TypeId itype_opl = p2r2_shared->itype_opl; + CV_TypeId *itype_fwd_map = p2r_shared->itype_fwd_map; + CV_TypeId itype_first = p2r_shared->itype_first; + CV_TypeId itype_opl = p2r_shared->itype_opl; ////////////////////////////////////////////////////////////// //- rjf: types pass 2: produce per-itype itype chain @@ -1653,23 +1653,23 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: allocate itype chain table if(lane_idx() == 0) { - p2r2_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r2_shared->itype_opl); + p2r_shared->itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)p2r_shared->itype_opl); } lane_sync(); //- rjf: do wide fill { - Rng1U64 range = lane_range(p2r2_shared->itype_opl); + Rng1U64 range = lane_range(p2r_shared->itype_opl); for EachInRange(idx, range) { CV_TypeId itype = (CV_TypeId)idx; - if(itype < p2r2_shared->itype_first) { continue; } + if(itype < p2r_shared->itype_first) { continue; } //- rjf: push initial itype - should be final-visited-itype for this itype { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } //- rjf: skip basic types for dependency walk @@ -1714,7 +1714,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itype @@ -1734,7 +1734,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itype @@ -1754,7 +1754,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk return itype @@ -1789,7 +1789,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk arg types @@ -1810,17 +1810,17 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->ret_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->arg_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->this_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itypes @@ -1865,7 +1865,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = arglist_itypes_base[idx]; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk arg types @@ -1886,7 +1886,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itype @@ -1906,12 +1906,12 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->entry_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->index_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itypes @@ -1936,7 +1936,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); c->itype = lf->base_itype; - SLLStackPush(p2r2_shared->itype_chains[itype], c); + SLLStackPush(p2r_shared->itype_chains[itype], c); } // rjf: push task to walk dependency itypes @@ -1954,7 +1954,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } lane_sync(); - P2R_TypeIdChain **itype_chains = p2r2_shared->itype_chains; + P2R_TypeIdChain **itype_chains = p2r_shared->itype_chains; ////////////////////////////////////////////////////////////// //- rjf: types pass 3: construct all types from TPI @@ -2494,16 +2494,16 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } } - p2r2_shared->itype_type_ptrs = itype_type_ptrs; - p2r2_shared->basic_type_ptrs = basic_type_ptrs; - p2r2_shared->all_types__pre_typedefs = all_types; + p2r_shared->itype_type_ptrs = itype_type_ptrs; + p2r_shared->basic_type_ptrs = basic_type_ptrs; + p2r_shared->all_types__pre_typedefs = all_types; #undef p2r_type_ptr_from_itype #undef p2r_builtin_type_ptr_from_kind } lane_sync(); - RDIM_Type **itype_type_ptrs = p2r2_shared->itype_type_ptrs; - RDIM_Type **basic_type_ptrs = p2r2_shared->basic_type_ptrs; - RDIM_TypeChunkList all_types__pre_typedefs = p2r2_shared->all_types__pre_typedefs; + RDIM_Type **itype_type_ptrs = p2r_shared->itype_type_ptrs; + RDIM_Type **basic_type_ptrs = p2r_shared->basic_type_ptrs; + RDIM_TypeChunkList all_types__pre_typedefs = p2r_shared->all_types__pre_typedefs; ////////////////////////////////////////////////////////////// //- rjf: types pass 4: build UDTs @@ -2515,14 +2515,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: set up if(lane_idx() == 0) { - p2r2_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); + p2r_shared->lanes_udts = push_array(arena, RDIM_UDTChunkList, lane_count()); } lane_sync(); //- rjf: do wide fill { U64 udts_chunk_cap = 4096; - RDIM_UDTChunkList *udts = &p2r2_shared->lanes_udts[lane_idx()]; + RDIM_UDTChunkList *udts = &p2r_shared->lanes_udts[lane_idx()]; Rng1U64 range = lane_range(itype_opl); for EachInRange(idx, range) { @@ -3145,7 +3145,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) #undef p2r_type_ptr_from_itype } lane_sync(); - RDIM_UDTChunkList *lanes_udts = p2r2_shared->lanes_udts; + RDIM_UDTChunkList *lanes_udts = p2r_shared->lanes_udts; ////////////////////////////////////////////////////////////// //- rjf: join all UDTs @@ -3154,11 +3154,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, lane_count()) { - rdim_udt_chunk_list_concat_in_place(&p2r2_shared->all_udts, &lanes_udts[idx]); + rdim_udt_chunk_list_concat_in_place(&p2r_shared->all_udts, &lanes_udts[idx]); } } lane_sync(); - RDIM_UDTChunkList all_udts = p2r2_shared->all_udts; + RDIM_UDTChunkList all_udts = p2r_shared->all_udts; ////////////////////////////////////////////////////////////// //- rjf: produce symbols from all streams @@ -3172,15 +3172,15 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // if(lane_idx() == 0) { - p2r2_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); - p2r2_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); - p2r2_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); - p2r2_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); - p2r2_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); - p2r2_shared->sym_lane_take_counter = 0; + p2r_shared->syms_locations = push_array(arena, RDIM_LocationChunkList, all_syms_count); + p2r_shared->syms_procedures = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r_shared->syms_global_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r_shared->syms_thread_variables = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r_shared->syms_constants = push_array(arena, RDIM_SymbolChunkList, all_syms_count); + p2r_shared->syms_scopes = push_array(arena, RDIM_ScopeChunkList, all_syms_count); + p2r_shared->syms_inline_sites = push_array(arena, RDIM_InlineSiteChunkList, all_syms_count); + p2r_shared->syms_typedefs = push_array(arena, RDIM_TypeChunkList, all_syms_count); + p2r_shared->sym_lane_take_counter = 0; } lane_sync(); @@ -3190,7 +3190,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for(;;) { //- rjf: take next sym - U64 sym_num = ins_atomic_u64_inc_eval(&p2r2_shared->sym_lane_take_counter); + U64 sym_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); if(sym_num > all_syms_count) { break; @@ -3208,14 +3208,14 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U64 sym_constants_chunk_cap = 16384; U64 sym_scopes_chunk_cap = 16384; U64 sym_inline_sites_chunk_cap = 16384; - RDIM_LocationChunkList *sym_locations = &p2r2_shared->syms_locations[sym_idx]; - RDIM_SymbolChunkList *sym_procedures = &p2r2_shared->syms_procedures[sym_idx]; - RDIM_SymbolChunkList *sym_global_variables = &p2r2_shared->syms_global_variables[sym_idx]; - RDIM_SymbolChunkList *sym_thread_variables = &p2r2_shared->syms_thread_variables[sym_idx]; - RDIM_SymbolChunkList *sym_constants = &p2r2_shared->syms_constants[sym_idx]; - RDIM_ScopeChunkList *sym_scopes = &p2r2_shared->syms_scopes[sym_idx]; - RDIM_InlineSiteChunkList *sym_inline_sites = &p2r2_shared->syms_inline_sites[sym_idx]; - RDIM_TypeChunkList *typedefs = &p2r2_shared->syms_typedefs[sym_idx]; + RDIM_LocationChunkList *sym_locations = &p2r_shared->syms_locations[sym_idx]; + RDIM_SymbolChunkList *sym_procedures = &p2r_shared->syms_procedures[sym_idx]; + RDIM_SymbolChunkList *sym_global_variables = &p2r_shared->syms_global_variables[sym_idx]; + RDIM_SymbolChunkList *sym_thread_variables = &p2r_shared->syms_thread_variables[sym_idx]; + RDIM_SymbolChunkList *sym_constants = &p2r_shared->syms_constants[sym_idx]; + RDIM_ScopeChunkList *sym_scopes = &p2r_shared->syms_scopes[sym_idx]; + RDIM_InlineSiteChunkList *sym_inline_sites = &p2r_shared->syms_inline_sites[sym_idx]; + RDIM_TypeChunkList *typedefs = &p2r_shared->syms_typedefs[sym_idx]; ////////////////////////// //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) @@ -3634,7 +3634,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; // rjf: build location - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); RDIM_Location *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); RDIM_Rng1U64 voff_range = {0, max_U64}; rdim_local_push_location_case(arena, sym_scopes, local, loc2, voff_range); @@ -3756,7 +3756,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL @@ -3799,11 +3799,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_size = rdi_addr_size_from_arch(arch); U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel->off; - RDIM_LocationInfo location_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_LocationInfo location_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); RDIM_Location *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_SUBFIELD_REGISTER @@ -3836,7 +3836,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE @@ -3873,7 +3873,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_size = rdi_addr_size_from_arch(arch); U32 byte_pos = 0; S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit location over ranges @@ -3906,11 +3906,11 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) U32 byte_pos = 0; B32 extra_indirection_to_value = 0; S64 var_off = defrange_register_rel->reg_off; - RDIM_LocationInfo loc_info = p2r2_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); // rjf: emit locations over ranges - p2r2_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); }break; //- rjf: FILESTATIC @@ -4106,69 +4106,69 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { for EachIndex(idx, all_syms_count) { - rdim_location_chunk_list_concat_in_place(&p2r2_shared->all_locations, &p2r2_shared->syms_locations[idx]); + rdim_location_chunk_list_concat_in_place(&p2r_shared->all_locations, &p2r_shared->syms_locations[idx]); } } if(lane_idx() == lane_from_task_idx(1)) ProfScope("join procedures") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_procedures, &p2r2_shared->syms_procedures[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_procedures, &p2r_shared->syms_procedures[idx]); } } if(lane_idx() == lane_from_task_idx(2)) ProfScope("join global variables") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_global_variables, &p2r2_shared->syms_global_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_global_variables, &p2r_shared->syms_global_variables[idx]); } } if(lane_idx() == lane_from_task_idx(3)) ProfScope("join thread variables") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_thread_variables, &p2r2_shared->syms_thread_variables[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_thread_variables, &p2r_shared->syms_thread_variables[idx]); } } if(lane_idx() == lane_from_task_idx(4)) ProfScope("join constants") { for EachIndex(idx, all_syms_count) { - rdim_symbol_chunk_list_concat_in_place(&p2r2_shared->all_constants, &p2r2_shared->syms_constants[idx]); + rdim_symbol_chunk_list_concat_in_place(&p2r_shared->all_constants, &p2r_shared->syms_constants[idx]); } } if(lane_idx() == lane_from_task_idx(5)) ProfScope("join scopes") { for EachIndex(idx, all_syms_count) { - rdim_scope_chunk_list_concat_in_place(&p2r2_shared->all_scopes, &p2r2_shared->syms_scopes[idx]); + rdim_scope_chunk_list_concat_in_place(&p2r_shared->all_scopes, &p2r_shared->syms_scopes[idx]); } } if(lane_idx() == lane_from_task_idx(6)) ProfScope("join inline sites") { for EachIndex(idx, all_syms_count) { - rdim_inline_site_chunk_list_concat_in_place(&p2r2_shared->all_inline_sites, &p2r2_shared->syms_inline_sites[idx]); + rdim_inline_site_chunk_list_concat_in_place(&p2r_shared->all_inline_sites, &p2r_shared->syms_inline_sites[idx]); } } if(lane_idx() == lane_from_task_idx(7)) ProfScope("join typedefs") { for EachIndex(idx, all_syms_count) { - rdim_type_chunk_list_concat_in_place(&p2r2_shared->all_types__pre_typedefs, &p2r2_shared->syms_typedefs[idx]); + rdim_type_chunk_list_concat_in_place(&p2r_shared->all_types__pre_typedefs, &p2r_shared->syms_typedefs[idx]); } - p2r2_shared->all_types = p2r2_shared->all_types__pre_typedefs; + p2r_shared->all_types = p2r_shared->all_types__pre_typedefs; } } lane_sync(); - RDIM_LocationChunkList all_locations = p2r2_shared->all_locations; - RDIM_SymbolChunkList all_procedures = p2r2_shared->all_procedures; - RDIM_SymbolChunkList all_global_variables = p2r2_shared->all_global_variables; - RDIM_SymbolChunkList all_thread_variables = p2r2_shared->all_thread_variables; - RDIM_SymbolChunkList all_constants = p2r2_shared->all_constants; - RDIM_ScopeChunkList all_scopes = p2r2_shared->all_scopes; - RDIM_InlineSiteChunkList all_inline_sites = p2r2_shared->all_inline_sites; - RDIM_TypeChunkList all_types = p2r2_shared->all_types; + RDIM_LocationChunkList all_locations = p2r_shared->all_locations; + RDIM_SymbolChunkList all_procedures = p2r_shared->all_procedures; + RDIM_SymbolChunkList all_global_variables = p2r_shared->all_global_variables; + RDIM_SymbolChunkList all_thread_variables = p2r_shared->all_thread_variables; + RDIM_SymbolChunkList all_constants = p2r_shared->all_constants; + RDIM_ScopeChunkList all_scopes = p2r_shared->all_scopes; + RDIM_InlineSiteChunkList all_inline_sites = p2r_shared->all_inline_sites; + RDIM_TypeChunkList all_types = p2r_shared->all_types; ////////////////////////////////////////////////////////////// //- rjf: bundle all outputs diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 3682e0f7..9cf33904 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -67,8 +67,8 @@ struct P2R_TypeIdChain //- rjf: main state bundle -typedef struct P2R2_Shared P2R2_Shared; -struct P2R2_Shared +typedef struct P2R_Shared P2R_Shared; +struct P2R_Shared { MSF_RawStreamTable *msf_raw_stream_table; U64 msf_stream_lane_counter; @@ -159,7 +159,7 @@ struct P2R2_Shared //////////////////////////////// //~ rjf: Globals -global P2R2_Shared *p2r2_shared = 0; +global P2R_Shared *p2r_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers @@ -184,8 +184,8 @@ internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_ty //~ rjf: Location Info Building Helpers internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); -internal RDIM_LocationInfo p2r2_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); -internal void p2r2_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); +internal RDIM_LocationInfo p2r_location_info_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); +internal void p2r_local_push_location_cases_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *loc, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); //////////////////////////////// //~ rjf: Top-Level Conversion Entry Point diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index 14f1839d..e886f697 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -49,14 +49,14 @@ rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_Binar } internal RDIM_BakeResults -rdim2_bake(Arena *arena, RDIM_BakeParams *params) +rdim_bake(Arena *arena, RDIM_BakeParams *params) { ////////////////////////////////////////////////////////////// //- rjf: set up shared state // if(lane_idx() == 0) { - rdim2_shared = push_array(arena, RDIM2_Shared, 1); + rdim_shared = push_array(arena, RDIM_Shared, 1); } lane_sync(); @@ -68,14 +68,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: gather scope vmap keys/markers if(lane_idx() == lane_from_task_idx(0)) ProfScope("gather scope vmap keys/markers") { - rdim2_shared->scope_vmap_count = params->scopes.scope_voff_count; - rdim2_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim2_shared->scope_vmap_count); - rdim2_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim2_shared->scope_vmap_count); + rdim_shared->scope_vmap_count = params->scopes.scope_voff_count; + rdim_shared->scope_vmap_keys = push_array_no_zero(arena, RDIM_SortKey, rdim_shared->scope_vmap_count); + rdim_shared->scope_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, rdim_shared->scope_vmap_count); + rdim_shared->scope_vmap_markers = push_array_no_zero(arena, RDIM_VMapMarker, rdim_shared->scope_vmap_count); ProfScope("fill keys/markers") { - RDIM_SortKey *key_ptr = rdim2_shared->scope_vmap_keys; - RDIM_VMapMarker *marker_ptr = rdim2_shared->scope_vmap_markers; + RDIM_SortKey *key_ptr = rdim_shared->scope_vmap_keys; + RDIM_VMapMarker *marker_ptr = rdim_shared->scope_vmap_markers; for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) { for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) @@ -163,10 +163,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } // rjf: store - rdim2_shared->unit_vmap_count = marker_count; - rdim2_shared->unit_vmap_keys = keys; - rdim2_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim2_shared->unit_vmap_markers = markers; + rdim_shared->unit_vmap_count = marker_count; + rdim_shared->unit_vmap_keys = keys; + rdim_shared->unit_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim_shared->unit_vmap_markers = markers; } //- rjf: gather global vmap keys/markers @@ -231,10 +231,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } //- rjf: store - rdim2_shared->global_vmap_count = marker_count; - rdim2_shared->global_vmap_keys = keys; - rdim2_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); - rdim2_shared->global_vmap_markers = markers; + rdim_shared->global_vmap_count = marker_count; + rdim_shared->global_vmap_keys = keys; + rdim_shared->global_vmap_keys__swap = push_array_no_zero(arena, RDIM_SortKey, marker_count); + rdim_shared->global_vmap_markers = markers; } } lane_sync(); @@ -247,8 +247,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); - rdim2_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); + rdim_shared->lane_digit_counts = push_array(arena, U32 *, lane_count()); + rdim_shared->lane_digit_offsets = push_array(arena, U32 *, lane_count()); } lane_sync(); @@ -261,9 +261,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } sort_tasks[] = { - {rdim2_shared->scope_vmap_count, rdim2_shared->scope_vmap_keys, rdim2_shared->scope_vmap_keys__swap}, - {rdim2_shared->unit_vmap_count, rdim2_shared->unit_vmap_keys, rdim2_shared->unit_vmap_keys__swap}, - {rdim2_shared->global_vmap_count, rdim2_shared->global_vmap_keys, rdim2_shared->global_vmap_keys__swap}, + {rdim_shared->scope_vmap_count, rdim_shared->scope_vmap_keys, rdim_shared->scope_vmap_keys__swap}, + {rdim_shared->unit_vmap_count, rdim_shared->unit_vmap_keys, rdim_shared->unit_vmap_keys__swap}, + {rdim_shared->global_vmap_count, rdim_shared->global_vmap_keys, rdim_shared->global_vmap_keys__swap}, }; for EachElement(sort_task_idx, sort_tasks) ProfScope("sort %I64u", sort_task_idx) { @@ -273,8 +273,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 bits_per_digit = 8; U64 digits_count = 64 / bits_per_digit; U64 num_possible_values_per_digit = 1 << bits_per_digit; - rdim2_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); - rdim2_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + rdim_shared->lane_digit_counts[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); + rdim_shared->lane_digit_offsets[lane_idx()] = push_array_no_zero(arena, U32, num_possible_values_per_digit); RDIM_SortKey *src = keys; RDIM_SortKey *dst = keys__swap; U64 element_count = vmap_count; @@ -282,7 +282,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { // rjf: count digit value occurrences per-lane { - U32 *digit_counts = rdim2_shared->lane_digit_counts[lane_idx()]; + U32 *digit_counts = rdim_shared->lane_digit_counts[lane_idx()]; MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); Rng1U64 range = lane_range(element_count); for EachInRange(idx, range) @@ -302,8 +302,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 layout_off = 0; for EachIndex(lane_idx, lane_count()) { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; - layout_off += rdim2_shared->lane_digit_counts[lane_idx][value_idx]; + rdim_shared->lane_digit_offsets[lane_idx][value_idx] = layout_off; + layout_off += rdim_shared->lane_digit_counts[lane_idx][value_idx]; } } } @@ -318,9 +318,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachIndex(lane_idx, lane_count()) { - rdim2_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; + rdim_shared->lane_digit_offsets[lane_idx][value_idx] += last_off; } - last_off = rdim2_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim2_shared->lane_digit_counts[lane_count()-1][value_idx]; + last_off = rdim_shared->lane_digit_offsets[lane_count()-1][value_idx] + rdim_shared->lane_digit_counts[lane_count()-1][value_idx]; } // NOTE(rjf): required that: (last_off == element_count) } @@ -328,7 +328,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: move { - U32 *lane_digit_offsets = rdim2_shared->lane_digit_offsets[lane_idx()]; + U32 *lane_digit_offsets = rdim_shared->lane_digit_offsets[lane_idx()]; Rng1U64 range = lane_range(element_count); for EachInRange(idx, range) { @@ -374,30 +374,30 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); task->name = str8_lit("scopes"); - task->count = rdim2_shared->scope_vmap_count; - task->keys = rdim2_shared->scope_vmap_keys; - task->markers = rdim2_shared->scope_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_scope_vmap.vmap; + task->count = rdim_shared->scope_vmap_count; + task->keys = rdim_shared->scope_vmap_keys; + task->markers = rdim_shared->scope_vmap_markers; + task->bake_vmap_out = &rdim_shared->baked_scope_vmap.vmap; SLLQueuePush(first_task, last_task, task); } if(lane_idx() == lane_from_task_idx(1)) { VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); task->name = str8_lit("units"); - task->count = rdim2_shared->unit_vmap_count; - task->keys = rdim2_shared->unit_vmap_keys; - task->markers = rdim2_shared->unit_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_unit_vmap.vmap; + task->count = rdim_shared->unit_vmap_count; + task->keys = rdim_shared->unit_vmap_keys; + task->markers = rdim_shared->unit_vmap_markers; + task->bake_vmap_out = &rdim_shared->baked_unit_vmap.vmap; SLLQueuePush(first_task, last_task, task); } if(lane_idx() == lane_from_task_idx(2)) { VMapBakeTask *task = push_array(scratch.arena, VMapBakeTask, 1); task->name = str8_lit("globals"); - task->count = rdim2_shared->global_vmap_count; - task->keys = rdim2_shared->global_vmap_keys; - task->markers = rdim2_shared->global_vmap_markers; - task->bake_vmap_out = &rdim2_shared->baked_global_vmap.vmap; + task->count = rdim_shared->global_vmap_count; + task->keys = rdim_shared->global_vmap_keys; + task->markers = rdim_shared->global_vmap_markers; + task->bake_vmap_out = &rdim_shared->baked_global_vmap.vmap; SLLQueuePush(first_task, last_task, task); } for(VMapBakeTask *task = first_task; task != 0; task = task->next) ProfScope("vmap bake for %.*s", str8_varg(task->name)) @@ -574,10 +574,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } - rdim2_shared->path_tree = tree; + rdim_shared->path_tree = tree; } lane_sync(); - RDIM_BakePathTree *path_tree = rdim2_shared->path_tree; + RDIM_BakePathTree *path_tree = rdim_shared->path_tree; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage gather all unsorted, joined, line table info; & sort @@ -590,8 +590,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: calculate header info if(lane_idx() == 0) { - rdim2_shared->line_tables_count = params->line_tables.total_count; - rdim2_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim2_shared->line_tables_count); + rdim_shared->line_tables_count = params->line_tables.total_count; + rdim_shared->src_line_tables = push_array(arena, RDIM_LineTable *, rdim_shared->line_tables_count); ProfScope("flatten chunk list") { U64 joined_idx = 0; @@ -599,16 +599,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachIndex(idx, n->count) { - rdim2_shared->src_line_tables[joined_idx] = &n->v[idx]; + rdim_shared->src_line_tables[joined_idx] = &n->v[idx]; joined_idx += 1; } } } - rdim2_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; - rdim2_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; - rdim2_shared->baked_line_tables.line_table_columns_count= 1; - rdim2_shared->line_table_block_take_counter = 0; + rdim_shared->baked_line_tables.line_tables_count = params->line_tables.total_count + 1; + rdim_shared->baked_line_tables.line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; + rdim_shared->baked_line_tables.line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; + rdim_shared->baked_line_tables.line_table_columns_count= 1; + rdim_shared->line_table_block_take_counter = 0; } lane_sync(); @@ -617,25 +617,25 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim2_shared->line_tables_count); + rdim_shared->unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, rdim_shared->line_tables_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim2_shared->line_tables_count); + rdim_shared->sorted_line_table_keys = push_array(arena, RDIM_SortKey *, rdim_shared->line_tables_count); } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim2_shared->baked_line_tables.line_tables_count); + rdim_shared->baked_line_tables.line_tables = push_array(arena, RDI_LineTable, rdim_shared->baked_line_tables.line_tables_count); ProfScope("lay out line tables") { U64 voffs_base_idx = 0; U64 lines_base_idx = 0; U64 cols_base_idx = 0; - for EachIndex(idx, rdim2_shared->line_tables_count) + for EachIndex(idx, rdim_shared->line_tables_count) { U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil - RDIM_LineTable *src = rdim2_shared->src_line_tables[idx]; - RDI_LineTable *dst = &rdim2_shared->baked_line_tables.line_tables[final_idx]; + RDIM_LineTable *src = rdim_shared->src_line_tables[idx]; + RDI_LineTable *dst = &rdim_shared->baked_line_tables.line_tables[final_idx]; dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 @@ -647,15 +647,15 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } if(lane_idx() == lane_from_task_idx(3)) { - rdim2_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_line_tables.line_table_voffs_count); + rdim_shared->baked_line_tables.line_table_voffs = push_array(arena, RDI_U64, rdim_shared->baked_line_tables.line_table_voffs_count); } if(lane_idx() == lane_from_task_idx(4)) { - rdim2_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim2_shared->baked_line_tables.line_table_lines_count); + rdim_shared->baked_line_tables.line_table_lines = push_array(arena, RDI_Line, rdim_shared->baked_line_tables.line_table_lines_count); } if(lane_idx() == lane_from_task_idx(5)) { - rdim2_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim2_shared->baked_line_tables.line_table_columns_count); + rdim_shared->baked_line_tables.line_table_columns = push_array(arena, RDI_Column, rdim_shared->baked_line_tables.line_table_columns_count); } } } @@ -665,21 +665,21 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) ProfScope("wide bake") { U64 line_table_block_size = 4096; - U64 line_table_block_count = (rdim2_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; + U64 line_table_block_count = (rdim_shared->line_tables_count + line_table_block_size - 1) / line_table_block_size; for(;;) { - U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim2_shared->line_table_block_take_counter); + U64 line_table_block_num = ins_atomic_u64_inc_eval(&rdim_shared->line_table_block_take_counter); if(0 == line_table_block_num || line_table_block_count < line_table_block_num) { break; } U64 line_table_block_idx = line_table_block_num-1; Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); - line_table_range.max = Min(rdim2_shared->line_tables_count, line_table_range.max); + line_table_range.max = Min(rdim_shared->line_tables_count, line_table_range.max); for EachInRange(line_table_idx, line_table_range) { - RDIM_LineTable *src = rdim2_shared->src_line_tables[line_table_idx]; - RDIM_UnsortedJoinedLineTable *dst = &rdim2_shared->unsorted_joined_line_tables[line_table_idx]; + RDIM_LineTable *src = rdim_shared->src_line_tables[line_table_idx]; + RDIM_UnsortedJoinedLineTable *dst = &rdim_shared->unsorted_joined_line_tables[line_table_idx]; //- rjf: gather dst->line_count = src->line_count; @@ -714,17 +714,17 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } //- rjf: sort - rdim2_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].line_keys, - rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count); + rdim_shared->sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, + rdim_shared->unsorted_joined_line_tables[line_table_idx].line_keys, + rdim_shared->unsorted_joined_line_tables[line_table_idx].key_count); //- rjf: fill - RDIM_SortKey *sorted_line_keys = rdim2_shared->sorted_line_table_keys[line_table_idx]; - U64 sorted_line_keys_count = rdim2_shared->unsorted_joined_line_tables[line_table_idx].key_count; - RDI_LineTable *dst_line_table = &rdim2_shared->baked_line_tables.line_tables[line_table_idx+1]; - U64 *arranged_voffs = rdim2_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; - RDI_Line *arranged_lines = rdim2_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; - RDI_Column *arranged_cols = rdim2_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; + RDIM_SortKey *sorted_line_keys = rdim_shared->sorted_line_table_keys[line_table_idx]; + U64 sorted_line_keys_count = rdim_shared->unsorted_joined_line_tables[line_table_idx].key_count; + RDI_LineTable *dst_line_table = &rdim_shared->baked_line_tables.line_tables[line_table_idx+1]; + U64 *arranged_voffs = rdim_shared->baked_line_tables.line_table_voffs + dst_line_table->voffs_base_idx; + RDI_Line *arranged_lines = rdim_shared->baked_line_tables.line_table_lines + dst_line_table->lines_base_idx; + RDI_Column *arranged_cols = rdim_shared->baked_line_tables.line_table_columns + dst_line_table->cols_base_idx; { for EachIndex(idx, sorted_line_keys_count) { @@ -751,10 +751,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); - RDI_U64 line_tables_count = rdim2_shared->line_tables_count; - RDIM_LineTable **src_line_tables = rdim2_shared->src_line_tables; - RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim2_shared->unsorted_joined_line_tables; - RDIM_SortKey **sorted_line_table_keys = rdim2_shared->sorted_line_table_keys; + RDI_U64 line_tables_count = rdim_shared->line_tables_count; + RDIM_LineTable **src_line_tables = rdim_shared->src_line_tables; + RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = rdim_shared->unsorted_joined_line_tables; + RDIM_SortKey **sorted_line_table_keys = rdim_shared->sorted_line_table_keys; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build string map @@ -764,23 +764,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: set up per-lane outputs if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - rdim2_shared->bake_string_map_topology.slots_count = (64 + - params->procedures.total_count*1 + - params->global_variables.total_count*1 + - params->thread_variables.total_count*1 + - params->types.total_count/2); - rdim2_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); - rdim2_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + rdim_shared->bake_string_map_topology.slots_count = (64 + + params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2); + rdim_shared->lane_bake_string_maps__loose = push_array(arena, RDIM_BakeStringMapLoose *, lane_count()); + rdim_shared->bake_string_map__loose = rdim_bake_string_map_loose_make(arena, &rdim_shared->bake_string_map_topology); } lane_sync(); //- rjf: set up this lane's map ProfScope("set up this lane's map") { - rdim2_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim2_shared->bake_string_map_topology); + rdim_shared->lane_bake_string_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(arena, &rdim_shared->bake_string_map_topology); } - RDIM_BakeStringMapTopology *lane_map_top = &rdim2_shared->bake_string_map_topology; - RDIM_BakeStringMapLoose *lane_map = rdim2_shared->lane_bake_string_maps__loose[lane_idx()]; + RDIM_BakeStringMapTopology *lane_map_top = &rdim_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *lane_map = rdim_shared->lane_bake_string_maps__loose[lane_idx()]; //- rjf: push all strings into this lane's map ProfScope("push all strings into this lane's map") @@ -923,13 +923,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + Rng1U64 slot_range = lane_range(rdim_shared->bake_string_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeStringMapLoose *src_map = rdim2_shared->lane_bake_string_maps__loose[src_lane_idx]; - RDIM_BakeStringMapLoose *dst_map = rdim2_shared->bake_string_map__loose; + RDIM_BakeStringMapLoose *src_map = rdim_shared->lane_bake_string_maps__loose[src_lane_idx]; + RDIM_BakeStringMapLoose *dst_map = rdim_shared->bake_string_map__loose; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; @@ -946,8 +946,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_string_map_topology.slots_count); + RDIM_BakeStringMapLoose *map = rdim_shared->bake_string_map__loose; + Rng1U64 slot_range = lane_range(rdim_shared->bake_string_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) @@ -961,32 +961,32 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: tighten string table ProfScope("tighten string table") { - RDIM_BakeStringMapLoose *map = rdim2_shared->bake_string_map__loose; - RDIM_BakeStringMapTopology *map_top = &rdim2_shared->bake_string_map_topology; + RDIM_BakeStringMapLoose *map = rdim_shared->bake_string_map__loose; + RDIM_BakeStringMapTopology *map_top = &rdim_shared->bake_string_map_topology; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, map_top, map); - rdim2_shared->bake_strings.slots_count = map_top->slots_count; - rdim2_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim2_shared->bake_strings.slots_count); - rdim2_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; - rdim2_shared->bake_strings.total_count = rdim2_shared->bake_strings.slots_base_idxs[rdim2_shared->bake_strings.slots_count]; + rdim_shared->bake_strings.slots_count = map_top->slots_count; + rdim_shared->bake_strings.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, rdim_shared->bake_strings.slots_count); + rdim_shared->bake_strings.slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; + rdim_shared->bake_strings.total_count = rdim_shared->bake_strings.slots_base_idxs[rdim_shared->bake_strings.slots_count]; } lane_sync(); ProfScope("fill tight map") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_strings.slots_count); + Rng1U64 slot_range = lane_range(rdim_shared->bake_strings.slots_count); for EachInRange(idx, slot_range) { if(map->slots[idx] != 0) { - rdim_memcpy_struct(&rdim2_shared->bake_strings.slots[idx], map->slots[idx]); + rdim_memcpy_struct(&rdim_shared->bake_strings.slots[idx], map->slots[idx]); } } } } } lane_sync(); - RDIM_BakeStringMapTight *bake_strings = &rdim2_shared->bake_strings; + RDIM_BakeStringMapTight *bake_strings = &rdim_shared->bake_strings; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps @@ -1014,8 +1014,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) Case(NormalSourcePaths, params->src_files.total_count); #undef Case } - rdim2_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); - rdim2_shared->bake_name_map_topology[k].slots_count = slot_count; + rdim_shared->lane_bake_name_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); + rdim_shared->bake_name_map_topology[k].slots_count = slot_count; } } lane_sync(); @@ -1023,9 +1023,9 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: wide build for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - rdim2_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_make(arena, top); - RDIM_BakeNameMap *map = rdim2_shared->lane_bake_name_maps[k][lane_idx()]; + RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; + rdim_shared->lane_bake_name_maps[k][lane_idx()] = rdim_bake_name_map_make(arena, top); + RDIM_BakeNameMap *map = rdim_shared->lane_bake_name_maps[k][lane_idx()]; B32 link_names = 0; RDIM_SymbolChunkList *symbols = 0; switch((RDI_NameMapKindEnum)k) @@ -1086,14 +1086,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { - rdim2_shared->bake_name_maps[k] = rdim_bake_name_map_make(arena, &rdim2_shared->bake_name_map_topology[k]); + rdim_shared->bake_name_maps[k] = rdim_bake_name_map_make(arena, &rdim_shared->bake_name_map_topology[k]); } } lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; //- rjf: join ProfScope("join") @@ -1103,7 +1103,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeNameMap *src_map = rdim2_shared->lane_bake_name_maps[k][src_lane_idx]; + RDIM_BakeNameMap *src_map = rdim_shared->lane_bake_name_maps[k][src_lane_idx]; RDIM_BakeNameMap *dst_map = map; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { @@ -1141,23 +1141,23 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: set up per-lane outputs if(lane_idx() == 0) ProfScope("set up per-lane outputs") { - rdim2_shared->bake_idx_run_map_topology.slots_count = (64 + - params->procedures.total_count + - params->global_variables.total_count + - params->thread_variables.total_count + - params->types.total_count); - rdim2_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); - rdim2_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + rdim_shared->bake_idx_run_map_topology.slots_count = (64 + + params->procedures.total_count + + params->global_variables.total_count + + params->thread_variables.total_count + + params->types.total_count); + rdim_shared->lane_bake_idx_run_maps__loose = push_array(arena, RDIM_BakeIdxRunMapLoose *, lane_count()); + rdim_shared->bake_idx_run_map__loose = rdim_bake_idx_run_map_loose_make(arena, &rdim_shared->bake_idx_run_map_topology); } lane_sync(); //- rjf: set up this lane's map ProfScope("set up this lane's map") { - rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim2_shared->bake_idx_run_map_topology); + rdim_shared->lane_bake_idx_run_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(arena, &rdim_shared->bake_idx_run_map_topology); } - RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim2_shared->bake_idx_run_map_topology; - RDIM_BakeIdxRunMapLoose *lane_map = rdim2_shared->lane_bake_idx_run_maps__loose[lane_idx()]; + RDIM_BakeIdxRunMapTopology *lane_map_top = &rdim_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *lane_map = rdim_shared->lane_bake_idx_run_maps__loose[lane_idx()]; //- rjf: wide fill of all index runs ProfScope("fill all lane index run maps") @@ -1192,8 +1192,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: bake runs of name map match lists for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; Rng1U64 slot_idx_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_idx_range) { @@ -1283,13 +1283,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: join ProfScope("join") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + Rng1U64 slot_range = lane_range(rdim_shared->bake_idx_run_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { - RDIM_BakeIdxRunMapLoose *src_map = rdim2_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; - RDIM_BakeIdxRunMapLoose *dst_map = rdim2_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapLoose *src_map = rdim_shared->lane_bake_idx_run_maps__loose[src_lane_idx]; + RDIM_BakeIdxRunMapLoose *dst_map = rdim_shared->bake_idx_run_map__loose; dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { @@ -1307,8 +1307,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: sort ProfScope("sort") { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_run_map_topology.slots_count); + RDIM_BakeIdxRunMapLoose *map = rdim_shared->bake_idx_run_map__loose; + Rng1U64 slot_range = lane_range(rdim_shared->bake_idx_run_map_topology.slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0 && map->slots[slot_idx]->total_count > 1) @@ -1330,40 +1330,40 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: tighten idx run table ProfScope("tighten idx run table") { - RDIM_BakeIdxRunMapLoose *map = rdim2_shared->bake_idx_run_map__loose; - RDIM_BakeIdxRunMapTopology *map_top = &rdim2_shared->bake_idx_run_map_topology; + RDIM_BakeIdxRunMapLoose *map = rdim_shared->bake_idx_run_map__loose; + RDIM_BakeIdxRunMapTopology *map_top = &rdim_shared->bake_idx_run_map_topology; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { - rdim2_shared->bake_idx_runs.slots_count = map_top->slots_count; - rdim2_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim2_shared->bake_idx_runs.slots_count); - rdim2_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim2_shared->bake_idx_runs.slots_count+1); + rdim_shared->bake_idx_runs.slots_count = map_top->slots_count; + rdim_shared->bake_idx_runs.slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, rdim_shared->bake_idx_runs.slots_count); + rdim_shared->bake_idx_runs.slots_base_idxs = rdim_push_array(arena, RDI_U64, rdim_shared->bake_idx_runs.slots_count+1); RDI_U64 encoding_idx_off = 0; for(RDI_U64 slot_idx = 0; slot_idx < map_top->slots_count; slot_idx += 1) { - rdim2_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; + rdim_shared->bake_idx_runs.slots_base_idxs[slot_idx] = encoding_idx_off; if(map->slots[slot_idx] != 0) { encoding_idx_off += map->slots_idx_counts[slot_idx]; } } - rdim2_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; + rdim_shared->bake_idx_runs.slots_base_idxs[map_top->slots_count] = encoding_idx_off; } lane_sync(); ProfScope("fill tight map") { - Rng1U64 slot_range = lane_range(rdim2_shared->bake_idx_runs.slots_count); + Rng1U64 slot_range = lane_range(rdim_shared->bake_idx_runs.slots_count); for EachInRange(idx, slot_range) { if(map->slots[idx] != 0) { - rdim_memcpy_struct(&rdim2_shared->bake_idx_runs.slots[idx], map->slots[idx]); + rdim_memcpy_struct(&rdim_shared->bake_idx_runs.slots[idx], map->slots[idx]); } } } } } lane_sync(); - RDIM_BakeIdxRunMap *bake_idx_runs = &rdim2_shared->bake_idx_runs; + RDIM_BakeIdxRunMap *bake_idx_runs = &rdim_shared->bake_idx_runs; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake strings @@ -1373,8 +1373,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) ProfScope("set up; lay out strings") { - rdim2_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; - rdim2_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim2_shared->baked_strings.string_offs_count); + rdim_shared->baked_strings.string_offs_count = bake_strings->total_count + 1; + rdim_shared->baked_strings.string_offs = rdim_push_array(arena, RDI_U32, rdim_shared->baked_strings.string_offs_count); RDI_U64 off_cursor = 0; for EachIndex(slot_idx, bake_strings->slots_count) { @@ -1384,13 +1384,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { RDIM_BakeString *src = &n->v[n_idx]; U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - rdim2_shared->baked_strings.string_offs[dst_idx] = off_cursor; + rdim_shared->baked_strings.string_offs[dst_idx] = off_cursor; off_cursor += src->string.size; } } } - rdim2_shared->baked_strings.string_data_size = off_cursor; - rdim2_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim2_shared->baked_strings.string_data_size); + rdim_shared->baked_strings.string_data_size = off_cursor; + rdim_shared->baked_strings.string_data = rdim_push_array(arena, RDI_U8, rdim_shared->baked_strings.string_data_size); } lane_sync(); @@ -1406,15 +1406,15 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { RDIM_BakeString *src = &n->v[n_idx]; U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; - U64 dst_off = rdim2_shared->baked_strings.string_offs[dst_idx]; - rdim_memcpy(rdim2_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); + U64 dst_off = rdim_shared->baked_strings.string_offs[dst_idx]; + rdim_memcpy(rdim_shared->baked_strings.string_data + dst_off, src->string.str, src->string.size); } } } } } lane_sync(); - RDIM_StringBakeResult baked_strings = rdim2_shared->baked_strings; + RDIM_StringBakeResult baked_strings = rdim_shared->baked_strings; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake idx runs @@ -1424,8 +1424,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->baked_idx_runs.idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; - rdim2_shared->baked_idx_runs.idx_runs = push_array(arena, RDI_U32, rdim2_shared->baked_idx_runs.idx_count); + rdim_shared->baked_idx_runs.idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; + rdim_shared->baked_idx_runs.idx_runs = push_array(arena, RDI_U32, rdim_shared->baked_idx_runs.idx_count); } lane_sync(); @@ -1437,10 +1437,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) { - StaticAssert(sizeof(rdim2_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); + StaticAssert(sizeof(rdim_shared->baked_idx_runs.idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); for EachIndex(n_idx, n->count) { - rdim_memcpy(rdim2_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); + rdim_memcpy(rdim_shared->baked_idx_runs.idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); off += n->v[n_idx].count; } } @@ -1448,7 +1448,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } lane_sync(); - RDIM_IndexRunBakeResult baked_idx_runs = rdim2_shared->baked_idx_runs; + RDIM_IndexRunBakeResult baked_idx_runs = rdim_shared->baked_idx_runs; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake name maps @@ -1462,15 +1462,15 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { - rdim2_shared->lane_name_map_node_counts[k] = push_array(arena, U64, lane_count()); - rdim2_shared->lane_name_map_node_offs[k] = push_array(arena, U64, lane_count()); + rdim_shared->lane_name_map_node_counts[k] = push_array(arena, U64, lane_count()); + rdim_shared->lane_name_map_node_offs[k] = push_array(arena, U64, lane_count()); } } lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) { - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; - RDIM_BakeNameMap *map = rdim2_shared->bake_name_maps[k]; + RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; + RDIM_BakeNameMap *map = rdim_shared->bake_name_maps[k]; Rng1U64 range = lane_range(top->slots_count); for EachInRange(idx, range) { @@ -1489,7 +1489,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) } } } - rdim2_shared->lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; + rdim_shared->lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; } } } @@ -1501,11 +1501,11 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) RDI_U64 node_off = 0; for EachIndex(l_idx, lane_count()) { - rdim2_shared->name_map_node_counts[k] += rdim2_shared->lane_name_map_node_counts[k][l_idx]; - rdim2_shared->lane_name_map_node_offs[k][l_idx] = node_off; - node_off += rdim2_shared->lane_name_map_node_counts[k][l_idx]; + rdim_shared->name_map_node_counts[k] += rdim_shared->lane_name_map_node_counts[k][l_idx]; + rdim_shared->lane_name_map_node_offs[k][l_idx] = node_off; + node_off += rdim_shared->lane_name_map_node_counts[k][l_idx]; } - rdim2_shared->total_name_map_node_count += rdim2_shared->name_map_node_counts[k]; + rdim_shared->total_name_map_node_count += rdim_shared->name_map_node_counts[k]; } } } @@ -1516,26 +1516,26 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->baked_top_level_name_maps.name_maps_count = RDI_NameMapKind_COUNT; - rdim2_shared->baked_top_level_name_maps.name_maps = push_array(arena, RDI_NameMap, rdim2_shared->baked_top_level_name_maps.name_maps_count); + rdim_shared->baked_top_level_name_maps.name_maps_count = RDI_NameMapKind_COUNT; + rdim_shared->baked_top_level_name_maps.name_maps = push_array(arena, RDI_NameMap, rdim_shared->baked_top_level_name_maps.name_maps_count); RDI_U32 bucket_off = 0; RDI_U32 node_off = 0; for EachNonZeroEnumVal(RDI_NameMapKind, k) { - rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; - rdim2_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; - rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim2_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 - rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim2_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 - bucket_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].bucket_count; - node_off += rdim2_shared->baked_top_level_name_maps.name_maps[k].node_count; + rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_base_idx = bucket_off; + rdim_shared->baked_top_level_name_maps.name_maps[k].node_base_idx = node_off; + rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_count = (RDI_U32)rdim_shared->bake_name_map_topology[k].slots_count; // TODO(rjf): @u64_to_u32 + rdim_shared->baked_top_level_name_maps.name_maps[k].node_count = (RDI_U32)rdim_shared->name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 + bucket_off += rdim_shared->baked_top_level_name_maps.name_maps[k].bucket_count; + node_off += rdim_shared->baked_top_level_name_maps.name_maps[k].node_count; } - rdim2_shared->baked_name_maps.buckets_count = bucket_off; - rdim2_shared->baked_name_maps.buckets = push_array(arena, RDI_NameMapBucket, rdim2_shared->baked_name_maps.buckets_count); + rdim_shared->baked_name_maps.buckets_count = bucket_off; + rdim_shared->baked_name_maps.buckets = push_array(arena, RDI_NameMapBucket, rdim_shared->baked_name_maps.buckets_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_name_maps.nodes_count = rdim2_shared->total_name_map_node_count; - rdim2_shared->baked_name_maps.nodes = push_array(arena, RDI_NameMapNode, rdim2_shared->baked_name_maps.nodes_count); + rdim_shared->baked_name_maps.nodes_count = rdim_shared->total_name_map_node_count; + rdim_shared->baked_name_maps.nodes = push_array(arena, RDI_NameMapNode, rdim_shared->baked_name_maps.nodes_count); } } lane_sync(); @@ -1545,13 +1545,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { - RDI_U64 write_node_off = rdim2_shared->lane_name_map_node_offs[k][lane_idx()]; - RDIM_BakeNameMapTopology *top = &rdim2_shared->bake_name_map_topology[k]; + RDI_U64 write_node_off = rdim_shared->lane_name_map_node_offs[k][lane_idx()]; + RDIM_BakeNameMapTopology *top = &rdim_shared->bake_name_map_topology[k]; U64 slots_count = top->slots_count; - RDIM_BakeNameMap *src_map = rdim2_shared->bake_name_maps[k]; - RDI_NameMap *dst_map = &rdim2_shared->baked_top_level_name_maps.name_maps[k]; - RDI_NameMapBucket *dst_buckets = rdim2_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; - RDI_NameMapNode *dst_nodes = rdim2_shared->baked_name_maps.nodes + dst_map->node_base_idx; + RDIM_BakeNameMap *src_map = rdim_shared->bake_name_maps[k]; + RDI_NameMap *dst_map = &rdim_shared->baked_top_level_name_maps.name_maps[k]; + RDI_NameMapBucket *dst_buckets = rdim_shared->baked_name_maps.buckets + dst_map->bucket_base_idx; + RDI_NameMapNode *dst_nodes = rdim_shared->baked_name_maps.nodes + dst_map->node_base_idx; Rng1U64 slot_range = lane_range(slots_count); for EachInRange(slot_idx, slot_range) { @@ -1666,7 +1666,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == 0) { - rdim2_shared->bake_src_line_maps = push_array(arena, RDIM_BakeSrcLineMap, params->src_files.total_count); + rdim_shared->bake_src_line_maps = push_array(arena, RDIM_BakeSrcLineMap, params->src_files.total_count); } lane_sync(); { @@ -1676,7 +1676,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { U64 file_idx = n->base_idx + n_idx; - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[file_idx]; + RDIM_BakeSrcLineMap *map = &rdim_shared->bake_src_line_maps[file_idx]; // rjf: set up map map->slots_count = n->v[n_idx].total_line_count; @@ -1735,22 +1735,22 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 map_count = params->src_files.total_count; if(lane_idx() == 0) { - rdim2_shared->bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); + rdim_shared->bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); } lane_sync(); for(;;) { - U64 map_num = ins_atomic_u64_inc_eval(&rdim2_shared->bake_src_line_map_take_counter); + U64 map_num = ins_atomic_u64_inc_eval(&rdim_shared->bake_src_line_map_take_counter); if(map_num < 1 || map_count < map_num) { break; } U64 map_idx = map_num-1; - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[map_idx]; + RDIM_BakeSrcLineMap *map = &rdim_shared->bake_src_line_maps[map_idx]; // rjf: gather keys - rdim2_shared->bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); - RDIM_SortKey *keys = rdim2_shared->bake_src_line_map_keys[map_idx]; + rdim_shared->bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); + RDIM_SortKey *keys = rdim_shared->bake_src_line_map_keys[map_idx]; { U64 key_idx = 0; for EachIndex(slot_idx, map->slots_count) @@ -1779,12 +1779,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); - rdim2_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); + rdim_shared->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); } lane_sync(); @@ -1797,10 +1797,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; for EachInRange(idx, range) { - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; - rdim2_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; - rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; - rdim2_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; + RDIM_BakeSrcLineMap *map = &rdim_shared->bake_src_line_maps[n->base_idx + idx]; + rdim_shared->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; + rdim_shared->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; + rdim_shared->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; } chunk_idx += 1; } @@ -1819,17 +1819,17 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; - rdim2_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; - rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; - rdim2_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; - num_layout_off += rdim2_shared->lane_chunk_src_file_num_counts[slot_idx]; - voff_layout_off += rdim2_shared->lane_chunk_src_file_voff_counts[slot_idx]; - map_layout_off += rdim2_shared->lane_chunk_src_file_map_counts[slot_idx]; + rdim_shared->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; + rdim_shared->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; + rdim_shared->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; + num_layout_off += rdim_shared->lane_chunk_src_file_num_counts[slot_idx]; + voff_layout_off += rdim_shared->lane_chunk_src_file_voff_counts[slot_idx]; + map_layout_off += rdim_shared->lane_chunk_src_file_map_counts[slot_idx]; } chunk_idx += 1; } - rdim2_shared->total_src_map_line_count = num_layout_off; - rdim2_shared->total_src_map_voff_count = voff_layout_off; + rdim_shared->total_src_map_line_count = num_layout_off; + rdim_shared->total_src_map_voff_count = voff_layout_off; } } lane_sync(); @@ -1842,16 +1842,16 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: set up if(lane_idx() == 0) { - rdim2_shared->baked_src_files.source_files_count = params->src_files.total_count+1; - rdim2_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim2_shared->baked_src_files.source_files_count); - rdim2_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; - rdim2_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim2_shared->baked_src_files.source_line_maps_count); - rdim2_shared->baked_src_files.source_line_map_nums_count = rdim2_shared->total_src_map_line_count; - rdim2_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_nums_count); - rdim2_shared->baked_src_files.source_line_map_rngs_count = rdim2_shared->total_src_map_line_count + rdim2_shared->baked_src_files.source_line_maps_count; - rdim2_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim2_shared->baked_src_files.source_line_map_rngs_count); - rdim2_shared->baked_src_files.source_line_map_voffs_count = rdim2_shared->total_src_map_voff_count; - rdim2_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_src_files.source_line_map_voffs_count); + rdim_shared->baked_src_files.source_files_count = params->src_files.total_count+1; + rdim_shared->baked_src_files.source_files = push_array(arena, RDI_SourceFile, rdim_shared->baked_src_files.source_files_count); + rdim_shared->baked_src_files.source_line_maps_count = params->src_files.source_line_map_count+1; + rdim_shared->baked_src_files.source_line_maps = push_array(arena, RDI_SourceLineMap, rdim_shared->baked_src_files.source_line_maps_count); + rdim_shared->baked_src_files.source_line_map_nums_count = rdim_shared->total_src_map_line_count; + rdim_shared->baked_src_files.source_line_map_nums = push_array(arena, RDI_U32, rdim_shared->baked_src_files.source_line_map_nums_count); + rdim_shared->baked_src_files.source_line_map_rngs_count = rdim_shared->total_src_map_line_count + rdim_shared->baked_src_files.source_line_maps_count; + rdim_shared->baked_src_files.source_line_map_rngs = push_array(arena, RDI_U32, rdim_shared->baked_src_files.source_line_map_rngs_count); + rdim_shared->baked_src_files.source_line_map_voffs_count = rdim_shared->total_src_map_voff_count; + rdim_shared->baked_src_files.source_line_map_voffs = push_array(arena, RDI_U64, rdim_shared->baked_src_files.source_line_map_voffs_count); } lane_sync(); @@ -1861,20 +1861,20 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { Rng1U64 range = lane_range(n->count); U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; - U64 dst_num_off = rdim2_shared->lane_chunk_src_file_num_offs[slot_idx]; - U64 dst_map_off = rdim2_shared->lane_chunk_src_file_map_offs[slot_idx]; - U64 dst_voff_off = rdim2_shared->lane_chunk_src_file_voff_offs[slot_idx]; + U64 dst_num_off = rdim_shared->lane_chunk_src_file_num_offs[slot_idx]; + U64 dst_map_off = rdim_shared->lane_chunk_src_file_map_offs[slot_idx]; + U64 dst_voff_off = rdim_shared->lane_chunk_src_file_voff_offs[slot_idx]; U64 dst_rng_off = dst_num_off + dst_map_off; for EachInRange(idx, range) { - RDIM_BakeSrcLineMap *map = &rdim2_shared->bake_src_line_maps[n->base_idx + idx]; - RDIM_SortKey *sorted_map_keys = rdim2_shared->bake_src_line_map_keys[n->base_idx + idx]; + RDIM_BakeSrcLineMap *map = &rdim_shared->bake_src_line_maps[n->base_idx + idx]; + RDIM_SortKey *sorted_map_keys = rdim_shared->bake_src_line_map_keys[n->base_idx + idx]; RDIM_SrcFile *src = &n->v[idx]; - RDI_SourceFile *dst = &rdim2_shared->baked_src_files.source_files[n->base_idx + idx + 1]; - RDI_SourceLineMap *dst_map = &rdim2_shared->baked_src_files.source_line_maps[dst_map_off]; - RDI_U32 *dst_nums = &rdim2_shared->baked_src_files.source_line_map_nums[dst_num_off]; - RDI_U32 *dst_rngs = &rdim2_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; - RDI_U64 *dst_voffs = &rdim2_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; + RDI_SourceFile *dst = &rdim_shared->baked_src_files.source_files[n->base_idx + idx + 1]; + RDI_SourceLineMap *dst_map = &rdim_shared->baked_src_files.source_line_maps[dst_map_off]; + RDI_U32 *dst_nums = &rdim_shared->baked_src_files.source_line_map_nums[dst_num_off]; + RDI_U32 *dst_rngs = &rdim_shared->baked_src_files.source_line_map_rngs[dst_rng_off]; + RDI_U64 *dst_voffs = &rdim_shared->baked_src_files.source_line_map_voffs[dst_voff_off]; //- rjf: fill file info Temp scratch = scratch_begin(&arena, 1); @@ -1928,10 +1928,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: allocate if(lane_idx() == 0) { - rdim2_shared->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); - rdim2_shared->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim_shared->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim_shared->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim_shared->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); + rdim_shared->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); } lane_sync(); @@ -1944,8 +1944,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(idx, range) { U64 slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; - rdim2_shared->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; - rdim2_shared->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; + rdim_shared->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; + rdim_shared->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; } chunk_idx += 1; } @@ -1963,10 +1963,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->udts.chunk_count + chunk_idx; - rdim2_shared->member_chunk_lane_offs[slot_idx] = member_layout_off; - rdim2_shared->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; - member_layout_off += rdim2_shared->member_chunk_lane_counts[slot_idx]; - enum_val_layout_off += rdim2_shared->enum_val_chunk_lane_counts[slot_idx]; + rdim_shared->member_chunk_lane_offs[slot_idx] = member_layout_off; + rdim_shared->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; + member_layout_off += rdim_shared->member_chunk_lane_counts[slot_idx]; + enum_val_layout_off += rdim_shared->enum_val_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } @@ -1984,18 +1984,18 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->baked_udts.udts_count = params->udts.total_count+1; - rdim2_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim2_shared->baked_udts.udts_count); + rdim_shared->baked_udts.udts_count = params->udts.total_count+1; + rdim_shared->baked_udts.udts = push_array(arena, RDI_UDT, rdim_shared->baked_udts.udts_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_udts.members_count = params->udts.total_member_count+1; - rdim2_shared->baked_udts.members = push_array(arena, RDI_Member, rdim2_shared->baked_udts.members_count); + rdim_shared->baked_udts.members_count = params->udts.total_member_count+1; + rdim_shared->baked_udts.members = push_array(arena, RDI_Member, rdim_shared->baked_udts.members_count); } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; - rdim2_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim2_shared->baked_udts.enum_members_count); + rdim_shared->baked_udts.enum_members_count = params->udts.total_enum_val_count+1; + rdim_shared->baked_udts.enum_members = push_array(arena, RDI_EnumMember, rdim_shared->baked_udts.enum_members_count); } } lane_sync(); @@ -2008,12 +2008,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { Rng1U64 range = lane_range(n->count); U64 layout_slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; - U64 member_layout_off = rdim2_shared->member_chunk_lane_offs[layout_slot_idx]; - U64 enum_val_layout_off = rdim2_shared->enum_val_chunk_lane_offs[layout_slot_idx]; + U64 member_layout_off = rdim_shared->member_chunk_lane_offs[layout_slot_idx]; + U64 enum_val_layout_off = rdim_shared->enum_val_chunk_lane_offs[layout_slot_idx]; for EachInRange(n_idx, range) { RDIM_UDT *src_udt = &n->v[n_idx]; - RDI_UDT *dst_udt = &rdim2_shared->baked_udts.udts[n->base_idx + n_idx + 1]; + RDI_UDT *dst_udt = &rdim_shared->baked_udts.udts[n->base_idx + n_idx + 1]; //- rjf: fill basics dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 @@ -2027,7 +2027,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 member_off_first = member_layout_off; for EachNode(src_member, RDIM_UDTMember, src_udt->first_member) { - RDI_Member *dst_member = &rdim2_shared->baked_udts.members[member_layout_off]; + RDI_Member *dst_member = &rdim_shared->baked_udts.members[member_layout_off]; dst_member->kind = src_member->kind; dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 @@ -2045,7 +2045,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 enum_val_off_first = enum_val_layout_off; for EachNode(src_enum_val, RDIM_UDTEnumVal, src_udt->first_enum_val) { - RDI_EnumMember *dst_member = &rdim2_shared->baked_udts.enum_members[enum_val_layout_off]; + RDI_EnumMember *dst_member = &rdim_shared->baked_udts.enum_members[enum_val_layout_off]; dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_enum_val->name); dst_member->val = src_enum_val->val; enum_val_layout_off += 1; @@ -2071,8 +2071,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->location_case_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); - rdim2_shared->location_case_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + rdim_shared->location_case_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); + rdim_shared->location_case_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * total_location_case_chunk_count); } lane_sync(); @@ -2088,7 +2088,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachNode(local, RDIM_Local, n->v[idx].first_local) { - rdim2_shared->location_case_chunk_lane_counts[slot_idx] += local->location_cases.count; + rdim_shared->location_case_chunk_lane_counts[slot_idx] += local->location_cases.count; } } chunk_idx += 1; @@ -2101,7 +2101,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { - rdim2_shared->location_case_chunk_lane_counts[slot_idx] += n->v[idx].location_cases.count; + rdim_shared->location_case_chunk_lane_counts[slot_idx] += n->v[idx].location_cases.count; } chunk_idx += 1; } @@ -2118,8 +2118,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; - rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; - location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + rdim_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim_shared->location_case_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } @@ -2128,12 +2128,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx * total_location_case_chunk_count + chunk_idx; - rdim2_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; - location_case_layout_off += rdim2_shared->location_case_chunk_lane_counts[slot_idx]; + rdim_shared->location_case_chunk_lane_offs[slot_idx] = location_case_layout_off; + location_case_layout_off += rdim_shared->location_case_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } - rdim2_shared->total_location_case_count = location_case_layout_off; + rdim_shared->total_location_case_count = location_case_layout_off; } } lane_sync(); @@ -2146,8 +2146,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->baked_location_blocks.location_blocks_count = rdim2_shared->total_location_case_count; - rdim2_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim2_shared->baked_location_blocks.location_blocks_count); + rdim_shared->baked_location_blocks.location_blocks_count = rdim_shared->total_location_case_count; + rdim_shared->baked_location_blocks.location_blocks = push_array(arena, RDI_LocationBlock, rdim_shared->baked_location_blocks.location_blocks_count); } lane_sync(); @@ -2158,7 +2158,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachNode(n, RDIM_ScopeChunkNode, params->scopes.first) { U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + U64 layout_off = rdim_shared->location_case_chunk_lane_offs[layout_slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { @@ -2166,7 +2166,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { for EachNode(src, RDIM_LocationCase, local->location_cases.first) { - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + RDI_LocationBlock *dst = &rdim_shared->baked_location_blocks.location_blocks[layout_off]; dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 @@ -2184,13 +2184,13 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) { U64 layout_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 layout_off = rdim2_shared->location_case_chunk_lane_offs[layout_slot_idx]; + U64 layout_off = rdim_shared->location_case_chunk_lane_offs[layout_slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { for EachNode(src, RDIM_LocationCase, n->v[idx].location_cases.first) { - RDI_LocationBlock *dst = &rdim2_shared->baked_location_blocks.location_blocks[layout_off]; + RDI_LocationBlock *dst = &rdim_shared->baked_location_blocks.location_blocks[layout_off]; dst->scope_off_first = (RDI_U32)src->voff_range.min; // TODO(rjf): @u64_to_u32 dst->scope_off_opl = (RDI_U32)src->voff_range.max; // TODO(rjf): @u64_to_u32 dst->location_data_off = (RDI_U32)rdim_off_from_location(src->location); // TODO(rjf): @u64_to_u32 @@ -2209,8 +2209,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == 0) { - rdim2_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; - rdim2_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim2_shared->baked_locations.location_data_size); + rdim_shared->baked_locations.location_data_size = params->locations.total_encoded_size+1; + rdim_shared->baked_locations.location_data = push_array(arena, RDI_U8, rdim_shared->baked_locations.location_data_size); } lane_sync(); for EachNode(n, RDIM_LocationChunkNode, params->locations.first) @@ -2219,7 +2219,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_Location *loc = &n->v[n_idx]; - RDI_U8 *dst = &rdim2_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; + RDI_U8 *dst = &rdim_shared->baked_locations.location_data[n->base_encoding_off + loc->relative_encoding_off + 1]; switch((RDI_LocationKindEnum)loc->info.kind) { case RDI_LocationKind_NULL:{}break; @@ -2261,10 +2261,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); - rdim2_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim_shared->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim_shared->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim_shared->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); + rdim_shared->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * params->scopes.chunk_count); } lane_sync(); @@ -2281,8 +2281,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) num_locals_in_this_lane_and_node += n->v[n_idx].local_count; num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; } - rdim2_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; - rdim2_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; + rdim_shared->scope_local_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; + rdim_shared->scope_voff_chunk_lane_counts[lane_idx()*params->scopes.chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; chunk_idx += 1; } } @@ -2299,10 +2299,10 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->scopes.chunk_count + chunk_idx; - rdim2_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; - rdim2_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; - local_layout_off += rdim2_shared->scope_local_chunk_lane_counts[slot_idx]; - voff_layout_off += rdim2_shared->scope_voff_chunk_lane_counts[slot_idx]; + rdim_shared->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; + rdim_shared->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; + local_layout_off += rdim_shared->scope_local_chunk_lane_counts[slot_idx]; + voff_layout_off += rdim_shared->scope_voff_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } @@ -2319,18 +2319,18 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: setup outputs if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->baked_scopes.scopes_count = params->scopes.total_count+1; - rdim2_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim2_shared->baked_scopes.scopes_count); + rdim_shared->baked_scopes.scopes_count = params->scopes.total_count+1; + rdim_shared->baked_scopes.scopes = push_array(arena, RDI_Scope, rdim_shared->baked_scopes.scopes_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; - rdim2_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim2_shared->baked_scopes.scope_voffs_count); + rdim_shared->baked_scopes.scope_voffs_count = params->scopes.scope_voff_count+1; + rdim_shared->baked_scopes.scope_voffs = push_array(arena, RDI_U64, rdim_shared->baked_scopes.scope_voffs_count); } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_scopes.locals_count = params->scopes.local_count+1; - rdim2_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim2_shared->baked_scopes.locals_count); + rdim_shared->baked_scopes.locals_count = params->scopes.local_count+1; + rdim_shared->baked_scopes.locals = push_array(arena, RDI_Local, rdim_shared->baked_scopes.locals_count); } lane_sync(); @@ -2341,22 +2341,22 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { Rng1U64 range = lane_range(n->count); U64 scope_chunk_lane_slot_idx = lane_idx()*params->scopes.chunk_count + chunk_idx; - U64 chunk_local_off = rdim2_shared->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; - U64 chunk_voff_off = rdim2_shared->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 chunk_local_off = rdim_shared->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; + U64 chunk_voff_off = rdim_shared->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; U64 location_block_chunk_lane_slot_idx = lane_idx() * total_location_case_chunk_count + chunk_idx; - U64 chunk_location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_chunk_lane_slot_idx]; + U64 chunk_location_block_off = rdim_shared->location_case_chunk_lane_offs[location_block_chunk_lane_slot_idx]; for EachInRange(n_idx, range) { U64 dst_idx = 1 + n->base_idx + n_idx; RDIM_Scope *src_scope = &n->v[n_idx]; - RDI_Scope *dst_scope = &rdim2_shared->baked_scopes.scopes[dst_idx]; + RDI_Scope *dst_scope = &rdim_shared->baked_scopes.scopes[dst_idx]; //- rjf: fill voff ranges U64 voff_idx_first = chunk_voff_off; for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) { - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; - rdim2_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; + rdim_shared->baked_scopes.scope_voffs[chunk_voff_off+0] = rng_n->v.min; + rdim_shared->baked_scopes.scope_voffs[chunk_voff_off+1] = rng_n->v.max; chunk_voff_off += 2; } U64 voff_idx_opl = chunk_voff_off; @@ -2365,7 +2365,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) U64 local_idx_first = chunk_local_off; for EachNode(src_local, RDIM_Local, src_scope->first_local) { - RDI_Local *dst_local = &rdim2_shared->baked_scopes.locals[chunk_local_off]; + RDI_Local *dst_local = &rdim_shared->baked_scopes.locals[chunk_local_off]; dst_local->kind = src_local->kind; dst_local->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_local->name); dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 @@ -2403,8 +2403,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == 0) { - rdim2_shared->baked_procedures.procedures_count = params->procedures.total_count+1; - rdim2_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim2_shared->baked_procedures.procedures_count); + rdim_shared->baked_procedures.procedures_count = params->procedures.total_count+1; + rdim_shared->baked_procedures.procedures = push_array(arena, RDI_Procedure, rdim_shared->baked_procedures.procedures_count); } lane_sync(); { @@ -2412,12 +2412,12 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachNode(n, RDIM_SymbolChunkNode, params->procedures.first) { U64 location_block_layout_slot_idx = lane_idx()*total_location_case_chunk_count + params->scopes.chunk_count + chunk_idx; - U64 location_block_off = rdim2_shared->location_case_chunk_lane_offs[location_block_layout_slot_idx]; + U64 location_block_off = rdim_shared->location_case_chunk_lane_offs[location_block_layout_slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_Symbol *src = &n->v[n_idx]; - RDI_Procedure *dst = &rdim2_shared->baked_procedures.procedures[n->base_idx + n_idx + 1]; + RDI_Procedure *dst = &rdim_shared->baked_procedures.procedures[n->base_idx + n_idx + 1]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); if(src->is_extern) @@ -2456,8 +2456,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); - rdim2_shared->constant_data_chunk_lane_offs = push_array(arena, U64, lane_count() * params->constants.chunk_count); + rdim_shared->constant_data_chunk_lane_counts = push_array(arena, U64, lane_count() * params->constants.chunk_count); + rdim_shared->constant_data_chunk_lane_offs = push_array(arena, U64, lane_count() * params->constants.chunk_count); } lane_sync(); @@ -2470,7 +2470,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { - rdim2_shared->constant_data_chunk_lane_counts[slot_idx] += n->v[idx].value_data.size; + rdim_shared->constant_data_chunk_lane_counts[slot_idx] += n->v[idx].value_data.size; } chunk_idx += 1; } @@ -2487,8 +2487,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->constants.chunk_count + chunk_idx; - rdim2_shared->constant_data_chunk_lane_offs[slot_idx] = layout_off; - layout_off += rdim2_shared->constant_data_chunk_lane_counts[slot_idx]; + rdim_shared->constant_data_chunk_lane_offs[slot_idx] = layout_off; + layout_off += rdim_shared->constant_data_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } @@ -2504,18 +2504,18 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->baked_constants.constant_values_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim2_shared->baked_constants.constant_values_count); + rdim_shared->baked_constants.constant_values_count = params->constants.total_count+1; + rdim_shared->baked_constants.constant_values = push_array(arena, RDI_U32, rdim_shared->baked_constants.constant_values_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; - rdim2_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim2_shared->baked_constants.constant_value_data_size); + rdim_shared->baked_constants.constant_value_data_size = params->constants.total_value_data_size; + rdim_shared->baked_constants.constant_value_data = push_array(arena, RDI_U8, rdim_shared->baked_constants.constant_value_data_size); } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_constants.constants_count = params->constants.total_count+1; - rdim2_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim2_shared->baked_constants.constants_count); + rdim_shared->baked_constants.constants_count = params->constants.total_count+1; + rdim_shared->baked_constants.constants = push_array(arena, RDI_Constant, rdim_shared->baked_constants.constants_count); } lane_sync(); @@ -2525,14 +2525,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachNode(n, RDIM_SymbolChunkNode, params->constants.first) { U64 slot_idx = lane_idx()*params->constants.chunk_count + chunk_idx; - U64 value_data_off = rdim2_shared->constant_data_chunk_lane_offs[slot_idx]; + U64 value_data_off = rdim_shared->constant_data_chunk_lane_offs[slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_Symbol *src = &n->v[n_idx]; - RDI_Constant *dst = &rdim2_shared->baked_constants.constants[1 + n->base_idx + n_idx]; - RDI_U32 *dst_value_off = &rdim2_shared->baked_constants.constant_values[1 + n->base_idx + n_idx]; - RDI_U8 *dst_value_data = rdim2_shared->baked_constants.constant_value_data + value_data_off; + RDI_Constant *dst = &rdim_shared->baked_constants.constants[1 + n->base_idx + n_idx]; + RDI_U32 *dst_value_off = &rdim_shared->baked_constants.constant_values[1 + n->base_idx + n_idx]; + RDI_U8 *dst_value_data = rdim_shared->baked_constants.constant_value_data + value_data_off; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 dst->constant_value_idx = 1 + n->base_idx + n_idx; @@ -2553,28 +2553,28 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) //- rjf: setup outputs if(lane_idx() == lane_from_task_idx(0)) { - rdim2_shared->baked_units.units_count = params->units.total_count+1; - rdim2_shared->baked_units.units = push_array(arena, RDI_Unit, rdim2_shared->baked_units.units_count); + rdim_shared->baked_units.units_count = params->units.total_count+1; + rdim_shared->baked_units.units = push_array(arena, RDI_Unit, rdim_shared->baked_units.units_count); } if(lane_idx() == lane_from_task_idx(1)) { - rdim2_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; - rdim2_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim2_shared->baked_type_nodes.type_nodes_count); + rdim_shared->baked_type_nodes.type_nodes_count = params->types.total_count+1; + rdim_shared->baked_type_nodes.type_nodes = push_array(arena, RDI_TypeNode, rdim_shared->baked_type_nodes.type_nodes_count); } if(lane_idx() == lane_from_task_idx(2)) { - rdim2_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; - rdim2_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim2_shared->baked_global_variables.global_variables_count); + rdim_shared->baked_global_variables.global_variables_count = params->global_variables.total_count+1; + rdim_shared->baked_global_variables.global_variables = push_array(arena, RDI_GlobalVariable, rdim_shared->baked_global_variables.global_variables_count); } if(lane_idx() == lane_from_task_idx(3)) { - rdim2_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; - rdim2_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim2_shared->baked_thread_variables.thread_variables_count); + rdim_shared->baked_thread_variables.thread_variables_count = params->thread_variables.total_count+1; + rdim_shared->baked_thread_variables.thread_variables = push_array(arena, RDI_ThreadVariable, rdim_shared->baked_thread_variables.thread_variables_count); } if(lane_idx() == lane_from_task_idx(4)) { - rdim2_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; - rdim2_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim2_shared->baked_inline_sites.inline_sites_count); + rdim_shared->baked_inline_sites.inline_sites_count = params->inline_sites.total_count+1; + rdim_shared->baked_inline_sites.inline_sites = push_array(arena, RDI_InlineSite, rdim_shared->baked_inline_sites.inline_sites_count); } lane_sync(); @@ -2587,7 +2587,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_Unit *src = &n->v[n_idx]; - RDI_Unit *dst = &rdim2_shared->baked_units.units[n->base_idx + n_idx + 1]; + RDI_Unit *dst = &rdim_shared->baked_units.units[n->base_idx + n_idx + 1]; dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); @@ -2609,7 +2609,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_Type *src = &n->v[n_idx]; - RDI_TypeNode *dst = &rdim2_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; + RDI_TypeNode *dst = &rdim_shared->baked_type_nodes.type_nodes[n->base_idx + n_idx + 1]; //- rjf: fill shared type node info dst->kind = src->kind; @@ -2683,7 +2683,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_Symbol *src = &n->v[n_idx]; - RDI_GlobalVariable *dst = &rdim2_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; + RDI_GlobalVariable *dst = &rdim_shared->baked_global_variables.global_variables[n->base_idx + n_idx + 1]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->voff = src->offset; dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 @@ -2714,7 +2714,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) for EachInRange(n_idx, range) { RDIM_Symbol *src = &n->v[n_idx]; - RDI_ThreadVariable *dst = &rdim2_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; + RDI_ThreadVariable *dst = &rdim_shared->baked_thread_variables.thread_variables[n->base_idx + n_idx + 1]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); @@ -2744,7 +2744,7 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { - RDI_InlineSite *dst = &rdim2_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; + RDI_InlineSite *dst = &rdim_shared->baked_inline_sites.inline_sites[n->base_idx + n_idx + 1]; RDIM_InlineSite *src = &n->v[n_idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 @@ -2764,14 +2764,14 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: set up if(lane_idx() == 0) { - rdim2_shared->baked_file_paths.nodes_count = path_tree->count; - rdim2_shared->baked_file_paths.nodes = push_array(arena, RDI_FilePathNode, rdim2_shared->baked_file_paths.nodes_count); - rdim2_shared->baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, rdim2_shared->baked_file_paths.nodes_count); + rdim_shared->baked_file_paths.nodes_count = path_tree->count; + rdim_shared->baked_file_paths.nodes = push_array(arena, RDI_FilePathNode, rdim_shared->baked_file_paths.nodes_count); + rdim_shared->baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, rdim_shared->baked_file_paths.nodes_count); { U64 idx = 0; for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) { - rdim2_shared->baked_file_path_src_nodes[idx] = n; + rdim_shared->baked_file_path_src_nodes[idx] = n; idx += 1; } } @@ -2780,11 +2780,11 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // rjf: fill { - Rng1U64 range = lane_range(rdim2_shared->baked_file_paths.nodes_count); + Rng1U64 range = lane_range(rdim_shared->baked_file_paths.nodes_count); for EachInRange(idx, range) { - RDIM_BakePathNode *src = rdim2_shared->baked_file_path_src_nodes[idx]; - RDI_FilePathNode *dst = &rdim2_shared->baked_file_paths.nodes[idx]; + RDIM_BakePathNode *src = rdim_shared->baked_file_path_src_nodes[idx]; + RDI_FilePathNode *dst = &rdim_shared->baked_file_paths.nodes[idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->source_file_idx = rdim_idx_from_src_file(src->src_file); if(src->parent != 0) @@ -2811,11 +2811,11 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) { if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") { - rdim2_shared->baked_top_level_info.top_level_info.arch = params->top_level_info.arch; - rdim2_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); - rdim2_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; - rdim2_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; - rdim2_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); + rdim_shared->baked_top_level_info.top_level_info.arch = params->top_level_info.arch; + rdim_shared->baked_top_level_info.top_level_info.exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); + rdim_shared->baked_top_level_info.top_level_info.exe_hash = params->top_level_info.exe_hash; + rdim_shared->baked_top_level_info.top_level_info.voff_max = params->top_level_info.voff_max; + rdim_shared->baked_top_level_info.top_level_info.producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") { @@ -2833,8 +2833,8 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) dst->foff_first = src->foff_first; dst->foff_opl = src->foff_opl; } - rdim2_shared->baked_binary_sections.binary_sections = dst_base; - rdim2_shared->baked_binary_sections.binary_sections_count = dst_idx; + rdim_shared->baked_binary_sections.binary_sections = dst_base; + rdim_shared->baked_binary_sections.binary_sections_count = dst_idx; } } lane_sync(); @@ -2844,29 +2844,29 @@ rdim2_bake(Arena *arena, RDIM_BakeParams *params) // RDIM_BakeResults result = {0}; { - result.top_level_info = rdim2_shared->baked_top_level_info; - result.binary_sections = rdim2_shared->baked_binary_sections; - result.units = rdim2_shared->baked_units; - result.unit_vmap = rdim2_shared->baked_unit_vmap; - result.src_files = rdim2_shared->baked_src_files; - result.line_tables = rdim2_shared->baked_line_tables; - result.type_nodes = rdim2_shared->baked_type_nodes; - result.udts = rdim2_shared->baked_udts; - result.global_variables = rdim2_shared->baked_global_variables; - result.global_vmap = rdim2_shared->baked_global_vmap; - result.thread_variables = rdim2_shared->baked_thread_variables; - result.constants = rdim2_shared->baked_constants; - result.procedures = rdim2_shared->baked_procedures; - result.scopes = rdim2_shared->baked_scopes; - result.inline_sites = rdim2_shared->baked_inline_sites; - result.scope_vmap = rdim2_shared->baked_scope_vmap; - result.top_level_name_maps = rdim2_shared->baked_top_level_name_maps; - result.name_maps = rdim2_shared->baked_name_maps; - result.file_paths = rdim2_shared->baked_file_paths; - result.strings = rdim2_shared->baked_strings; - result.idx_runs = rdim2_shared->baked_idx_runs; - result.locations = rdim2_shared->baked_locations; - result.location_blocks2 = rdim2_shared->baked_location_blocks; + result.top_level_info = rdim_shared->baked_top_level_info; + result.binary_sections = rdim_shared->baked_binary_sections; + result.units = rdim_shared->baked_units; + result.unit_vmap = rdim_shared->baked_unit_vmap; + result.src_files = rdim_shared->baked_src_files; + result.line_tables = rdim_shared->baked_line_tables; + result.type_nodes = rdim_shared->baked_type_nodes; + result.udts = rdim_shared->baked_udts; + result.global_variables = rdim_shared->baked_global_variables; + result.global_vmap = rdim_shared->baked_global_vmap; + result.thread_variables = rdim_shared->baked_thread_variables; + result.constants = rdim_shared->baked_constants; + result.procedures = rdim_shared->baked_procedures; + result.scopes = rdim_shared->baked_scopes; + result.inline_sites = rdim_shared->baked_inline_sites; + result.scope_vmap = rdim_shared->baked_scope_vmap; + result.top_level_name_maps = rdim_shared->baked_top_level_name_maps; + result.name_maps = rdim_shared->baked_name_maps; + result.file_paths = rdim_shared->baked_file_paths; + result.strings = rdim_shared->baked_strings; + result.idx_runs = rdim_shared->baked_idx_runs; + result.locations = rdim_shared->baked_locations; + result.location_blocks2 = rdim_shared->baked_location_blocks; } return result; diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index e5b03675..9dfea4e2 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -62,8 +62,8 @@ struct RDIM_UnsortedJoinedLineTable //- rjf: shared state bundle -typedef struct RDIM2_Shared RDIM2_Shared; -struct RDIM2_Shared +typedef struct RDIM_Shared RDIM_Shared; +struct RDIM_Shared { RDI_U64 scope_vmap_count; RDIM_SortKey *scope_vmap_keys; @@ -178,11 +178,11 @@ struct RDIM2_Shared RDIM_BinarySectionBakeResult baked_binary_sections; }; -global RDIM2_Shared *rdim2_shared = 0; +global RDIM_Shared *rdim_shared = 0; internal RDIM_DataModel rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch); internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections); -internal RDIM_BakeResults rdim2_bake(Arena *arena, RDIM_BakeParams *params); +internal RDIM_BakeResults rdim_bake(Arena *arena, RDIM_BakeParams *params); internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in); #endif // RDI_MAKE_LOCAL_H From 0c161f83c7719da12e01cb9ad28b73817c8ec2ee Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 5 Sep 2025 17:09:01 -0700 Subject: [PATCH 139/302] fix clang --- src/lib_rdi_make/rdi_make.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index a6d717ee..0ccff4fb 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -320,7 +320,7 @@ rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) //- rjf: sortable range sorting -RSFORCEINLINE int +RDI_PROC RSFORCEINLINE int rdim_sort_key_is_before(void *l, void *r) { return ((RDIM_SortKey *)l)->key < ((RDIM_SortKey *)r)->key; @@ -1185,7 +1185,7 @@ rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_ rdim_memzero_struct(to_push); } -RSFORCEINLINE int +RDI_PROC RSFORCEINLINE int rdim_bake_string_is_before(void *l, void *r) { return str8_is_before(((RDIM_BakeString *)l)->string, ((RDIM_BakeString *)r)->string); @@ -1407,7 +1407,7 @@ rdim_bake_idx_run_chunk_list_concat_in_place(RDIM_BakeIdxRunChunkList *dst, RDIM rdim_memzero_struct(to_push); } -RSFORCEINLINE int +RDI_PROC RSFORCEINLINE int rdim_bake_idx_run_is_before(void *l, void *r) { B32 is_less_than = 0; @@ -1635,7 +1635,7 @@ rdim_bake_name_chunk_list_concat_in_place(RDIM_BakeNameChunkList *dst, RDIM_Bake rdim_memzero_struct(to_push); } -RSFORCEINLINE int +RDI_PROC RSFORCEINLINE int rdim_bake_name_is_before(void *l, void *r) { RDIM_BakeName *lhs = (RDIM_BakeName *)l; From 40d6ce2f59deb4a2af8e8d54d63058554f40ad9f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 6 Sep 2025 09:53:04 -0700 Subject: [PATCH 140/302] do not return zeroes for top-level structures in pdb parser; ensure you have a top-level readable pointer, always --- src/pdb/pdb_parse.c | 155 +++++++++++++++++--------------- src/pdb/pdb_parse.h | 4 +- src/rdi_from_pdb/rdi_from_pdb.c | 2 +- src/rdi_from_pdb/rdi_from_pdb.h | 2 +- 4 files changed, 87 insertions(+), 76 deletions(-) diff --git a/src/pdb/pdb_parse.c b/src/pdb/pdb_parse.c index 0caff005..ad88308e 100644 --- a/src/pdb/pdb_parse.c +++ b/src/pdb/pdb_parse.c @@ -215,18 +215,22 @@ pdb_strtbl_from_data(Arena *arena, String8 data){ return(result); } -internal PDB_DbiParsed* -pdb_dbi_from_data(Arena *arena, String8 data){ - ProfBegin("pdb_dbi_from_data"); +internal PDB_DbiParsed * +pdb_dbi_from_data(Arena *arena, String8 data) +{ + ProfBeginFunction(); + PDB_DbiParsed *result = push_array(arena, PDB_DbiParsed, 1);; - // get header + // rjf: extract header PDB_DbiHeader *header = 0; - if (sizeof(*header) <= data.size){ + if(sizeof(*header) <= data.size) + { header = (PDB_DbiHeader*)data.str; } - PDB_DbiParsed *result = 0; - if (header != 0 && header->sig == PDB_DbiHeaderSignature_V1){ + // rjf: parse + if(header != 0 && header->sig == PDB_DbiHeaderSignature_V1) + { // extract range sizes U64 range_size[PDB_DbiRange_COUNT]; range_size[PDB_DbiRange_ModuleInfo] = header->module_info_size; @@ -238,7 +242,6 @@ pdb_dbi_from_data(Arena *arena, String8 data){ range_size[PDB_DbiRange_DbgHeader] = header->dbg_header_size; // fill result - result = push_array(arena, PDB_DbiParsed, 1); result->data = data; result->machine_type = header->machine; result->gsi_sn = header->gsi_sn; @@ -249,7 +252,8 @@ pdb_dbi_from_data(Arena *arena, String8 data){ // fill result's range offsets { U64 cursor = sizeof(*header); - for (U64 i = 0; i < (U64)(PDB_DbiRange_COUNT); i += 1){ + for(U64 i = 0; i < (U64)(PDB_DbiRange_COUNT); i += 1) + { result->range_off[i] = cursor; cursor += range_size[i]; cursor = ClampTop(cursor, data.size); @@ -263,36 +267,36 @@ pdb_dbi_from_data(Arena *arena, String8 data){ U64 dbg_streams_size_raw = dbg_streams_max - dbg_streams_min; U64 dbg_streams_size = ClampTop(dbg_streams_size_raw, sizeof(result->dbg_streams)); MemoryCopy(result->dbg_streams, data.str + dbg_streams_min, dbg_streams_size); - if (dbg_streams_size < sizeof(result->dbg_streams)){ + if(dbg_streams_size < sizeof(result->dbg_streams)) + { U64 filled_count = dbg_streams_size/sizeof(MSF_StreamNumber); - MemorySet(result->dbg_streams + filled_count, 0xff, - (ArrayCount(result->dbg_streams) - filled_count)*sizeof(MSF_StreamNumber)); + MemorySet(result->dbg_streams + filled_count, 0xff, (ArrayCount(result->dbg_streams) - filled_count)*sizeof(MSF_StreamNumber)); } } - ProfEnd(); - - return(result); + return result; } -internal PDB_TpiParsed* -pdb_tpi_from_data(Arena *arena, String8 data){ - ProfBegin("pdb_tpi_from_data"); +internal PDB_TpiParsed * +pdb_tpi_from_data(Arena *arena, String8 data) +{ + ProfBeginFunction(); + PDB_TpiParsed *result = push_array(arena, PDB_TpiParsed, 1); - // get header + // rjf: extract header PDB_TpiHeader *header = 0; if (sizeof(*header) <= data.size){ header = (PDB_TpiHeader*)data.str; } - PDB_TpiParsed *result = 0; - if (header != 0 && header->version == PDB_TpiVersion_IMPV80){ + // rjf: parse + if(header != 0 && header->version == PDB_TpiVersion_IMPV80) + { U64 leaf_first_raw = header->header_size; U64 leaf_first = ClampTop(leaf_first_raw, data.size); U64 leaf_opl_raw = leaf_first + header->leaf_data_size; U64 leaf_opl = ClampTop(leaf_opl_raw, data.size); - result = push_array(arena, PDB_TpiParsed, 1); result->data = data; result->leaf_first = leaf_first; @@ -313,20 +317,18 @@ pdb_tpi_from_data(Arena *arena, String8 data){ } ProfEnd(); - - return(result); + return result; } internal PDB_TpiHashParsed* -pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, String8 data, String8 aux_data){ - ProfBegin("pdb_tpi_hash_from_data"); - - PDB_TpiHashParsed *result = 0; - +pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, String8 data, String8 aux_data) +{ + ProfBeginFunction(); + PDB_TpiHashParsed *result = push_array(arena, PDB_TpiHashParsed, 1); U32 stride = tpi->hash_key_size; U32 bucket_count = tpi->hash_bucket_count; - if (1 <= stride && stride <= 8 && bucket_count > 0 && data.str != 0){ - + if(1 <= stride && stride <= 8 && bucket_count > 0 && data.str != 0) + { // allocate buckets PDB_TpiHashBlock **buckets = push_array(arena, PDB_TpiHashBlock*, bucket_count); @@ -436,32 +438,33 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, Str } // fill result - result = push_array(arena, PDB_TpiHashParsed, 1); result->data = data; result->aux_data = aux_data; result->buckets = buckets; result->bucket_count = bucket_count; result->bucket_mask = bucket_mask; } - ProfEnd(); - - return(result); + return result; } -internal PDB_GsiParsed* -pdb_gsi_from_data(Arena *arena, String8 data){ - ProfBegin("pdb_gsi_from_data"); +internal PDB_GsiParsed * +pdb_gsi_from_data(Arena *arena, String8 data) +{ + ProfBeginFunction(); + PDB_GsiParsed *result = push_array(arena, PDB_GsiParsed, 1); - // get header + // rjf: extract header PDB_GsiHeader *header = 0; - if (sizeof(*header) <= data.size){ + if(sizeof(*header) <= data.size) + { header = (PDB_GsiHeader*)data.str; } - PDB_GsiParsed *result = 0; - if (header != 0 && header->signature == PDB_GsiSignature_Basic && - header->version == PDB_GsiVersion_V70 && header->bucket_data_size != 0){ + // rjf: parse + if(header != 0 && header->signature == PDB_GsiSignature_Basic && + header->version == PDB_GsiVersion_V70 && header->bucket_data_size != 0) + { Temp scratch = scratch_begin(&arena, 1); // hash offset @@ -479,7 +482,8 @@ pdb_gsi_from_data(Arena *arena, String8 data){ // get bitmask & packed offset arrays U8 *bitmasks = 0; U8 *packed_offsets = 0; - if (bitmask_off + bitmask_byte_size <= data.size){ + if(bitmask_off + bitmask_byte_size <= data.size) + { bitmasks = (data.str + bitmask_off); packed_offsets = (data.str + offsets_off); } @@ -487,7 +491,8 @@ pdb_gsi_from_data(Arena *arena, String8 data){ // unpack U32 *unpacked_offsets = 0; - if (packed_offsets != 0){ + if(packed_offsets != 0) + { unpacked_offsets = push_array(scratch.arena, U32, slot_count); U32 *bitmask_ptr = (U32*)bitmasks; @@ -496,34 +501,38 @@ pdb_gsi_from_data(Arena *arena, String8 data){ U32 *src_opl = src_ptr + packed_offset_count; U32 *dst_ptr = unpacked_offsets; U32 *dst_opl = dst_ptr + slot_count; - for (; bitmask_ptr < bitmask_opl && src_ptr < src_opl; bitmask_ptr += 1){ + for(; bitmask_ptr < bitmask_opl && src_ptr < src_opl; bitmask_ptr += 1) + { U32 bits = *bitmask_ptr; U32 src_max = (U32)(src_opl - src_ptr); U32 dst_max = (U32)(dst_opl - dst_ptr); U32 k_max0 = ClampTop(32, dst_max); U32 k_max = ClampTop(k_max0, src_max); - for (U32 k = 0; k < k_max; k += 1){ - if ((bits & 1) == 1){ + for(U32 k = 0; k < k_max; k += 1) + { + if((bits & 1) == 1) + { *dst_ptr = *src_ptr; src_ptr += 1; } - else{ + else + { *dst_ptr = 0xFFFFFFFF; } dst_ptr += 1; bits >>= 1; } } - for (; dst_ptr < dst_opl; dst_ptr += 1){ + for(; dst_ptr < dst_opl; dst_ptr += 1) + { *dst_ptr = 0xFFFFFFFF; } } // construct table B32 bad_table = 0; - if (unpacked_offsets != 0){ - result = push_array(arena, PDB_GsiParsed, 1); - + if(unpacked_offsets != 0) + { // hash records PDB_GsiHashRecord *hash_records = (PDB_GsiHashRecord*)(data.str + hash_record_array_off); U32 hash_record_count = header->hash_record_arr_size/sizeof(PDB_GsiHashRecord); @@ -539,13 +548,16 @@ pdb_gsi_from_data(Arena *arena, String8 data){ // build table PDB_GsiHashRecord *hash_record_ptr = hash_records + hash_record_count - 1; U32 prev_n = hash_record_count; - for (U32 i = slot_count; i > 1;){ + for(U32 i = slot_count; i > 1;) + { i -= 1; - if (unpacked_offsets[i] != 0xFFFFFFFF){ + if(unpacked_offsets[i] != 0xFFFFFFFF) + { // determine hash record range to use // * The "12" here is the result of some really sloppy PDB magic. U32 n = unpacked_offsets[i]/12; - if (n > prev_n){ + if(n > prev_n) + { bad_table = 1; break; } @@ -553,7 +565,8 @@ pdb_gsi_from_data(Arena *arena, String8 data){ // fill this bucket U32 *bucket_offs = push_array_aligned(arena, U32, num_steps, 4); - for (U32 j = num_steps; j > 0;){ + for(U32 j = num_steps; j > 0;) + { j -= 1; // * The "- 1" is more sloppy PDB magic. bucket_offs[j] = hash_record_ptr->symbol_off - 1; @@ -568,13 +581,11 @@ pdb_gsi_from_data(Arena *arena, String8 data){ } } } - scratch_end(scratch); } ProfEnd(); - - return(result); + return result; } internal U64 @@ -703,18 +714,20 @@ pdb_comp_unit_array_from_data(Arena *arena, String8 data){ return(result); } -internal PDB_CompUnitContributionArray* +internal PDB_CompUnitContributionArray pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_SectionHeaderArray sections) { PDB_CompUnitContribution *contributions = 0; U64 count = 0; - if (data.size >= sizeof(PDB_DbiSectionContribVersion)){ + if(data.size >= sizeof(PDB_DbiSectionContribVersion)) + { PDB_DbiSectionContribVersion *version = (PDB_DbiSectionContribVersion*)data.str; // determine array layout from version U32 item_size = 0; U32 array_off = 0; - switch (*version){ + switch(*version) + { default: { // TODO(allen): do we have a test case for this? @@ -743,11 +756,12 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_Sect // fill array PDB_CompUnitContribution *contribution_ptr = contributions; U64 cursor = array_off; - for (; cursor + item_size <= data.size; cursor += item_size){ + for(; cursor + item_size <= data.size; cursor += item_size) + { PDB_DbiSectionContrib40 *sc = (PDB_DbiSectionContrib40*)(data.str + cursor); - if (sc->size > 0 && 1 <= sc->sec && sc->sec <= section_count){ + if(sc->size > 0 && 1 <= sc->sec && sc->sec <= section_count) + { U64 voff = section_headers[sc->sec - 1].voff + sc->sec_off; - contribution_ptr->mod = sc->mod; contribution_ptr->voff_first = voff; contribution_ptr->voff_opl = voff + sc->size; @@ -758,11 +772,10 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_Sect } // fill result - PDB_CompUnitContributionArray *result = push_array(arena, PDB_CompUnitContributionArray, 1); - result->contributions = contributions; - result->count = count; - - return(result); + PDB_CompUnitContributionArray result = {0}; + result.contributions = contributions; + result.count = count; + return result; } //////////////////////////////// diff --git a/src/pdb/pdb_parse.h b/src/pdb/pdb_parse.h index 51d20f31..a01b2592 100644 --- a/src/pdb/pdb_parse.h +++ b/src/pdb/pdb_parse.h @@ -211,9 +211,7 @@ internal COFF_SectionHeaderArray pdb_coff_section_array_from_data(Arena *arena, internal PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena, String8 module_info_data); -internal PDB_CompUnitContributionArray* -pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data, - COFF_SectionHeaderArray sections); +internal PDB_CompUnitContributionArray pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data, COFF_SectionHeaderArray sections); //////////////////////////////// //~ PDB Dbi Functions diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 8f4a88f6..458e8256 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -562,7 +562,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) PDB_TpiHashParsed *ipi_hash = p2r_shared->ipi_hash; CV_LeafParsed *ipi_leaf = p2r_shared->ipi_leaf; PDB_CompUnitArray *comp_units = p2r_shared->comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions = p2r_shared->comp_unit_contributions; + PDB_CompUnitContributionArray *comp_unit_contributions = &p2r_shared->comp_unit_contributions; ////////////////////////////////////////////////////////////// //- rjf: bucket compilation unit contributions diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index 9cf33904..bb16e8ee 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -93,7 +93,7 @@ struct P2R_Shared PDB_TpiHashParsed *ipi_hash; CV_LeafParsed *ipi_leaf; PDB_CompUnitArray *comp_units; - PDB_CompUnitContributionArray *comp_unit_contributions; + PDB_CompUnitContributionArray comp_unit_contributions; RDIM_Rng1U64ChunkList *unit_ranges; U64 sym_c13_unit_lane_counter; From a11406ac51bf32996f3b5d96214fba2d13627696 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 3 Sep 2025 12:58:34 -0700 Subject: [PATCH 141/302] declare thunk symobls as functions --- src/pe/pe_make_import_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pe/pe_make_import_table.c b/src/pe/pe_make_import_table.c index d4fcf1e2..450b4a60 100644 --- a/src/pe/pe_make_import_table.c +++ b/src/pe/pe_make_import_table.c @@ -33,7 +33,7 @@ pe_make_indirect_jump_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *cod static const U64 JMP_OPERAND_OFFSET = 2; coff_obj_writer_section_push_reloc(obj_writer, code_sect, jmp_data_offset + JMP_OPERAND_OFFSET, iat_symbol, COFF_Reloc_X64_Rel32); - COFF_ObjSymbol *jmp_thunk_symbol = coff_obj_writer_push_symbol_extern(obj_writer, thunk_name, jmp_data_offset, code_sect); + COFF_ObjSymbol *jmp_thunk_symbol = coff_obj_writer_push_symbol_extern_func(obj_writer, thunk_name, jmp_data_offset, code_sect); ProfEnd(); return jmp_thunk_symbol; @@ -64,7 +64,7 @@ pe_make_load_thunk_x64(COFF_ObjWriter *obj_writer, COFF_ObjSection *code_sect, C // emit symbol String8 thunk_name = push_str8f(obj_writer->arena, "__imp_load_%S", func_name); - COFF_ObjSymbol *load_thunk_symbol = coff_obj_writer_push_symbol_extern(obj_writer, thunk_name, load_thunk_data_offset, code_sect); + COFF_ObjSymbol *load_thunk_symbol = coff_obj_writer_push_symbol_extern_func(obj_writer, thunk_name, load_thunk_data_offset, code_sect); ProfEnd(); return load_thunk_symbol; From 21163264d434ed72c8375ae8c540f6a46d54f828 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 3 Sep 2025 13:04:13 -0700 Subject: [PATCH 142/302] redirect entry point to CRT version if name is inferred --- src/linker/lnk.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 49ec85d8..3200a455 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1373,6 +1373,8 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer internal void lnk_resolve_entry_point(LNK_Config *config, LNK_SymbolTable *symtab, LNK_Link *link) { + B32 is_entry_point_name_inferred = config->entry_point_name.size == 0; + // loop over all possible subsystems and entry point names and pick // subsystem that has a defined entry point symbol if (config->entry_point_name.size == 0) { @@ -1423,9 +1425,11 @@ subsystem_inferred_from_entry:; // do we have an entry point name? if (config->entry_point_name.size) { - // redirect user entry to appropriate CRT entry - String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); - config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; + if (is_entry_point_name_inferred) { + // redirect user entry to appropriate CRT entry + String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); + config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; + } // generate undefined symbol for entry point lnk_include_symbol(config, config->entry_point_name, 0); From d92f45784db848b650215b3a2bc8aa9d9f9758a9 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 3 Sep 2025 13:41:05 -0700 Subject: [PATCH 143/302] rename defined symbol to obj ref, as the symbol table no longer has scopes and it makes no sense to refer to them that way --- src/linker/lnk.c | 86 ++++++++++++------------- src/linker/lnk_debug_info.c | 4 +- src/linker/lnk_obj.c | 10 +-- src/linker/lnk_symbol_table.c | 116 +++++++++++++++++----------------- src/linker/lnk_symbol_table.h | 18 +++--- 5 files changed, 115 insertions(+), 119 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 3200a455..4c4a0acd 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1190,7 +1190,7 @@ lnk_lib_member_ref_is_before(void *raw_a, void *raw_b) LNK_LibMemberRef **a = raw_a, **b = raw_b; LNK_Symbol *a_pull_in_ref = (*a)->lib->was_member_linked[(*a)->member_idx]; LNK_Symbol *b_pull_in_ref = (*b)->lib->was_member_linked[(*b)->member_idx]; - return lnk_symbol_defined_is_before(a_pull_in_ref, b_pull_in_ref); + return lnk_symbol_is_before(a_pull_in_ref, b_pull_in_ref); } internal LNK_LibMemberRef ** @@ -1507,7 +1507,7 @@ lnk_link_inputs_(TP_Context *tp, LNK_Symbol *symbol = c->v[i].symbol; if (symbol->is_lib_member_linked) { continue; } - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Undefined) { U32 member_idx; @@ -1515,14 +1515,14 @@ lnk_link_inputs_(TP_Context *tp, lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); } } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->ref.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); } } else if (search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->defined); + LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->ref); COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); if (dep_interp == COFF_SymbolValueInterp_Weak) { @@ -1570,7 +1570,7 @@ lnk_link_inputs_(TP_Context *tp, // create import stub (later replaced with acutal import generated by linker) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *import_symbol = lnk_make_defined_symbol(symtab->arena->v[0], link_symbol->name, import_stub->defined.obj, import_stub->defined.symbol_idx); + LNK_Symbol *import_symbol = lnk_make_obj_ref_symbol(symtab->arena->v[0], link_symbol->name, import_stub->ref.obj, import_stub->ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); // search DLL symbol list @@ -1640,7 +1640,7 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->v.from); if (symbol_ht) { - COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); + COFF_SymbolValueInterpType interp = lnk_interp_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { // clear out slot so weak symbol can replace undefined symbol (general rule is // weak symbol is not allowed to replace undefined) @@ -1944,7 +1944,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); if (symbol_interp == COFF_SymbolValueInterp_Undefined) { count += 1; } @@ -1957,18 +1957,18 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); if (symbol_interp == COFF_SymbolValueInterp_Undefined) { unresolved[cursor++] = chunk->v[i].symbol; } } } - radsort(unresolved, count, lnk_symbol_defined_ptr_is_before); + radsort(unresolved, count, lnk_symbol_ptr_is_before); for EachIndex(i, count) { LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->ref.obj, "unresolved symbol %S", symbol->name); } // TODO: /FORCE @@ -2057,10 +2057,10 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root->defined.obj; + t->obj = root->ref.obj; t->relocs.count = 1; t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root->defined.symbol_idx; + t->relocs.v[0].isymbol = root->ref.symbol_idx; SLLStackPush(task_stack, t); } @@ -2100,33 +2100,33 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj struct Task *t = task_stack; SLLStackPop(task_stack); for EachIndex(reloc_idx, t->relocs.count) { COFF_Reloc *reloc = &t->relocs.v[reloc_idx]; - LNK_SymbolDefined reloc_defn = (LNK_SymbolDefined){ .obj = t->obj, .symbol_idx = reloc->isymbol }; + LNK_ObjSymbolRef reloc_defn = (LNK_ObjSymbolRef){ .obj = t->obj, .symbol_idx = reloc->isymbol }; COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_defn.obj, reloc_defn.symbol_idx); COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed); - LNK_SymbolDefined ref_symbol = reloc_defn; + LNK_ObjSymbolRef ref_symbol = reloc_defn; for (;;) { COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); - LNK_SymbolDefined next_ref = {0}; + LNK_ObjSymbolRef next_ref = {0}; if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { - ref_symbol = symlink->defined; + ref_symbol = symlink->ref; } break; } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = defn->defined; + next_ref = defn->ref; } else { MemoryZeroStruct(&ref_symbol); break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = defn->defined; + next_ref = defn->ref; } else { break; } @@ -2219,7 +2219,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj } internal B32 -lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_SymbolDefined *symbol_out) +lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out) { B32 is_resolved = 1; COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); @@ -2227,14 +2227,14 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_Symbol switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); - *symbol_out = symlink ? symlink->defined : symbol; + *symbol_out = symlink ? symlink->ref : symbol; } break; case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->defined.symbol_idx); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Undefined) { - *symbol_out = defn->defined; + *symbol_out = defn->ref; } else { is_resolved = 0; } @@ -2242,19 +2242,19 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_Symbol case COFF_SymbolValueInterp_Undefined: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); if (defn) { - *symbol_out = defn->defined; + *symbol_out = defn->ref; } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = defn->defined; + *symbol_out = defn->ref; } break; case COFF_SymbolValueInterp_Abs: { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = defn->defined; + *symbol_out = defn->ref; } else { *symbol_out = symbol; } @@ -2378,8 +2378,8 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, section_number); if (symlink == 0) { continue; } - COFF_ParsedSymbol symlink_parsed = lnk_parsed_symbol_from_defined(symlink); - task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->defined.obj->input_idx][symlink_parsed.section_number - 1]; + COFF_ParsedSymbol symlink_parsed = lnk_parse_symbol(symlink); + task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->ref.obj->input_idx][symlink_parsed.section_number - 1]; } ProfEnd(); } @@ -2422,12 +2422,12 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number); - if (symlink && symlink->defined.obj != obj) { + if (symlink && symlink->ref.obj != obj) { U32 section_number; U32 value; if (symbol.storage_class == COFF_SymStorageClass_External) { // COMDAT leader may be at a different offset, so update this symbol with leader's offset - COFF_ParsedSymbol parsed_symlink = lnk_parsed_symbol_from_coff_symbol_idx(symlink->defined.obj, symlink->defined.symbol_idx); + COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink); section_number = symbol.section_number; value = parsed_symlink.value; } else { @@ -2485,11 +2485,7 @@ lnk_common_block_contrib_is_before(void *raw_a, void *raw_b) if (a->u.size == b->u.size) { LNK_Symbol *a_symbol = a->symbol; LNK_Symbol *b_symbol = b->symbol; - if (a_symbol->defined.obj->input_idx == b_symbol->defined.obj->input_idx) { - is_before = a_symbol->defined.symbol_idx < b_symbol->defined.symbol_idx; - } else { - is_before = a_symbol->defined.obj->input_idx < b_symbol->defined.obj->input_idx; - } + is_before = lnk_symbol_is_before(a_symbol, b_symbol); } else { is_before = a->u.size > b->u.size; } @@ -2508,8 +2504,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx]; LNK_Symbol *symbol = contrib->symbol; - LNK_Obj *obj = symbol->defined.obj; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->defined.symbol_idx); + LNK_Obj *obj = symbol->ref.obj; + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->ref.symbol_idx); U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1; if (obj->header.is_big_obj) { @@ -2522,7 +2518,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) symbol16->section_number = safe_cast_u16(section_number); } - task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->defined.symbol_idx] = 1; + task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->ref.symbol_idx] = 1; } ProfEnd(); @@ -2543,7 +2539,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task) if (interp == COFF_SymbolValueInterp_Common) { LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->defined.symbol_idx); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx); Assert(coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class) == COFF_SymbolValueInterp_Regular); if (defn) { if (obj->header.is_big_obj) { @@ -2621,8 +2617,8 @@ lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patch COFF_SymbolValueInterpType fixup_dst_type = coff_interp_symbol(fixup_dst.section_number, fixup_dst.value, fixup_dst.storage_class); if (fixup_type != fixup_dst_type) { continue; } - LNK_SymbolDefined symbol_to_resolve = { .obj = obj, .symbol_idx = symbol_idx }; - LNK_SymbolDefined fixup_symbol = {0}; + LNK_ObjSymbolRef symbol_to_resolve = { .obj = obj, .symbol_idx = symbol_idx }; + LNK_ObjSymbolRef fixup_symbol = {0}; B32 is_resolved = lnk_resolve_symbol(symtab, symbol_to_resolve, &fixup_symbol); if (is_resolved) { COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx); @@ -2824,7 +2820,7 @@ THREAD_POOL_TASK_FUNC(lnk_count_common_block_contribs_task) for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { task->u.common_block.counts[task_id] += 1; @@ -2843,7 +2839,7 @@ THREAD_POOL_TASK_FUNC(lnk_fill_out_common_block_contribs_task) for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { LNK_CommonBlockContrib *contrib = &task->u.common_block.contribs[cursor++]; @@ -4270,13 +4266,13 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, "__NULL_IMPORT_DESCRIPTOR"); LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); if (idata_sect && null_import_desc && null_thunk_data) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parse_symbol(null_import_desc); LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT); import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off; import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; - COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_thunk_data->defined.obj, null_thunk_data->defined.symbol_idx); + COFF_ParsedSymbol null_thunk_data_parsed = lnk_parse_symbol(null_thunk_data); U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value; U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off; PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); @@ -4292,7 +4288,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab,"\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); if (didat_sect && null_import_desc && last_null_thunk) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parse_symbol(null_import_desc); LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DELAY_IMPORT); import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 1c7581a9..44d38728 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3021,9 +3021,9 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) U64 node_idx = 0; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); - if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->defined.obj)) { continue; } + if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->ref.obj)) { continue; } COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp != COFF_SymbolValueInterp_Regular) { continue; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 514f0df7..fc5abf37 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -355,27 +355,27 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) if (sect_header->flags & COFF_SectionFlag_LnkRemove) { break; } - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Weak: { - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Undefined: { if (symbol.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Common: { - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 869ea4bc..024d5569 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -2,38 +2,38 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_Symbol * -lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx) +lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx) { - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->defined.obj = obj; - symbol->defined.symbol_idx = symbol_idx; + LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); + symbol->name = name; + symbol->ref.obj = obj; + symbol->ref.symbol_idx = symbol_idx; return symbol; } internal B32 -lnk_symbol_defined_is_before(void *raw_a, void *raw_b) +lnk_symbol_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - LNK_Lib *a_lib = lnk_obj_get_lib(a->defined.obj); - LNK_Lib *b_lib = lnk_obj_get_lib(b->defined.obj); + LNK_Lib *a_lib = lnk_obj_get_lib(a->ref.obj); + LNK_Lib *b_lib = lnk_obj_get_lib(b->ref.obj); U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0; U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0; if (a_lib_input_idx == b_lib_input_idx) { - if (a->defined.obj->input_idx == b->defined.obj->input_idx) { - return a->defined.symbol_idx < b->defined.symbol_idx; + if (a->ref.obj->input_idx == b->ref.obj->input_idx) { + return a->ref.symbol_idx < b->ref.symbol_idx; } - return a->defined.obj->input_idx < b->defined.obj->input_idx; + return a->ref.obj->input_idx < b->ref.obj->input_idx; } return a_lib_input_idx < b_lib_input_idx; } internal B32 -lnk_symbol_defined_ptr_is_before(void *raw_a, void *raw_b) +lnk_symbol_ptr_is_before(void *raw_a, void *raw_b) { - return lnk_symbol_defined_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); + return lnk_symbol_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); } internal void @@ -120,7 +120,7 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->defined.symbol_idx, src->defined.obj->path, src->defined.symbol_idx); + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->ref.symbol_idx, src->ref.obj->path, src->ref.symbol_idx); } internal B32 @@ -128,10 +128,10 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { B32 can_replace = 0; - LNK_Obj *dst_obj = dst->defined.obj; - LNK_Obj *src_obj = src->defined.obj; - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->defined.symbol_idx); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->defined.symbol_idx); + LNK_Obj *dst_obj = dst->ref.obj; + LNK_Obj *src_obj = src->ref.obj; + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx); COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); @@ -151,7 +151,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) weak_parsed = src_parsed; } - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->ref.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { // NOTE: MSVC does not let a weak symbol to replace an undefined one, // but LLD links without errors or warnings, meaning undefined symbols @@ -163,12 +163,12 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; } else { - can_replace = lnk_symbol_defined_is_before(src, dst); + can_replace = lnk_symbol_is_before(src, dst); } } // undefined vs undefined else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { - can_replace = lnk_symbol_defined_is_before(src, dst); + can_replace = lnk_symbol_is_before(src, dst); } // undefined vs common else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { @@ -196,7 +196,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } // abs vs common else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) { - if (lnk_symbol_defined_is_before(dst, src)) { + if (lnk_symbol_is_before(dst, src)) { can_replace = 1; } else { lnk_error_multiply_defined_symbol(dst, src); @@ -204,7 +204,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } // common vs abs else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) { - if (lnk_symbol_defined_is_before(dst, src)) { + if (lnk_symbol_is_before(dst, src)) { lnk_error_multiply_defined_symbol(dst, src); } } @@ -214,16 +214,16 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } // weak vs weak else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->defined.obj->header.is_big_obj); - COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->ref.obj->header.is_big_obj); + COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->ref.obj->header.is_big_obj); if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { - if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { + if (lnk_symbol_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { can_replace = 0; } else { lnk_error_multiply_defined_symbol(dst, src); } } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { + if (lnk_symbol_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { can_replace = 1; } else { lnk_error_multiply_defined_symbol(dst, src); @@ -231,7 +231,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { lnk_error_multiply_defined_symbol(dst, src); } else { - can_replace = lnk_symbol_defined_is_before(src, dst); + can_replace = lnk_symbol_is_before(src, dst); } } // weak vs regular/abs/common @@ -250,7 +250,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) U32 dst_section_length; U32 dst_check_sum; if (dst_interp == COFF_SymbolValueInterp_Regular) { - dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->defined.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); + dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->ref.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); } else if (dst_interp == COFF_SymbolValueInterp_Common) { dst_select = COFF_ComdatSelect_Largest; dst_section_length = dst_parsed.value; @@ -264,7 +264,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) U32 src_section_length, src_checks; U32 src_check_sum; if (src_interp == COFF_SymbolValueInterp_Regular) { - src_is_comdat = lnk_try_comdat_props_from_section_number(src->defined.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); + src_is_comdat = lnk_try_comdat_props_from_section_number(src->ref.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); } else if (src_interp == COFF_SymbolValueInterp_Common) { src_select = COFF_ComdatSelect_Largest; src_section_length = src_parsed.value; @@ -356,18 +356,18 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) internal void lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->defined.symbol_idx); + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx); COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); if (dst_interp == COFF_SymbolValueInterp_Regular) { // remove replaced section from the output - COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->defined.obj, dst_parsed.section_number); + COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->ref.obj, dst_parsed.section_number); dst_sect->flags |= COFF_SectionFlag_LnkRemove; // remove associated sections from the output - for (U32Node *associated_section = dst->defined.obj->associated_sections[dst_parsed.section_number]; + for (U32Node *associated_section = dst->ref.obj->associated_sections[dst_parsed.section_number]; associated_section != 0; associated_section = associated_section->next) { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->defined.obj, associated_section->data); + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->ref.obj, associated_section->data); section_header->flags |= COFF_SectionFlag_LnkRemove; } } @@ -375,10 +375,10 @@ lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) // assert leader section is live #if BUILD_DEBUG { - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->defined.symbol_idx); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx); COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); if (src_interp == COFF_SymbolValueInterp_Regular) { - COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->defined.obj, src_parsed.section_number); + COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->ref.obj, src_parsed.section_number); AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); } } @@ -506,32 +506,32 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk } internal COFF_ParsedSymbol -lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) +lnk_parse_symbol(LNK_Symbol *symbol) { - return lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); + return lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx); } internal COFF_SymbolValueInterpType -lnk_interp_from_symbol(LNK_Symbol *symbol) +lnk_interp_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); return coff_interp_from_parsed_symbol(symbol_parsed); } -internal LNK_SymbolDefined -lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) +internal LNK_ObjSymbolRef +lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) { Temp scratch = scratch_begin(0,0); - struct S { struct S *next; LNK_SymbolDefined symbol; B32 is_anti_dep; }; + struct S { struct S *next; LNK_ObjSymbolRef symbol; B32 is_anti_dep; }; struct S *sf = 0, *sl = 0; - LNK_SymbolDefined current_symbol = symbol; + LNK_ObjSymbolRef current_symbol = symbol; for (;;) { // guard against self-referencing weak symbols struct S *was_visited = 0; for (struct S *s = sf; s != 0; s = s->next) { - if (MemoryCompare(&s->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = s; break; } + if (MemoryCompare(&s->symbol, ¤t_symbol, sizeof(LNK_ObjSymbolRef)) == 0) { was_visited = s; break; } } if (was_visited) { String8List chain = {0}; @@ -559,10 +559,10 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) // does weak symbol have a definition? LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->defined.obj, defn_symbol->defined.symbol_idx); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->ref.obj, defn_symbol->ref.symbol_idx); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Weak) { - current_symbol = defn_symbol->defined; + current_symbol = defn_symbol->ref; break; } @@ -571,24 +571,24 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) // no definition -- fallback to default symbol COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); - current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; + current_symbol = (LNK_ObjSymbolRef){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); - tag_interp = lnk_interp_from_symbol(dep_symbol); + tag_interp = lnk_interp_symbol(dep_symbol); } if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); - COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); + COFF_SymbolValueInterpType defn_interp = lnk_interp_symbol(defn_symbol); // unresolved undefined symbol if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } // follow symbol definition - current_symbol = defn_symbol->defined; + current_symbol = defn_symbol->ref; } else { break; } } @@ -666,15 +666,15 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); + LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol->ref); COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); - if (symbol->defined.obj->header.is_big_obj) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->ref.obj->header.is_big_obj); + if (symbol->ref.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; symbol32->section_number = COFF_Symbol_UndefinedSection; symbol32->value = 0; @@ -686,7 +686,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) symbol16->storage_class = COFF_SymStorageClass_External; } } else { - symbol->defined = resolve; + symbol->ref = resolve; } } } @@ -708,7 +708,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); } } @@ -721,7 +721,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx); ISectOff sc = {0}; sc.isect = parsed_symbol.section_number; diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index d7554022..cc633568 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -5,17 +5,17 @@ // --- Symbol ------------------------------------------------------------------ -typedef struct LNK_SymbolDefined +typedef struct LNK_ObjSymbolRef { struct LNK_Obj *obj; U32 symbol_idx; -} LNK_SymbolDefined; +} LNK_ObjSymbolRef; typedef struct LNK_Symbol { - String8 name; - B8 is_lib_member_linked; - LNK_SymbolDefined defined; + String8 name; + B8 is_lib_member_linked; + LNK_ObjSymbolRef ref; } LNK_Symbol; // --- Symbol Containers ------------------------------------------------------- @@ -88,7 +88,7 @@ typedef struct // --- Symbol Make ------------------------------------------------------------- -internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); +internal LNK_Symbol * lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); // --- Symbol Containers ------------------------------------------------------ @@ -109,9 +109,9 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A // --- Symbol Helpers ---------------------------------------------------------- -internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol); -internal COFF_SymbolValueInterpType lnk_interp_from_symbol(LNK_Symbol *symbol); -internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol); +internal COFF_ParsedSymbol lnk_parse_symbol(LNK_Symbol *symbol); +internal COFF_SymbolValueInterpType lnk_interp_symbol(LNK_Symbol *symbol); +internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol); // --- Symbol Table ------------------------------------------------------------ From a6432cce8e38468cb4e943434ac121bef60f431a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 5 Sep 2025 18:27:25 -0700 Subject: [PATCH 144/302] improve unresolved symbol errors - collect symbol references and print out objs that reference unresolved symbol - print source file location of the references --- src/linker/codeview_ext/codeview.c | 68 ++++++++- src/linker/codeview_ext/codeview.h | 2 +- src/linker/lnk.c | 236 +++++++++++++++++++---------- src/linker/lnk_config.c | 79 ++++++---- src/linker/lnk_config.h | 6 + src/linker/lnk_debug_helper.c | 1 - src/linker/lnk_debug_info.c | 3 +- src/linker/lnk_error.h | 2 +- src/linker/lnk_obj.c | 75 ++++++++- src/linker/lnk_obj.h | 7 + src/linker/lnk_symbol_table.c | 156 +++++++++++++------ src/linker/lnk_symbol_table.h | 14 +- 12 files changed, 484 insertions(+), 165 deletions(-) diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index b427c911..4dceeaa2 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -1606,6 +1606,12 @@ cv_c13_collect_source_file_names(Arena *arena, CV_ChecksumList checksum_list, St // $$Lines +internal void +cv_c13_lines_header_list_concat_in_place(CV_C13LinesHeaderList *list, CV_C13LinesHeaderList *to_concat) +{ + SLLConcatInPlace(list, to_concat); +} + internal CV_C13LinesHeaderList cv_c13_lines_from_sub_sections(Arena *arena, String8 c13_data, Rng1U64 ss_range) { @@ -1840,7 +1846,64 @@ cv_c13_make_lines_accel(Arena *arena, U64 lines_count, CV_LineArray *lines) return accel; } -#if 0 +internal CV_LinesAccel * +cv_lines_accel_from_debug_s(Arena *arena, CV_DebugS debug_s) +{ + // parse $$LINES + U64 c13_lines_count = 0; + CV_LineArray *c13_lines = 0; + { + String8List raw_lines_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_Lines); + + for (String8Node *raw_lines_node = raw_lines_list.first; raw_lines_node != 0; raw_lines_node = raw_lines_node->next) { + Temp temp = temp_begin(arena); + CV_C13LinesHeaderList parsed_list = cv_c13_lines_from_sub_sections(temp.arena, raw_lines_node->string, rng_1u64(0, raw_lines_node->string.size)); + c13_lines_count += parsed_list.count; + temp_end(temp); + } + + c13_lines = push_array_no_zero(arena, CV_LineArray, c13_lines_count); + + U64 c13_lines_idx = 0; + for (String8Node *raw_lines_node = raw_lines_list.first; raw_lines_node != 0; raw_lines_node = raw_lines_node->next) { + String8 raw_lines = raw_lines_node->string; + CV_C13LinesHeaderList parsed_list = cv_c13_lines_from_sub_sections(arena, raw_lines, rng_1u64(0, raw_lines.size)); + + for(CV_C13LinesHeaderNode *header_node = parsed_list.first; header_node != 0; header_node = header_node->next) { + c13_lines[c13_lines_idx++] = cv_c13_line_array_from_data(arena, raw_lines, 0, header_node->v); + } + } + } + + return cv_c13_make_lines_accel(arena, c13_lines_count, c13_lines); +} + +internal U64 +cv_nearest_line(CV_Line *arr, U64 count, U64 value) +{ + if(count > 1 && arr[0].voff <= value && value < arr[count-1].voff) + { + U64 l = 0; + U64 r = count - 1; + for (; l <= r; ) { + U64 m = l + (r - l) / 2; + if (arr[m].voff == value) { + return m; + } else if (arr[m].voff < value) { + l = m + 1; + } else { + r = m - 1; + } + } + return l; + } + else if (count == 1 && arr[0].voff == value) + { + return 0; + } + return max_U64; +} + internal CV_Line * cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count) { @@ -1849,7 +1912,7 @@ cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count) U64 voff_line_count = 0; CV_Line *lines = 0; - U64 map_idx = bsearch_nearest_u64(accel->map, accel->map_count, voff, sizeof(accel->map[0]), OffsetOf(CV_Line, voff)); + U64 map_idx = cv_nearest_line(accel->map, accel->map_count, voff); if(map_idx < accel->map_count) { U64 near_voff = accel->map[map_idx].voff; @@ -1874,7 +1937,6 @@ cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count) ProfEnd(); return lines; } -#endif //////////////////////////////// // $$InlineeLines Accel diff --git a/src/linker/codeview_ext/codeview.h b/src/linker/codeview_ext/codeview.h index c8d09c0a..421af3c2 100644 --- a/src/linker/codeview_ext/codeview.h +++ b/src/linker/codeview_ext/codeview.h @@ -455,7 +455,7 @@ internal String8List cv_c13_collect_source_file_names(Arena *arena, CV_ChecksumL // $$Lines internal CV_C13LinesHeaderList cv_c13_lines_from_sub_sections(Arena *arena, String8 c13_data, Rng1U64 ss_range); -internal CV_LineArray cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13LinesHeader parsed_lines); +internal CV_LineArray cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13LinesHeader parsed_lines); // $$InlineeLines internal CV_C13InlineeLinesParsedList cv_c13_inlinee_lines_from_sub_sections(Arena *arena, String8List raw_inlinee_lines); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 4c4a0acd..11816d90 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -194,6 +194,11 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gfids"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gxfg"); + // set limits on unresolved symbol errors + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, ""); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, "1000"); + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, "10"); + // set default max worker count if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool)) { lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, ""); @@ -1507,22 +1512,24 @@ lnk_link_inputs_(TP_Context *tp, LNK_Symbol *symbol = c->v[i].symbol; if (symbol->is_lib_member_linked) { continue; } + LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); } } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->ref.obj->header.is_big_obj); + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { U32 member_idx; if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); } } else if (search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->ref); + LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol_ref); COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); if (dep_interp == COFF_SymbolValueInterp_Weak) { @@ -1569,8 +1576,9 @@ lnk_link_inputs_(TP_Context *tp, hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); // create import stub (later replaced with acutal import generated by linker) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *import_symbol = lnk_make_obj_ref_symbol(symtab->arena->v[0], link_symbol->name, import_stub->ref.obj, import_stub->ref.symbol_idx); + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + LNK_ObjSymbolRef import_symbol_ref = lnk_get_obj_symbol_ref(import_stub); + LNK_Symbol *import_symbol = lnk_make_obj_ref_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); // search DLL symbol list @@ -1936,45 +1944,116 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // { ProfBegin("Report Unresolved Symbols"); - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); - U64 count = 0; - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - count += 1; + U64 unresolved_symbols_count = 0; + LNK_Symbol **unresolved_symbols = 0; + { + U64 chunks_count = 0; + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); + + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + unresolved_symbols_count += 1; + } } } - } - U64 cursor = 0; - LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count); - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - unresolved[cursor++] = chunk->v[i].symbol; + unresolved_symbols = push_array(scratch.arena, LNK_Symbol *, unresolved_symbols_count); + if (unresolved_symbols_count) { + U64 cursor = 0; + for EachIndex(chunk_idx, chunks_count) { + LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; + for EachIndex(i, chunk->count) { + LNK_Symbol *symbol = chunk->v[i].symbol; + if (lnk_interp_symbol(symbol) == COFF_SymbolValueInterp_Undefined) { + unresolved_symbols[cursor++] = chunk->v[i].symbol; + } + } } } + + radsort(unresolved_symbols, unresolved_symbols_count, lnk_symbol_ptr_is_before); } - radsort(unresolved, count, lnk_symbol_ptr_is_before); + for EachIndex(i, unresolved_symbols_count) { + LNK_Symbol *symbol = unresolved_symbols[i]; - for EachIndex(i, count) { - LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->ref.obj, "unresolved symbol %S", symbol->name); + if (i > config->unresolved_symbol_limit) { + lnk_error(LNK_Error_UnresolvedSymbol, "too many unresolved symbol errors, stopping now"); + break; + } + + String8List supp_info = {0}; + { + U64 refs_count = 0; + LNK_ObjSymbolRef **refs = lnk_get_obj_symbol_ref_many(scratch.arena, symbol, &refs_count); + for EachIndex(ref_idx, refs_count) { + LNK_ObjSymbolRef *ref = refs[ref_idx]; + LNK_Obj *obj = ref->obj; + COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj); + String8 string_table = lnk_coff_string_table_from_obj(obj); + + CV_DebugS debug_s = {0}; + CV_LinesAccel *debug_lines = 0; + String8 debug_checksums = {0}; + String8 debug_strings = {0}; + + for EachIndex(sect_idx, obj->header.section_count_no_null) { + COFF_SectionHeader *section_header = §ion_table[sect_idx]; + String8 section_name = coff_name_from_section_header(string_table, section_header); + U64 section_number = sect_idx+1; + COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header); + for EachIndex(reloc_idx, relocs.count) { + if (supp_info.node_count > config->unresolved_symbol_ref_limit) { + str8_list_pushf(scratch.arena, &supp_info, "too many unresolved symbol references reported, stopping now"); + break; + } + COFF_Reloc *reloc = &relocs.v[reloc_idx]; + if (reloc->isymbol == ref->symbol_idx) { + U64 line_matches_count = 0; + CV_Line *line_matches = 0; + if (config->map_lines_for_unresolved_symbols == LNK_SwitchState_Yes) { + if (debug_lines == 0) { + debug_s = lnk_debug_s_from_obj(scratch.arena, obj); + debug_lines = cv_lines_accel_from_debug_s(scratch.arena, debug_s); + debug_checksums = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms).first->string; + debug_strings = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable).first->string; + } + line_matches_count = 0; + line_matches = cv_line_from_voff(debug_lines, reloc->apply_off, &line_matches_count); + } + + if (line_matches) { + for EachIndex(i, line_matches_count) { + CV_Line line = line_matches[i]; + CV_C13Checksum checksum = {0}; + String8 file_name = {0}; + str8_deserial_read_struct(debug_checksums, line.file_off, &checksum); + str8_deserial_read_cstr(debug_strings, checksum.name_off, &file_name); + str8_list_pushf(scratch.arena, &supp_info, "%S: %S:%u", lnk_loc_from_obj(scratch.arena, obj), file_name, line.line_num); + } + } else { + str8_list_pushf(scratch.arena, &supp_info, "%S: %S(%llx)+%x", lnk_loc_from_obj(scratch.arena, obj), section_name, section_number, reloc->apply_off); + } + } + } + } + } + } + + lnk_error(LNK_Error_UnresolvedSymbol, "unresolved symbol %S", symbol->name); + lnk_supplement_error_list(supp_info); } // TODO: /FORCE - if (count) { + if (unresolved_symbols_count) { lnk_exit(LNK_Error_UnresolvedSymbol); } + ProfEnd(); } @@ -2054,13 +2133,14 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj // push tasks for each root symbol for (LNK_IncludeSymbolNode *root_n = config->include_symbol_list.first; root_n != 0; root_n = root_n->next) { - LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); + LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); + LNK_ObjSymbolRef root_ref = lnk_get_obj_symbol_ref(root); struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root->ref.obj; + t->obj = root_ref.obj; t->relocs.count = 1; t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root->ref.symbol_idx; + t->relocs.v[0].isymbol = root_ref.symbol_idx; SLLStackPush(task_stack, t); } @@ -2113,20 +2193,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { - ref_symbol = symlink->ref; + ref_symbol = lnk_get_obj_symbol_ref(symlink); } break; } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = defn->ref; + next_ref = lnk_get_obj_symbol_ref(defn); } else { MemoryZeroStruct(&ref_symbol); break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = defn->ref; + next_ref = lnk_get_obj_symbol_ref(defn); } else { break; } @@ -2227,14 +2307,14 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); - *symbol_out = symlink ? symlink->ref : symbol; + *symbol_out = symlink ? lnk_get_obj_symbol_ref(symlink) : symbol; } break; case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx); - COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); + COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn); + COFF_SymbolValueInterpType defn_interp = lnk_interp_symbol(defn); if (defn_interp != COFF_SymbolValueInterp_Undefined) { - *symbol_out = defn->ref; + *symbol_out = lnk_get_obj_symbol_ref(defn); } else { is_resolved = 0; } @@ -2242,19 +2322,19 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb case COFF_SymbolValueInterp_Undefined: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); if (defn) { - *symbol_out = defn->ref; + *symbol_out = lnk_get_obj_symbol_ref(defn); } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = defn->ref; + *symbol_out = lnk_get_obj_symbol_ref(defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = defn->ref; + *symbol_out = lnk_get_obj_symbol_ref(defn); } else { *symbol_out = symbol; } @@ -2379,7 +2459,8 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) if (symlink == 0) { continue; } COFF_ParsedSymbol symlink_parsed = lnk_parse_symbol(symlink); - task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->ref.obj->input_idx][symlink_parsed.section_number - 1]; + LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink); + task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink_ref.obj->input_idx][symlink_parsed.section_number - 1]; } ProfEnd(); } @@ -2422,29 +2503,32 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number); - if (symlink && symlink->ref.obj != obj) { - U32 section_number; - U32 value; - if (symbol.storage_class == COFF_SymStorageClass_External) { - // COMDAT leader may be at a different offset, so update this symbol with leader's offset - COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink); - section_number = symbol.section_number; - value = parsed_symlink.value; - } else { - // COMDAT section may have static symbols which are now invalid to relocate against - section_number = LNK_REMOVED_SECTION_NUMBER_32; - value = max_U32; - task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; - } + if (symlink) { + LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink); + if (symlink_ref.obj != obj) { + U32 section_number; + U32 value; + if (symbol.storage_class == COFF_SymStorageClass_External) { + // COMDAT leader may be at a different offset, so update this symbol with leader's offset + COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink); + section_number = symbol.section_number; + value = parsed_symlink.value; + } else { + // COMDAT section may have static symbols which are now invalid to relocate against + section_number = LNK_REMOVED_SECTION_NUMBER_32; + value = max_U32; + task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; + } - if (obj->header.is_big_obj) { - COFF_Symbol32 *symbol32 = symbol.raw_symbol; - symbol32->section_number = section_number; - symbol32->value = value; - } else { - COFF_Symbol16 *symbol16 = symbol.raw_symbol; - symbol16->section_number = (U16)section_number; - symbol16->value = value; + if (obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol.raw_symbol; + symbol32->section_number = section_number; + symbol32->value = value; + } else { + COFF_Symbol16 *symbol16 = symbol.raw_symbol; + symbol16->section_number = (U16)section_number; + symbol16->value = value; + } } } } @@ -2504,11 +2588,11 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx]; LNK_Symbol *symbol = contrib->symbol; - LNK_Obj *obj = symbol->ref.obj; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->ref.symbol_idx); + LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); + COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1; - if (obj->header.is_big_obj) { + if (symbol_ref.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = parsed_symbol.raw_symbol; symbol32->value = contrib->u.offset; symbol32->section_number = safe_cast_u32(section_number); @@ -2518,7 +2602,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) symbol16->section_number = safe_cast_u16(section_number); } - task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->ref.symbol_idx] = 1; + task->u.patch_symtabs.was_symbol_patched[symbol_ref.obj->input_idx][symbol_ref.symbol_idx] = 1; } ProfEnd(); @@ -2536,11 +2620,10 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task) for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Common) { LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx); - Assert(coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class) == COFF_SymbolValueInterp_Regular); + COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn); + Assert(lnk_interp_symbol(defn) == COFF_SymbolValueInterp_Regular); if (defn) { if (obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol.raw_symbol; @@ -2720,13 +2803,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize); String8 section_data = str8_substr(data, section_frange); - // find section relocs - COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header); - COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); - // apply relocs - for EachIndex(reloc_idx, reloc_info.count) { - COFF_Reloc *reloc = &relocs[reloc_idx]; + COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header); + for EachIndex(reloc_idx, relocs.count) { + COFF_Reloc *reloc = &relocs.v[reloc_idx]; // error check relocation if (obj->header.machine == COFF_MachineType_X64) { diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 79a413a4..8a1bb9a6 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -121,38 +121,41 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = { LNK_CmdSwitch_NotImplemented, 0, "WX", "", "" }, //- internal switches - { LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, - { LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." }, - { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." }, - { LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." }, - { LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, - { LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" }, - { LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, - { LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" }, - { LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, - { LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, - { LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, - { LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, - { LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" }, - { LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, - { LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, - { LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, - { LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." }, - { LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, - { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, - { LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" }, - { LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, - { LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, - { LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, - { LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." }, - { LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." }, + { LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, + { LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." }, + { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." }, + { LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, 0, "RAD_MAP_LINES_FOR_UNRESOLVED_SYMBOLS", "[:NO]", "Use debug info to print source file location for unresolved symbol" }, + { LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." }, + { LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." }, + { LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" }, + { LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." }, + { LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" }, + { LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" }, + { LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." }, + { LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" }, + { LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME }, + { LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" }, + { LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." }, + { LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, + { LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, + { LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." }, + { LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, + { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, + { LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" }, + { LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" }, + { LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, + { LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, + { LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, 0, "RAD_UNRESOLVED_SYMBOL_LIMIT", ":#", "Limits number of unresolved symbol errors linker reports." }, + { LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." }, + { LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." }, + { LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." }, { LNK_CmdSwitch_Help, 0, "HELP", "", "" }, { LNK_CmdSwitch_Help, 0, "?", "", "" }, @@ -1776,6 +1779,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List config->rad_chunk_map = LNK_SwitchState_Yes; } break; + case LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols: { + lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->map_lines_for_unresolved_symbols); + } break; + case LNK_CmdSwitch_Rad_MemoryMapFiles: { lnk_cmd_switch_set_flag_32(obj, cmd_switch, value_strings, &config->io_flags, LNK_IO_Flags_MemoryMapFiles); } break; @@ -2005,6 +2012,14 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List lnk_cmd_switch_parse_u32(obj, cmd_switch, value_strings, &config->time_stamp, 0); } break; + case LNK_CmdSwitch_Rad_UnresolvedSymbolLimit: { + lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->unresolved_symbol_limit, 0); + } break; + + case LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit: { + lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->unresolved_symbol_ref_limit, 0); + } break; + case LNK_CmdSwitch_Rad_Version: { fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL); os_abort(0); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 780a2e12..5c81ab44 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -164,6 +164,7 @@ typedef enum LNK_CmdSwitch_Rad_Log, LNK_CmdSwitch_Rad_Logo, LNK_CmdSwitch_Rad_Map, + LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, LNK_CmdSwitch_Rad_MemoryMapFiles, LNK_CmdSwitch_Rad_MtPath, LNK_CmdSwitch_Rad_OsVer, @@ -178,6 +179,8 @@ typedef enum LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_TargetOs, LNK_CmdSwitch_Rad_TimeStamp, + LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, + LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, LNK_CmdSwitch_Rad_Version, LNK_CmdSwitch_Rad_Workers, LNK_CmdSwitch_Rad_WriteTempFiles, @@ -409,6 +412,9 @@ typedef struct LNK_Config HashTable *include_symbol_ht; HashTable *delay_load_ht; HashTable *disallow_lib_ht; + U64 unresolved_symbol_limit; + U64 unresolved_symbol_ref_limit; + LNK_SwitchState map_lines_for_unresolved_symbols; } LNK_Config; // --- MSVC Error Codes -------------------------------------------------------- diff --git a/src/linker/lnk_debug_helper.c b/src/linker/lnk_debug_helper.c index 6c0da272..7d1b7017 100644 --- a/src/linker/lnk_debug_helper.c +++ b/src/linker/lnk_debug_helper.c @@ -72,4 +72,3 @@ lnk_make_dll_import_debug_symbols(Arena *arena, COFF_MachineType machine, String return debug_symbols; } - diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 44d38728..5b07d9a5 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3021,9 +3021,10 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) U64 node_idx = 0; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; + LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); - if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->ref.obj)) { continue; } + if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol_ref.obj)) { continue; } COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp != COFF_SymbolValueInterp_Regular) { continue; } diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 2c34eee4..7a7e4a28 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -37,7 +37,6 @@ typedef enum LNK_Error_IllegalSectionMerge, LNK_Error_IllegalRelocation, LNK_Error_CircularMerge, - LNK_Error_UnresolvedSymbol, LNK_Error_AssociativeLoop, LNK_Error_AlternateNameConflict, LNK_Error_RelocationAgainstRemovedSection, @@ -55,6 +54,7 @@ typedef enum LNK_Error_UndefinedIsWeak, LNK_Error_WeakCycle, LNK_Error_InvalidLib, + LNK_Error_UnresolvedSymbol, LNK_Error_Last, LNK_Warning_First, diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index fc5abf37..50e2ecf6 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -1,11 +1,25 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal String8 +lnk_loc_from_obj(Arena *arena, LNK_Obj *obj) +{ + String8 obj_path = str8_skip_last_slash(obj ? obj->path : str8_lit("RADLINK")); + String8 lib_path = str8_skip_last_slash(lnk_obj_get_lib_path(obj)); + String8 result; + if (lib_path.size) { + result = push_str8f(arena, "%S(%S)", lib_path, obj_path); + } else { + result = push_str8_copy(arena, obj_path); + } + return result; +} + internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...) { va_list args; va_start(args, fmt); - String8 obj_path = obj ? obj->path : str8_lit("RADLINK"); + String8 obj_path = obj ? obj->path : str8_zero(); String8 lib_path = lnk_obj_get_lib_path(obj); lnk_error_with_loc_fv(code, obj_path, lib_path, fmt, args); va_end(args); @@ -494,12 +508,27 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number) return section_header; } +internal COFF_RelocArray +lnk_coff_relocs_from_section_header(LNK_Obj *obj, COFF_SectionHeader *section_header) +{ + COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header); + COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); + COFF_RelocArray result = { .count = reloc_info.count, .v = relocs }; + return result; +} + internal COFF_SectionHeader * lnk_coff_section_table_from_obj(LNK_Obj *obj) { return (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; } +internal String8 +lnk_coff_string_table_from_obj(LNK_Obj *obj) +{ + return str8_substr(obj->data, obj->header.string_table_range); +} + internal COFF_RelocArray lnk_coff_reloc_info_from_section_number(LNK_Obj *obj, U64 section_number) { @@ -684,3 +713,47 @@ lnk_directive_info_from_raw_directives(Arena *arena, LNK_Obj *obj, String8List r return directive_info; } +internal CV_DebugS +lnk_debug_s_from_obj(Arena *arena, LNK_Obj *obj) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List raw_debug_s = {0}; + { + COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj); + String8 string_table = lnk_coff_string_table_from_obj(obj); + for EachIndex(sect_idx, obj->header.section_count_no_null) { + COFF_SectionHeader *section_header = §ion_table[sect_idx]; + String8 section_name = coff_name_from_section_header(string_table, section_header); + if (str8_match(section_name, str8_lit(".debug$S"), 0)) { + String8 debug_s = str8_substr(obj->data, rng_1u64(section_header->foff, section_header->foff + section_header->fsize)); + str8_list_push(scratch.arena, &raw_debug_s, debug_s); + } + } + } + + CV_DebugS debug_s = {0}; + { + for (String8Node *node = raw_debug_s.first; node != 0; node = node->next) { + // parse & merge sub sections + CV_DebugS ds = cv_parse_debug_s(scratch.arena, node->string); + cv_debug_s_concat_in_place(&debug_s, &ds); + + // make sure there is one string table + String8List string_data_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable); + if (string_data_list.node_count > 1) { + break; + } + + // make sure there is one file checksum table + String8List checksum_data_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms); + if (checksum_data_list.node_count > 1) { + continue; + } + } + } + + scratch_end(scratch); + return debug_s; +} + diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 48a4c880..3f449725 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -89,6 +89,7 @@ typedef struct // --- Error ------------------------------------------------------------------- +internal String8 lnk_loc_from_obj(Arena *arena, LNK_Obj *obj); internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...); internal void lnk_error_input_obj(LNK_ErrorCode code, struct LNK_Input *input, char *fmt, ...); @@ -115,7 +116,9 @@ internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_n internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff(LNK_Obj *obj, void *coff_symbol); internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx); internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number); +internal COFF_RelocArray lnk_coff_relocs_from_section_header(LNK_Obj *obj, COFF_SectionHeader *section_header); internal COFF_SectionHeader * lnk_coff_section_table_from_obj(LNK_Obj *obj); +internal String8 lnk_coff_string_table_from_obj(LNK_Obj *obj); internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out); internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx); @@ -130,3 +133,7 @@ internal void lnk_parse_msvc_linker_directive(Arena *arena, LNK_Obj internal String8List lnk_raw_directives_from_obj(Arena *arena, LNK_Obj *obj); internal LNK_DirectiveInfo lnk_directive_info_from_raw_directives(Arena *arena, LNK_Obj *obj, String8List raw_directives); +// --- Debug Info -------------------------------------------------------------- + +internal CV_DebugS lnk_debug_s_from_obj(Arena *arena, LNK_Obj *obj); + diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 024d5569..1759be9c 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -4,30 +4,51 @@ internal LNK_Symbol * lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx) { + LNK_ObjSymbolRefNode *ref = push_array(arena, LNK_ObjSymbolRefNode, 1); + ref->v.obj = obj; + ref->v.symbol_idx = symbol_idx; + LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); symbol->name = name; - symbol->ref.obj = obj; - symbol->ref.symbol_idx = symbol_idx; + symbol->refs = ref; + return symbol; } +internal int +lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b) +{ + LNK_ObjSymbolRef *a_ref = raw_a; + LNK_ObjSymbolRef *b_ref = raw_b; + LNK_Lib *a_lib = lnk_obj_get_lib(a_ref->obj); + LNK_Lib *b_lib = lnk_obj_get_lib(b_ref->obj); + U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0; + U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0; + + if (a_lib_input_idx == b_lib_input_idx) { + if (a_ref->obj->input_idx == b_ref->obj->input_idx) { + return a_ref->symbol_idx < b_ref->symbol_idx; + } + return a_ref->obj->input_idx < b_ref->obj->input_idx; + } + + return a_lib_input_idx < b_lib_input_idx; +} + +internal int +lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b) +{ + LNK_ObjSymbolRef **a = raw_a, **b = raw_b; + return lnk_obj_symbol_ref_is_before(*a, *b); +} + internal B32 lnk_symbol_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - - LNK_Lib *a_lib = lnk_obj_get_lib(a->ref.obj); - LNK_Lib *b_lib = lnk_obj_get_lib(b->ref.obj); - U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0; - U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0; - - if (a_lib_input_idx == b_lib_input_idx) { - if (a->ref.obj->input_idx == b->ref.obj->input_idx) { - return a->ref.symbol_idx < b->ref.symbol_idx; - } - return a->ref.obj->input_idx < b->ref.obj->input_idx; - } - return a_lib_input_idx < b_lib_input_idx; + LNK_ObjSymbolRef a_ref = lnk_get_obj_symbol_ref(a); + LNK_ObjSymbolRef b_ref = lnk_get_obj_symbol_ref(b); + return lnk_obj_symbol_ref_is_before(&a_ref, &b_ref); } internal B32 @@ -120,7 +141,9 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->ref.symbol_idx, src->ref.obj->path, src->ref.symbol_idx); + LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); + LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst_ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst_ref.symbol_idx, src_ref.obj->path, src_ref.symbol_idx); } internal B32 @@ -128,12 +151,14 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { B32 can_replace = 0; - LNK_Obj *dst_obj = dst->ref.obj; - LNK_Obj *src_obj = src->ref.obj; - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx); - COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); - COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); + COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst); + COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src); + COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst); + COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src); + LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); + LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + LNK_Obj *dst_obj = dst_ref.obj; + LNK_Obj *src_obj = src_ref.obj; // undefined vs regular if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { @@ -151,7 +176,8 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) weak_parsed = src_parsed; } - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->ref.obj->header.is_big_obj); + LNK_ObjSymbolRef weak_symbol_ref = lnk_get_obj_symbol_ref(weak); + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak_symbol_ref.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { // NOTE: MSVC does not let a weak symbol to replace an undefined one, // but LLD links without errors or warnings, meaning undefined symbols @@ -214,8 +240,8 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) } // weak vs weak else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->ref.obj->header.is_big_obj); - COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->ref.obj->header.is_big_obj); + COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst_ref.obj->header.is_big_obj); + COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src_ref.obj->header.is_big_obj); if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { if (lnk_symbol_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { can_replace = 0; @@ -250,7 +276,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) U32 dst_section_length; U32 dst_check_sum; if (dst_interp == COFF_SymbolValueInterp_Regular) { - dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->ref.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); + dst_is_comdat = lnk_try_comdat_props_from_section_number(dst_ref.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); } else if (dst_interp == COFF_SymbolValueInterp_Common) { dst_select = COFF_ComdatSelect_Largest; dst_section_length = dst_parsed.value; @@ -264,7 +290,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) U32 src_section_length, src_checks; U32 src_check_sum; if (src_interp == COFF_SymbolValueInterp_Regular) { - src_is_comdat = lnk_try_comdat_props_from_section_number(src->ref.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); + src_is_comdat = lnk_try_comdat_props_from_section_number(src_ref.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); } else if (src_interp == COFF_SymbolValueInterp_Common) { src_select = COFF_ComdatSelect_Largest; src_section_length = src_parsed.value; @@ -356,29 +382,38 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) internal void lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx); - COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); + COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst); + COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst); + LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); + if (dst_interp == COFF_SymbolValueInterp_Regular) { // remove replaced section from the output - COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->ref.obj, dst_parsed.section_number); + COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst_ref.obj, dst_parsed.section_number); dst_sect->flags |= COFF_SectionFlag_LnkRemove; // remove associated sections from the output - for (U32Node *associated_section = dst->ref.obj->associated_sections[dst_parsed.section_number]; + for (U32Node *associated_section = dst_ref.obj->associated_sections[dst_parsed.section_number]; associated_section != 0; associated_section = associated_section->next) { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->ref.obj, associated_section->data); + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst_ref.obj, associated_section->data); section_header->flags |= COFF_SectionFlag_LnkRemove; } } + // merge symbol refs + LNK_ObjSymbolRefNode *src_last_ref; + for (src_last_ref = src->refs; src_last_ref->next != 0; src_last_ref = src_last_ref->next); + src_last_ref->next = dst->refs; + // assert leader section is live #if BUILD_DEBUG { - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx); - COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); + COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src); + COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src); + LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + if (src_interp == COFF_SymbolValueInterp_Regular) { - COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->ref.obj, src_parsed.section_number); + COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src_ref.obj, src_parsed.section_number); AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); } } @@ -505,10 +540,42 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk return chunks; } +internal LNK_ObjSymbolRef +lnk_get_obj_symbol_ref(LNK_Symbol *symbol) +{ + return symbol->refs->v; +} + +internal U64 +lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol) +{ + U64 count = 0; + for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, count += 1); + return count; +} + +internal LNK_ObjSymbolRef ** +lnk_get_obj_symbol_ref_many(Arena *arena, LNK_Symbol *symbol, U64 *count_out) +{ + // TODO: would be simpler if we sorted refs on insert/update + U64 refs_count = lnk_get_obj_symbol_ref_count(symbol); + LNK_ObjSymbolRef **refs = push_array(arena, LNK_ObjSymbolRef *, refs_count); + U64 i = 0; + for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, i += 1) { + refs[i] = &node->v; + } + radsort(refs, refs_count, lnk_obj_symbol_ref_ptr_is_before); + if (count_out) { + *count_out = refs_count; + } + return refs; +} + internal COFF_ParsedSymbol lnk_parse_symbol(LNK_Symbol *symbol) { - return lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx); + LNK_ObjSymbolRef ref = lnk_get_obj_symbol_ref(symbol); + return lnk_parsed_symbol_from_coff_symbol_idx(ref.obj, ref.symbol_idx); } internal COFF_SymbolValueInterpType @@ -559,10 +626,10 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) // does weak symbol have a definition? LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->ref.obj, defn_symbol->ref.symbol_idx); + COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn_symbol); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Weak) { - current_symbol = defn_symbol->ref; + current_symbol = lnk_get_obj_symbol_ref(defn_symbol); break; } @@ -588,7 +655,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } // follow symbol definition - current_symbol = defn_symbol->ref; + current_symbol = lnk_get_obj_symbol_ref(defn_symbol); } else { break; } } @@ -666,15 +733,16 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; + LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol->ref); + LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol_ref); COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->ref.obj->header.is_big_obj); - if (symbol->ref.obj->header.is_big_obj) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); + if (symbol_ref.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; symbol32->section_number = COFF_Symbol_UndefinedSection; symbol32->value = 0; @@ -686,7 +754,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) symbol16->storage_class = COFF_SymStorageClass_External; } } else { - symbol->ref = resolve; + symbol->refs->v = resolve; } } } @@ -721,7 +789,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); ISectOff sc = {0}; sc.isect = parsed_symbol.section_number; diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index cc633568..78bd1291 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -11,11 +11,17 @@ typedef struct LNK_ObjSymbolRef U32 symbol_idx; } LNK_ObjSymbolRef; +typedef struct LNK_ObjSymbolRefNode +{ + struct LNK_ObjSymbolRefNode *next; + LNK_ObjSymbolRef v; +} LNK_ObjSymbolRefNode; + typedef struct LNK_Symbol { - String8 name; - B8 is_lib_member_linked; - LNK_ObjSymbolRef ref; + String8 name; + B8 is_lib_member_linked; + LNK_ObjSymbolRefNode *refs; } LNK_Symbol; // --- Symbol Containers ------------------------------------------------------- @@ -109,6 +115,8 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A // --- Symbol Helpers ---------------------------------------------------------- +internal LNK_ObjSymbolRef lnk_get_obj_symbol_ref(LNK_Symbol *symbol); +internal U64 lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol); internal COFF_ParsedSymbol lnk_parse_symbol(LNK_Symbol *symbol); internal COFF_SymbolValueInterpType lnk_interp_symbol(LNK_Symbol *symbol); internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol); From 3459070f71d0155e3b9ded43ae03547f0121204e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 5 Sep 2025 23:48:38 -0700 Subject: [PATCH 145/302] remove windows.h from blake3 --- src/third_party/blake3/c/blake3_dispatch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/third_party/blake3/c/blake3_dispatch.c b/src/third_party/blake3/c/blake3_dispatch.c index 78f7ddb6..0082f974 100644 --- a/src/third_party/blake3/c/blake3_dispatch.c +++ b/src/third_party/blake3/c/blake3_dispatch.c @@ -6,7 +6,6 @@ #if defined(IS_X86) #if defined(_MSC_VER) -#include #include #elif defined(__GNUC__) #include @@ -15,6 +14,7 @@ #endif #endif + #if !defined(BLAKE3_ATOMICS) #if defined(__has_include) #if __has_include() && !defined(_MSC_VER) @@ -32,9 +32,9 @@ #define ATOMIC_LOAD(x) x #define ATOMIC_STORE(x, y) x = y #elif defined(_MSC_VER) -#define ATOMIC_INT LONG -#define ATOMIC_LOAD(x) InterlockedOr(&x, 0) -#define ATOMIC_STORE(x, y) InterlockedExchange(&x, y) +#define ATOMIC_INT long +#define ATOMIC_LOAD(x) _InterlockedOr(&x, 0) +#define ATOMIC_STORE(x, y) _InterlockedExchange(&x, y) #else #define ATOMIC_INT int #define ATOMIC_LOAD(x) x From 069d6836907191f54421c93214e3b58a69d8445a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 6 Sep 2025 00:21:37 -0700 Subject: [PATCH 146/302] fix crash when obj does not have debug info --- src/linker/lnk.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 11816d90..8d54cf49 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2018,10 +2018,12 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer CV_Line *line_matches = 0; if (config->map_lines_for_unresolved_symbols == LNK_SwitchState_Yes) { if (debug_lines == 0) { + String8List raw_checksums = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms); + String8List raw_strings = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable); debug_s = lnk_debug_s_from_obj(scratch.arena, obj); debug_lines = cv_lines_accel_from_debug_s(scratch.arena, debug_s); - debug_checksums = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms).first->string; - debug_strings = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable).first->string; + debug_checksums = str8_list_first(&raw_checksums); + debug_strings = str8_list_first(&raw_strings); } line_matches_count = 0; line_matches = cv_line_from_voff(debug_lines, reloc->apply_off, &line_matches_count); From 80b65bc0fbb4bd2fa14239c7f70a2de2c1c4f688 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 8 Sep 2025 16:06:45 -0700 Subject: [PATCH 147/302] fix treatment of unitless pdbs --- src/rdi_from_pdb/rdi_from_pdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 458e8256..ad32b4a6 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1113,8 +1113,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) p2r_shared->sym_lane_take_counter = 0; } lane_sync(); - RDIM_Unit *units = p2r_shared->all_units.first->v; - U64 units_count = p2r_shared->all_units.first->count; + RDIM_Unit *units = p2r_shared->all_units.first ? p2r_shared->all_units.first->v : 0; + U64 units_count = p2r_shared->all_units.first ? p2r_shared->all_units.first->count : 0; RDIM_LineTableChunkList *units_line_tables = p2r_shared->units_line_tables; Assert(units_count == comp_units->count); From 222c220d9957d834b5404ae66948dfbd209bfbd8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 6 Sep 2025 11:33:35 -0700 Subject: [PATCH 148/302] make xxhash API funcs static and hash string size too --- src/base/base_strings.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index ce7af60c..95ba9d38 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -378,12 +378,12 @@ str8_is_before(String8 a, String8 b) { result = 1; break; - } - else if(a.str[off] > b.str[off]) - { - result = 0; - break; - } + } + else if(a.str[off] > b.str[off]) + { + result = 0; + break; + } else if(off+1 == common_size) { result = (a.size < b.size); @@ -2808,8 +2808,7 @@ str8_compar(String8 a, String8 b, B32 ignore_case) return cmp; } -internal int -str8_compar_ignore_case(const void *a, const void *b) +internal int str8_compar_ignore_case(const void *a, const void *b) { return str8_compar(*(String8*)a, *(String8*)b, 1); } @@ -2831,6 +2830,7 @@ str8_is_before_case_sensitive(const void *a, const void *b) //~ rjf: Basic String Hashes #if !defined(XXH_IMPLEMENTATION) +# define XXH_PRIVATE_API # define XXH_IMPLEMENTATION # define XXH_STATIC_LINKING_ONLY # include "third_party/xxHash/xxhash.h" @@ -2839,7 +2839,10 @@ str8_is_before_case_sensitive(const void *a, const void *b) internal U64 u64_hash_from_seed_str8(U64 seed, String8 string) { - U64 result = XXH3_64bits_withSeed(string.str, string.size, seed); + XXH3_state_t hasher; XXH3_64bits_reset_withSeed(&hasher, seed); + XXH3_64bits_update(&hasher, &string.size, sizeof(string.size)); + XXH3_64bits_update(&hasher, string.str, string.size); + XXH64_hash_t result = XXH3_64bits_digest(&hasher); return result; } From 7cea036bc1d1bf12aa5815bbc012d5b5f8f7209c Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 6 Sep 2025 11:44:04 -0700 Subject: [PATCH 149/302] clean up pass over symbol table - rename functions for consistency - remove unused code --- src/linker/lnk.c | 78 ++++----- src/linker/lnk_debug_info.c | 4 +- src/linker/lnk_obj.c | 10 +- src/linker/lnk_symbol_table.c | 315 +++++++++++++--------------------- src/linker/lnk_symbol_table.h | 47 +++-- 5 files changed, 189 insertions(+), 265 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 8d54cf49..5233ea7a 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1512,8 +1512,8 @@ lnk_link_inputs_(TP_Context *tp, LNK_Symbol *symbol = c->v[i].symbol; if (symbol->is_lib_member_linked) { continue; } - LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); - COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Undefined) { @@ -1577,8 +1577,8 @@ lnk_link_inputs_(TP_Context *tp, // create import stub (later replaced with acutal import generated by linker) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_ObjSymbolRef import_symbol_ref = lnk_get_obj_symbol_ref(import_stub); - LNK_Symbol *import_symbol = lnk_make_obj_ref_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); + LNK_ObjSymbolRef import_symbol_ref = lnk_ref_from_symbol(import_stub); + LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); // search DLL symbol list @@ -1648,7 +1648,7 @@ lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->v.from); if (symbol_ht) { - COFF_SymbolValueInterpType interp = lnk_interp_symbol(symbol_ht->symbol); + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { // clear out slot so weak symbol can replace undefined symbol (general rule is // weak symbol is not allowed to replace undefined) @@ -1955,7 +1955,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); if (symbol_interp == COFF_SymbolValueInterp_Undefined) { unresolved_symbols_count += 1; } @@ -1969,7 +1969,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - if (lnk_interp_symbol(symbol) == COFF_SymbolValueInterp_Undefined) { + if (lnk_interp_from_symbol(symbol) == COFF_SymbolValueInterp_Undefined) { unresolved_symbols[cursor++] = chunk->v[i].symbol; } } @@ -1990,7 +1990,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer String8List supp_info = {0}; { U64 refs_count = 0; - LNK_ObjSymbolRef **refs = lnk_get_obj_symbol_ref_many(scratch.arena, symbol, &refs_count); + LNK_ObjSymbolRef **refs = lnk_ref_from_symbol_many(scratch.arena, symbol, &refs_count); for EachIndex(ref_idx, refs_count) { LNK_ObjSymbolRef *ref = refs[ref_idx]; LNK_Obj *obj = ref->obj; @@ -2136,7 +2136,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj // push tasks for each root symbol for (LNK_IncludeSymbolNode *root_n = config->include_symbol_list.first; root_n != 0; root_n = root_n->next) { LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); - LNK_ObjSymbolRef root_ref = lnk_get_obj_symbol_ref(root); + LNK_ObjSymbolRef root_ref = lnk_ref_from_symbol(root); struct Task *t = push_array(scratch.arena, struct Task, 1); t->obj = root_ref.obj; @@ -2195,20 +2195,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { - ref_symbol = lnk_get_obj_symbol_ref(symlink); + ref_symbol = lnk_ref_from_symbol(symlink); } break; } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = lnk_get_obj_symbol_ref(defn); + next_ref = lnk_ref_from_symbol(defn); } else { MemoryZeroStruct(&ref_symbol); break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = lnk_get_obj_symbol_ref(defn); + next_ref = lnk_ref_from_symbol(defn); } else { break; } @@ -2309,14 +2309,14 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); - *symbol_out = symlink ? lnk_get_obj_symbol_ref(symlink) : symbol; + *symbol_out = symlink ? lnk_ref_from_symbol(symlink) : symbol; } break; case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn); - COFF_SymbolValueInterpType defn_interp = lnk_interp_symbol(defn); + COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn); + COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn); if (defn_interp != COFF_SymbolValueInterp_Undefined) { - *symbol_out = lnk_get_obj_symbol_ref(defn); + *symbol_out = lnk_ref_from_symbol(defn); } else { is_resolved = 0; } @@ -2324,19 +2324,19 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb case COFF_SymbolValueInterp_Undefined: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); if (defn) { - *symbol_out = lnk_get_obj_symbol_ref(defn); + *symbol_out = lnk_ref_from_symbol(defn); } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = lnk_get_obj_symbol_ref(defn); + *symbol_out = lnk_ref_from_symbol(defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); - *symbol_out = lnk_get_obj_symbol_ref(defn); + *symbol_out = lnk_ref_from_symbol(defn); } else { *symbol_out = symbol; } @@ -2460,8 +2460,8 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, section_number); if (symlink == 0) { continue; } - COFF_ParsedSymbol symlink_parsed = lnk_parse_symbol(symlink); - LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink); + COFF_ParsedSymbol symlink_parsed = lnk_parsed_from_symbol(symlink); + LNK_ObjSymbolRef symlink_ref = lnk_ref_from_symbol(symlink); task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink_ref.obj->input_idx][symlink_parsed.section_number - 1]; } ProfEnd(); @@ -2506,13 +2506,13 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) if (interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number); if (symlink) { - LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink); + LNK_ObjSymbolRef symlink_ref = lnk_ref_from_symbol(symlink); if (symlink_ref.obj != obj) { U32 section_number; U32 value; if (symbol.storage_class == COFF_SymStorageClass_External) { // COMDAT leader may be at a different offset, so update this symbol with leader's offset - COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink); + COFF_ParsedSymbol parsed_symlink = lnk_parsed_from_symbol(symlink); section_number = symbol.section_number; value = parsed_symlink.value; } else { @@ -2590,8 +2590,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx]; LNK_Symbol *symbol = contrib->symbol; - LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); - COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_from_symbol(symbol); U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1; if (symbol_ref.obj->header.is_big_obj) { @@ -2624,8 +2624,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Common) { LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name); - COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn); - Assert(lnk_interp_symbol(defn) == COFF_SymbolValueInterp_Regular); + COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn); + Assert(lnk_interp_from_symbol(defn) == COFF_SymbolValueInterp_Regular); if (defn) { if (obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol.raw_symbol; @@ -2902,7 +2902,7 @@ THREAD_POOL_TASK_FUNC(lnk_count_common_block_contribs_task) for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { task->u.common_block.counts[task_id] += 1; @@ -2921,7 +2921,7 @@ THREAD_POOL_TASK_FUNC(lnk_fill_out_common_block_contribs_task) for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { LNK_CommonBlockContrib *contrib = &task->u.common_block.contribs[cursor++]; @@ -3856,7 +3856,7 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config LNK_Symbol *entry_symbol = lnk_symbol_table_search(symtab, config->entry_point_name); if (entry_symbol) { - *entry_point_va = safe_cast_u32(lnk_virt_off_from_symbol(section_table, entry_symbol)); + *entry_point_va = safe_cast_u32(lnk_voff_from_symbol(section_table, entry_symbol)); } scratch_end(scratch); @@ -4293,13 +4293,13 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT { LNK_Symbol *load_config_symbol = lnk_symbol_table_search(symtab, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); if (load_config_symbol) { - U64 load_config_foff = lnk_file_off_from_symbol(image_section_table, load_config_symbol); + U64 load_config_foff = lnk_foff_from_symbol(image_section_table, load_config_symbol); String8 load_config_data = str8_skip(image_data, load_config_foff); U32 load_config_size = 0; if (sizeof(load_config_size) <= load_config_data.size) { PE_DataDirectory *load_config_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_LOAD_CONFIG); - load_config_dir->virt_off = lnk_virt_off_from_symbol(image_section_table, load_config_symbol); + load_config_dir->virt_off = lnk_voff_from_symbol(image_section_table, load_config_symbol); load_config_dir->virt_size = load_config_size; } else { // TODO: report corrupted load config @@ -4348,13 +4348,13 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, "__NULL_IMPORT_DESCRIPTOR"); LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); if (idata_sect && null_import_desc && null_thunk_data) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parse_symbol(null_import_desc); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_from_symbol(null_import_desc); LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT); import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off; import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; - COFF_ParsedSymbol null_thunk_data_parsed = lnk_parse_symbol(null_thunk_data); + COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_from_symbol(null_thunk_data); U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value; U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off; PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); @@ -4370,7 +4370,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab,"\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); if (didat_sect && null_import_desc && last_null_thunk) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parse_symbol(null_import_desc); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_from_symbol(null_import_desc); LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DELAY_IMPORT); import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect); @@ -4395,7 +4395,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT } // patch-in align - U64 tls_header_foff = lnk_file_off_from_symbol(image_section_table, tls_used_symbol); + U64 tls_header_foff = lnk_foff_from_symbol(image_section_table, tls_used_symbol); B32 is_tls_header64 = coff_word_size_from_machine(config->machine) == 8; if (is_tls_header64) { PE_TLSHeader64 *tls_header = str8_deserial_get_raw_ptr(image_data, tls_header_foff, sizeof(*tls_header)); @@ -4407,7 +4407,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch directory PE_DataDirectory *tls_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_TLS); - tls_dir->virt_off = lnk_virt_off_from_symbol(image_section_table, tls_used_symbol); + tls_dir->virt_off = lnk_voff_from_symbol(image_section_table, tls_used_symbol); tls_dir->virt_size = is_tls_header64 ? sizeof(PE_TLSHeader64) : sizeof(PE_TLSHeader32); ProfEnd(); @@ -4476,13 +4476,13 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT } if (guid_pdb_symbol) { - U64 cv_guid_foff = lnk_file_off_from_symbol(image_section_table, guid_pdb_symbol); + U64 cv_guid_foff = lnk_foff_from_symbol(image_section_table, guid_pdb_symbol); Guid *cv_guid = str8_deserial_get_raw_ptr(image_data, cv_guid_foff, sizeof(*cv_guid)); *cv_guid = config->guid; } if (guid_rdi_symbol) { - U64 cv_guid_foff = lnk_file_off_from_symbol(image_section_table, guid_rdi_symbol); + U64 cv_guid_foff = lnk_foff_from_symbol(image_section_table, guid_rdi_symbol); Guid *cv_guid = str8_deserial_get_raw_ptr(image_data, cv_guid_foff, sizeof(*cv_guid)); *cv_guid = config->guid; } diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 5b07d9a5..acc4ac15 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3021,8 +3021,8 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) U64 node_idx = 0; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); - COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol_ref.obj)) { continue; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 50e2ecf6..ac4ca13f 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -369,27 +369,27 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) if (sect_header->flags & COFF_SectionFlag_LnkRemove) { break; } - LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Weak: { - LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Undefined: { if (symbol.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Common: { - LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_make_obj_ref_symbol(arena, symbol.name, obj, symbol_idx); + LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 1759be9c..04159186 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_Symbol * -lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx) +lnk_make_symbol(Arena *arena, String8 name, LNK_Obj *obj, U32 symbol_idx) { LNK_ObjSymbolRefNode *ref = push_array(arena, LNK_ObjSymbolRefNode, 1); ref->v.obj = obj; @@ -24,14 +24,12 @@ lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b) LNK_Lib *b_lib = lnk_obj_get_lib(b_ref->obj); U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0; U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0; - if (a_lib_input_idx == b_lib_input_idx) { if (a_ref->obj->input_idx == b_ref->obj->input_idx) { return a_ref->symbol_idx < b_ref->symbol_idx; } return a_ref->obj->input_idx < b_ref->obj->input_idx; } - return a_lib_input_idx < b_lib_input_idx; } @@ -42,16 +40,16 @@ lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b) return lnk_obj_symbol_ref_is_before(*a, *b); } -internal B32 +internal int lnk_symbol_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - LNK_ObjSymbolRef a_ref = lnk_get_obj_symbol_ref(a); - LNK_ObjSymbolRef b_ref = lnk_get_obj_symbol_ref(b); + LNK_ObjSymbolRef a_ref = lnk_ref_from_symbol(a); + LNK_ObjSymbolRef b_ref = lnk_ref_from_symbol(b); return lnk_obj_symbol_ref_is_before(&a_ref, &b_ref); } -internal B32 +internal int lnk_symbol_ptr_is_before(void *raw_a, void *raw_b) { return lnk_symbol_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); @@ -73,56 +71,6 @@ lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol) return node; } -internal void -lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat) -{ - SLLConcatInPlace(list, to_concat); -} - -internal void -lnk_symbol_concat_in_place_array(LNK_SymbolList *list, LNK_SymbolList *to_concat, U64 to_concat_count) -{ - SLLConcatInPlaceArray(list, to_concat, to_concat_count); -} - -internal LNK_SymbolList -lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr) -{ - LNK_SymbolList list = {0}; - LNK_SymbolNode *node_arr = push_array_no_zero(arena, LNK_SymbolNode, arr.count); - for (U64 i = 0; i < arr.count; i += 1) { - LNK_SymbolNode *node = &node_arr[i]; - node->next = 0; - node->data = &arr.v[i]; - lnk_symbol_list_push_node(&list, node); - } - return list; -} - -internal LNK_SymbolNodeArray -lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list) -{ - LNK_SymbolNodeArray result = {0}; - result.count = 0; - result.v = push_array_no_zero(arena, LNK_SymbolNode *, list.count); - for (LNK_SymbolNode *i = list.first; i != 0; i = i->next, ++result.count) { - result.v[result.count] = i; - } - return result; -} - -internal LNK_SymbolArray -lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list) -{ - LNK_SymbolArray arr = {0}; - arr.count = 0; - arr.v = push_array_no_zero(arena, LNK_Symbol, list.count); - for (LNK_SymbolNode *node = list.first; node != 0; node = node->next) { - arr.v[arr.count++] = *node->data; - } - return arr; -} - internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList *list, U64 cap) { @@ -141,8 +89,8 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); - LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst); + LNK_ObjSymbolRef src_ref = lnk_ref_from_symbol(src); lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst_ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst_ref.symbol_idx, src_ref.obj->path, src_ref.symbol_idx); } @@ -151,12 +99,12 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { B32 can_replace = 0; - COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst); - COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src); - COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst); - COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src); - LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); - LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + COFF_ParsedSymbol dst_parsed = lnk_parsed_from_symbol(dst); + COFF_ParsedSymbol src_parsed = lnk_parsed_from_symbol(src); + COFF_SymbolValueInterpType dst_interp = lnk_interp_from_symbol(dst); + COFF_SymbolValueInterpType src_interp = lnk_interp_from_symbol(src); + LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst); + LNK_ObjSymbolRef src_ref = lnk_ref_from_symbol(src); LNK_Obj *dst_obj = dst_ref.obj; LNK_Obj *src_obj = src_ref.obj; @@ -176,7 +124,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) weak_parsed = src_parsed; } - LNK_ObjSymbolRef weak_symbol_ref = lnk_get_obj_symbol_ref(weak); + LNK_ObjSymbolRef weak_symbol_ref = lnk_ref_from_symbol(weak); COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak_symbol_ref.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { // NOTE: MSVC does not let a weak symbol to replace an undefined one, @@ -382,9 +330,9 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) internal void lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst); - COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst); - LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst); + COFF_ParsedSymbol dst_parsed = lnk_parsed_from_symbol(dst); + COFF_SymbolValueInterpType dst_interp = lnk_interp_from_symbol(dst); + LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst); if (dst_interp == COFF_SymbolValueInterp_Regular) { // remove replaced section from the output @@ -408,9 +356,9 @@ lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) // assert leader section is live #if BUILD_DEBUG { - COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src); - COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src); - LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src); + COFF_ParsedSymbol src_parsed = lnk_parsed_from_symbol(src); + COFF_SymbolValueInterpType src_interp = lnk_interp_from_symbol(src); + LNK_ObjSymbolRef src_ref = lnk_ref_from_symbol(src); if (src_interp == COFF_SymbolValueInterp_Regular) { COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src_ref.obj, src_parsed.section_number); @@ -541,13 +489,13 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk } internal LNK_ObjSymbolRef -lnk_get_obj_symbol_ref(LNK_Symbol *symbol) +lnk_ref_from_symbol(LNK_Symbol *symbol) { return symbol->refs->v; } internal U64 -lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol) +lnk_ref_count_from_symbol(LNK_Symbol *symbol) { U64 count = 0; for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, count += 1); @@ -555,10 +503,10 @@ lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol) } internal LNK_ObjSymbolRef ** -lnk_get_obj_symbol_ref_many(Arena *arena, LNK_Symbol *symbol, U64 *count_out) +lnk_ref_from_symbol_many(Arena *arena, LNK_Symbol *symbol, U64 *count_out) { // TODO: would be simpler if we sorted refs on insert/update - U64 refs_count = lnk_get_obj_symbol_ref_count(symbol); + U64 refs_count = lnk_ref_count_from_symbol(symbol); LNK_ObjSymbolRef **refs = push_array(arena, LNK_ObjSymbolRef *, refs_count); U64 i = 0; for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, i += 1) { @@ -572,19 +520,100 @@ lnk_get_obj_symbol_ref_many(Arena *arena, LNK_Symbol *symbol, U64 *count_out) } internal COFF_ParsedSymbol -lnk_parse_symbol(LNK_Symbol *symbol) +lnk_parsed_from_symbol(LNK_Symbol *symbol) { - LNK_ObjSymbolRef ref = lnk_get_obj_symbol_ref(symbol); + LNK_ObjSymbolRef ref = lnk_ref_from_symbol(symbol); return lnk_parsed_symbol_from_coff_symbol_idx(ref.obj, ref.symbol_idx); } internal COFF_SymbolValueInterpType -lnk_interp_symbol(LNK_Symbol *symbol) +lnk_interp_from_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); return coff_interp_from_parsed_symbol(symbol_parsed); } +internal U64 +lnk_symbol_table_hasher(String8 string) +{ + return u64_hash_from_str8(string); +} + +internal LNK_SymbolTable * +lnk_symbol_table_init(TP_Arena *arena) +{ + LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); + symtab->arena = arena; + symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); + return symtab; +} + +internal void +lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) +{ + U64 hash = lnk_symbol_table_hasher(symbol->name); + lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunks[worker_id], &symtab->root, hash, symbol); +} + +internal void +lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol) +{ + lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, symbol); +} + +internal LNK_SymbolHashTrie * +lnk_symbol_table_search_(LNK_SymbolTable *symtab, String8 name) +{ + U64 hash = lnk_symbol_table_hasher(name); + return lnk_symbol_hash_trie_search(symtab->root, hash, name); +} + +internal LNK_Symbol * +lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name) +{ + LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, name); + return trie ? trie->symbol : 0; +} + +internal LNK_Symbol * +lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + + va_list args; va_start(args, fmt); + String8 name = push_str8fv(scratch.arena, fmt, args); + va_end(args); + + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name); + + scratch_end(scratch); + return symbol; +} + +internal ISectOff +lnk_sc_from_symbol(LNK_Symbol *symbol) +{ + COFF_ParsedSymbol parsed_symbol = lnk_parsed_from_symbol(symbol); + ISectOff sc = { .isect = parsed_symbol.section_number, .off = parsed_symbol.value }; + return sc; +} + +internal U64 +lnk_voff_from_symbol(COFF_SectionHeader **image_section_table, LNK_Symbol *symbol) +{ + ISectOff sc = lnk_sc_from_symbol(symbol); + U64 voff = image_section_table[sc.isect]->voff + sc.off; + return voff; +} + +internal U64 +lnk_foff_from_symbol(COFF_SectionHeader **image_section_table, LNK_Symbol *symbol) +{ + ISectOff sc = lnk_sc_from_symbol(symbol); + U64 foff = image_section_table[sc.isect]->foff + sc.off; + return foff; +} + internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) { @@ -626,10 +655,10 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) // does weak symbol have a definition? LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn_symbol); + COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn_symbol); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); if (defn_interp != COFF_SymbolValueInterp_Weak) { - current_symbol = lnk_get_obj_symbol_ref(defn_symbol); + current_symbol = lnk_ref_from_symbol(defn_symbol); break; } @@ -643,19 +672,19 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); - tag_interp = lnk_interp_symbol(dep_symbol); + tag_interp = lnk_interp_from_symbol(dep_symbol); } if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); - COFF_SymbolValueInterpType defn_interp = lnk_interp_symbol(defn_symbol); + COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); // unresolved undefined symbol if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } // follow symbol definition - current_symbol = lnk_get_obj_symbol_ref(defn_symbol); + current_symbol = lnk_ref_from_symbol(defn_symbol); } else { break; } } @@ -664,67 +693,6 @@ exit:; return current_symbol; } -internal U64 -lnk_symbol_hash(String8 string) -{ - XXH3_state_t hasher; XXH3_64bits_reset(&hasher); - XXH3_64bits_update(&hasher, &string.size, sizeof(string.size)); - XXH3_64bits_update(&hasher, string.str, string.size); - XXH64_hash_t result = XXH3_64bits_digest(&hasher); - return result; -} - -internal LNK_SymbolTable * -lnk_symbol_table_init(TP_Arena *arena) -{ - LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); - symtab->arena = arena; - symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); - return symtab; -} - -internal void -lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) -{ - U64 hash = lnk_symbol_hash(symbol->name); - lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunks[worker_id], &symtab->root, hash, symbol); -} - -internal void -lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol) -{ - lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, symbol); -} - -internal LNK_SymbolHashTrie * -lnk_symbol_table_search_(LNK_SymbolTable *symtab, String8 name) -{ - U64 hash = lnk_symbol_hash(name); - return lnk_symbol_hash_trie_search(symtab->root, hash, name); -} - -internal LNK_Symbol * -lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name) -{ - LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, name); - return trie ? trie->symbol : 0; -} - -internal LNK_Symbol * -lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...) -{ - Temp scratch = scratch_begin(0, 0); - - va_list args; va_start(args, fmt); - String8 name = push_str8fv(scratch.arena, fmt, args); - va_end(args); - - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name); - - scratch_end(scratch); - return symbol; -} - internal THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) { @@ -733,8 +701,8 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol); - COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol); + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol_ref); @@ -763,20 +731,19 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) { - Temp scratch = scratch_begin(0,0); + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + U64 chunks_count = 0; LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); - - ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask task = { .symtab = symtab, .chunks = chunks }; - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &task); + tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &(LNK_ReplaceWeakSymbolsWithDefaultSymbolTask){ .symtab = symtab, .chunks = chunks }); #if BUILD_DEBUG for EachIndex(chunk_idx, chunks_count) { LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); } } @@ -786,43 +753,3 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) ProfEnd(); } -internal ISectOff -lnk_sc_from_symbol(LNK_Symbol *symbol) -{ - COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol); - - ISectOff sc = {0}; - sc.isect = parsed_symbol.section_number; - sc.off = parsed_symbol.value; - - return sc; -} - -internal U64 -lnk_isect_from_symbol(LNK_Symbol *symbol) -{ - return lnk_sc_from_symbol(symbol).isect; -} - -internal U64 -lnk_sect_off_from_symbol(LNK_Symbol *symbol) -{ - return lnk_sc_from_symbol(symbol).off; -} - -internal U64 -lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol) -{ - ISectOff sc = lnk_sc_from_symbol(symbol); - U64 voff = section_table[sc.isect]->voff + sc.off; - return voff; -} - -internal U64 -lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol) -{ - ISectOff sc = lnk_sc_from_symbol(symbol); - U64 foff = section_table[sc.isect]->foff + sc.off; - return foff; -} - diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 78bd1291..3a5e52b1 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -39,12 +39,6 @@ typedef struct LNK_SymbolList LNK_SymbolNode *last; } LNK_SymbolList; -typedef struct LNK_SymbolNodeArray -{ - U64 count; - LNK_SymbolNode **v; -} LNK_SymbolNodeArray; - typedef struct LNK_SymbolArray { U64 count; @@ -92,19 +86,19 @@ typedef struct LNK_SymbolHashTrieChunk **chunks; } LNK_ReplaceWeakSymbolsWithDefaultSymbolTask; -// --- Symbol Make ------------------------------------------------------------- +// --- Symbol ----------------------------------------------------------------- -internal LNK_Symbol * lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); +internal LNK_Symbol * lnk_make_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); + +internal int lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b); +internal int lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b); +internal int lnk_symbol_is_before(void *raw_a, void *raw_b); +internal int lnk_symbol_ptr_is_before(void *raw_a, void *raw_b); // --- Symbol Containers ------------------------------------------------------ -internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node); -internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol); -internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat); -internal void lnk_symbol_concat_in_place_array(LNK_SymbolList *list, LNK_SymbolList *to_concat, U64 to_concat_count); -internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr); -internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list); -internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list); +internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node); +internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol); // --- Symbol Hash Trie -------------------------------------------------------- @@ -115,15 +109,14 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A // --- Symbol Helpers ---------------------------------------------------------- -internal LNK_ObjSymbolRef lnk_get_obj_symbol_ref(LNK_Symbol *symbol); -internal U64 lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol); -internal COFF_ParsedSymbol lnk_parse_symbol(LNK_Symbol *symbol); -internal COFF_SymbolValueInterpType lnk_interp_symbol(LNK_Symbol *symbol); -internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol); +internal LNK_ObjSymbolRef lnk_ref_from_symbol(LNK_Symbol *symbol); +internal U64 lnk_ref_count_from_symbol(LNK_Symbol *symbol); +internal COFF_ParsedSymbol lnk_parsed_from_symbol(LNK_Symbol *symbol); +internal COFF_SymbolValueInterpType lnk_interp_from_symbol(LNK_Symbol *symbol); // --- Symbol Table ------------------------------------------------------------ -internal U64 lnk_symbol_hash(String8 string); +internal U64 lnk_symbol_table_hasher(String8 string); internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena); internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); @@ -133,8 +126,12 @@ internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, cha // --- Symbol Contrib Helpers -------------------------------------------------- internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol); -internal U64 lnk_isect_from_symbol(LNK_Symbol *symbol); -internal U64 lnk_sect_off_from_symbol(LNK_Symbol *symbol); -internal U64 lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol); -internal U64 lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol); +internal U64 lnk_voff_from_symbol(COFF_SectionHeader **image_section_table, LNK_Symbol *symbol); +internal U64 lnk_foff_from_symbol(COFF_SectionHeader **image_section_table, LNK_Symbol *symbol); + +// --- Weak Symbol ------------------------------------------------------------- + +internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol); + +internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab); From 8f749f4239865b8579f886652f92bcb1f9455ab2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 6 Sep 2025 16:15:25 -0700 Subject: [PATCH 150/302] use global symbol table to detect duplicate imports --- src/linker/lnk.c | 58 +++++++++++++++++++++++++++--------------------- src/linker/lnk.h | 1 - 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 5233ea7a..a5e18edd 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1544,18 +1544,18 @@ lnk_link_inputs_(TP_Context *tp, } } + // sort library member refs to match the order of their appearance in the respective obj symbol tables LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members); radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before); - // load lib member refs + // push inputs for lib member refs for EachIndex(i, queued_members.count) { - LNK_LibMemberRef *member_ref = member_refs[i]; - LNK_Lib *lib = member_ref->lib; - U32 member_offset = lib->member_offsets[member_ref->member_idx]; - LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; + LNK_LibMemberRef *member_ref = member_refs[i]; + LNK_Lib *lib = member_ref->lib; + LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { @@ -1564,44 +1564,54 @@ lnk_link_inputs_(TP_Context *tp, // import machine compat check if (import_header.machine != config->machine) { - lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)", - import_header.func_name, - coff_string_from_machine_type(import_header.machine), - coff_string_from_machine_type(config->machine)); + LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol); + lnk_error_obj(LNK_Error_IncompatibleMachine, + ref.obj, + "symbol %S pulls-in import from %S for an incompatible machine %S (expected machine %S)", + link_symbol->name, + str8_chop_last_slash(lib->path), + coff_string_from_machine_type(import_header.machine), + coff_string_from_machine_type(config->machine)); break; } - // skip duplicate import inputer - if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name)) { break; } - hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); + // was import already created? + LNK_Symbol *is_import_loaded = lnk_symbol_table_search(symtab, link_symbol->name); + if (is_import_loaded) { + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(is_import_loaded); + if (interp != COFF_SymbolValueInterp_Undefined) { + break; + } + } - // create import stub (later replaced with acutal import generated by linker) + // create import stub symbol (later replaced with actual import) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); LNK_ObjSymbolRef import_symbol_ref = lnk_ref_from_symbol(import_stub); LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); - // search DLL symbol list - B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); - String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; - HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; + // find DLL with import symbols + B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); + String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; + HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + + // create record for a first time-DLL if (import_symbols == 0) { import_symbols = push_array(imps->arena, PE_MakeImportList, 1); str8_list_push(imps->arena, dll_names, import_header.dll_name); hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols); } - // push symbol - PE_MakeImport make_import = { .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }; - pe_make_import_header_list_push(imps->arena, import_symbols, make_import); + // push make import info + pe_make_import_header_list_push(imps->arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }); } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); // obj path in thin archive has slash appended which screws up - // file lookup on disk; it couble be there to enable paths to symbols + // file lookup on disk; it could be there to enable paths to symbols // but we don't use this feature String8 slash = str8_lit("/"); if (str8_ends_with(obj_path, slash, 0)) { @@ -1610,8 +1620,7 @@ lnk_link_inputs_(TP_Context *tp, B32 is_thin = lib->type == COFF_Archive_Thin; if (is_thin) { - - // obj path in thin archive is relative to directory with archive + // obj path in thin archive is relative to the directory with archive String8List obj_path_list = {0}; str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); str8_list_push(scratch.arena, &obj_path_list, obj_path); @@ -1714,7 +1723,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer imps->arena = imps_arena; imps->static_imports = hash_table_init(imps->arena, 0x1000); imps->delayed_imports = hash_table_init(imps->arena, 0x1000); - imps->import_stub_ht = hash_table_init(imps->arena, 0x10000); } // input :null_obj diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 3712a5d9..9f358a56 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -82,7 +82,6 @@ typedef struct LNK_ImportTables String8List static_dll_names; HashTable *static_imports; HashTable *delayed_imports; - HashTable *import_stub_ht; } LNK_ImportTables; typedef struct LNK_Link From 082f6cf6fd727859f141054115ade1a7d484bd53 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 14:24:15 -0700 Subject: [PATCH 151/302] fix free block check and remove unused free_size field --- src/base/base_arena.c | 28 +++++++++++++--------------- src/base/base_arena.h | 1 - 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/base/base_arena.c b/src/base/base_arena.c index 0d9300e2..22778571 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -62,7 +62,6 @@ arena_alloc_(ArenaParams *params) arena->allocation_site_file = params->allocation_site_file; arena->allocation_site_line = params->allocation_site_line; #if ARENA_FREE_LIST - arena->free_size = 0; arena->free_last = 0; #endif AsanPoisonMemoryRegion(base, commit_size); @@ -95,22 +94,22 @@ arena_push(Arena *arena, U64 size, U64 align, B32 zero) Arena *new_block = 0; #if ARENA_FREE_LIST - Arena *prev_block; - for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev) { - if(new_block->res >= AlignPow2(size, align)) + Arena *prev_block; + for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev) { - if(prev_block) + if(new_block->res >= AlignPow2(new_block->pos, align) + size) { - prev_block->prev = new_block->prev; + if(prev_block) + { + prev_block->prev = new_block->prev; + } + else + { + arena->free_last = new_block->prev; + } + break; } - else - { - arena->free_last = new_block->prev; - } - arena->free_size -= new_block->res_size; - AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE); - break; } } #endif @@ -209,9 +208,8 @@ arena_pop_to(Arena *arena, U64 pos) { prev = current->prev; current->pos = ARENA_HEADER_SIZE; - arena->free_size += current->res_size; SLLStackPush_N(arena->free_last, current, prev); - AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res_size - ARENA_HEADER_SIZE); + AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE); } #else for(Arena *prev = 0; current->base_pos >= big_pos; current = prev) diff --git a/src/base/base_arena.h b/src/base/base_arena.h index 589d67bf..99fd33bb 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -42,7 +42,6 @@ struct Arena char *allocation_site_file; int allocation_site_line; #if ARENA_FREE_LIST - U64 free_size; Arena *free_last; #endif }; From 8a22910d9bb14cd12ac1d514b0acb46823d75fb3 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 16:07:39 -0700 Subject: [PATCH 152/302] add "Links" log type for diagnosing linked lib members --- src/linker/lnk_log.c | 1 + src/linker/lnk_log.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/linker/lnk_log.c b/src/linker/lnk_log.c index a78a7ca9..1904996c 100644 --- a/src/linker/lnk_log.c +++ b/src/linker/lnk_log.c @@ -45,6 +45,7 @@ lnk_log_type_from_string(String8 string) "SizeBreakdown", LNK_Log_SizeBreakdown, "LinkStats", LNK_Log_LinkStats, "Timers", LNK_Log_Timers, + "Links", LNK_Log_Links, }; Assert(ArrayCount(map) == LNK_Log_Count); diff --git a/src/linker/lnk_log.h b/src/linker/lnk_log.h index 6e43393b..a1e24157 100644 --- a/src/linker/lnk_log.h +++ b/src/linker/lnk_log.h @@ -14,6 +14,7 @@ typedef enum LNK_Log_SizeBreakdown, LNK_Log_LinkStats, LNK_Log_Timers, + LNK_Log_Links, LNK_Log_Count } LNK_LogType; From 00536f7ea8d37986407403f928f7cda043a2ad99 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 16:12:45 -0700 Subject: [PATCH 153/302] rewrite set linked symbol logic to respect declaration order in obj symbol table --- src/linker/lnk_lib.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 3d3c7cfb..c137ca86 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -200,9 +200,34 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U internal B32 lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) { - LNK_Symbol *slot = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], link_symbol, 0); - B32 is_first_queue_attempt = (slot == 0); - return is_first_queue_attempt; + local_persist LNK_Symbol null_symbol; + + LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); + B32 is_first_set = (slot == 0); + + for (;;) { + // update slot symbol if it is empty or link symbol comes before symbol in the slot + if (slot && slot != &null_symbol) { + if (lnk_symbol_is_before(slot, link_symbol)) { + slot = link_symbol; + } + } else { + slot = link_symbol; + } + + // try to insert back updated slot symbol + LNK_Symbol *was_replaced = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], slot, &null_symbol); + + // exit if slot symbol was null + if (was_replaced == &null_symbol) { + break; + } + + // reload slot symbol + slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); + } + + return is_first_set; } internal B32 From 71939863059b552ef121796c7262f5fb09369296 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 19:36:47 -0700 Subject: [PATCH 154/302] binary search for strings --- src/linker/base_ext/base_strings.c | 32 ++++++++++++++++++++++++++++++ src/linker/base_ext/base_strings.h | 1 + 2 files changed, 33 insertions(+) diff --git a/src/linker/base_ext/base_strings.c b/src/linker/base_ext/base_strings.c index 4f085bcd..232a4f99 100644 --- a/src/linker/base_ext/base_strings.c +++ b/src/linker/base_ext/base_strings.c @@ -21,3 +21,35 @@ str8_list_pop_front(String8List *list) return node; } +internal U64 +str8_array_bsearch(String8Array arr, String8 value) +{ + if (arr.count > 1) { + int lo_compar = str8_compar_case_sensitive(&value, &arr.v[0]); + if (lo_compar == 0) { + return 0; + } + + int hi_compar = str8_compar_case_sensitive(&value, &arr.v[arr.count-1]); + if (hi_compar == 0){ + return arr.count-1; + } + + if (lo_compar > 0 && hi_compar < 0) { + for (U64 l = 0, r = arr.count -1; l <= r; ) { + U64 m = l + (r- l) / 2; + int cmp = str8_compar_case_sensitive(&arr.v[m], &value); + if (cmp == 0) { + return m; + } else if (cmp < 0) { + l = m + 1; + } else { + r = m - 1; + } + } + } + } else if (arr.count == 1 && str8_match(arr.v[0], value, 0)) { + return 0; + } + return max_U64; +} diff --git a/src/linker/base_ext/base_strings.h b/src/linker/base_ext/base_strings.h index 85377c4c..c982e700 100644 --- a/src/linker/base_ext/base_strings.h +++ b/src/linker/base_ext/base_strings.h @@ -8,3 +8,4 @@ internal String8Node * str8_list_pop_front(String8List *list); internal B32 str8_starts_with(String8 string, String8 expected_prefix); +internal U64 str8_array_bsearch(String8Array arr, String8 value); From fb46d0bba4b9d45595b9b9bf74a7798f04dd43e6 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 19:46:58 -0700 Subject: [PATCH 155/302] sort symbol names in first member header --- src/linker/lnk_lib.c | 81 +++++++++++++++++++++++++++++--------------- src/linker/lnk_lib.h | 8 ++++- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index c137ca86..fea9c9b3 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -13,6 +13,13 @@ lnk_lib_node_ptr_is_before(void *raw_a, void *raw_b) return lnk_lib_node_is_before(*(LNK_Lib **)raw_a, *(LNK_Lib **)raw_b); } +internal B32 +lnk_first_member_sort_key_is_before(void *raw_a, void *raw_b) +{ + LNK_FirstMemberSortKey *a = raw_a, *b = raw_b; + return str8_is_before_case_sensitive(&a->symbol_name, &b->symbol_name); +} + internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_Lib *lib_out) { @@ -24,16 +31,17 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L return 0; } + // TODO: report parse errors COFF_ArchiveParse parse = coff_archive_parse_from_data(data); if (parse.error.size) { return 0; } - U32 member_count = 0; - U64 symbol_count = 0; - String8 string_table = {0}; - U16 *symbol_indices = 0; - U32 *member_offsets = 0; + U32 member_count = 0; + U64 symbol_count = 0; + String8Array symbol_names = {0}; + U16 *symbol_indices = 0; + U32 *member_offsets = 0; // try to init library from optional second member if (parse.second_member.member_count) { @@ -43,9 +51,17 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L member_count = second_member.member_count; symbol_count = second_member.symbol_count; - string_table = second_member.string_table; member_offsets = second_member.member_offsets; symbol_indices = second_member.symbol_indices; + + // parse symbol names + { + Temp scratch = scratch_begin(&arena, 1); + String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); + Assert(symbol_name_list.node_count >= symbol_count); + symbol_names = str8_array_from_list(arena, &symbol_name_list); + scratch_end(scratch); + } } // first member is deprecated however tools emit it for compatibility reasons // and lld-link with /DLL emits only first member @@ -55,8 +71,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L COFF_ArchiveFirstMember first_member = parse.first_member; Assert(first_member.symbol_count == first_member.member_offset_count); - symbol_count = first_member.symbol_count; - string_table = first_member.string_table; + symbol_count = first_member.symbol_count; // convert big endian offsets for (U32 offset_idx = 0; offset_idx < symbol_count; offset_idx += 1) { @@ -84,6 +99,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L member_count = member_off_ht->count; member_offsets = push_array_no_zero(arena, U32, member_count); + for EachIndex(bucket_idx, member_off_ht->cap) { BucketList *bucket = &member_off_ht->buckets[bucket_idx]; for (BucketNode *n = bucket->first; n != 0; n = n->next) { @@ -92,28 +108,39 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L member_offsets[member_off_idx] = member_off; } } + + // parse symbol names + String8Array symbol_names; + { + Temp scratch = scratch_begin(&arena, 1); + String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); + Assert(symbol_name_list.node_count >= first_member.symbol_count); + symbol_names = str8_array_from_list(arena, &symbol_name_list); + scratch_end(scratch); + } + + // sort lexically symbol names + LNK_FirstMemberSortKey *sort_keys = push_array_no_zero(scratch.arena, LNK_FirstMemberSortKey, first_member.symbol_count); + for EachIndex(symbol_idx, first_member.symbol_count) { + sort_keys[symbol_idx].symbol_name = symbol_names.v[symbol_idx]; + sort_keys[symbol_idx].member_off_idx = symbol_indices[symbol_idx]; + } + radsort(sort_keys, first_member.symbol_count, lnk_first_member_sort_key_is_before); + + for EachIndex(symbol_idx, first_member.symbol_count) { + symbol_names.v[symbol_idx] = sort_keys[symbol_idx].symbol_name; + symbol_indices[symbol_idx] = sort_keys[symbol_idx].member_off_idx; + } } scratch_end(scratch); } - // parse string table - String8Array symbol_names; - { - Temp scratch = scratch_begin(&arena, 1); - String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); - Assert(symbol_name_list.node_count >= symbol_count); - symbol_names = str8_array_from_list(arena, &symbol_name_list); - scratch_end(scratch); - } - - symbol_count = Min(symbol_count, symbol_names.count); - // init lib lib_out->path = push_str8_copy(arena, path); lib_out->data = data; lib_out->type = type; - lib_out->symbol_count = symbol_count; + lib_out->symbol_count = Min(symbol_count, symbol_names.count); // TODO: warn about mismatched number of symbol names and symbol count in the header lib_out->member_offsets = member_offsets; lib_out->symbol_indices = symbol_indices; lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count); @@ -233,14 +260,12 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out) { - // TODO: symbol names are already sorted, replace with binary search - for EachIndex(symbol_idx, lib->symbol_count) { - if (str8_match(lib->symbol_names.v[symbol_idx], symbol_name, 0)) { - if (member_idx_out) { - *member_idx_out = lib->symbol_indices[symbol_idx] - 1; - } - return 1; + U64 symbol_idx = str8_array_bsearch(lib->symbol_names, symbol_name); + if (symbol_idx < lib->symbol_count) { + if (member_idx_out) { + *member_idx_out = lib->symbol_indices[symbol_idx]-1; } + return 1; } return 0; } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 056456e1..826b507f 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -36,6 +36,12 @@ typedef struct LNK_LibList LNK_LibNode *last; } LNK_LibList; +typedef struct LNK_FirstMemberSortKey +{ + String8 symbol_name; + U16 member_off_idx; +} LNK_FirstMemberSortKey; + // --- Workers Contexts -------------------------------------------------------- typedef struct @@ -60,7 +66,7 @@ internal LNK_Lib ** lnk_array_from_lib_list(Arena *arena, LNK_LibList list internal void lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node); internal LNK_LibNodeArray lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U64 inputs_count, struct LNK_Input **inputs); -internal B32 lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *trigger); +internal B32 lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol); internal B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out); From ee3832ea3baa497873afa1e1bddc260088dd93b7 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 21:11:12 -0700 Subject: [PATCH 156/302] parallel for lib symbol search --- src/coff/coff_parse.c | 13 +- src/coff/coff_parse.h | 3 +- src/linker/lnk.c | 449 ++++++++++++++++++++++-------------------- src/linker/lnk.h | 9 + src/linker/lnk_lib.c | 1 - 5 files changed, 263 insertions(+), 212 deletions(-) diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c index e3bd1dff..3f9e81ca 100644 --- a/src/coff/coff_parse.c +++ b/src/coff/coff_parse.c @@ -731,7 +731,7 @@ coff_parse_second_archive_member(COFF_ArchiveMember *member) } internal String8 -coff_parse_long_name(String8 long_names, String8 name) +coff_decode_raw_member_name(String8 long_names, String8 name) { String8 result = name; if (name.size > 0 && name.str[0] == '/') { @@ -751,6 +751,17 @@ coff_parse_long_name(String8 long_names, String8 name) return result; } +internal String8 +coff_decode_member_name(String8 long_names, String8 name) +{ + String8 member_name = coff_decode_raw_member_name(long_names, name); + String8 slash = str8_lit("/"); + if (str8_ends_with(member_name, slash, 0)) { + member_name = str8_chop(member_name, slash.size); + } + return member_name; +} + internal U64 coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out) { diff --git a/src/coff/coff_parse.h b/src/coff/coff_parse.h index 3125c1f8..4156b6c6 100644 --- a/src/coff/coff_parse.h +++ b/src/coff/coff_parse.h @@ -307,7 +307,8 @@ internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive); internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out); internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member); internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member); -internal String8 coff_parse_long_name (String8 long_names, String8 name); +internal String8 coff_decode_raw_member_name (String8 long_names, String8 name); +internal String8 coff_decode_member_name (String8 long_names, String8 name); internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out); internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a5e18edd..a3794d0f 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1189,6 +1189,12 @@ lnk_lib_member_ref_list_push_node(LNK_LibMemberRefList *list, LNK_LibMemberRef * list->count += 1; } +internal void +lnk_lib_member_ref_list_concat_in_place_array(LNK_LibMemberRefList *list, LNK_LibMemberRefList *to_concat_arr, U64 count) +{ + SLLConcatInPlaceArray(list, to_concat_arr, count); +} + internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b) { @@ -1262,7 +1268,7 @@ internal void lnk_load_libs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link) { for EachIndex(input_source, LNK_InputSource_Count) { - //ProfBegin("Input Libs [Count %llu]", inputer->new_libs[i].count); + ProfBegin("Input Libs [Count %llu]", inputer->new_libs[input_source].count); LNK_InputPtrArray new_input_libs = lnk_inputer_flush(arena->v[0], tp, inputer, config->io_flags, &inputer->libs, &inputer->new_libs[input_source]); @@ -1288,6 +1294,14 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer U64 objs_count = 0; LNK_ObjNode *objs = lnk_load_objs(tp, arena, config, inputer, symtab, link, &objs_count); lnk_obj_list_push_node_many(&link->objs, objs_count, objs); + + // if delay load DLLs are present, include delay load helper symbol + if (config->machine != COFF_MachineType_Unknown && config->delay_load_helper_name.size == 0 && config->delay_load_dll_list.node_count) { + config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); + if (config->delay_load_helper_name.size) { + lnk_include_symbol(config, config->delay_load_helper_name, 0); + } + } // handle /INCLUDE { @@ -1372,182 +1386,224 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // load new libs lnk_load_libs(tp, arena, config, inputer, link); + // resolve entry point + if (link->try_to_resolve_entry_point) { + B32 is_entry_point_name_inferred = config->entry_point_name.size == 0; + + // loop over all possible subsystems and entry point names and pick + // subsystem that has a defined entry point symbol + if (config->entry_point_name.size == 0) { + PE_WindowsSubsystem subsys_first = config->subsystem; + PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1; + LNK_Symbol *entry_point_symbol = 0; + for (U64 subsys_idx = subsys_first; subsys_idx < subsys_last; subsys_idx += 1) { + String8Array entry_points = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, entry_points.v[i]); + if (symbol) { + config->subsystem = subsys_idx; + config->entry_point_name = entry_points.v[i]; + goto found_entry_and_subsystem; + } + } + } + found_entry_and_subsystem:; + } + + // search for entry point in libs + if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); + for EachIndex(entry_idx, entry_points.count) { + for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, entry_points.v[entry_idx], 0)) { + config->entry_point_name = entry_points.v[entry_idx]; + goto found_entry_in_libs; + } + } + } + found_entry_in_libs:; + } + + // infer subsystem from entry point name + if (config->entry_point_name.size != 0 && config->subsystem == PE_WindowsSubsystem_UNKNOWN) { + for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { + String8Array entry_points = pe_get_entry_point_names(config->machine, subsys_idx, config->file_characteristics); + for EachIndex(i, entry_points.count) { + if (str8_match(entry_points.v[i], config->entry_point_name, 0)) { + config->subsystem = subsys_idx; + goto subsystem_inferred_from_entry; + } + } + } + subsystem_inferred_from_entry:; + } + + // do we have an entry point name? + if (config->entry_point_name.size) { + if (is_entry_point_name_inferred) { + // redirect user entry to appropriate CRT entry + String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); + config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; + } + + // generate undefined symbol for entry point + lnk_include_symbol(config, config->entry_point_name, 0); + + // do we have a subsystem? + if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { + // if subsystem version not specified set default values + if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { + config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); + } + + // check subsystem version against allowed min version + Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); + if (version_compar(config->subsystem_ver, min_subsystem_ver) < 0) { + lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", + config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); + } + + // by default terminal server is enabled for windows and console applications + if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { + if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { + config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; + } + } + + // entry point found! + link->try_to_resolve_entry_point = 0; + } else { + lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); + } + } + } + scratch_end(scratch); } internal void -lnk_resolve_entry_point(LNK_Config *config, LNK_SymbolTable *symtab, LNK_Link *link) +lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, U32 member_idx) { - B32 is_entry_point_name_inferred = config->entry_point_name.size == 0; + B32 is_first_set = lnk_lib_set_link_symbol(lib, member_idx, link_symbol); + if (is_first_set) { + link_symbol->is_lib_member_linked = 1; - // loop over all possible subsystems and entry point names and pick - // subsystem that has a defined entry point symbol - if (config->entry_point_name.size == 0) { - PE_WindowsSubsystem subsys_first = config->subsystem; - PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1; - LNK_Symbol *entry_point_symbol = 0; - for (U64 subsys_idx = subsys_first; subsys_idx < subsys_last; subsys_idx += 1) { - String8Array entry_points = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); - for EachIndex(i, entry_points.count) { - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, entry_points.v[i]); - if (symbol) { - config->subsystem = subsys_idx; - config->entry_point_name = entry_points.v[i]; - goto found_entry_and_subsystem; - } - } - } -found_entry_and_subsystem:; - } - - // search for entry point in libs - if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) { - String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); - for EachIndex(entry_idx, entry_points.count) { - for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { - if (lnk_search_lib(&lib_n->data, entry_points.v[entry_idx], 0)) { - config->entry_point_name = entry_points.v[entry_idx]; - goto found_entry_in_libs; - } - } - } -found_entry_in_libs:; - } - - // infer subsystem from entry point name - if (config->entry_point_name.size != 0 && config->subsystem == PE_WindowsSubsystem_UNKNOWN) { - for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { - String8Array entry_points = pe_get_entry_point_names(config->machine, subsys_idx, config->file_characteristics); - for EachIndex(i, entry_points.count) { - if (str8_match(entry_points.v[i], config->entry_point_name, 0)) { - config->subsystem = subsys_idx; - goto subsystem_inferred_from_entry; - } - } - } -subsystem_inferred_from_entry:; - } - - // do we have an entry point name? - if (config->entry_point_name.size) { - if (is_entry_point_name_inferred) { - // redirect user entry to appropriate CRT entry - String8 crt_entry_point_name = msvcrt_ctr_entry_from_user_entry(config->entry_point_name); - config->entry_point_name = crt_entry_point_name.size ? crt_entry_point_name : config->entry_point_name; - } - - // generate undefined symbol for entry point - lnk_include_symbol(config, config->entry_point_name, 0); - - // do we have a subsystem? - if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) { - // if subsystem version not specified set default values - if (config->subsystem_ver.major == 0 && config->subsystem_ver.minor == 0) { - config->subsystem_ver = lnk_get_default_subsystem_version(config->subsystem, config->machine); - } - - // check subsystem version against allowed min version - Version min_subsystem_ver = lnk_get_min_subsystem_version(config->subsystem, config->machine); - if (version_compar(config->subsystem_ver, min_subsystem_ver) < 0) { - lnk_error(LNK_Error_Cmdl, "subsystem version %I64u.%I64u can't be lower than %I64u.%I64u", - config->subsystem_ver.major, config->subsystem_ver.minor, min_subsystem_ver.major, min_subsystem_ver.minor); - } - - // by default terminal server is enabled for windows and console applications - if (~config->flags & LNK_ConfigFlag_NoTsAware && ~config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { - if (config->subsystem == PE_WindowsSubsystem_WINDOWS_GUI || config->subsystem == PE_WindowsSubsystem_WINDOWS_CUI) { - config->dll_characteristics |= PE_DllCharacteristic_TERMINAL_SERVER_AWARE; - } - } - - // entry point found! - link->try_to_resolve_entry_point = 0; - } else { - lnk_error(LNK_Error_NoSubsystem, "unknown subsystem, please use /SUBSYSTEM to set subsytem type you need"); - } - } -} - -internal void -lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *trigger_symbol, LNK_Lib *lib, U32 member_idx) -{ - if (lnk_lib_set_link_symbol(lib, member_idx, trigger_symbol)) { LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1); member_ref->lib = lib; member_ref->member_idx = member_idx; lnk_lib_member_ref_list_push_node(queued_members, member_ref); - - trigger_symbol->is_lib_member_linked = 1; } } +internal +THREAD_POOL_TASK_FUNC(lnk_search_lib_task) +{ + ProfBeginFunction(); + + LNK_SearchLibTask *task = raw_task; + LNK_Lib *lib = task->lib; + LNK_SymbolTable *symtab = task->symtab; + LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id]; + + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[task_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + if (symbol->is_lib_member_linked) { continue; } + + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + U32 member_idx; + if (lnk_search_lib(lib, symbol->name, &member_idx)) { + lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } + } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + U32 member_idx; + if (lnk_search_lib(lib, symbol->name, &member_idx)) { + lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } + } else if (task->search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol_ref); + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } + } + } + } + } + } + + ProfEnd(); +} + internal void -lnk_link_inputs_(TP_Context *tp, +lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, - LNK_ImportTables *imps, - B32 search_anti_deps) + LNK_ImportTables *imps) { Temp scratch = scratch_begin(arena->v, arena->count); - lnk_load_inputs(tp, arena, config, inputer, symtab, link); - + B32 search_anti_deps = 0; for (U64 resolved_members_count = 0; ; resolved_members_count = 0) { - if (link->try_to_resolve_entry_point) { - lnk_resolve_entry_point(config, symtab, link); - } + lnk_load_inputs(tp, arena, config, inputer, symtab, link); for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { do { lnk_load_inputs(tp, arena, config, inputer, symtab, link); LNK_LibMemberRefList queued_members = {0}; - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - if (symbol->is_lib_member_linked) { continue; } - - LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); - COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); - } - } else if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { - lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx); - } - } else if (search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol_ref); - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - U32 member_idx; - if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { - lnk_queue_lib_member(scratch.arena, &queued_members, symbol, &lib_n->data, member_idx); - } - } - } - } - } - } + { + LNK_SearchLibTask task = {0}; + task.search_anti_deps = search_anti_deps; + task.lib = &lib_n->data; + task.symtab = symtab; + task.member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count); + tp_for_parallel_prof(tp, arena, tp->worker_count, lnk_search_lib_task, &task, "Search Lib"); + lnk_lib_member_ref_list_concat_in_place_array(&queued_members, task.member_ref_lists, tp->worker_count); } - // sort library member refs to match the order of their appearance in the respective obj symbol tables + // sort library member refs to match the order of their appearance in obj symbol tables LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members); radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before); + if (queued_members.count) { + lnk_log(LNK_Log_Links, "Searching %S:", lib_n->data.path); + + for EachIndex(i, queued_members.count) { + Temp temp = temp_begin(scratch.arena); + + LNK_LibMemberRef *member_ref = member_refs[i]; + LNK_Lib *lib = member_ref->lib; + LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; + + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); + COFF_DataType member_type = coff_data_type_from_data(member_info.data); + String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name); + + U64 refs_count = 0; + LNK_ObjSymbolRef **refs = lnk_ref_from_symbol_many(temp.arena, link_symbol, &refs_count); + lnk_log(LNK_Log_Links, "\tFound %S in %S", link_symbol->name, str8_skip_last_slash(member_name)); + for EachIndex(i, refs_count) { + lnk_log(LNK_Log_Links, "\t\tReferenced in %S", lnk_loc_from_obj(temp.arena, refs[i]->obj)); + } + + temp_end(temp); + } + } + // push inputs for lib member refs for EachIndex(i, queued_members.count) { LNK_LibMemberRef *member_ref = member_refs[i]; @@ -1557,6 +1613,7 @@ lnk_link_inputs_(TP_Context *tp, // parse member COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); COFF_DataType member_type = coff_data_type_from_data(member_info.data); + String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name); switch (member_type) { case COFF_DataType_Import: { @@ -1608,27 +1665,16 @@ lnk_link_inputs_(TP_Context *tp, } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { - String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); - - // obj path in thin archive has slash appended which screws up - // file lookup on disk; it could be there to enable paths to symbols - // but we don't use this feature - String8 slash = str8_lit("/"); - if (str8_ends_with(obj_path, slash, 0)) { - obj_path = str8_chop(obj_path, slash.size); - } - - B32 is_thin = lib->type == COFF_Archive_Thin; - if (is_thin) { + if (lib->type == COFF_Archive_Thin) { // obj path in thin archive is relative to the directory with archive String8List obj_path_list = {0}; str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); - str8_list_push(scratch.arena, &obj_path_list, obj_path); - obj_path = str8_path_list_join_by_style(inputer->arena, &obj_path_list, config->path_style); + str8_list_push(scratch.arena, &obj_path_list, member_name); + String8 obj_path = str8_path_list_join_by_style(inputer->arena, &obj_path_list, config->path_style); lnk_inputer_push_obj_thin(inputer, member_ref, obj_path); } else { - lnk_inputer_push_obj(inputer, member_ref, obj_path, member_info.data); + lnk_inputer_push_obj(inputer, member_ref, member_name, member_info.data); } } break; case COFF_DataType_Null: break; @@ -1640,64 +1686,49 @@ lnk_link_inputs_(TP_Context *tp, } while (lnk_inputer_has_items(inputer)); } + if (resolved_members_count == 0) { + search_anti_deps = 0; + + // replace undefined symbols that have an alternate name with a weak symbol + for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->v.from); + if (symbol_ht) { + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); + if (interp == COFF_SymbolValueInterp_Undefined) { + // clear out slot so weak symbol can replace undefined symbol (general rule is + // weak symbol is not allowed to replace undefined) + LNK_Symbol *undef_symbol = symbol_ht->symbol; + symbol_ht->symbol = 0; + + // make obj with alternamte name symbol + String8 alt_name_obj_data; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); + COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.from, COFF_WeakExt_SearchLibrary, 0); + COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.to, COFF_WeakExt_AntiDependency, from_symbol); + coff_obj_writer_set_default_symbol(from_symbol, to_symbol); + alt_name_obj_data = coff_obj_writer_serialize(arena->v[0], obj_writer); + coff_obj_writer_release(&obj_writer); + } + + LNK_Obj *obj_with_alt_name = alt_name_n->v.obj; + String8 obj_with_alt_name_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); + lnk_inputer_push_obj_linkgen(inputer, obj_with_alt_name ? obj_with_alt_name->link_member : 0, obj_with_alt_name_path, alt_name_obj_data); + + search_anti_deps = 1; + } + } + } + + resolved_members_count = lnk_inputer_has_items(inputer); + } + if (resolved_members_count == 0) { break; } } scratch_end(scratch); } -internal void -lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, LNK_ImportTables *imps) -{ - lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 0); - - // handle /ALTERNATENAME - { - // replace undefined symbols that have an alternate name with a weak symbol - for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { - LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->v.from); - if (symbol_ht) { - COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); - if (interp == COFF_SymbolValueInterp_Undefined) { - // clear out slot so weak symbol can replace undefined symbol (general rule is - // weak symbol is not allowed to replace undefined) - LNK_Symbol *undef_symbol = symbol_ht->symbol; - symbol_ht->symbol = 0; - - // make obj with alternamte name symbol - String8 alt_name_obj_data; - { - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_Unknown); - COFF_ObjSymbol *from_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.from, COFF_WeakExt_SearchLibrary, 0); - COFF_ObjSymbol *to_symbol = coff_obj_writer_push_symbol_weak(obj_writer, alt_name_n->v.to, COFF_WeakExt_AntiDependency, from_symbol); - coff_obj_writer_set_default_symbol(from_symbol, to_symbol); - alt_name_obj_data = coff_obj_writer_serialize(arena->v[0], obj_writer); - coff_obj_writer_release(&obj_writer); - } - - LNK_Obj *obj_with_alt_name = alt_name_n->v.obj; - String8 obj_with_alt_name_path = obj_with_alt_name ? obj_with_alt_name->path : str8_lit("RADLINK"); - lnk_inputer_push_obj_linkgen(inputer, obj_with_alt_name ? obj_with_alt_name->link_member : 0, obj_with_alt_name_path, alt_name_obj_data); - - lnk_load_inputs(tp, arena, config, inputer, symtab, link); - } - } - } - } - - // - // include delay load helper - // - if (config->machine != COFF_MachineType_Unknown && config->delay_load_helper_name.size == 0 && config->delay_load_dll_list.node_count) { - config->delay_load_helper_name = mscrt_delay_load_helper_name_from_machine(config->machine); - if (config->delay_load_helper_name.size) { - lnk_include_symbol(config, config->delay_load_helper_name, 0); - } - } - - lnk_link_inputs_(tp, arena, config, inputer, symtab, link, imps, 1); -} - internal LNK_Link * lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab) { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 9f358a56..afe090da 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -154,6 +154,14 @@ typedef struct LNK_BaseRelocPageArray // --- Workers Contexts -------------------------------------------------------- +typedef struct +{ + B32 search_anti_deps; + LNK_SymbolTable *symtab; + LNK_Lib *lib; + LNK_LibMemberRefList *member_ref_lists; +} LNK_SearchLibTask; + typedef struct { LNK_SymbolTable *symtab; @@ -283,6 +291,7 @@ internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_I // --- Link Context ------------------------------------------------------------ internal void lnk_lib_member_ref_list_push_node(LNK_LibMemberRefList *list, LNK_LibMemberRef *node); +internal void lnk_lib_member_ref_list_concat_in_place_array(LNK_LibMemberRefList *list, LNK_LibMemberRefList *to_concat_arr, U64 count); internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b); internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index fea9c9b3..1f317a16 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -110,7 +110,6 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L } // parse symbol names - String8Array symbol_names; { Temp scratch = scratch_begin(&arena, 1); String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); From 24b427fe72377227b400152c1e742e205f5c21f3 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 19:50:31 -0700 Subject: [PATCH 157/302] delete unused blake3 headers --- src/linker/base_ext/base_blake3_asm.c | 13 ------------- src/linker/base_ext/base_blake3_asm.h | 18 ------------------ 2 files changed, 31 deletions(-) delete mode 100644 src/linker/base_ext/base_blake3_asm.c delete mode 100644 src/linker/base_ext/base_blake3_asm.h diff --git a/src/linker/base_ext/base_blake3_asm.c b/src/linker/base_ext/base_blake3_asm.c deleted file mode 100644 index b9d4c470..00000000 --- a/src/linker/base_ext/base_blake3_asm.c +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "../third_party_ext/blake3/blake3_portable.c" - -#if defined(__aarch64__) || defined(_M_ARM64) -#include "../third_party_ext/blake3/blake3_neon.c" -#endif - -#include "../third_party_ext/blake3/blake3_dispatch.c" -#include "../third_party_ext/blake3/blake3.c" - -#pragma comment (lib, "blake3") diff --git a/src/linker/base_ext/base_blake3_asm.h b/src/linker/base_ext/base_blake3_asm.h deleted file mode 100644 index 1efded7e..00000000 --- a/src/linker/base_ext/base_blake3_asm.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_BLAKE3_H -#define BASE_BLAKE3_H - -#include "../third_party_ext/blake3/blake3.h" - -static void -blake3(void* out, size_t outlen, void* in, size_t inlen) -{ - blake3_hasher hasher; - blake3_hasher_init(&hasher); - blake3_hasher_update(&hasher, in, inlen); - blake3_hasher_finalize(&hasher, (uint8_t*)out, outlen); -} - -#endif // BASE_BLAKE3_H From bbe430cc2fc5ea188c8ccfae7e0f845ae4cb82df Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 21:13:13 -0700 Subject: [PATCH 158/302] write first linker member header with symbol names grouped by member --- src/coff/coff_lib_writer.c | 202 ++++++++++++++++++++----------------- src/coff/coff_lib_writer.h | 3 +- 2 files changed, 113 insertions(+), 92 deletions(-) diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index aaf590e0..aeb9a3d2 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -5,8 +5,8 @@ internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol) { COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1); - node->next = 0; - node->data = symbol; + node->next = 0; + node->data = symbol; SLLQueuePush(list->first, list->last, node); list->count += 1; return node; @@ -16,8 +16,8 @@ internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member) { COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1); - node->next = 0; - node->data = member; + node->next = 0; + node->data = member; SLLQueuePush(list->first, list->last, node); list->count += 1; return node; @@ -29,8 +29,7 @@ coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList li COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2); COFF_LibWriterSymbol *ptr = arr + 1; for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) { - ptr->name = push_str8_copy(arena, i->data.name); - ptr->member_idx = i->data.member_idx; + *ptr = i->data; } MemoryZeroStruct(&arr[0]); MemoryZeroStruct(&arr[list.count+1]); @@ -58,17 +57,30 @@ coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b) } internal int -coff_lib_writer_symbol_is_before(void *raw_a, void *raw_b) +coff_lib_writer_symbol_is_before_name(void *raw_a, void *raw_b) { - int compar = coff_lib_writer_symbol_name_compar(raw_a, raw_b); - return compar < 0; + return coff_lib_writer_symbol_name_compar(raw_a, raw_b) < 0; +} + +internal int +coff_lib_writer_symbol_is_before_member_idx(void *raw_a, void *raw_b) +{ + COFF_LibWriterSymbol *a = raw_a, *b = raw_b; + return a->member_idx < b->member_idx; } internal void -coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count) +coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count) { Assert(count >= 2); - radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before); + radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_name); +} + +internal void +coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count) +{ + Assert(count >= 2); + radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_member_idx); } internal COFF_LibWriter * @@ -93,36 +105,21 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d U64 member_idx = writer->member_list.count; // push obj member - COFF_LibWriterMember member = {0}; - member.name = obj_path; - member.data = obj_data; - coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member); + COFF_LibWriterMember member = { .name = obj_path, .data = obj_data }; + COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member); // push external symbols - { - COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data); - String8 string_table = str8_substr(obj_data, obj_header.string_table_range); - String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range); - - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - void *symbol_ptr; - if (obj_header.is_big_obj) { - symbol_ptr = &((COFF_Symbol32 *)symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol32(string_table, symbol_ptr); - } else { - symbol_ptr = &((COFF_Symbol16 *)symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol16(string_table, symbol_ptr); - } - - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) { - if (symbol.storage_class == COFF_SymStorageClass_External) { - COFF_LibWriterSymbol lib_symbol = {0}; - lib_symbol.name = symbol.name; - lib_symbol.member_idx = member_idx; - coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol); - } + COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data); + String8 string_table = str8_substr(obj_data, obj_header.string_table_range); + String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range); + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = coff_parse_symbol(obj_header, string_table, symbol_table, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); + if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) { + if (symbol.storage_class == COFF_SymStorageClass_External) { + COFF_LibWriterSymbol lib_symbol = { .name = symbol.name, .member_idx = member_idx }; + coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol); } } } @@ -133,30 +130,29 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type) { - // push import member U64 member_idx = lib_writer->member_list.count; - COFF_LibWriterMember member = {0}; - member.name = dll_name; - member.data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type); - coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member); + + String8 member_data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type); + COFF_LibWriterMember member = { .name = dll_name, .data = member_data }; + COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member); if (name.size) { switch (import_type) { case COFF_ImportHeader_Code: { COFF_LibWriterSymbol thunk_symbol = {0}; - thunk_symbol.name = push_str8_copy(lib_writer->arena, name); - thunk_symbol.member_idx = member_idx; + thunk_symbol.name = push_str8_copy(lib_writer->arena, name); + thunk_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol); COFF_LibWriterSymbol imp_symbol = {0}; - imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); - imp_symbol.member_idx = member_idx; + imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); + imp_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol); } break; case COFF_ImportHeader_Data: { COFF_LibWriterSymbol imp_symbol = {0}; - imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); - imp_symbol.member_idx = member_idx; + imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); + imp_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol); } break; case COFF_ImportHeader_Const: { NotImplemented; } break; @@ -170,29 +166,17 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta { Temp scratch = scratch_begin(&arena, 1); - // symbol & member lists -> arrays - U64 symbols_count; - COFF_LibWriterSymbol *symbols; - U64 member_count; - COFF_LibWriterMember *member_array; - { - U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; - COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); - coff_lib_writer_symbol_array_sort(symbols_with_null, symbols_count_with_null); - symbols_count = symbols_count_with_null - 2; - symbols = symbols_with_null + 1; - - member_count = lib_writer->member_list.count; - member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list); - } + // member lists -> arrays + U64 member_count = lib_writer->member_list.count; + COFF_LibWriterMember *member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list); // serialize members - U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count); - String8List long_names_list = {0}; - String8List member_data_list = {0}; + U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count); + String8List long_names_list = {0}; + String8List member_data_list = {0}; { HashTable *name_ht = hash_table_init(scratch.arena, 1024); - for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) { + for EachIndex(member_idx, member_count) { COFF_LibWriterMember *member = &member_array[member_idx]; // make member name @@ -227,7 +211,7 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta } } - // long names member + // write long names member if (long_names_list.total_size) { String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size); String8 data = str8_list_join(scratch.arena, &long_names_list, 0); @@ -243,26 +227,16 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta // compute size for symbol string table U32 name_buffer_size = 0; - for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) { - name_buffer_size += ptr->name.size; + for (COFF_LibWriterSymbolNode *node = lib_writer->symbol_list.first; node != 0; node = node->next) { + name_buffer_size += node->data.name.size; name_buffer_size += 1; // null } - - // write symbol name buffer - U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); - { - U64 name_cursor = 0; - for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) { - MemoryCopy(name_buffer + name_cursor, ptr->name.str, ptr->name.size); - name_buffer[name_cursor + ptr->name.size] = '\0'; - name_cursor += ptr->name.size + 1; - } - } - + + // compute members base offset U64 members_base_offset; { - U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * symbols_count + name_buffer_size; - U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * symbols_count + name_buffer_size; + U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib_writer->symbol_list.count + name_buffer_size; + U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * lib_writer->symbol_list.count + name_buffer_size; U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size; sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign); @@ -279,8 +253,31 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta } } - // second linker member + // write second linker member if (emit_second_member) { + U64 symbols_count; + COFF_LibWriterSymbol *symbols; + { + U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; + COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); + coff_lib_writer_symbol_array_sort_on_name(symbols_with_null, symbols_count_with_null); + + symbols_count = symbols_count_with_null - 2; + symbols = symbols_with_null + 1; + } + + // write symbol name buffer + U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); + { + U64 name_cursor = 0; + for EachIndex(symbol_idx, symbols_count) { + COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; + MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size); + name_buffer[name_cursor + symbol->name.size] = '\0'; + name_cursor += symbol->name.size + 1; + } + } + U32 member_count32 = safe_cast_u32(member_count); U32 symbol_count32 = safe_cast_u32(symbols_count); @@ -288,14 +285,14 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count); // write member offset array - for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) { + for EachIndex(member_idx, member_count) { U64 member_offset = members_base_offset + member_offsets[member_idx]; U32 member_off32 = safe_cast_u32(member_offset); member_off32_arr[member_idx] = member_off32; } // write member offset indices for each symbol - for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) { + for EachIndex(symbol_idx, symbols_count) { // member offset indices are 1-based U64 member_idx = symbols[symbol_idx].member_idx + 1; U16 member_idx16 = safe_cast_u16(member_idx); @@ -323,12 +320,35 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta str8_list_push_front(scratch.arena, &member_data_list, member_header); } - // first linker member (obsolete, but kept for compatability reasons) + // write first linker member (obsolete, but kept for compatability reasons) { + U64 symbols_count; + COFF_LibWriterSymbol *symbols; + { + U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; + COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); + coff_lib_writer_symbol_array_sort_on_member_idx(symbols_with_null, symbols_count_with_null); + + symbols_count = symbols_count_with_null - 2; + symbols = symbols_with_null + 1; + } + + // write symbol name buffer + U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); + { + U64 name_cursor = 0; + for EachIndex(symbol_idx, symbols_count) { + COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; + MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size); + name_buffer[name_cursor + symbol->name.size] = '\0'; + name_cursor += symbol->name.size + 1; + } + } + U32 symbol_count_be = from_be_u32(symbols_count); U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count); - for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) { + for EachIndex(symbol_idx, symbols_count) { COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; // write big endian member offset diff --git a/src/coff/coff_lib_writer.h b/src/coff/coff_lib_writer.h index 2c501409..ab9dfc99 100644 --- a/src/coff/coff_lib_writer.h +++ b/src/coff/coff_lib_writer.h @@ -57,7 +57,8 @@ internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *aren internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list); internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list); -internal void coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count); +internal void coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count); +internal void coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count); internal COFF_LibWriter * coff_lib_writer_alloc(void); internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr); From 58e3af5b3c2ddad19a11869303621c9f41395e08 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 21:10:35 -0700 Subject: [PATCH 159/302] test for linking using first and second lib headers --- src/torture/torture.c | 92 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/torture/torture.c b/src/torture/torture.c index e3f80040..71c97119 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -23,6 +23,9 @@ #include "coff/coff_lib_writer.h" #include "pe/pe.h" #include "pe/pe_section_flags.h" +#include "linker/base_ext/base_core.h" +#include "linker/base_ext/base_arena.h" +#include "linker/base_ext/base_arrays.h" #include "linker/hash_table.h" #include "base/base_inc.c" @@ -33,6 +36,9 @@ #include "coff/coff_lib_writer.c" #include "pe/pe.c" #include "linker/hash_table.c" +#include "linker/base_ext/base_core.c" +#include "linker/base_ext/base_arena.c" +#include "linker/base_ext/base_arrays.c" #include "linker/lnk_cmd_line.h" #include "linker/lnk_cmd_line.c" @@ -4768,6 +4774,90 @@ exit:; return result; } +internal T_Result +t_first_member_header(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("8"), 0x8, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("1"), 0x1, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("9"), 0x9, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("7"), 0x7, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("4"), 0x4, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("5"), 0x5, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("2"), 0x2, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("3"), 0x3, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("6"), 0x6, COFF_SymStorageClass_External); + obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 lib; + { + COFF_LibWriter *lib_writer = coff_lib_writer_alloc(); + coff_lib_writer_push_obj(lib_writer, str8_lit("obj.obj"), obj); + lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 0); + coff_lib_writer_release(&lib_writer); + } + + t_write_file(str8_lit("test.lib"), lib); + t_write_entry_obj(); + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe test.lib entry.obj /include:1 /include:2 /include:3 /include:4 /include:5 /include:6 /include:7 /include:8 /include:9"); + if (linker_exit_code != 0) goto exit; + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_second_member_header(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("8"), 0x8, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("1"), 0x1, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("9"), 0x9, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("7"), 0x7, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("4"), 0x4, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("5"), 0x5, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("2"), 0x2, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("3"), 0x3, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("6"), 0x6, COFF_SymStorageClass_External); + obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 lib; + { + COFF_LibWriter *lib_writer = coff_lib_writer_alloc(); + coff_lib_writer_push_obj(lib_writer, str8_lit("obj.obj"), obj); + lib = coff_lib_writer_serialize(scratch.arena, lib_writer, 0, 0, 1); + coff_lib_writer_release(&lib_writer); + } + + t_write_file(str8_lit("test.lib"), lib); + t_write_entry_obj(); + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe test.lib entry.obj /include:1 /include:2 /include:3 /include:4 /include:5 /include:6 /include:7 /include:8 /include:9"); + if (linker_exit_code != 0) goto exit; + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + internal T_Result t_opt_ref_dangling_section(void) { @@ -4927,6 +5017,8 @@ entry_point(CmdLine *cmdline) { "empty_section", t_empty_section }, { "removed_section", t_removed_section }, { "function_pad_min", t_function_pad_min }, + { "first_member_header", t_first_member_header }, + { "second_member_header", t_second_member_header }, }; // From fc0a7d51d35a7e067cb3831c574d74c726f278ef Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 21:14:57 -0700 Subject: [PATCH 160/302] warning fixes --- src/torture/torture.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/torture/torture.c b/src/torture/torture.c index 71c97119..78951f77 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -3116,7 +3116,7 @@ t_import_export(void) } #if OS_WINDOWS - BOOL is_dir_set = SetDllDirectoryA(g_wdir.str); + BOOL is_dir_set = SetDllDirectoryA((LPCSTR)g_wdir.str); AssertAlways(is_dir_set); HANDLE export_dll = LoadLibrary("export.dll"); @@ -5143,7 +5143,7 @@ entry_point(CmdLine *cmdline) // { U64 max_label_size = 0; - for (U64 i = 0; i < ArrayCount(target_array); i += 1) { max_label_size = Max(max_label_size, cstring8_length(target_array[i].label)); } + for (U64 i = 0; i < ArrayCount(target_array); i += 1) { max_label_size = Max(max_label_size, cstring8_length((U8*)target_array[i].label)); } U64 dots_min = 10; U64 dots_size = max_label_size+dots_min; @@ -5191,7 +5191,7 @@ entry_point(CmdLine *cmdline) T_Result result = t_run(target_array[target_idx].r); - U64 dots_count = (max_label_size - cstring8_length(target_array[target_idx].label)) + dots_min; + U64 dots_count = (max_label_size - cstring8_length((U8*)target_array[target_idx].label)) + dots_min; String8 msg = push_str8f(scratch.arena, "%s%.*s%s", target_array[target_idx].label, dots_count, dots, t_string_from_result(result)); // run progress From 98a05728b34ad5f83b44e2fcb9e634efd7838f48 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 7 Sep 2025 21:50:34 -0700 Subject: [PATCH 161/302] add check for whether weak symbol is resolved --- src/linker/lnk.c | 16 +++++---- src/linker/lnk_symbol_table.c | 63 ++++++++++++++++------------------- src/linker/lnk_symbol_table.h | 2 +- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a3794d0f..a36440c5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1528,13 +1528,15 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task) lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); } } else if (task->search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol_ref); - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - U32 member_idx; - if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { - lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + LNK_ObjSymbolRef dep_symbol = {0}; + if (lnk_resolve_weak_symbol(symtab, symbol_ref, &dep_symbol)) { + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } } } } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 04159186..270a4c57 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -614,11 +614,13 @@ lnk_foff_from_symbol(COFF_SectionHeader **image_section_table, LNK_Symbol *symbo return foff; } -internal LNK_ObjSymbolRef -lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) +internal B32 +lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *resolved_symbol_out) { Temp scratch = scratch_begin(0,0); + B32 is_resolved = 0; + struct S { struct S *next; LNK_ObjSymbolRef symbol; B32 is_anti_dep; }; struct S *sf = 0, *sl = 0; @@ -641,8 +643,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) String8 chain_string = str8_list_join(scratch.arena, &chain, &(StringJoin){ .sep = str8_lit("\n") }); lnk_error_obj(LNK_Error_WeakCycle, symbol.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", symbol_parsed.name, chain_string); - MemoryZeroStruct(¤t_symbol); - break; + goto exit; } COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); @@ -688,9 +689,14 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol) } else { break; } } + if (resolved_symbol_out) { + *resolved_symbol_out = current_symbol; + } + is_resolved = 1; + exit:; scratch_end(scratch); - return current_symbol; + return is_resolved; } internal @@ -705,24 +711,26 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol_ref); - COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); - COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); - if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); - if (symbol_ref.obj->header.is_big_obj) { - COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; - symbol32->section_number = COFF_Symbol_UndefinedSection; - symbol32->value = 0; - symbol32->storage_class = COFF_SymStorageClass_External; + LNK_ObjSymbolRef resolve = {0}; + if (lnk_resolve_weak_symbol(symtab, symbol_ref, &resolve)) { + COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); + COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); + if (resolve_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); + if (symbol_ref.obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; + symbol32->section_number = COFF_Symbol_UndefinedSection; + symbol32->value = 0; + symbol32->storage_class = COFF_SymStorageClass_External; + } else { + COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; + symbol16->section_number = COFF_Symbol_UndefinedSection; + symbol16->value = 0; + symbol16->storage_class = COFF_SymStorageClass_External; + } } else { - COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; - symbol16->section_number = COFF_Symbol_UndefinedSection; - symbol16->value = 0; - symbol16->storage_class = COFF_SymStorageClass_External; + symbol->refs->v = resolve; } - } else { - symbol->refs->v = resolve; } } } @@ -733,22 +741,9 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - U64 chunks_count = 0; LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &(LNK_ReplaceWeakSymbolsWithDefaultSymbolTask){ .symtab = symtab, .chunks = chunks }); - -#if BUILD_DEBUG - for EachIndex(chunk_idx, chunks_count) { - LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_SymbolValueInterpType symbol_interp = lnk_interp_from_symbol(symbol); - AssertAlways(symbol_interp != COFF_SymbolValueInterp_Weak); - } - } -#endif - scratch_end(scratch); ProfEnd(); } diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 3a5e52b1..afa4ebd5 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -131,7 +131,7 @@ internal U64 lnk_foff_from_symbol(COFF_SectionHeader **image_section_table, // --- Weak Symbol ------------------------------------------------------------- -internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol); +internal B32 lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *resolved_symbol_out); internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab); From 763bb57459a5351f72792f52219a858ee25c56dd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 8 Sep 2025 12:32:22 -0700 Subject: [PATCH 162/302] revert hasher --- src/base/base_strings.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 95ba9d38..7b3252b9 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -2839,10 +2839,7 @@ str8_is_before_case_sensitive(const void *a, const void *b) internal U64 u64_hash_from_seed_str8(U64 seed, String8 string) { - XXH3_state_t hasher; XXH3_64bits_reset_withSeed(&hasher, seed); - XXH3_64bits_update(&hasher, &string.size, sizeof(string.size)); - XXH3_64bits_update(&hasher, string.str, string.size); - XXH64_hash_t result = XXH3_64bits_digest(&hasher); + U64 result = XXH3_64bits_withSeed(string.str, string.size, seed); return result; } From b1609017c54783ad334be880d304bb76f799fcb1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 8 Sep 2025 12:32:38 -0700 Subject: [PATCH 163/302] inline xxhash functions --- src/base/base_strings.c | 2 +- src/linker/lnk.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 7b3252b9..119e9e2b 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -2830,7 +2830,7 @@ str8_is_before_case_sensitive(const void *a, const void *b) //~ rjf: Basic String Hashes #if !defined(XXH_IMPLEMENTATION) -# define XXH_PRIVATE_API +# define XXH_INLINE_ALL # define XXH_IMPLEMENTATION # define XXH_STATIC_LINKING_ONLY # include "third_party/xxHash/xxhash.h" diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a36440c5..910ccbe7 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -17,7 +17,7 @@ #define MD5_API static #include "third_party/md5/md5.c" #include "third_party/md5/md5.h" -#define XXH_PRIVATE_API +#define XXH_INLINE_ALL #define XXH_IMPLEMENTATION #define XXH_STATIC_LINKING_ONLY #include "third_party/xxHash/xxhash.c" From e021079d05ceafa058b8d1cbf53b516ac2113419 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 9 Sep 2025 08:28:08 -0700 Subject: [PATCH 164/302] bump rdi encoding version --- src/lib_rdi/rdi.h | 2 +- src/rdi/rdi.mdesk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib_rdi/rdi.h b/src/lib_rdi/rdi.h index e6449d20..20394e53 100644 --- a/src/lib_rdi/rdi.h +++ b/src/lib_rdi/rdi.h @@ -52,7 +52,7 @@ typedef int64_t RDI_S64; // "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 12 +#define RDI_ENCODING_VERSION 13 //////////////////////////////////////////////////////////////// //~ Format Types & Functions diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index bb1e2421..68876a09 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -62,7 +62,7 @@ ""; "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 12"; + "#define RDI_ENCODING_VERSION 13"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; From 26606d789510a7ae69ab26d88cca1578cf8b069b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 15 Sep 2025 11:32:22 -0700 Subject: [PATCH 165/302] do not strip enums/aliases on array index ops --- src/eval/eval_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 83876875..ab6da91f 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -503,7 +503,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default) E_TypeKey r_restype = e_type_key_unwrap(r.type_key, E_TypeUnwrapFlag_AllDecorative); E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); E_TypeKind r_restype_kind = e_type_kind_from_key(r_restype); - E_TypeKey direct_type = e_type_key_unwrap(l_restype, E_TypeUnwrapFlag_All); + E_TypeKey direct_type = e_type_key_unwrap(l_restype, E_TypeUnwrapFlag_All & ~(E_TypeUnwrapFlag_Enums|E_TypeUnwrapFlag_Aliases)); U64 direct_type_size = e_type_byte_size_from_key(direct_type); // rjf: bad conditions? -> error if applicable, exit From cf94b3757e888dfb214799099f6a9e9b4e8df0a1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 15 Sep 2025 13:02:32 -0700 Subject: [PATCH 166/302] wide rdi dumping --- src/rdi/rdi_local.c | 161 ++++++++++++++++++++++++++++++++------------ 1 file changed, 119 insertions(+), 42 deletions(-) diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index cb1be2cc..874c35dd 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -512,19 +512,46 @@ rdi_strings_from_locations(Arena *arena, RDI_Parsed *rdi, RDI_Arch arch, Rng1U64 internal String8List rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags flags) { - String8List strings = {0}; + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); String8 indent = str8_lit(" "); -#define dump(str) str8_list_push(arena, &strings, (str)) -#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__) -#define DumpSubset(name) if(flags & RDI_DumpSubsetFlag_##name) DeferLoop(dumpf("////////////////////////////////\n//~ %S\n\n%S:\n{", rdi_name_title_from_dump_subset_table[RDI_DumpSubset_##name], rdi_name_lowercase_from_dump_subset_table[RDI_DumpSubset_##name]), dump(str8_lit("}\n\n"))) + + ////////////////////////////// + //- rjf: set up + // + typedef struct DumpSubsetOutputNode DumpSubsetOutputNode; + struct DumpSubsetOutputNode + { + DumpSubsetOutputNode *next; + RDI_DumpSubset subset; + String8List *lane_strings; + }; + local_persist DumpSubsetOutputNode *first_output_node = 0; + local_persist DumpSubsetOutputNode *last_output_node = 0; + local_persist String8List result_strings = {0}; + String8List *strings = 0; +#define dump(str) str8_list_push(arena, strings, (str)) +#define dumpf(...) str8_list_pushf(arena, strings, __VA_ARGS__) +#define DumpSubset(name) \ +if(lane_idx() == 0)\ +{\ +DumpSubsetOutputNode *n = push_array(scratch.arena, DumpSubsetOutputNode, 1);\ +SLLQueuePush(first_output_node, last_output_node, n);\ +n->subset = RDI_DumpSubset_##name;\ +n->lane_strings = push_array(scratch.arena, String8List, lane_count());\ +}\ +lane_sync();\ +strings = &last_output_node->lane_strings[lane_idx()];\ +lane_sync(); if(flags & RDI_DumpSubsetFlag_##name) ProfScope(#name) ////////////////////////////// //- rjf: dump data sections // DumpSubset(DataSections) { - dumpf("\n"); - for EachIndex(idx, rdi->sections_count) + if(lane_idx() == 0) { dumpf("\n"); } + Rng1U64 range = lane_range(rdi->sections_count); + for EachInRange(idx, range) { Temp scratch = scratch_begin(&arena, 1); RDI_SectionKind kind = (RDI_SectionKind)idx; @@ -540,14 +567,17 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(TopLevelInfo) { - RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); - Temp scratch = scratch_begin(&arena, 1); - dumpf("\n"); - dumpf(" arch: %S\n", rdi_string_from_arch(scratch.arena, tli->arch)); - dumpf(" exe_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->exe_name_string_idx)); - dumpf(" voff_max: %#08llx\n", tli->voff_max); - dumpf(" producer_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->producer_name_string_idx)); - scratch_end(scratch); + if(lane_idx() == 0) + { + RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); + Temp scratch = scratch_begin(&arena, 1); + dumpf("\n"); + dumpf(" arch: %S\n", rdi_string_from_arch(scratch.arena, tli->arch)); + dumpf(" exe_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->exe_name_string_idx)); + dumpf(" voff_max: %#08llx\n", tli->voff_max); + dumpf(" producer_name: '%S'\n", str8_from_rdi_string_idx(rdi, tli->producer_name_string_idx)); + scratch_end(scratch); + } } ////////////////////////////// @@ -555,10 +585,14 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(BinarySections) { + if(lane_idx() == 0) + { + dumpf("\n // %-16s %-16s %-12s %-12s %-12s %s\n", "name", "flags", "voff_first", "voff_opl", "foff_first", "foff_opl"); + } U64 count = 0; RDI_BinarySection *v = rdi_table_from_name(rdi, BinarySections, &count); - dumpf("\n // %-16s %-16s %-12s %-12s %-12s %s\n", "name", "flags", "voff_first", "voff_opl", "foff_first", "foff_opl"); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { Temp scratch = scratch_begin(&arena, 1); RDI_BinarySection *bin_section = &v[idx]; @@ -581,11 +615,12 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(FilePaths) { - dumpf("\n"); + if(lane_idx() == 0) { dumpf("\n"); } U64 count = 0; RDI_FilePathNode *v = rdi_table_from_name(rdi, FilePathNodes, &count); RDI_FilePathNode *nil = &v[0]; - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_FilePathNode *root = &v[idx]; if(root->parent_path_node != 0) { continue; } @@ -636,7 +671,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_SourceFile *v = rdi_table_from_name(rdi, SourceFiles, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_SourceFile *source_file = &v[idx]; dumpf("\n { file_path_node_idx: %4u, source_line_map: %4u, path: %-192S } // source_file[%I64u]", @@ -645,7 +681,7 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla push_str8f(arena, "'%S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)), idx); } - dumpf("\n"); + if(lane_idx() == lane_count()-1) { dumpf("\n"); } } ////////////////////////////// @@ -655,7 +691,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_Unit *v = rdi_table_from_name(rdi, Units, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_Unit *unit = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -678,10 +715,11 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(UnitVMap) { + if(lane_idx() == 0) { dumpf("\n"); } U64 count = 0; RDI_VMapEntry *v = rdi_table_from_name(rdi, UnitVMap, &count); - dumpf("\n"); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { dumpf(" {0x%I64x => %I64u}\n", v[idx].voff, v[idx].idx); } @@ -694,7 +732,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_LineTable *v = rdi_table_from_name(rdi, LineTables, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_LineTable *line_table = &v[idx]; RDI_ParsedLineTable parsed_line_table = {0}; @@ -730,7 +769,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_SourceLineMap *v = rdi_table_from_name(rdi, SourceLineMaps, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { Temp scratch = scratch_begin(&arena, 1); RDI_ParsedSourceLineMap line_map = {0}; @@ -762,7 +802,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_TypeNode *v = rdi_table_from_name(rdi, TypeNodes, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { Temp scratch = scratch_begin(&arena, 1); RDI_TypeNode *type = &v[idx]; @@ -853,7 +894,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla RDI_Member *all_members = rdi_table_from_name(rdi, Members, &all_members_count); U64 all_enum_members_count = 0; RDI_EnumMember *all_enum_members = rdi_table_from_name(rdi, EnumMembers, &all_enum_members_count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_UDT *udt = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -910,7 +952,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_GlobalVariable *v = rdi_table_from_name(rdi, GlobalVariables, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_GlobalVariable *gvar = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -929,10 +972,11 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(GlobalVariablesVMap) { + if(lane_idx() == 0) { dumpf("\n"); } U64 count = 0; RDI_VMapEntry *v = rdi_table_from_name(rdi, GlobalVMap, &count); - dumpf("\n"); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { dumpf(" {0x%I64x => %I64u}\n", v[idx].voff, v[idx].idx); } @@ -945,7 +989,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_ThreadVariable *v = rdi_table_from_name(rdi, ThreadVariables, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_ThreadVariable *tvar = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -966,7 +1011,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_Constant *v = rdi_table_from_name(rdi, Constants, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_Constant *cnst = &v[idx]; dumpf("\n '%S': // constant[%I64u]\n {\n", str8_from_rdi_string_idx(rdi, cnst->name_string_idx), idx); @@ -983,7 +1029,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); U64 count = 0; RDI_Procedure *v = rdi_table_from_name(rdi, Procedures, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_Procedure *proc = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -1023,7 +1070,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla U64 count = 0; RDI_Scope *v = rdi_table_from_name(rdi, Scopes, &count); RDI_Scope *nil = &v[0]; - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { if(v[idx].parent_scope_idx != 0) { continue; } RDI_Scope *root = &v[idx]; @@ -1132,10 +1180,11 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla // DumpSubset(ScopeVMap) { + if(lane_idx() == 0) { dumpf("\n"); } U64 count = 0; RDI_VMapEntry *v = rdi_table_from_name(rdi, ScopeVMap, &count); - dumpf("\n"); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { dumpf(" {0x%I64x => %I64u}\n", v[idx].voff, v[idx].idx); } @@ -1148,7 +1197,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; RDI_InlineSite *v = rdi_table_from_name(rdi, InlineSites, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_InlineSite *inline_site = &v[idx]; Temp scratch = scratch_begin(&arena, 1); @@ -1165,7 +1215,7 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla inline_site_idx); scratch_end(scratch); } - dumpf("\n"); + if(lane_idx() == lane_count()-1) { dumpf("\n"); } } ////////////////////////////// @@ -1176,7 +1226,8 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla Temp scratch = scratch_begin(&arena, 1); U64 count = 0; RDI_NameMap *v = rdi_table_from_name(rdi, NameMaps, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { RDI_ParsedNameMap name_map = {0}; rdi_parsed_from_name_map(rdi, &v[idx], &name_map); @@ -1226,15 +1277,41 @@ rdi_dump_list_from_parsed(Arena *arena, RDI_Parsed *rdi, RDI_DumpSubsetFlags fla { U64 count = 0; U32 *v = rdi_table_from_name(rdi, StringTable, &count); - for EachIndex(idx, count) + Rng1U64 range = lane_range(count); + for EachInRange(idx, range) { dumpf("\n \"%S\" // string[%I64u]", str8_from_rdi_string_idx(rdi, idx), idx); } - dumpf("\n"); + if(lane_idx() == lane_count()-1) { dumpf("\n"); } } + ////////////////////////////// + //- rjf: join results + // + lane_sync(); + if(lane_idx() == 0) + { + for EachNode(n, DumpSubsetOutputNode, first_output_node) + { + String8List subset_strings = {0}; + for EachIndex(idx, lane_count()) + { + str8_list_concat_in_place(&subset_strings, &n->lane_strings[idx]); + } + if(subset_strings.total_size != 0) + { + str8_list_pushf(arena, &result_strings, "////////////////////////////////\n//~ %S\n\n%S:\n{", rdi_name_title_from_dump_subset_table[n->subset], rdi_name_lowercase_from_dump_subset_table[n->subset]); + str8_list_concat_in_place(&result_strings, &subset_strings); + str8_list_pushf(arena, &result_strings, "}\n\n"); + } + } + } + lane_sync(); + #undef DumpSubset #undef dumpf #undef dump - return strings; + scratch_end(scratch); + ProfEnd(); + return result_strings; } From c7bb49092f5122983832bf9de37d56eaad4f6f71 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 15 Sep 2025 13:28:43 -0700 Subject: [PATCH 167/302] radbin dump: isolate output bundling on lane 0 --- src/radbin/radbin.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index c54468bb..1086608b 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -1084,7 +1084,6 @@ rb_thread_entry_point(void *p) { RDI_Parsed rdi = {0}; RDI_ParseStatus rdi_status = rdi_parse(f->data.str, f->data.size, &rdi); - String8 error = {0}; switch(rdi_status) { default:{}break; @@ -1094,7 +1093,10 @@ rb_thread_entry_point(void *p) case RDI_ParseStatus_Good: { String8List dump = rdi_dump_list_from_parsed(arena, &rdi, rdi_dump_subset_flags); - str8_list_concat_in_place(&output_blobs, &dump); + if(lane_idx() == 0) + { + str8_list_concat_in_place(&output_blobs, &dump); + } }break; } }break; @@ -1106,7 +1108,10 @@ rb_thread_entry_point(void *p) str8_list_pushf(arena, &output_blobs, "// %S (%S) (DWARF)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); { String8List dump = dw_dump_list_from_sections(arena, &dw, arch, dw_dump_subset_flags); - str8_list_concat_in_place(&output_blobs, &dump); + if(lane_idx() == 0) + { + str8_list_concat_in_place(&output_blobs, &dump); + } } } } From 2a8ca37cb30608886a22c4b6a49223b5832f34a3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 15 Sep 2025 14:10:30 -0700 Subject: [PATCH 168/302] record & restore target window on runs --- src/os/gfx/linux/os_gfx_linux.c | 17 +++++++++++++++++ src/os/gfx/os_gfx.h | 6 ++++++ src/os/gfx/stub/os_gfx_stub.c | 17 +++++++++++++++++ src/os/gfx/win32/os_gfx_win32.c | 19 +++++++++++++++++++ src/radbin/radbin.c | 12 ++++++++++-- src/raddbg/raddbg_core.c | 7 +++++++ src/raddbg/raddbg_core.h | 3 +++ 7 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/os/gfx/linux/os_gfx_linux.c b/src/os/gfx/linux/os_gfx_linux.c index 12a9aa56..9485225b 100644 --- a/src/os/gfx/linux/os_gfx_linux.c +++ b/src/os/gfx/linux/os_gfx_linux.c @@ -327,6 +327,23 @@ os_dpi_from_window(OS_Handle handle) return 96.f; } +//////////////////////////////// +//~ rjf: @os_hooks External Windows (Implemented Per-OS) + +internal OS_Handle +os_focused_external_window(void) +{ + OS_Handle result = {0}; + // TODO(rjf) + return result; +} + +internal void +os_focus_external_window(OS_Handle handle) +{ + // TODO(rjf) +} + //////////////////////////////// //~ rjf: @os_hooks Monitors (Implemented Per-OS) diff --git a/src/os/gfx/os_gfx.h b/src/os/gfx/os_gfx.h index d56a71ca..8eabfd57 100644 --- a/src/os/gfx/os_gfx.h +++ b/src/os/gfx/os_gfx.h @@ -163,6 +163,12 @@ internal Rng2F32 os_rect_from_window(OS_Handle window); internal Rng2F32 os_client_rect_from_window(OS_Handle window); internal F32 os_dpi_from_window(OS_Handle window); +//////////////////////////////// +//~ rjf: @os_hooks External Windows (Implemented Per-OS) + +internal OS_Handle os_focused_external_window(void); +internal void os_focus_external_window(OS_Handle handle); + //////////////////////////////// //~ rjf: @os_hooks Monitors (Implemented Per-OS) diff --git a/src/os/gfx/stub/os_gfx_stub.c b/src/os/gfx/stub/os_gfx_stub.c index 3a095ab2..e1e9b805 100644 --- a/src/os/gfx/stub/os_gfx_stub.c +++ b/src/os/gfx/stub/os_gfx_stub.c @@ -149,6 +149,23 @@ os_dpi_from_window(OS_Handle window) return 96.f; } +//////////////////////////////// +//~ rjf: @os_hooks External Windows (Implemented Per-OS) + +internal OS_Handle +os_focused_external_window(void) +{ + OS_Handle result = {0}; + // TODO(rjf) + return result; +} + +internal void +os_focus_external_window(OS_Handle handle) +{ + // TODO(rjf) +} + //////////////////////////////// //~ rjf: @os_hooks Monitors (Implemented Per-OS) diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index dac8bde7..7874d97e 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -1367,6 +1367,25 @@ os_dpi_from_window(OS_Handle handle) return result; } +//////////////////////////////// +//~ rjf: @os_hooks External Windows (Implemented Per-OS) + +internal OS_Handle +os_focused_external_window(void) +{ + HWND hwnd = GetForegroundWindow(); + OS_Handle result = {(U64)hwnd}; + return result; +} + +internal void +os_focus_external_window(OS_Handle handle) +{ + HWND hwnd = (HWND)handle.u64[0]; + SetForegroundWindow(hwnd); + SetFocus(hwnd); +} + //////////////////////////////// //~ rjf: @os_hooks Monitors (Implemented Per-OS) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 1086608b..fc59c69c 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -999,7 +999,11 @@ rb_thread_entry_point(void *p) for(RB_FileNode *n = input_files.first; n != 0; n = n->next) { RB_File *f = n->v; - str8_list_pushf(arena, &output_blobs, "// %S (%S)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); + if(lane_idx() == 0) + { + str8_list_pushf(arena, &output_blobs, "// %S (%S)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); + } + lane_sync(); //- rjf: unpack file parses Arch arch = Arch_Null; @@ -1105,7 +1109,11 @@ rb_thread_entry_point(void *p) //- rjf: dump file extension info if(f->format_flags & RB_FileFormatFlag_HasDWARF) { - str8_list_pushf(arena, &output_blobs, "// %S (%S) (DWARF)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); + if(lane_idx() == 0) + { + str8_list_pushf(arena, &output_blobs, "// %S (%S) (DWARF)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); + } + lane_sync(); { String8List dump = dw_dump_list_from_sections(arena, &dw, arch, dw_dump_subset_flags); if(lane_idx() == 0) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 21bec84a..e05c43d1 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -12807,6 +12807,12 @@ rd_frame(void) } } + // rjf: run -> refocus pre-stop focused window + if(kind == RD_CmdKind_Run) + { + os_focus_external_window(rd_state->prestop_focused_window); + } + // rjf: run -> no active targets, no processes, but we only have one target? -> just launch it, then select it if((kind == RD_CmdKind_Run || kind == RD_CmdKind_StepInto || @@ -17071,6 +17077,7 @@ rd_frame(void) } if(ws != &rd_nil_window_state) { + rd_state->prestop_focused_window = os_focused_external_window(); os_window_set_minimized(ws->os, 0); os_window_bring_to_front(ws->os); os_window_focus(ws->os); diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 2cdcabc0..f56ec8ed 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -705,6 +705,9 @@ struct RD_State B32 bind_change_active; RD_CfgID bind_change_binding_id; String8 bind_change_cmd_name; + + // rjf: pre-stop focused window + OS_Handle prestop_focused_window; }; //////////////////////////////// From 1b82c5280359af3d15e24605d88dbdf74e3f0c82 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 15 Sep 2025 17:18:59 -0700 Subject: [PATCH 169/302] only enable priority thread running on initial run loop; do not pay the cost every run loop iteration --- src/ctrl/ctrl_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 07f828fb..b9b51256 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -5930,7 +5930,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; DMN_TrapChunkList entry_traps = {0}; - for(;;) + for(U64 run_loop_idx = 0;; run_loop_idx += 1) { ////////////////////////// //- rjf: choose low level traps @@ -5954,7 +5954,10 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: setup run controls // DMN_RunCtrls run_ctrls = {0}; - run_ctrls.priority_thread = target_thread.dmn_handle; + if(run_loop_idx == 0) + { + run_ctrls.priority_thread = target_thread.dmn_handle; + } run_ctrls.ignore_previous_exception = 1; run_ctrls.run_entity_count = frozen_threads.count; run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count); From 937c6c8bced789b0e47970c2920d45f9752bd2e9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 16 Sep 2025 10:17:02 -0700 Subject: [PATCH 170/302] eliminate radcon, eliminate unused string helpers --- src/base/base_strings.c | 686 ++++++++++++++++--------------- src/base/base_strings.h | 49 +-- src/coff/coff.c | 194 ++++----- src/coff/coff_obj_writer.c | 123 +++--- src/ctrl/ctrl_core.c | 4 +- src/dbg_engine/dbg_engine_core.c | 2 +- src/dbgi/dbgi.c | 2 +- src/os/gfx/os_gfx.c | 10 +- src/radcon/radcon.c | 481 ---------------------- src/radcon/radcon.h | 66 --- src/radcon/radcon_main.c | 94 ----- src/raddump/raddump.c | 2 +- src/scratch/parse_inline_sites.c | 2 +- 13 files changed, 548 insertions(+), 1167 deletions(-) delete mode 100644 src/radcon/radcon.c delete mode 100644 src/radcon/radcon.h delete mode 100644 src/radcon/radcon_main.c diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 119e9e2b..d2ea3244 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -50,7 +50,7 @@ char_is_digit(U8 c, U32 base) } internal U8 -char_to_lower(U8 c) +lower_from_char(U8 c) { if(char_is_upper(c)) { @@ -60,7 +60,7 @@ char_to_lower(U8 c) } internal U8 -char_to_upper(U8 c) +upper_from_char(U8 c) { if(char_is_lower(c)) { @@ -70,7 +70,7 @@ char_to_upper(U8 c) } internal U8 -char_to_correct_slash(U8 c) +correct_slash_from_char(U8 c) { if(char_is_slash(c)) { @@ -242,7 +242,7 @@ upper_from_str8(Arena *arena, String8 string) string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { - string.str[idx] = char_to_upper(string.str[idx]); + string.str[idx] = upper_from_char(string.str[idx]); } return string; } @@ -253,7 +253,7 @@ lower_from_str8(Arena *arena, String8 string) string = push_str8_copy(arena, string); for(U64 idx = 0; idx < string.size; idx += 1) { - string.str[idx] = char_to_lower(string.str[idx]); + string.str[idx] = lower_from_char(string.str[idx]); } return string; } @@ -292,13 +292,13 @@ str8_match(String8 a, String8 b, StringMatchFlags flags) U8 bt = b.str[i]; if(case_insensitive) { - at = char_to_upper(at); - bt = char_to_upper(bt); + at = upper_from_char(at); + bt = upper_from_char(bt); } if(slash_insensitive) { - at = char_to_correct_slash(at); - bt = char_to_correct_slash(bt); + at = correct_slash_from_char(at); + bt = correct_slash_from_char(bt); } if(at != bt) { @@ -324,14 +324,14 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags U8 needle_first_char_adjusted = needle.str[0]; if(adjusted_flags & StringMatchFlag_CaseInsensitive) { - needle_first_char_adjusted = char_to_upper(needle_first_char_adjusted); + needle_first_char_adjusted = upper_from_char(needle_first_char_adjusted); } for(;p < stop_p; p += 1) { U8 haystack_char_adjusted = *p; if(adjusted_flags & StringMatchFlag_CaseInsensitive) { - haystack_char_adjusted = char_to_upper(haystack_char_adjusted); + haystack_char_adjusted = upper_from_char(haystack_char_adjusted); } if(haystack_char_adjusted == needle_first_char_adjusted) { @@ -397,41 +397,46 @@ str8_is_before(String8 a, String8 b) //~ rjf: String Slicing internal String8 -str8_substr(String8 str, Rng1U64 range){ +str8_substr(String8 str, Rng1U64 range) +{ range.min = ClampTop(range.min, str.size); range.max = ClampTop(range.max, str.size); str.str += range.min; str.size = dim_1u64(range); - return(str); + return str; } internal String8 -str8_prefix(String8 str, U64 size){ +str8_prefix(String8 str, U64 size) +{ str.size = ClampTop(size, str.size); - return(str); + return str; } internal String8 -str8_skip(String8 str, U64 amt){ +str8_skip(String8 str, U64 amt) +{ amt = ClampTop(amt, str.size); str.str += amt; str.size -= amt; - return(str); + return str; } internal String8 -str8_postfix(String8 str, U64 size){ +str8_postfix(String8 str, U64 size) +{ size = ClampTop(size, str.size); str.str = (str.str + str.size) - size; str.size = size; - return(str); + return str; } internal String8 -str8_chop(String8 str, U64 amt){ +str8_chop(String8 str, U64 amt) +{ amt = ClampTop(amt, str.size); str.size -= amt; - return(str); + return str; } internal String8 @@ -550,11 +555,13 @@ push_cstr(Arena *arena, String8 str) //- rjf: string -> integer internal S64 -sign_from_str8(String8 string, String8 *string_tail){ +sign_from_str8(String8 string, String8 *string_tail) +{ // count negative signs U64 neg_count = 0; U64 i = 0; - for (; i < string.size; i += 1){ + for(; i < string.size; i += 1) + { if (string.str[i] == '-'){ neg_count += 1; } @@ -568,18 +575,23 @@ sign_from_str8(String8 string, String8 *string_tail){ // output integer sign S64 sign = (neg_count & 1)?-1:+1; - return(sign); + return sign; } internal B32 -str8_is_integer(String8 string, U32 radix){ +str8_is_integer(String8 string, U32 radix) +{ B32 result = 0; - if (string.size > 0){ - if (1 < radix && radix <= 16){ + if(string.size > 0) + { + if(1 < radix && radix <= 16) + { result = 1; - for (U64 i = 0; i < string.size; i += 1){ + for(U64 i = 0; i < string.size; i += 1) + { U8 c = string.str[i]; - if (!(c < 0x80) || integer_symbol_reverse[c] >= radix){ + if(!(c < 0x80) || integer_symbol_reverse[c] >= radix) + { result = 0; break; } @@ -590,22 +602,26 @@ str8_is_integer(String8 string, U32 radix){ } internal U64 -u64_from_str8(String8 string, U32 radix){ +u64_from_str8(String8 string, U32 radix) +{ U64 x = 0; - if (1 < radix && radix <= 16){ - for (U64 i = 0; i < string.size; i += 1){ + if(1 < radix && radix <= 16) + { + for(U64 i = 0; i < string.size; i += 1) + { x *= radix; x += integer_symbol_reverse[string.str[i]&0x7F]; } } - return(x); + return x; } internal S64 -s64_from_str8(String8 string, U32 radix){ +s64_from_str8(String8 string, U32 radix) +{ S64 sign = sign_from_str8(string, &string); S64 x = (S64)u64_from_str8(string, radix) * sign; - return(x); + return x; } internal U32 @@ -626,36 +642,41 @@ s32_from_str8(String8 string, U32 radix) internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x) -{ - U64 radix, prefix_size; - // hex - if(str8_match(str8_prefix(string, 2), str8_lit("0x"), StringMatchFlag_CaseInsensitive)) - { - radix = 0x10, prefix_size = 2; - } - // binary - else if(str8_match(str8_prefix(string, 2), str8_lit("0b"), StringMatchFlag_CaseInsensitive)) - { - radix = 2, prefix_size = 2; - } - // octal - else if(str8_match(str8_prefix(string, 1), str8_lit("0"), StringMatchFlag_CaseInsensitive) && string.size > 1) - { - radix = 010, prefix_size = 1; - } - // decimal - else - { - radix = 10, prefix_size = 0; - } - +{ + // rjf: unpack radix / prefix size based on string prefix + U64 radix = 0; + U64 prefix_size = 0; + { + // hex + if(str8_match(str8_prefix(string, 2), str8_lit("0x"), StringMatchFlag_CaseInsensitive)) + { + radix = 0x10, prefix_size = 2; + } + // binary + else if(str8_match(str8_prefix(string, 2), str8_lit("0b"), StringMatchFlag_CaseInsensitive)) + { + radix = 2, prefix_size = 2; + } + // octal + else if(str8_match(str8_prefix(string, 1), str8_lit("0"), StringMatchFlag_CaseInsensitive) && string.size > 1) + { + radix = 010, prefix_size = 1; + } + // decimal + else + { + radix = 10, prefix_size = 0; + } + } + + // rjf: convert if we can String8 integer = str8_skip(string, prefix_size); B32 is_integer = str8_is_integer(integer, radix); if(is_integer) { *x = u64_from_str8(integer, radix); - } - + } + return is_integer; } @@ -675,78 +696,78 @@ try_s64_from_str8_c_rules(String8 string, S64 *x) internal String8 str8_from_memory_size(Arena *arena, U64 size) { - String8 result; - - if(size < KB(1)) - { - result = push_str8f(arena, "%llu Bytes", size); - } - else if(size < MB(1)) - { - result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100); - } - else if(size < GB(1)) - { - result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100); - } - else if(size < TB(1)) - { - result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100); - } - else - { - result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100); - } - + String8 result = {0}; + { + if(size < KB(1)) + { + result = push_str8f(arena, "%llu Bytes", size); + } + else if(size < MB(1)) + { + result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100); + } + else if(size < GB(1)) + { + result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100); + } + else if(size < TB(1)) + { + result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100); + } + else + { + result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100); + } + } return result; } internal String8 str8_from_count(Arena *arena, U64 count) { - String8 result; - - if(count < 1 * 1000) + String8 result = {0}; { - result = push_str8f(arena, "%llu", count); - } - else if(count < 1000000) - { - U64 frac = ((count * 100) / 1000) % 100; - if(frac > 0) + if(count < 1 * 1000) { - result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac); + result = push_str8f(arena, "%llu", count); + } + else if(count < 1000000) + { + U64 frac = ((count * 100) / 1000) % 100; + if(frac > 0) + { + result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac); + } + else + { + result = push_str8f(arena, "%lluK", count / 1000); + } + } + else if(count < 1000000000) + { + U64 frac = ((count * 100) / 1000000) % 100; + if(frac > 0) + { + result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac); + } + else + { + result = push_str8f(arena, "%lluM", count / 1000000); + } } else { - result = push_str8f(arena, "%lluK", count / 1000); + U64 frac = ((count * 100) * 1000000000) % 100; + if(frac > 0) + { + result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac); + } + else + { + result = push_str8f(arena, "%lluB", count / 1000000000, frac); + } } } - else if(count < 1000000000) - { - U64 frac = ((count * 100) / 1000000) % 100; - if(frac > 0) - { - result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac); - } - else - { - result = push_str8f(arena, "%lluM", count / 1000000); - } - } - else - { - U64 frac = ((count * 100) * 1000000000) % 100; - if(frac > 0) - { - result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac); - } - else - { - result = push_str8f(arena, "%lluB", count / 1000000000, frac); - } - } - return result; } @@ -859,7 +880,7 @@ str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_se } else { - result.str[result.size - idx - 1] = char_to_lower(integer_symbols[u64_reduce%radix]); + result.str[result.size - idx - 1] = lower_from_char(integer_symbols[u64_reduce%radix]); u64_reduce /= radix; } digits_until_separator -= 1; @@ -951,73 +972,74 @@ f64_from_str8(String8 string) //////////////////////////////// //~ rjf: String List Construction Functions -internal String8Node* -str8_list_push_node(String8List *list, String8Node *node){ - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - list->total_size += node->string.size; - return(node); -} - -internal String8Node* -str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string){ - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - list->total_size += string.size; - node->string = string; - return(node); -} - -internal String8Node* -str8_list_push_node_front(String8List *list, String8Node *node){ - SLLQueuePushFront(list->first, list->last, node); - list->node_count += 1; - list->total_size += node->string.size; - return(node); -} - -internal String8Node* -str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string){ - SLLQueuePushFront(list->first, list->last, node); - list->node_count += 1; - list->total_size += string.size; - node->string = string; - return(node); -} - -internal String8Node* -str8_list_push(Arena *arena, String8List *list, String8 string){ - String8Node *node = push_array_no_zero(arena, String8Node, 1); - str8_list_push_node_set_string(list, node, string); - return(node); -} - internal String8Node * -str8_list_push_cstr(Arena *arena, String8List *list, String8 string) +str8_list_push_node(String8List *list, String8Node *node) { - String8Node *node = str8_list_push(arena, list, string); - local_persist String8 null = str8_lit_comp("\0"); - str8_list_push(arena, list, null); + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; return node; } -internal String8Node* -str8_list_push_front(Arena *arena, String8List *list, String8 string){ +internal String8Node * +str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string) +{ + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return node; +} + +internal String8Node * +str8_list_push_node_front(String8List *list, String8Node *node) +{ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += node->string.size; + return node; +} + +internal String8Node * +str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string) +{ + SLLQueuePushFront(list->first, list->last, node); + list->node_count += 1; + list->total_size += string.size; + node->string = string; + return node; +} + +internal String8Node * +str8_list_push(Arena *arena, String8List *list, String8 string) +{ + String8Node *node = push_array_no_zero(arena, String8Node, 1); + str8_list_push_node_set_string(list, node, string); + return node; +} + +internal String8Node * +str8_list_push_front(Arena *arena, String8List *list, String8 string) +{ String8Node *node = push_array_no_zero(arena, String8Node, 1); str8_list_push_node_front_set_string(list, node, string); - return(node); + return node; } internal void -str8_list_concat_in_place(String8List *list, String8List *to_push){ - if(to_push->node_count != 0){ - if (list->last){ +str8_list_concat_in_place(String8List *list, String8List *to_push) +{ + if(to_push->node_count != 0) + { + if(list->last) + { list->node_count += to_push->node_count; list->total_size += to_push->total_size; list->last->next = to_push->first; list->last = to_push->last; } - else{ + else + { *list = *to_push; } MemoryZeroStruct(to_push); @@ -1048,7 +1070,8 @@ str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){ } internal String8Node* -str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ +str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) +{ va_list args; va_start(args, fmt); String8 string = push_str8fv(arena, fmt, args); @@ -1058,7 +1081,8 @@ str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...){ } internal String8Node* -str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ +str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...) +{ va_list args; va_start(args, fmt); String8 string = push_str8fv(arena, fmt, args); @@ -1068,11 +1092,11 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...){ } internal String8List -str8_list_copy(Arena *arena, String8List *list){ +str8_list_copy(Arena *arena, String8List *list) +{ String8List result = {0}; - for (String8Node *node = list->first; - node != 0; - node = node->next){ + for(String8Node *node = list->first; node != 0; node = node->next) + { String8Node *new_node = push_array_no_zero(arena, String8Node, 1); String8 new_string = push_str8_copy(arena, node->string); str8_list_push_node_set_string(&result, new_node, new_string); @@ -1080,103 +1104,89 @@ str8_list_copy(Arena *arena, String8List *list){ return result; } +//////////////////////////////// +//~ rjf: String Splitting & Joining + internal String8List -str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags){ +str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags) +{ String8List list = {0}; - B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); - U8 *ptr = string.str; U8 *opl = string.str + string.size; - for (;ptr < opl;){ + for(;ptr < opl;) + { U8 *first = ptr; - for (;ptr < opl; ptr += 1){ + for(;ptr < opl; ptr += 1) + { U8 c = *ptr; B32 is_split = 0; - for (U64 i = 0; i < split_char_count; i += 1){ - if (split_chars[i] == c){ + for(U64 i = 0; i < split_char_count; i += 1) + { + if(split_chars[i] == c) + { is_split = 1; break; } } - if (is_split){ + if(is_split) + { break; } } - String8 string = str8_range(first, ptr); - if (keep_empties || string.size > 0){ + if(keep_empties || string.size > 0) + { str8_list_push(arena, &list, string); } ptr += 1; } - - return(list); -} - -internal String8List -str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags){ - String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); return list; } internal String8List -str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags){ - String8List result = {0}; - for (String8Node *node = list.first; node != 0; node = node->next){ - String8List split = str8_split_by_string_chars(arena, node->string, split_chars, flags); - str8_list_concat_in_place(&result, &split); - } - return result; +str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags) +{ + String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); + return list; } internal String8 -str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params){ +str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params) +{ StringJoin join = {0}; - if (optional_params != 0){ + if(optional_params != 0) + { MemoryCopyStruct(&join, optional_params); } - U64 sep_count = 0; - if (list->node_count > 0){ + if(list->node_count > 0) + { sep_count = list->node_count - 1; } - String8 result; result.size = join.pre.size + join.post.size + sep_count*join.sep.size + list->total_size; U8 *ptr = result.str = push_array_no_zero(arena, U8, result.size + 1); - MemoryCopy(ptr, join.pre.str, join.pre.size); ptr += join.pre.size; - for (String8Node *node = list->first; - node != 0; - node = node->next){ + for(String8Node *node = list->first; + node != 0; + node = node->next) + { MemoryCopy(ptr, node->string.str, node->string.size); ptr += node->string.size; - if (node->next != 0){ + if(node->next != 0) + { MemoryCopy(ptr, join.sep.str, join.sep.size); ptr += join.sep.size; } } MemoryCopy(ptr, join.post.str, join.post.size); ptr += join.post.size; - *ptr = 0; - return result; } -internal void -str8_list_from_flags(Arena *arena, String8List *list, - U32 flags, String8 *flag_string_table, U32 flag_string_count){ - for (U32 i = 0; i < flag_string_count; i += 1){ - U32 flag = (1 << i); - if (flags & flag){ - str8_list_push(arena, list, flag_string_table[i]); - } - } -} - //////////////////////////////// //~ rjf: Basic Data Structure Stringification Helpers @@ -1208,7 +1218,7 @@ internal String8Array str8_array_from_list(Arena *arena, String8List *list) { String8Array array; - array.count = list->node_count; + array.count = list->node_count; array.v = push_array_no_zero(arena, String8, array.count); U64 idx = 0; for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) @@ -1281,7 +1291,7 @@ str8_from_version(Arena *arena, U64 version) U64 version_major = MajorFromVersion(version); U64 version_minor = MinorFromVersion(version); U64 version_patch = PatchFromVersion(version); - String8 result = push_str8f(arena, "%I64d.%I64d.%I64d", version_major, version_minor, version_patch); + String8 result = str8f(arena, "%I64d.%I64d.%I64d", version_major, version_minor, version_patch); return result; } @@ -1400,7 +1410,13 @@ str8_split_path(Arena *arena, String8 string) internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style) { - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(0, 0); + typedef struct String8MetaNode String8MetaNode; + struct String8MetaNode + { + String8MetaNode *next; + String8Node *node; + }; String8MetaNode *stack = 0; String8MetaNode *free_meta_node = 0; String8Node *first = path->first; @@ -1773,23 +1789,25 @@ internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext) { String8 file_name_no_ext = str8_chop_last_dot(file_name); - String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext); + String8 result = str8f(arena, "%S.%S", file_name_no_ext, ext); return result; } //////////////////////////////// //~ rjf: UTF-8 & UTF-16 Decoding/Encoding -read_only global U8 utf8_class[32] = { +read_only global U8 utf8_class[32] = +{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; internal UnicodeDecode -utf8_decode(U8 *str, U64 max){ +utf8_decode(U8 *str, U64 max) +{ UnicodeDecode result = {1, max_U32}; U8 byte = str[0]; U8 byte_class = utf8_class[byte >> 3]; - switch (byte_class) + switch(byte_class) { case 1: { @@ -1797,10 +1815,10 @@ utf8_decode(U8 *str, U64 max){ }break; case 2: { - if (1 < max) + if(1 < max) { U8 cont_byte = str[1]; - if (utf8_class[cont_byte >> 3] == 0) + if(utf8_class[cont_byte >> 3] == 0) { result.codepoint = (byte & bitmask5) << 6; result.codepoint |= (cont_byte & bitmask6); @@ -1810,11 +1828,11 @@ utf8_decode(U8 *str, U64 max){ }break; case 3: { - if (2 < max) + if(2 < max) { U8 cont_byte[2] = {str[1], str[2]}; - if (utf8_class[cont_byte[0] >> 3] == 0 && - utf8_class[cont_byte[1] >> 3] == 0) + if(utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0) { result.codepoint = (byte & bitmask4) << 12; result.codepoint |= ((cont_byte[0] & bitmask6) << 6); @@ -1825,12 +1843,12 @@ utf8_decode(U8 *str, U64 max){ }break; case 4: { - if (3 < max) + if(3 < max) { U8 cont_byte[3] = {str[1], str[2], str[3]}; - if (utf8_class[cont_byte[0] >> 3] == 0 && - utf8_class[cont_byte[1] >> 3] == 0 && - utf8_class[cont_byte[2] >> 3] == 0) + if(utf8_class[cont_byte[0] >> 3] == 0 && + utf8_class[cont_byte[1] >> 3] == 0 && + utf8_class[cont_byte[2] >> 3] == 0) { result.codepoint = (byte & bitmask3) << 18; result.codepoint |= ((cont_byte[0] & bitmask6) << 12); @@ -1845,11 +1863,13 @@ utf8_decode(U8 *str, U64 max){ } internal UnicodeDecode -utf16_decode(U16 *str, U64 max){ +utf16_decode(U16 *str, U64 max) +{ UnicodeDecode result = {1, max_U32}; result.codepoint = str[0]; result.inc = 1; - if (max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000){ + if(max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000) + { result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000); result.inc = 2; } @@ -1857,58 +1877,63 @@ utf16_decode(U16 *str, U64 max){ } internal U32 -utf8_encode(U8 *str, U32 codepoint){ +utf8_encode(U8 *str, U32 codepoint) +{ U32 inc = 0; - if (codepoint <= 0x7F){ + if(codepoint <= 0x7F) + { str[0] = (U8)codepoint; inc = 1; } - else if (codepoint <= 0x7FF){ + else if(codepoint <= 0x7FF) + { str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5); str[1] = bit8 | (codepoint & bitmask6); inc = 2; } - else if (codepoint <= 0xFFFF){ + else if(codepoint <= 0xFFFF) + { str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4); str[1] = bit8 | ((codepoint >> 6) & bitmask6); str[2] = bit8 | ( codepoint & bitmask6); inc = 3; } - else if (codepoint <= 0x10FFFF){ + else if(codepoint <= 0x10FFFF) + { str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3); str[1] = bit8 | ((codepoint >> 12) & bitmask6); str[2] = bit8 | ((codepoint >> 6) & bitmask6); str[3] = bit8 | ( codepoint & bitmask6); inc = 4; } - else{ + else + { str[0] = '?'; inc = 1; } - return(inc); + return inc; } internal U32 -utf16_encode(U16 *str, U32 codepoint){ +utf16_encode(U16 *str, U32 codepoint) +{ U32 inc = 1; - if (codepoint == max_U32){ + if(codepoint == max_U32) + { str[0] = (U16)'?'; } - else if (codepoint < 0x10000){ + else if(codepoint < 0x10000) + { str[0] = (U16)codepoint; } - else{ + else + { U32 v = codepoint - 0x10000; str[0] = safe_cast_u16(0xD800 + (v >> 10)); str[1] = safe_cast_u16(0xDC00 + (v & bitmask10)); inc = 2; } - return(inc); -} - -internal U32 -utf8_from_utf32_single(U8 *buffer, U32 character){ - return(utf8_encode(buffer, character)); + return inc; } //////////////////////////////// @@ -2010,7 +2035,7 @@ str32_from_8(Arena *arena, String8 in) } //////////////////////////////// -//~ String -> Enum Conversions +//~ rjf: Basic Types & Space Enum -> String Conversions read_only global struct { @@ -2028,42 +2053,45 @@ StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_c internal OperatingSystem operating_system_from_string(String8 string) { - for(U64 i = 0; i < ArrayCount(g_os_enum_map); ++i) + for EachElement(idx, g_os_enum_map) { - if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive)) + if(str8_match(g_os_enum_map[idx].string, string, StringMatchFlag_CaseInsensitive)) { - return g_os_enum_map[i].os; + return g_os_enum_map[idx].os; } } return OperatingSystem_Null; } -//////////////////////////////// -//~ rjf: Basic Types & Space Enum -> String Conversions - internal String8 -string_from_dimension(Dimension dimension){ - local_persist String8 strings[] = { +string_from_dimension(Dimension dimension) +{ + read_only local_persist String8 strings[] = + { str8_lit_comp("X"), str8_lit_comp("Y"), str8_lit_comp("Z"), str8_lit_comp("W"), }; String8 result = str8_lit("error"); - if ((U32)dimension < 4){ + if((U32)dimension < 4) + { result = strings[dimension]; } return result; } internal String8 -string_from_side(Side side){ - local_persist String8 strings[] = { +string_from_side(Side side) +{ + local_persist String8 strings[] = + { str8_lit_comp("Min"), str8_lit_comp("Max"), }; String8 result = str8_lit("error"); - if ((U32)side < 2){ + if((U32)side < 2) + { result = strings[side]; } return result; @@ -2081,27 +2109,27 @@ string_from_operating_system(OperatingSystem os) } internal String8 -string_from_arch(Arch arch){ - local_persist String8 strings[] = { - str8_lit_comp("Null"), - str8_lit_comp("x64"), - str8_lit_comp("x86"), - str8_lit_comp("arm64"), - str8_lit_comp("arm32"), - }; - String8 result = str8_lit("error"); - if (arch < Arch_COUNT){ - result = strings[arch]; - } +string_from_arch(Arch arch) +{ + String8 result = {0}; + switch(arch) + { + case Arch_Null: {result = str8_lit("Null");}break; + case Arch_x64: {result = str8_lit("x64");}break; + case Arch_x86: {result = str8_lit("x86");}break; + case Arch_arm64: {result = str8_lit("arm64");}break; + case Arch_arm32: {result = str8_lit("arm32");}break; + case Arch_COUNT: + {result = str8_lit("Invalid");}break; + } return result; } -//////////////////////////////// -//~ rjf: Time Types -> String - internal String8 -string_from_week_day(WeekDay week_day){ - local_persist String8 strings[] = { +string_from_week_day(WeekDay week_day) +{ + read_only local_persist String8 strings[] = + { str8_lit_comp("Sun"), str8_lit_comp("Mon"), str8_lit_comp("Tue"), @@ -2111,15 +2139,18 @@ string_from_week_day(WeekDay week_day){ str8_lit_comp("Sat"), }; String8 result = str8_lit("Err"); - if ((U32)week_day < WeekDay_COUNT){ + if((U32)week_day < WeekDay_COUNT) + { result = strings[week_day]; } return result; } internal String8 -string_from_month(Month month){ - local_persist String8 strings[] = { +string_from_month(Month month) +{ + read_only local_persist String8 strings[] = + { str8_lit_comp("Jan"), str8_lit_comp("Feb"), str8_lit_comp("Mar"), @@ -2134,21 +2165,25 @@ string_from_month(Month month){ str8_lit_comp("Dec"), }; String8 result = str8_lit("Err"); - if ((U32)month < Month_COUNT){ + if((U32)month < Month_COUNT) + { result = strings[month]; } return result; } internal String8 -push_date_time_string(Arena *arena, DateTime *date_time){ +string_from_date_time(Arena *arena, DateTime *date_time) +{ char *mon_str = (char*)string_from_month(date_time->month).str; U32 adjusted_hour = date_time->hour%12; - if (adjusted_hour == 0){ + if(adjusted_hour == 0) + { adjusted_hour = 12; } char *ampm = "am"; - if (date_time->hour >= 12){ + if(date_time->hour >= 12) + { ampm = "pm"; } String8 result = push_str8f(arena, "%d %s %d, %02d:%02d:%02d %s", @@ -2158,26 +2193,33 @@ push_date_time_string(Arena *arena, DateTime *date_time){ } internal String8 -push_file_name_date_time_string(Arena *arena, DateTime *date_time){ +string_from_date_time__file_name(Arena *arena, DateTime *date_time) +{ char *mon_str = (char*)string_from_month(date_time->month).str; - String8 result = push_str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", - date_time->year, mon_str, date_time->day, - date_time->hour, date_time->min, date_time->sec); + String8 result = str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", + date_time->year, mon_str, date_time->day, + date_time->hour, date_time->min, date_time->sec); return result; } internal String8 -string_from_elapsed_time(Arena *arena, DateTime dt){ +string_from_elapsed_time(Arena *arena, DateTime dt) +{ Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; - if (dt.year){ + if(dt.year) + { str8_list_pushf(scratch.arena, &list, "%dy", dt.year); str8_list_pushf(scratch.arena, &list, "%um", dt.mon); str8_list_pushf(scratch.arena, &list, "%ud", dt.day); - } else if (dt.mon){ + } + else if(dt.mon) + { str8_list_pushf(scratch.arena, &list, "%um", dt.mon); str8_list_pushf(scratch.arena, &list, "%ud", dt.day); - } else if (dt.day){ + } + else if (dt.day) + { str8_list_pushf(scratch.arena, &list, "%ud", dt.day); } str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec); @@ -2188,23 +2230,23 @@ string_from_elapsed_time(Arena *arena, DateTime dt){ } //////////////////////////////// -//~ Globally UNique Ids +//~ rjf: String <-> Globally Unique IDs internal String8 string_from_guid(Arena *arena, Guid guid) { - String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - guid.data1, - guid.data2, - guid.data3, - guid.data4[0], - guid.data4[1], - guid.data4[2], - guid.data4[3], - guid.data4[4], - guid.data4[5], - guid.data4[6], - guid.data4[7]); + String8 result = str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + guid.data1, + guid.data2, + guid.data3, + guid.data4[0], + guid.data4[1], + guid.data4[2], + guid.data4[3], + guid.data4[4], + guid.data4[5], + guid.data4[6], + guid.data4[7]); return result; } @@ -2458,7 +2500,7 @@ wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba) { - String8 hex_string = push_str8f(arena, "%02x%02x%02x%02x", (U8)(rgba.x*255.f), (U8)(rgba.y*255.f), (U8)(rgba.z*255.f), (U8)(rgba.w*255.f)); + String8 hex_string = str8f(arena, "%02x%02x%02x%02x", (U8)(rgba.x*255.f), (U8)(rgba.y*255.f), (U8)(rgba.z*255.f), (U8)(rgba.w*255.f)); return hex_string; } @@ -2471,7 +2513,7 @@ rgba_from_hex_string_4f32(String8 hex_string) { if(char_is_digit(hex_string.str[idx], 16)) { - byte_text[byte_text_idx] = char_to_lower(hex_string.str[idx]); + byte_text[byte_text_idx] = lower_from_char(hex_string.str[idx]); byte_text_idx += 1; } } @@ -2774,8 +2816,8 @@ str8_compar(String8 a, String8 b, B32 ignore_case) U64 size = Min(a.size, b.size); if (ignore_case) { for (U64 i = 0; i < size; ++i) { - U8 la = char_to_lower(a.str[i]); - U8 lb = char_to_lower(b.str[i]); + U8 la = lower_from_char(a.str[i]); + U8 lb = lower_from_char(b.str[i]); if (la < lb) { cmp = -1; break; diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 830f7762..06459427 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -38,13 +38,6 @@ struct String8Node String8 string; }; -typedef struct String8MetaNode String8MetaNode; -struct String8MetaNode -{ - String8MetaNode *next; - String8Node *node; -}; - typedef struct String8List String8List; struct String8List { @@ -59,6 +52,7 @@ struct String8Array { String8 *v; U64 count; + U64 total_size; }; //////////////////////////////// @@ -152,9 +146,9 @@ internal B32 char_is_lower(U8 c); internal B32 char_is_alpha(U8 c); internal B32 char_is_slash(U8 c); internal B32 char_is_digit(U8 c, U32 base); -internal U8 char_to_lower(U8 c); -internal U8 char_to_upper(U8 c); -internal U8 char_to_correct_slash(U8 c); +internal U8 lower_from_char(U8 c); +internal U8 upper_from_char(U8 c); +internal U8 correct_slash_from_char(U8 c); //////////////////////////////// //~ rjf: C-String Measurement @@ -262,12 +256,12 @@ internal F64 f64_from_str8(String8 string); //////////////////////////////// //~ rjf: String List Construction Functions -internal String8Node* str8_list_push_node(String8List *list, String8Node *node); -internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string); -internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node); -internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string); -internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string); -internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string); +internal String8Node *str8_list_push_node(String8List *list, String8Node *node); +internal String8Node *str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node *str8_list_push_node_front(String8List *list, String8Node *node); +internal String8Node *str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string); +internal String8Node *str8_list_push(Arena *arena, String8List *list, String8 string); +internal String8Node *str8_list_push_front(Arena *arena, String8List *list, String8 string); internal void str8_list_concat_in_place(String8List *list, String8List *to_push); internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align); internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...); @@ -280,9 +274,7 @@ internal String8List str8_list_copy(Arena *arena, String8List *list); internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags); internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags); -internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags); internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params); -internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count); //////////////////////////////// //~ rjf: Basic Data Stringification Helpers @@ -298,7 +290,7 @@ internal String8Array str8_array_reserve(Arena *arena, U64 count); internal String8Array str8_array_copy(Arena *arena, String8Array array); //////////////////////////////// -//~ rjf: String Version Helpers +//~ rjf: String <-> Version Helpers internal U64 version_from_str8(String8 string); internal String8 str8_from_version(Arena *arena, U64 version); @@ -362,7 +354,6 @@ internal UnicodeDecode utf8_decode(U8 *str, U64 max); internal UnicodeDecode utf16_decode(U16 *str, U64 max); internal U32 utf8_encode(U8 *str, U32 codepoint); internal U32 utf16_encode(U16 *str, U32 codepoint); -internal U32 utf8_from_utf32_single(U8 *buffer, U32 character); //////////////////////////////// //~ rjf: Unicode String Conversions @@ -373,29 +364,21 @@ internal String8 str8_from_32(Arena *arena, String32 in); internal String32 str32_from_8(Arena *arena, String8 in); //////////////////////////////// -//~ String -> Enum Conversions +//~ rjf: Basic Types & Space Enum <-> String Conversions internal OperatingSystem operating_system_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Basic Types & Space Enum -> String Conversions - internal String8 string_from_dimension(Dimension dimension); internal String8 string_from_side(Side side); internal String8 string_from_operating_system(OperatingSystem os); internal String8 string_from_arch(Arch arch); - -//////////////////////////////// -//~ rjf: Time Types -> String - internal String8 string_from_week_day(WeekDay week_day); internal String8 string_from_month(Month month); -internal String8 push_date_time_string(Arena *arena, DateTime *date_time); -internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time); +internal String8 string_from_date_time(Arena *arena, DateTime *date_time); +internal String8 string_from_date_time__file_name(Arena *arena, DateTime *date_time); internal String8 string_from_elapsed_time(Arena *arena, DateTime dt); //////////////////////////////// -//~ Globally Unique Ids +//~ rjf: String <-> Globally Unique IDs internal String8 string_from_guid(Arena *arena, Guid guid); internal B32 try_guid_from_string(String8 string, Guid *guid_out); @@ -467,4 +450,4 @@ internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, Stri internal U64 u64_hash_from_seed_str8(U64 seed, String8 string); internal U64 u64_hash_from_str8(String8 string); -#endif //BASE_STRINGS_H +#endif // BASE_STRINGS_H diff --git a/src/coff/coff.c b/src/coff/coff.c index e3879768..a37bc009 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -31,21 +31,21 @@ coff_section_flag_from_align_size(U64 align) { COFF_SectionFlags flags = 0; switch (align) { - case 0: flags = COFF_SectionAlign_None; break; - case 1: flags = COFF_SectionAlign_1Bytes; break; - case 2: flags = COFF_SectionAlign_2Bytes; break; - case 4: flags = COFF_SectionAlign_4Bytes; break; - case 8: flags = COFF_SectionAlign_8Bytes; break; - case 16: flags = COFF_SectionAlign_16Bytes; break; - case 32: flags = COFF_SectionAlign_32Bytes; break; - case 64: flags = COFF_SectionAlign_64Bytes; break; - case 128: flags = COFF_SectionAlign_128Bytes; break; - case 256: flags = COFF_SectionAlign_256Bytes; break; - case 512: flags = COFF_SectionAlign_512Bytes; break; - case 1024: flags = COFF_SectionAlign_1024Bytes; break; - case 2048: flags = COFF_SectionAlign_2048Bytes; break; - case 4096: flags = COFF_SectionAlign_4096Bytes; break; - case 8192: flags = COFF_SectionAlign_8192Bytes; break; + case 0: flags = COFF_SectionAlign_None; break; + case 1: flags = COFF_SectionAlign_1Bytes; break; + case 2: flags = COFF_SectionAlign_2Bytes; break; + case 4: flags = COFF_SectionAlign_4Bytes; break; + case 8: flags = COFF_SectionAlign_8Bytes; break; + case 16: flags = COFF_SectionAlign_16Bytes; break; + case 32: flags = COFF_SectionAlign_32Bytes; break; + case 64: flags = COFF_SectionAlign_64Bytes; break; + case 128: flags = COFF_SectionAlign_128Bytes; break; + case 256: flags = COFF_SectionAlign_256Bytes; break; + case 512: flags = COFF_SectionAlign_512Bytes; break; + case 1024: flags = COFF_SectionAlign_1024Bytes; break; + case 2048: flags = COFF_SectionAlign_2048Bytes; break; + case 4096: flags = COFF_SectionAlign_4096Bytes; break; + case 8192: flags = COFF_SectionAlign_8192Bytes; break; } flags <<= COFF_SectionFlag_AlignShift; return flags; @@ -182,67 +182,67 @@ coff_pick_reloc_value_x64(COFF_Reloc_X64 type, { U64 reloc_value_size = 0; S64 reloc_value = 0; - + switch (type) { - case COFF_Reloc_X64_Abs: {} break; - case COFF_Reloc_X64_Addr64: { - reloc_value_size = 8; - reloc_value = symbol_virtual_offset + (S64)image_base; - } break; - case COFF_Reloc_X64_Addr32: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset + (S64)image_base); - } break; - case COFF_Reloc_X64_Addr32Nb: { - reloc_value_size = 4; - reloc_value = symbol_virtual_offset; - } break; - case COFF_Reloc_X64_Rel32: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 0)); - } break; - case COFF_Reloc_X64_Rel32_1: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 1)); - } break; - case COFF_Reloc_X64_Rel32_2: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 2)); - } break; - case COFF_Reloc_X64_Rel32_3: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 3)); - } break; - case COFF_Reloc_X64_Rel32_4: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 4)); - } break; - case COFF_Reloc_X64_Rel32_5: { - reloc_value_size = 4; - reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 5)); - } break; - case COFF_Reloc_X64_Section: { - reloc_value_size = 4; - reloc_value = symbol_section_number; - } break; - case COFF_Reloc_X64_SecRel: { - reloc_value_size = 4; - reloc_value = symbol_section_offset; - } break; - case COFF_Reloc_X64_SecRel7: - case COFF_Reloc_X64_Token: - case COFF_Reloc_X64_SRel32: - case COFF_Reloc_X64_Pair: - case COFF_Reloc_X64_SSpan32: - case COFF_Reloc_X64_Unknown_11: { - NotImplemented; - } break; + case COFF_Reloc_X64_Abs: {} break; + case COFF_Reloc_X64_Addr64: { + reloc_value_size = 8; + reloc_value = symbol_virtual_offset + (S64)image_base; + } break; + case COFF_Reloc_X64_Addr32: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset + (S64)image_base); + } break; + case COFF_Reloc_X64_Addr32Nb: { + reloc_value_size = 4; + reloc_value = symbol_virtual_offset; + } break; + case COFF_Reloc_X64_Rel32: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 0)); + } break; + case COFF_Reloc_X64_Rel32_1: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 1)); + } break; + case COFF_Reloc_X64_Rel32_2: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 2)); + } break; + case COFF_Reloc_X64_Rel32_3: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 3)); + } break; + case COFF_Reloc_X64_Rel32_4: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 4)); + } break; + case COFF_Reloc_X64_Rel32_5: { + reloc_value_size = 4; + reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 5)); + } break; + case COFF_Reloc_X64_Section: { + reloc_value_size = 4; + reloc_value = symbol_section_number; + } break; + case COFF_Reloc_X64_SecRel: { + reloc_value_size = 4; + reloc_value = symbol_section_offset; + } break; + case COFF_Reloc_X64_SecRel7: + case COFF_Reloc_X64_Token: + case COFF_Reloc_X64_SRel32: + case COFF_Reloc_X64_Pair: + case COFF_Reloc_X64_SSpan32: + case COFF_Reloc_X64_Unknown_11: { + NotImplemented; + } break; } - + COFF_RelocValue result = {0}; result.size = reloc_value_size; result.value = reloc_value; - + return result; } @@ -265,7 +265,7 @@ coff_make_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stam str8_list_pushf(scratch.arena, &list, "%-10u", size); str8_list_pushf(scratch.arena, &list, "`\n"); String8 result = str8_list_join(arena, &list, 0); - + Assert(result.size == sizeof(COFF_ArchiveMemberHeader)); scratch_end(scratch); return result; @@ -302,18 +302,18 @@ coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) { String8 ordinal_data = {0}; switch (machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: { - U64 *ordinal = push_array(arena, U64, 1); - *ordinal = coff_make_ordinal64(hint); - ordinal_data = str8_struct(ordinal); - } break; - case COFF_MachineType_X86: { - U32 *ordinal = push_array(arena, U32, 1); - *ordinal = coff_make_ordinal32(hint); - ordinal_data = str8_struct(ordinal); - } break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { + U64 *ordinal = push_array(arena, U64, 1); + *ordinal = coff_make_ordinal64(hint); + ordinal_data = str8_struct(ordinal); + } break; + case COFF_MachineType_X86: { + U32 *ordinal = push_array(arena, U32, 1); + *ordinal = coff_make_ordinal32(hint); + ordinal_data = str8_struct(ordinal); + } break; + default: { NotImplemented; } break; } return ordinal_data; } @@ -331,7 +331,7 @@ coff_make_import_header(Arena *arena, COFF_ImportHeaderFlags flags = 0; flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift; flags |= import_by << COFF_ImportHeader_ImportByShift; - + COFF_ImportHeader header = {0}; header.sig1 = COFF_MachineType_Unknown; header.sig2 = max_U16; @@ -368,12 +368,12 @@ coff_code_align_byte_from_machine(COFF_MachineType machine) { U8 align_byte = 0; switch (machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: - case COFF_MachineType_X86: { - align_byte = 0xCC; - } break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: + case COFF_MachineType_X86: { + align_byte = 0xCC; + } break; + default: { NotImplemented; } break; } return align_byte; } @@ -383,11 +383,11 @@ coff_default_align_from_machine(COFF_MachineType machine) { U16 align = 0; switch (machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: { - align = 16; - } break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { + align = 16; + } break; + default: { NotImplemented; } break; } return align; } @@ -472,7 +472,7 @@ coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp) result = str8_lit("-1"); } else { DateTime dt = date_time_from_unix_time(time_stamp); - result = push_date_time_string(arena, &dt); + result = string_from_date_time(arena, &dt); } return result; } diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 2a8a91af..419fc398 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -20,14 +20,14 @@ internal String8 coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) { Temp scratch = scratch_begin(&arena, 1); - + String8List srl = {0}; - + String8List string_table = {0}; U32 *string_table_size = push_array(scratch.arena, U32, 1); *string_table_size = sizeof(*string_table_size); str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size)); - + // // assing section numbers // @@ -41,11 +41,11 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) COFF_ObjSection *sect = §_n->v; sect->section_number = sect_idx+1; obj_sections[sect_idx] = sect; - + } } AssertAlways(obj_sections_count <= max_U16); - + // // serialize symbol table // @@ -55,26 +55,27 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) U64 symbol_idx = 0; for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) { COFF_ObjSymbol *s = &symbol_n->v; - + // assign symbol index s->idx = symbol_idx++; symbol_idx += s->aux_symbols.node_count; } } - + U64 symbol_idx = 0; for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) { COFF_ObjSymbol *s = &symbol_n->v; - + COFF_Symbol16 *d = push_array(scratch.arena, COFF_Symbol16, 1); str8_list_push(scratch.arena, &symbol_table, str8_struct(d)); - + COFF_SymbolName name = {0}; // long name if (s->name.size > sizeof(name.short_name)) { U64 string_table_offset = string_table.total_size; - str8_list_push_cstr(scratch.arena, &string_table, s->name); - + str8_list_push(scratch.arena, &string.table, s->name); + str8_list_push(scratch.arena, &string.table, str8_lit("\0")); + name.long_name.zeroes = 0; name.long_name.string_table_offset = safe_cast_u32(string_table_offset); } @@ -83,22 +84,22 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) MemoryCopyStr8(name.short_name, s->name); MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size); } - + // symbol header AssertAlways(s->aux_symbols.node_count <= max_U8); d->name = name; d->value = s->value; switch (s->loc.type) { - case COFF_SymbolLocation_Null: break; - case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break; - case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break; - case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break; - case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break; + case COFF_SymbolLocation_Null: break; + case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break; + case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break; + case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break; + case COFF_SymbolLocation_Common: d->section_number = COFF_Symbol_UndefinedSection; break; } d->type = s->type; d->storage_class = s->storage_class; d->aux_symbol_count = 0; - + U64 start_symbol_idx = symbol_idx; if (s->storage_class == COFF_SymStorageClass_WeakExternal) { if (s->aux_symbols.node_count > 0) { @@ -106,7 +107,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) COFF_SymbolWeakExt *d_weak = push_array(scratch.arena, COFF_SymbolWeakExt, 1); d_weak->tag_index = s_weak->tag ? s_weak->tag->idx : max_U32; d_weak->characteristics = s_weak->characteristics; - + str8_list_push(scratch.arena, &symbol_table, str8_struct(d_weak)); symbol_idx += 1; } @@ -114,32 +115,32 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) if (s->aux_symbols.node_count > 0) { Assert(s->loc.type == COFF_SymbolLocation_Section); COFF_ObjSection *sect = s->loc.u.section; - + COFF_ObjSymbolSecDef *s_sd = (COFF_ObjSymbolSecDef *)s->aux_symbols.first->string.str; COFF_SymbolSecDef *d_sd = push_array(scratch.arena, COFF_SymbolSecDef, 1); - + d_sd->length = safe_cast_u32(sect->data.total_size); d_sd->number_of_relocations = (U16)sect->reloc_count; d_sd->check_sum = 0; d_sd->number_lo = s_sd->selection == COFF_ComdatSelect_Associative ? safe_cast_u16(s_sd->associate->section_number) : 0; d_sd->selection = s_sd->selection; - + str8_list_push(scratch.arena, &symbol_table, str8_struct(d_sd)); symbol_idx += 1; } } - + U8 processed_aux_symbol_count = (U8)(symbol_idx - start_symbol_idx); - + for (U64 aux_idx = processed_aux_symbol_count; aux_idx < s->aux_symbols.node_count; aux_idx += 1) { COFF_Symbol16 *a = push_array(scratch.arena, COFF_Symbol16, 1); str8_list_push(scratch.arena, &symbol_table, str8_struct(a)); } - + d->aux_symbol_count = (U8)s->aux_symbols.node_count; } } - + // // file header // @@ -152,35 +153,35 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) file_header->optional_header_size = 0; file_header->flags = 0; str8_list_push(scratch.arena, &srl, str8_struct(file_header)); - + // // section table // - + COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count); str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count)); { for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) { COFF_ObjSection *s = obj_sections[sect_idx]; COFF_SectionHeader *d = §ab[sect_idx]; - + // section name String8 sect_name = s->name; if (sect_name.size > sizeof(d->name)) { U64 sect_name_off = string_table.total_size; str8_list_push_cstr(scratch.arena, &string_table, sect_name); - + sect_name = push_str8f(scratch.arena, "/%u", sect_name_off); AssertAlways(sect_name.size <= sizeof(d->name)); } - + // alloc zero nodes for (String8Node *data_n = s->data.first; data_n != 0; data_n = data_n->next) { if (data_n->string.str == 0 && data_n->string.size > 0) { data_n->string = str8(push_array(scratch.arena, U8, data_n->string.size), data_n->string.size); } } - + // section data U64 data_foff = 0; U64 data_size = 0; @@ -189,7 +190,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) data_size = s->data.total_size; str8_list_concat_in_place(&srl, &s->data); } - + // section relocs U64 relocs_foff = 0; if (s->reloc_count) { @@ -206,7 +207,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) relocs_foff = srl.total_size; str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count)); } - + // section header MemoryCopyStr8(d->name, sect_name); MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size); @@ -221,7 +222,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) d->flags = s->flags; } } - + // // symbol table // @@ -229,7 +230,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) file_header->symbol_table_foff = srl.total_size; str8_list_concat_in_place(&srl, &symbol_table); } - + // // string table // @@ -237,12 +238,12 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) *string_table_size = safe_cast_u32(string_table.total_size); str8_list_concat_in_place(&srl, &string_table); } - + // // join // String8 obj = str8_list_join(arena, &srl, 0); - + scratch_end(scratch); return obj; } @@ -253,15 +254,15 @@ coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_Sect COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1); SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n); obj_writer->sect_count += 1; - + COFF_ObjSection *sect = §_n->v; sect->name = name; sect->flags = flags; - + if (data.size) { str8_list_push(obj_writer->arena, §->data, data); } - + return sect; } @@ -271,14 +272,14 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1); SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n); obj_writer->symbol_count += 1; - + COFF_ObjSymbol *s = &n->v; s->name = name; s->value = value; s->loc = loc; s->type = type; s->storage_class = storage_class; - + return s; } @@ -307,9 +308,9 @@ coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 COFF_SymbolLocation loc = {0}; loc.type = COFF_SymbolLocation_Section; loc.u.section = section; - + COFF_SymbolType symtype = {0}; - + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, symtype, COFF_SymStorageClass_Static); return s; } @@ -341,13 +342,13 @@ coff_obj_writer_push_symbol_weak(COFF_ObjWriter *obj_writer, String8 name, COFF_ COFF_SymbolLocation loc = {0}; COFF_SymbolType symtype = {0}; COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, COFF_Symbol_UndefinedSection, loc, symtype, COFF_SymStorageClass_WeakExternal); - + COFF_ObjSymbolWeak *weak_ext = push_array(obj_writer->arena, COFF_ObjSymbolWeak, 1); weak_ext->tag = tag; weak_ext->characteristics = characteristics; - + str8_list_push(obj_writer->arena, &s->aux_symbols, str8_struct(weak_ext)); - + return s; } @@ -398,10 +399,10 @@ coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ COFF_SymbolLocation loc = {0}; loc.type = COFF_SymbolLocation_Section; loc.u.section = sect; - + // strip align flags COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift); - + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section); return s; } @@ -430,12 +431,12 @@ coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection * COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1); SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n); sect->reloc_count += 1; - + COFF_ObjReloc *reloc = &reloc_n->v; reloc->apply_off = apply_off; reloc->symbol = symbol; reloc->type = type; - + return reloc; } @@ -444,9 +445,9 @@ coff_obj_writer_section_push_reloc_addr32(COFF_ObjWriter *obj_writer, COFF_ObjSe { COFF_RelocType reloc_type = 0; switch (obj_writer->machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32; break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32; break; + default: { NotImplemented; } break; } return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type); } @@ -456,9 +457,9 @@ coff_obj_writer_section_push_reloc_addr(COFF_ObjWriter *obj_writer, COFF_ObjSect { COFF_RelocType reloc_type = 0; switch (obj_writer->machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr64; break; + default: { NotImplemented; } break; } return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type); } @@ -468,9 +469,9 @@ coff_obj_writer_section_push_reloc_voff(COFF_ObjWriter *obj_writer, COFF_ObjSect { COFF_RelocType reloc_type = 0; switch (obj_writer->machine) { - case COFF_MachineType_Unknown: break; - case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break; - default: { NotImplemented; } break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: reloc_type = COFF_Reloc_X64_Addr32Nb; break; + default: { NotImplemented; } break; } return coff_obj_writer_section_push_reloc(obj_writer, sect, apply_off, symbol, reloc_type); } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index b9b51256..ec12c673 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3991,8 +3991,8 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope * String8 filename_normalized = push_str8_copy(scratch.arena, filename); for(U64 idx = 0; idx < filename_normalized.size; idx += 1) { - filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); - filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); + filename_normalized.str[idx] = lower_from_char(filename_normalized.str[idx]); + filename_normalized.str[idx] = correct_slash_from_char(filename_normalized.str[idx]); } // rjf: filename -> src_id diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 980f99ae..e72a46aa 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -37,7 +37,7 @@ d_hash_from_seed_string__case_insensitive(U64 seed, String8 string) U64 result = seed; for(U64 i = 0; i < string.size; i += 1) { - result = ((result << 5) + result) + char_to_lower(string.str[i]); + result = ((result << 5) + result) + lower_from_char(string.str[i]); } return result; } diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 87bb07ec..49aec576 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -13,7 +13,7 @@ di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags) U64 result = seed; for(U64 i = 0; i < string.size; i += 1) { - result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? char_to_lower(string.str[i]) : string.str[i]); + result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? lower_from_char(string.str[i]) : string.str[i]); } return result; } diff --git a/src/os/gfx/os_gfx.c b/src/os/gfx/os_gfx.c index ec0ccade..3b584ec0 100644 --- a/src/os/gfx/os_gfx.c +++ b/src/os/gfx/os_gfx.c @@ -35,13 +35,9 @@ internal String8List os_string_list_from_modifiers(Arena *arena, OS_Modifiers modifiers) { String8List result = {0}; - String8 modifier_strs[] = - { - str8_lit("Ctrl"), - str8_lit("Shift"), - str8_lit("Alt"), - }; - str8_list_from_flags(arena, &result, modifiers, modifier_strs, ArrayCount(modifier_strs)); + if(modifiers & OS_Modifier_Ctrl) { str8_list_push(arena, &result, str8_lit("Ctrl")); } + if(modifiers & OS_Modifier_Shift) { str8_list_push(arena, &result, str8_lit("Shift")); } + if(modifiers & OS_Modifier_Alt) { str8_list_push(arena, &result, str8_lit("Alt")); } return result; } diff --git a/src/radcon/radcon.c b/src/radcon/radcon.c deleted file mode 100644 index 1cd0643b..00000000 --- a/src/radcon/radcon.c +++ /dev/null @@ -1,481 +0,0 @@ -internal String8 -rc_data_from_file_path(Arena *arena, String8 path) -{ - String8 data = os_data_from_file_path(arena, path); - if (data.size == 0) { - fprintf(stderr, "error: unable to read file %.*s\n", str8_varg(path)); - os_abort(1); - } - return data; -} - -internal RC_Context -rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl) -{ - Temp scratch = scratch_begin(&arena, 1); - - if (cmdl->inputs.node_count > 2) { - fprintf(stderr, "error: too many input files on the command line.\n"); - os_abort(1); - } - - B32 is_pe_present = 0; - B32 is_pdb_present = 0; - B32 is_elf_present = 0; - B32 is_elf_debug_present = 0; - String8 pe_name = {0}; - String8 pe_data = {0}; - String8 pdb_name = {0}; - String8 pdb_data = {0}; - String8 elf_name = {0}; - String8 elf_data = {0}; - String8 elf_debug_name = {0}; - String8 elf_debug_data = {0}; - - // - // Set typed inputs - // - if (cmd_line_has_flag(cmdl, str8_lit("pe"))) { - pe_name = cmd_line_string(cmdl, str8_lit("pe")); - pe_data = rc_data_from_file_path(arena, pe_name); - if (!pe_check_magic(pe_data)) { - fprintf(stderr, "error: -pe:%.*s is not of PE format\n", str8_varg(pe_name)); - os_abort(1); - } - is_pe_present = 1; - } - if (cmd_line_has_flag(cmdl, str8_lit("pdb"))) { - pdb_name = cmd_line_string(cmdl, str8_lit("pdb")); - pdb_data = rc_data_from_file_path(arena, pdb_name); - if (!msf_check_magic_20(pdb_data) && !msf_check_magic_70(pdb_data)) { - fprintf(stderr, "error: -pdb:%.*s is not of PDB format\n", str8_varg(pdb_name)); - os_abort(1); - } - is_pdb_present = 1; - } - if (cmd_line_has_flag(cmdl, str8_lit("elf"))) { - elf_name = cmd_line_string(cmdl, str8_lit("elf")); - elf_data = rc_data_from_file_path(arena, elf_name); - if (!elf_check_magic(elf_data)) { - fprintf(stderr, "error: -elf:%.*s is not of ELF format\n", str8_varg(elf_name)); - os_abort(1); - } - is_elf_present = 1; - } - if (cmd_line_has_flag(cmdl, str8_lit("elf_debug"))) { - elf_debug_name = cmd_line_string(cmdl, str8_lit("elf_debug")); - elf_debug_data = rc_data_from_file_path(arena, elf_debug_name); - if (!elf_check_magic(elf_debug_data)) { - fprintf(stderr, "error: -elf_debug:%.*s is not of ELF format\n", str8_varg(elf_debug_name)); - os_abort(1); - } - is_elf_debug_present = 1; - } - - // - // Pick conversion driver - // - RC_Driver driver = RC_Driver_Null; - if (cmd_line_has_flag(cmdl, str8_lit("driver"))) { - String8 driver_name = cmd_line_string(cmdl, str8_lit("driver")); - if (str8_match(driver_name, str8_lit("dwarf"), StringMatchFlag_CaseInsensitive)) { - driver = RC_Driver_Dwarf; - } else if (str8_match(driver_name, str8_lit("pdb"), StringMatchFlag_CaseInsensitive)) { - driver = RC_Driver_Pdb; - } else { - fprintf(stderr, "error: unknown driver \"%.*s\"\n", str8_varg(driver_name)); - os_abort(1); - } - } - - // - // Load inputs - // - for (String8Node *input_n = cmdl->inputs.first; input_n != 0; input_n = input_n->next) { - String8 input_data = os_data_from_file_path(arena, input_n->string); - - if (input_data.size == 0) { - fprintf(stderr, "unable to read input %.*s\n", str8_varg(input_n->string)); - os_abort(1); - } - - if (pe_check_magic(input_data)) { - if (is_pe_present) { - fprintf(stderr, "error: too many PE files are specified on the command line\n"); - fprintf(stderr, " selected: %.*s\n", str8_varg(pe_name)); - fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string)); - os_abort(1); - } - pe_data = input_data; - pe_name = input_n->string; - is_pe_present = 1; - } else if (elf_check_magic(input_data)) { - ELF_Bin elf = elf_bin_from_data(input_data); - B32 is_dwarf_present = dw_is_dwarf_present_from_bin(input_data, &elf); - if (is_dwarf_present) { - if (is_elf_debug_present) { - fprintf(stderr, "error: ambiguous input, both ELFs have DWARF debug sections, please use --elf: --elf_debug: to clarify inputs.\n"); - os_abort(1); - } - elf_debug_name = input_n->string; - elf_debug_data = input_data; - is_elf_debug_present = 1; - } else { - elf_name = input_n->string; - elf_data = input_data; - is_elf_present = 1; - } - } else if (msf_check_magic_20(input_data) || msf_check_magic_70(input_data)) { - if (is_pdb_present) { - fprintf(stderr, "error: too many PDB files are specified on the command line\n"); - fprintf(stderr, " selected: %.*s\n", str8_varg(pdb_name)); - fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string)); - continue; - } - pdb_name = input_n->string; - pdb_data = input_data; - is_pdb_present = 1; - } else { - fprintf(stderr, "error: unknown file format %.*s\n", str8_varg(input_n->string)); - } - } - - // - // Validate input combos - // - if ((is_pe_present || is_pdb_present) && (is_elf_present || is_elf_debug_present)) { - fprintf(stderr, "error: invalid combination of inputs provided, we convert only (PE|PDB) or (ELF|ELF_DEBUG) at a time.\n"); - if (is_pe_present) { - fprintf(stderr, " PE: %.*s\n", str8_varg(pe_name)); - } - if (is_pdb_present) { - fprintf(stderr, " PDB: %.*s\n", str8_varg(pdb_name)); - } - if (is_elf_present) { - fprintf(stderr, " ELF: %.*s\n", str8_varg(elf_name)); - } - if (is_elf_debug_present) { - fprintf(stderr, " ELF Debug: %.*s\n", str8_varg(elf_debug_name)); - } - os_abort(1); - } - - if (is_pe_present && (is_elf_present || is_elf_debug_present)) { - fprintf(stderr, "error: command line has too many image types specified.\n"); - os_abort(1); - } - - - ExecutableImageKind image = ExecutableImageKind_Null; - String8 image_name = {0}; - String8 image_data = {0}; - String8 debug_name = {0}; - String8 debug_data = {0}; - - B32 check_guid = 0; - Guid pe_pdb_guid = {0}; - - B32 elf_has_debug_link = 0; - ELF_GnuDebugLink debug_link = {0}; - - // - // Input has PE/COFF - // - if (is_pe_present) { - image = ExecutableImageKind_CoffPe; - image_name = pe_name; - image_data = pe_data; - - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, pe_data); - String8 raw_debug_dir = str8_substr(pe_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); - PE_DebugInfoList debug_dir = pe_debug_info_list_from_raw_debug_dir(scratch.arena, pe_data, raw_debug_dir); - for (PE_DebugInfoNode *debug_n = debug_dir.first; debug_n != 0; debug_n = debug_n->next) { - PE_DebugInfo *debug = &debug_n->v; - if (debug->header.type == PE_DebugDirectoryType_CODEVIEW) { - if (debug->u.codeview.magic == PE_CODEVIEW_PDB70_MAGIC) { - check_guid = 1; - pe_pdb_guid = debug->u.codeview.pdb70.header.guid; - - if (!is_pdb_present) { - pdb_name = debug->u.codeview.pdb70.path; - pdb_data = rc_data_from_file_path(arena, pdb_name); - is_pdb_present = 1; - } - - break; - } - } - } - - if (driver == RC_Driver_Null || driver == RC_Driver_Dwarf) { - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, pe_data); - String8 raw_section_table = str8_substr(pe_data, pe.section_table_range); - String8 string_table = str8_substr(pe_data, pe.string_table_range); - U64 section_count = raw_section_table.size / sizeof(COFF_SectionHeader); - COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; - if (dw_is_dwarf_present_coff_section_table(pe_data, string_table, section_count, section_table)) { - driver = RC_Driver_Dwarf; - debug_name = pe_name; - debug_data = pe_data; - goto driver_found; - } else if (driver == RC_Driver_Dwarf) { - fprintf(stderr, "error: image doesn't have DWARF debug sections.\n"); - os_abort(1); - } - } - } - - if (is_elf_present || is_elf_debug_present) { - if (driver != RC_Driver_Null && driver != RC_Driver_Dwarf) { - fprintf(stderr, "error: ELF inputs are only supported when using DWARF driver.\n"); - os_abort(1); - } - - // - // Load image ELF - // - ELF_Bin elf = elf_bin_from_data(elf_data); - B32 has_elf_dwarf = dw_is_dwarf_present_from_elf_bin(elf_data, &elf); - - // - // ELF doesn't have debug info and no .debug was specified on command line, - // try to load .debug via debug link - // - if (is_elf_present && !is_elf_debug_present) { - elf_has_debug_link = elf_parse_debug_link(elf_data, &elf, &debug_link); - } - if (elf_has_debug_link) { - elf_debug_data = rc_data_from_file_path(arena, debug_link.path); - is_elf_debug_present = 1; - } - - // - // Load .debug ELF - // - ELF_Bin elf_debug = elf_bin_from_data(elf_debug_data); - B32 has_elf_debug_dwarf = dw_is_dwarf_present_from_elf_bin(elf_debug_data, &elf_debug); - - // - // Input is image ELF and .debug ELF - // - B32 is_split_elf = is_elf_present && is_elf_debug_present && !has_elf_dwarf && has_elf_debug_dwarf; - if (is_split_elf) { - driver = RC_Driver_Dwarf; - image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? ExecutableImageKind_Elf64 : ExecutableImageKind_Elf32; - image_name = elf_name; - image_data = elf_data; - debug_name = elf_debug_name; - debug_data = elf_debug_data; - goto driver_found; - } - - // - // Input ELF is image with debug info - // - B32 is_monolithic_elf = is_elf_present && !is_elf_debug_present && has_elf_dwarf; - if (is_monolithic_elf) { - driver = RC_Driver_Dwarf; - image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? ExecutableImageKind_Elf64 : ExecutableImageKind_Elf32; - image_name = elf_name; - image_data = elf_data; - debug_name = elf_name; - debug_data = elf_data; - goto driver_found; - } - - // - // Input ELF is .debug - // - B32 is_debug_elf = !is_elf_present && is_elf_debug_present && has_elf_debug_dwarf; - if (is_debug_elf) { - driver = RC_Driver_Dwarf; - image = ELF_HdrIs64Bit(elf_debug.hdr.e_ident) ? ExecutableImageKind_Elf64 : ExecutableImageKind_Elf32; - debug_name = elf_debug_name; - debug_data = elf_debug_data; - goto driver_found; - } - } - - // - // Input is PDB - // - if (is_pdb_present) { - if (driver == RC_Driver_Null || driver == RC_Driver_Pdb) { - driver = RC_Driver_Pdb; - debug_name = pdb_name; - debug_data = pdb_data; - goto driver_found; - } else if (driver == RC_Driver_Dwarf) { - fprintf(stderr, "error: unable to select DWARF conversion driver because convert doesn't support PDB as input format.\n"); - os_abort(1); - } else { - InvalidPath; - } - } - - driver_found:; - - // - // Handle -out param - // - String8 out_name = {0}; - if (cmd_line_has_flag(cmdl, str8_lit("out"))) { - out_name = cmd_line_string(cmdl, str8_lit("out")); - if (out_name.size == 0) { - fprintf(stderr, "error: -out parameter doesn't have a value\n"); - os_abort(1); - } - } else { - if (image_name.size) { - out_name = path_replace_file_extension(arena, image_name, str8_lit("rdi")); - } else { - out_name = path_replace_file_extension(arena, debug_name, str8_lit("rdi")); - } - } - - - // - // Validate driver input - // - if (driver == RC_Driver_Pdb && - !is_pdb_present && (is_elf_present || is_elf_debug_present)) { - fprintf(stderr, "error: DWARF is an invalid input for PDB driver\n"); - os_abort(1); - } - - - RC_Context ctx = {0}; - ctx.driver = driver; - ctx.image = image; - ctx.image_name = image_name; - ctx.image_data = image_data; - ctx.debug_name = debug_name; - ctx.debug_data = debug_data; - ctx.flags = RC_Flag_Strings| - RC_Flag_IndexRuns| - RC_Flag_BinarySections| - RC_Flag_Units| - RC_Flag_Procedures| - RC_Flag_GlobalVariables| - RC_Flag_ThreadVariables| - RC_Flag_Scopes| - RC_Flag_Locals| - RC_Flag_Types| - RC_Flag_UDTs| - RC_Flag_LineInfo| - RC_Flag_GlobalVariableNameMap| - RC_Flag_ThreadVariableNameMap| - RC_Flag_ProcedureNameMap| - RC_Flag_TypeNameMap| - RC_Flag_LinkNameProcedureNameMap| - RC_Flag_NormalSourcePathNameMap; - if (check_guid) { - ctx.flags |= RC_Flag_CheckPdbGuid; - ctx.guid = pe_pdb_guid; - } - if (elf_has_debug_link) { - ctx.flags |= RC_Flag_CheckElfChecksum; - ctx.debug_link = debug_link; - } - ctx.out_name = out_name; - - scratch_end(scratch); - return ctx; -} - -internal String8List -rc_run(Arena *arena, RC_Context *rc) -{ - Temp scratch = scratch_begin(&arena, 1); - - ProfBegin("Convert"); - RDIM_LocalState *local_state = rdim_local_init(); - RDIM_BakeParams *convert2bake = 0; - switch (rc->driver) { - case RC_Driver_Null: break; - case RC_Driver_Dwarf: convert2bake = d2r_convert(scratch.arena, local_state, rc); break; - case RC_Driver_Pdb: convert2bake = p2r_convert(scratch.arena, local_state, rc); break; - } - ProfEnd(); - - if (rc->errors.node_count) { - NotImplemented; - } - - ProfBegin("Bake"); - RDIM_BakeResults bake2srlz = rdim_bake(local_state, convert2bake); - ProfEnd(); - - ProfBegin("Serialize Bake"); - RDIM_SerializedSectionBundle srlz2file = rdim_serialized_section_bundle_from_bake_results(&bake2srlz); - ProfEnd(); - - RDIM_SerializedSectionBundle srlz2file_compressed = srlz2file; - if (rc->flags & RC_Flag_Compress) { - ProfBegin("Compress"); - srlz2file_compressed = rdim_compress(scratch.arena, &srlz2file); - ProfEnd(); - } - - ProfBegin("Serialize"); - String8List raw_rdi = rdim_file_blobs_from_section_bundle(scratch.arena, &srlz2file_compressed); - ProfEnd(); - - scratch_end(scratch); - return raw_rdi; -} - -internal String8 -rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl) -{ - Temp scratch = scratch_begin(&arena, 1); - RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl); - String8List raw_rdi = rc_run(scratch.arena, &rc); - String8 result = str8_list_join(arena, &raw_rdi, 0); - scratch_end(scratch); - return result; -} - -internal void -rc_main(CmdLine *cmdl) -{ - B32 do_help = (cmd_line_has_flag(cmdl, str8_lit("help")) || - cmd_line_has_flag(cmdl, str8_lit("h")) || - cmd_line_has_flag(cmdl, str8_lit("?")) || - cmdl->argc == 1); - if (do_help) { - fprintf(stderr, "--- Help ---------------------------------------------------------------------\n"); - fprintf(stderr, " %s\n\n", BUILD_TITLE_STRING_LITERAL); - fprintf(stderr, " Usage: radcon [Options] [Files]\n\n"); - fprintf(stderr, " Options:\n"); - fprintf(stderr, " -pe: Path to Win32 executable image\n"); - fprintf(stderr, " -pdb: Path to PDB\n"); - fprintf(stderr, " -elf: Path to ELF\n"); - fprintf(stderr, " -elf_debug: Path to ELF with debug info\n"); - fprintf(stderr, " -out: Path at which the output RDI debug info will be written\n"); - fprintf(stderr, " -driver: Sets converter for debug info\n"); - } else { - Temp scratch = scratch_begin(0,0); - - // make converter context - RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl); - - // make RDI from context - String8List raw_rdi = rc_run(scratch.arena, &rc); - - // output RDI - if (rc.errors.node_count == 0) { - if (!os_write_data_list_to_file_path(rc.out_name, raw_rdi)) { - str8_list_pushf(scratch.arena, &rc.errors, "no write access to path %.*s", str8_varg(rc.out_name)); - } - } - - // report any errors - for (String8Node *error_n = rc.errors.first; error_n != 0; error_n = error_n->next) { - fprintf(stderr, "error: %.*s\n", str8_varg(error_n->string)); - } - - scratch_end(scratch); - } -} - diff --git a/src/radcon/radcon.h b/src/radcon/radcon.h deleted file mode 100644 index 06458d85..00000000 --- a/src/radcon/radcon.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADCON_H -#define RADCON_H - -typedef U32 RC_Flags; -enum -{ - RC_Flag_Strings = (1 << 0), - RC_Flag_IndexRuns = (1 << 1), - RC_Flag_BinarySections = (1 << 2), - RC_Flag_Units = (1 << 3), - RC_Flag_Procedures = (1 << 4), - RC_Flag_GlobalVariables = (1 << 5), - RC_Flag_ThreadVariables = (1 << 6), - RC_Flag_Scopes = (1 << 7), - RC_Flag_Locals = (1 << 8), - RC_Flag_Types = (1 << 9), - RC_Flag_UDTs = (1 << 10), - RC_Flag_LineInfo = (1 << 11), - RC_Flag_GlobalVariableNameMap = (1 << 12), - RC_Flag_ThreadVariableNameMap = (1 << 13), - RC_Flag_ProcedureNameMap = (1 << 14), - RC_Flag_TypeNameMap = (1 << 15), - RC_Flag_LinkNameProcedureNameMap= (1 << 16), - RC_Flag_NormalSourcePathNameMap = (1 << 17), - RC_Flag_Compress = (1 << 18), - RC_Flag_StrictDwarfParse = (1 << 19), - RC_Flag_Deterministic = (1 << 20), - RC_Flag_CheckPdbGuid = (1 << 21), - RC_Flag_CheckElfChecksum = (1 << 22), - RC_Flag_All = 0xffffffff, -}; - -typedef enum -{ - RC_Driver_Null, - RC_Driver_Dwarf, - RC_Driver_Pdb, -} RC_Driver; - -typedef struct RC_Context -{ - ExecutableImageKind image; - RC_Driver driver; - String8 image_name; - String8 image_data; - String8 debug_name; - String8 debug_data; - String8 out_name; - RC_Flags flags; - Guid guid; - ELF_GnuDebugLink debug_link; - String8List errors; -} RC_Context; - -//////////////////////////////// - -internal RC_Context rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl); -internal String8List rc_run(Arena *arena, RC_Context *rc); -internal String8 rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl); -internal void rc_main(CmdLine *cmdl); - -#endif // RADCON_H - diff --git a/src/radcon/radcon_main.c b/src/radcon/radcon_main.c deleted file mode 100644 index 0681750f..00000000 --- a/src/radcon/radcon_main.c +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#define BUILD_TITLE "Epic Games Tools (R) RAD Debug Info Converter" -#define BUILD_CONSOLE_INTERFACE 1 - -//////////////////////////////// -// Third Party - -#include "third_party/rad_lzb_simple/rad_lzb_simple.h" -#include "third_party/rad_lzb_simple/rad_lzb_simple.c" -#define XXH_STATIC_LINKING_ONLY -#include "third_party/xxHash/xxhash.c" -#include "third_party/xxHash/xxhash.h" -#define SINFL_IMPLEMENTATION -#include "third_party/sinfl/sinfl.h" -#include "third_party/radsort/radsort.h" - -//////////////////////////////// -// RDI Format Library - -#include "lib_rdi_format/rdi_format.h" -#include "lib_rdi_format/rdi_format.c" - -//////////////////////////////// -// Headers - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "async/async.h" -#include "rdi_make/rdi_make_local.h" -#include "linker/hash_table.h" -#include "coff/coff.h" -#include "coff/coff_parse.h" -#include "pe/pe.h" -#include "elf/elf.h" -#include "elf/elf_parse.h" -#include "codeview/codeview.h" -#include "codeview/codeview_parse.h" -#include "dwarf/dwarf.h" -#include "dwarf/dwarf_parse.h" -#include "dwarf/dwarf_coff.h" -#include "dwarf/dwarf_elf.h" -#include "msf/msf.h" -#include "msf/msf_parse.h" -#include "pdb/pdb.h" -#include "pdb/pdb_parse.h" -#include "pdb/pdb_stringize.h" -#include "radcon.h" -#include "radcon_coff.h" -#include "radcon_elf.h" -#include "radcon_cv.h" -#include "radcon_dwarf.h" -#include "radcon_pdb.h" - -//////////////////////////////// -// Implementations - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "async/async.c" -#include "rdi_make/rdi_make_local.c" -#include "linker/hash_table.c" -#include "coff/coff.c" -#include "coff/coff_parse.c" -#include "pe/pe.c" -#include "elf/elf.c" -#include "elf/elf_parse.c" -#include "codeview/codeview.c" -#include "codeview/codeview_parse.c" -#include "msf/msf.c" -#include "msf/msf_parse.c" -#include "pdb/pdb.c" -#include "pdb/pdb_parse.c" -#include "pdb/pdb_stringize.c" -#include "dwarf/dwarf.c" -#include "dwarf/dwarf_parse.c" -#include "dwarf/dwarf_coff.c" -#include "dwarf/dwarf_elf.c" -#include "radcon.c" -#include "radcon_coff.c" -#include "radcon_elf.c" -#include "radcon_cv.c" -#include "radcon_dwarf.c" -#include "radcon_pdb.c" - -//////////////////////////////// - -internal void -entry_point(CmdLine *cmdl) -{ - rc_main(cmdl); -} - diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index edb6a2f4..04192a6d 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -275,7 +275,7 @@ rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input DateTime universal_dt = os_now_universal_time(); DateTime local_dt = os_local_time_from_universal(&universal_dt); - String8 time = push_date_time_string(scratch.arena, &local_dt); + String8 time = string_from_date_time(scratch.arena, &local_dt); String8 full_path = os_full_path_from_path(scratch.arena, input_path); rd_printf("# %S, [%S] %S", time, input_type_string, full_path); diff --git a/src/scratch/parse_inline_sites.c b/src/scratch/parse_inline_sites.c index f6ae9eed..bd2bb656 100644 --- a/src/scratch/parse_inline_sites.c +++ b/src/scratch/parse_inline_sites.c @@ -266,7 +266,7 @@ entry_point(CmdLine *cmdl) // print run info DateTime now_time_universal = os_now_universal_time(); DateTime now_time_local = os_local_time_from_universal_time(&now_time_universal); - String8 now_time_str = push_date_time_string(arena, &now_time_local); + String8 now_time_str = string_from_date_time(arena, &now_time_local); fprintf(stdout, "Time: %.*s\n", str8_varg(now_time_str)); fprintf(stdout, "File: %.*s\n", str8_varg(pdb_name)); fprintf(stdout, "Size: %llu (bytes)\n", pdb_data.size); From c7c86cd360ac9c03ca75f785e70ea0dcf7c212df Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:35:47 -0700 Subject: [PATCH 171/302] do not report unresolved symbols in debug info sections --- src/linker/lnk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 910ccbe7..c1392b07 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2044,6 +2044,9 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer String8 debug_strings = {0}; for EachIndex(sect_idx, obj->header.section_count_no_null) { + if (lnk_is_coff_section_debug(obj, sect_idx)) { + continue; + } COFF_SectionHeader *section_header = §ion_table[sect_idx]; String8 section_name = coff_name_from_section_header(string_table, section_header); U64 section_number = sect_idx+1; @@ -2051,7 +2054,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer for EachIndex(reloc_idx, relocs.count) { if (supp_info.node_count > config->unresolved_symbol_ref_limit) { str8_list_pushf(scratch.arena, &supp_info, "too many unresolved symbol references reported, stopping now"); - break; + goto next_undefined_symbol; } COFF_Reloc *reloc = &relocs.v[reloc_idx]; if (reloc->isymbol == ref->symbol_idx) { @@ -2059,9 +2062,9 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer CV_Line *line_matches = 0; if (config->map_lines_for_unresolved_symbols == LNK_SwitchState_Yes) { if (debug_lines == 0) { + debug_s = lnk_debug_s_from_obj(scratch.arena, obj); String8List raw_checksums = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms); String8List raw_strings = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable); - debug_s = lnk_debug_s_from_obj(scratch.arena, obj); debug_lines = cv_lines_accel_from_debug_s(scratch.arena, debug_s); debug_checksums = str8_list_first(&raw_checksums); debug_strings = str8_list_first(&raw_strings); From c47b35f635f5756993953958b76aa9ef57a63814 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:48:27 -0700 Subject: [PATCH 172/302] update link symbol set logic to replace import address symbols with jump thunk symbols --- src/linker/lnk_lib.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 1f317a16..dc696abb 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -228,13 +228,22 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) { local_persist LNK_Symbol null_symbol; - LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); - B32 is_first_set = (slot == 0); + B32 is_first_set; + + LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); for (;;) { + is_first_set = (slot == 0); + // update slot symbol if it is empty or link symbol comes before symbol in the slot if (slot && slot != &null_symbol) { - if (lnk_symbol_is_before(slot, link_symbol)) { + if (!str8_starts_with(link_symbol->name, str8_lit("__imp_")) && str8_starts_with(slot->name, str8_lit("__imp_"))) { + // replace import address symbol with jump thunk symbol + slot = link_symbol; + is_first_set = 1; + } else if (str8_starts_with(link_symbol->name, str8_lit("__imp_")) && !str8_starts_with(slot->name, str8_lit("__imp_"))) { + // no need to replace + } else if (lnk_symbol_is_before(slot, link_symbol)) { slot = link_symbol; } } else { From d6596efac8c75f439e98c48c369e0e8b3cf5994e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:49:16 -0700 Subject: [PATCH 173/302] allow weak symbols to resolve to other weak symbols --- src/linker/lnk_symbol_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 270a4c57..94bc4ddb 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -675,7 +675,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_Ob LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); tag_interp = lnk_interp_from_symbol(dep_symbol); } - if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } + if (tag_interp == COFF_SymbolValueInterp_Weak) { break; } } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); From b5a2bbaf544f92507c1747d4407e7e1af118abca Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:50:41 -0700 Subject: [PATCH 174/302] early-out of default library searches --- src/linker/lnk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index c1392b07..e2a37e11 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1110,6 +1110,11 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou lnk_log(LNK_Log_InputLib, "Input Lib: %S", first_match); input = lnk_inputer_push_thin(inputer->arena, &inputer->new_libs[input_source], inputer->libs_ht, first_match); + // store input path to early-out of file searches for default libs + if (!str8_match(first_match, path, StringMatchFlag_CaseInsensitive)) { + hash_table_push_path_raw(inputer->arena, inputer->libs_ht, path, input); + } + exit:; scratch_end(scratch); return input; From 5aff575feb7256323ec463fd97aa6b7101feb821 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:52:06 -0700 Subject: [PATCH 175/302] discard empty symbol nodes --- src/linker/lnk_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index dc696abb..530c5427 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -112,7 +112,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L // parse symbol names { Temp scratch = scratch_begin(&arena, 1); - String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); + String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0); Assert(symbol_name_list.node_count >= first_member.symbol_count); symbol_names = str8_array_from_list(arena, &symbol_name_list); scratch_end(scratch); From 7095a8cd6eadadbd0095a889575fe11b1d17314a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 16:57:11 -0700 Subject: [PATCH 176/302] fix bug where new object tracking failed, causing certain objs to be skipped during the symbol table input step --- src/linker/lnk.c | 63 ++++++++++++++++++++++---------------------- src/linker/lnk.h | 7 ++--- src/linker/lnk_lib.c | 3 --- src/linker/lnk_obj.c | 2 -- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e2a37e11..fc7e4943 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1139,6 +1139,8 @@ lnk_inputer_has_items(LNK_Inputer *inputer) internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs) { + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); ProfBegin("Gather Thin Inputs"); @@ -1184,6 +1186,7 @@ lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Fla lnk_input_list_concat_in_place(all_inputs, new_inputs); scratch_end(scratch); + ProfEnd(); return result; } @@ -1223,7 +1226,7 @@ lnk_array_from_lib_member_list(Arena *arena, LNK_LibMemberRefList list) internal LNK_ObjNode * lnk_load_objs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out) { - ProfBegin("Input Objs [Count %llu]", inputer->new_objs.count); + ProfBeginV("Load Objs [Count %llu]", inputer->new_objs.count); Temp scratch = scratch_begin(arena->v, arena->count); // load obj inputer from disk @@ -1292,6 +1295,7 @@ lnk_load_libs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer * internal void lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link) { + ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); U64 obj_id_base = link->objs.count; @@ -1308,12 +1312,13 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } } - // handle /INCLUDE { + ProfBegin("Process /INCLUDE"); + // group include symbols by obj HashTable *ht = hash_table_init(scratch.arena, 64); - for (LNK_IncludeSymbolNode *node = config->include_symbol_list.first; node != 0; node = node->next) { - LNK_IncludeSymbol *include_symbol = &node->v; + for (; *link->last_include; link->last_include = &(*link->last_include)->next) { + LNK_IncludeSymbol *include_symbol = &(*link->last_include)->v; // skip, include symbol is already in the global symbol table if (lnk_symbol_table_search(symtab, include_symbol->name)) { @@ -1352,27 +1357,22 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer lnk_obj_list_push_node(&link->objs, include_obj); } } + + ProfEnd(); } - // assign input indices to objs + // finalize input indices on new objs and push external symbols to the symbol table { U64 node_idx = 0; - for (LNK_ObjNode *node = objs; node != 0; node = node->next, node_idx += 1) { - node->data.input_idx = obj_id_base + node_idx; + for (LNK_ObjNode **n = link->last_symbol_input; *n; n = &(*n)->next, node_idx += 1) { + (*n)->data.input_idx = obj_id_base + node_idx; } - } - // input indices on objs are finalized, push external symbols to the global symbol table - { - U64 new_objs_count = 0; - for (LNK_ObjNode *node = objs; node != 0; node = node->next) { new_objs_count += 1; } - - LNK_Obj **new_objs = push_array(scratch.arena, LNK_Obj *, new_objs_count); - { - U64 node_idx = 0; - for (LNK_ObjNode *node = objs; node != 0; node = node->next) { - new_objs[node_idx++] = &node->data; - } + U64 new_objs_count = node_idx; + LNK_Obj **new_objs = push_array(scratch.arena, LNK_Obj *, node_idx); + node_idx = 0; + for (; *link->last_symbol_input; link->last_symbol_input = &(*link->last_symbol_input)->next, node_idx += 1) { + new_objs[node_idx] = &(*link->last_symbol_input)->data; } lnk_push_obj_symbols(tp, arena, symtab, new_objs_count, new_objs); @@ -1484,6 +1484,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } scratch_end(scratch); + ProfEnd(); } internal void @@ -1504,8 +1505,6 @@ lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Sym internal THREAD_POOL_TASK_FUNC(lnk_search_lib_task) { - ProfBeginFunction(); - LNK_SearchLibTask *task = raw_task; LNK_Lib *lib = task->lib; LNK_SymbolTable *symtab = task->symtab; @@ -1519,7 +1518,6 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task) LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { U32 member_idx; if (lnk_search_lib(lib, symbol->name, &member_idx)) { @@ -1548,8 +1546,6 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task) } } } - - ProfEnd(); } internal void @@ -1561,6 +1557,7 @@ lnk_link_inputs(TP_Context *tp, LNK_Link *link, LNK_ImportTables *imps) { + ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); B32 search_anti_deps = 0; @@ -1568,17 +1565,15 @@ lnk_link_inputs(TP_Context *tp, lnk_load_inputs(tp, arena, config, inputer, symtab, link); for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { + ProfBeginV("Search %S", str8_skip_last_slash(lib_n->data.path)); do { lnk_load_inputs(tp, arena, config, inputer, symtab, link); LNK_LibMemberRefList queued_members = {0}; { - LNK_SearchLibTask task = {0}; - task.search_anti_deps = search_anti_deps; - task.lib = &lib_n->data; - task.symtab = symtab; + LNK_SearchLibTask task = { .search_anti_deps = search_anti_deps, .lib = &lib_n->data, .symtab = symtab }; task.member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count); - tp_for_parallel_prof(tp, arena, tp->worker_count, lnk_search_lib_task, &task, "Search Lib"); + tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &task); lnk_lib_member_ref_list_concat_in_place_array(&queued_members, task.member_ref_lists, tp->worker_count); } @@ -1606,7 +1601,7 @@ lnk_link_inputs(TP_Context *tp, for EachIndex(i, refs_count) { lnk_log(LNK_Log_Links, "\t\tReferenced in %S", lnk_loc_from_obj(temp.arena, refs[i]->obj)); } - + temp_end(temp); } } @@ -1691,6 +1686,7 @@ lnk_link_inputs(TP_Context *tp, resolved_members_count += queued_members.count; } while (lnk_inputer_has_items(inputer)); + ProfEnd(); } if (resolved_members_count == 0) { @@ -1734,17 +1730,20 @@ lnk_link_inputs(TP_Context *tp, } scratch_end(scratch); + ProfEnd(); } internal LNK_Link * lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab) { + ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); // // init link context // LNK_Link *link = push_array(arena->v[0], LNK_Link, 1); + link->last_symbol_input = &link->objs.first; link->last_include = &config->include_symbol_list.first; link->last_default_lib = &config->input_default_lib_list.first; link->last_obj_lib = &config->input_obj_lib_list.first; @@ -1986,7 +1985,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } // - // report undefined symbols + // report unresolved symbols // { ProfBegin("Report Unresolved Symbols"); @@ -2094,6 +2093,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } } } + next_undefined_symbol:; } lnk_error(LNK_Error_UnresolvedSymbol, "unresolved symbol %S", symbol->name); @@ -2149,6 +2149,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } scratch_end(scratch); + ProfEnd(); return link; } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index afe090da..4cf1404c 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -77,17 +77,18 @@ typedef struct LNK_Inputer typedef struct LNK_ImportTables { - Arena *arena; + Arena *arena; String8List delayed_dll_names; String8List static_dll_names; - HashTable *static_imports; - HashTable *delayed_imports; + HashTable *static_imports; + HashTable *delayed_imports; } LNK_ImportTables; typedef struct LNK_Link { LNK_ObjList objs; LNK_LibList libs; + LNK_ObjNode **last_symbol_input; LNK_IncludeSymbolNode **last_include; String8Node **last_cmd_lib; String8Node **last_default_lib; diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 530c5427..bcf06da7 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -23,8 +23,6 @@ lnk_first_member_sort_key_is_before(void *raw_a, void *raw_b) internal B32 lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_Lib *lib_out) { - ProfBeginFunction(); - // is data archive? COFF_ArchiveType type = coff_archive_type_from_data(data); if (type == COFF_Archive_Null) { @@ -147,7 +145,6 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L lib_out->long_names = parse.long_names; lib_out->input_idx = input_idx; - ProfEnd(); return 1; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index ac4ca13f..cb1ace28 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -312,8 +312,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) obj->associated_sections = associated_sections; obj->node = &task->objs[task_id]; obj->link_member = input->link_member; - - ProfEnd(); } internal LNK_ObjNode * From 488849792c1dea80e7f062930b42f062e94c0d78 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 18:59:07 -0700 Subject: [PATCH 177/302] change file search to return on first match --- src/linker/lnk.c | 16 +++-------- src/linker/lnk_debug_info.c | 33 +++++------------------ src/linker/lnk_io.c | 54 +++++++++++-------------------------- src/linker/lnk_io.h | 2 -- 4 files changed, 26 insertions(+), 79 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index fc7e4943..67f5bdec 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1083,10 +1083,10 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou } // search disk for library - String8List matches = lnk_file_search(scratch.arena, config->lib_dir_list, path); + String8 first_match = lnk_find_first_file(scratch.arena, config->lib_dir_list, path); // warn about missing library - if (matches.node_count == 0) { + if (first_match.size == 0) { KeyValuePair *was_reported = hash_table_search_path(inputer->missing_lib_ht, path); if (was_reported == 0) { hash_table_push_path_u64(inputer->arena, inputer->missing_lib_ht, path, 0); @@ -1095,18 +1095,12 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou goto exit; } - String8 first_match = matches.first->string; + // was input with full path already loaded? input = hash_table_search_path_raw(inputer->libs_ht, first_match); if (input) { goto exit; } - // warn about multiple matches - if (matches.node_count > 1) { - lnk_error(LNK_Warning_MultipleLibMatch, "multiple libraries match `%S` (picking first match)", path); - lnk_supplement_error_list(matches); - } - lnk_log(LNK_Log_InputLib, "Input Lib: %S", first_match); input = lnk_inputer_push_thin(inputer->arena, &inputer->new_libs[input_source], inputer->libs_ht, first_match); @@ -2878,7 +2872,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) S64 symbol_voff = 0; { COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, reloc->isymbol); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); if (interp == COFF_SymbolValueInterp_Regular) { if (symbol.section_number == lnk_obj_get_removed_section_number(obj)) { if (!lnk_is_coff_section_debug(obj, sect_idx)) { @@ -2887,7 +2881,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) } continue; } - symbol_secnum = symbol.section_number; symbol_secoff = symbol.value; symbol_voff = safe_cast_u32((U64)task->image_section_table[symbol.section_number]->voff + (U64)symbol_secoff); @@ -2898,7 +2891,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) if (str8_match(symbol.name, str8_lit("__ImageBase"), 0)) { symbol.value = task->image_base; } - symbol_secnum = 0; symbol_secoff = 0; symbol_voff = (S64)symbol.value - (S64)task->image_base; diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index acc4ac15..b2de09a1 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -549,29 +549,11 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla CV_TypeServerInfo ts = cv_type_server_info_from_leaf(leaf); // search disk for type server - String8List match_list = lnk_file_search(scratch.arena, lib_dir_list, ts.name); - - // chop file name from path and search on it - // - // TODO: check if ts.name is a path and in that case do file search - if (match_list.node_count == 0) { - String8 file_name = str8_skip_last_slash(ts.name); - match_list = lnk_file_search(scratch.arena, lib_dir_list, file_name); - } + String8 type_server_path = lnk_find_first_file(scratch.arena, lib_dir_list, ts.name); + // report no match B32 do_debug_info_discard = 0; - - // too many matches? - if (match_list.node_count > 1) { - if (!hash_table_search_path(ignored_path_ht, ts.name)) { - hash_table_push_path_u64(scratch.arena, ignored_path_ht, ts.name, 0); - lnk_error_obj(LNK_Warning_MultipleExternalTypeServers, obj_arr[obj_idx], "located multiple external type servers:"); - lnk_supplement_error_list(match_list); - } - do_debug_info_discard = 1; - } - // no match? - else if (match_list.node_count == 0) { + if (type_server_path.size == 0) { if (!hash_table_search_path(ignored_path_ht, ts.name)) { hash_table_push_string_u64(scratch.arena, ignored_path_ht, ts.name, 0); lnk_error_obj(LNK_Warning_MissingExternalTypeServer, obj_arr[obj_idx], "unable to open external type server %S", ts.name); @@ -585,7 +567,6 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla continue; } - String8 path = match_list.first->string; { struct HT_Value { CV_TypeServerInfo ts; @@ -594,7 +575,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla }; // was this type server queued? - KeyValuePair *is_path_queued = hash_table_search_path(type_server_path_ht, path); + KeyValuePair *is_path_queued = hash_table_search_path(type_server_path_ht, type_server_path); if (is_path_queued) { struct HT_Value *present = is_path_queued->value_raw; @@ -616,12 +597,12 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla // when we search matches on disk we store path on scratch, // make path copy in case we need it for error reporting - path = push_str8_copy(tp_arena->v[0], path); + type_server_path = push_str8_copy(tp_arena->v[0], type_server_path); // fill out type server info we read from obj CV_TypeServerInfoNode *ts_info_node = push_array(scratch.arena, CV_TypeServerInfoNode, 1); ts_info_node->data = ts; - ts_info_node->data.name = path; + ts_info_node->data.name = type_server_path; // push to type server info list SLLQueuePush(ts_info_list.first, ts_info_list.last, ts_info_node); @@ -640,7 +621,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla value->ts_idx = ts_idx; // update hash table - hash_table_push_path_raw(scratch.arena, type_server_path_ht, path, value); + hash_table_push_path_raw(scratch.arena, type_server_path_ht, type_server_path, value); } } } diff --git a/src/linker/lnk_io.c b/src/linker/lnk_io.c index c9626617..49172cfe 100644 --- a/src/linker/lnk_io.c +++ b/src/linker/lnk_io.c @@ -48,51 +48,27 @@ lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_ return write_size; } -internal String8List -lnk_file_search(Arena *arena, String8List dir_list, String8 file_path) +internal String8 +lnk_find_first_file(Arena *arena, String8List dir_list, String8 path) { ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - String8List match_list; MemoryZeroStruct(&match_list); - - if (os_file_path_exists(file_path)) { - String8 str = push_str8_copy(arena, file_path); - str8_list_push(arena, &match_list, str); - } - - PathStyle file_path_style = path_style_from_str8(file_path); - B32 is_relative = file_path_style != PathStyle_WindowsAbsolute && - file_path_style != PathStyle_UnixAbsolute; - - if (is_relative) { - for (String8Node *i = dir_list.first; i != 0; i = i->next) { - String8List path_list = {0}; - str8_list_push(scratch.arena, &path_list, i->string); - str8_list_push(scratch.arena, &path_list, file_path); - String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute); - B32 file_exists = os_file_path_exists(path); - if (file_exists) { - B32 is_unique = 1; - OS_FileID file_id = os_id_from_file_path(path); - for (String8Node *k = match_list.first; k != 0; k = k->next) { - OS_FileID test_id = os_id_from_file_path(k->string); - int cmp = os_file_id_compare(test_id, file_id) != 0; - if (cmp == 0) { - is_unique = 0; - break; - } - } - if (is_unique) { - String8 str = push_str8_copy(arena, path); - str8_list_push(arena, &match_list, str); - } + String8 result = {0}; + if (os_file_path_exists(path)) { + result = path; + } else { + Temp scratch = scratch_begin(&arena, 1); + String8 file_name = str8_skip_last_slash(path); + for EachNode(n, String8Node, dir_list.first) { + String8 full_path = push_str8f(scratch.arena, "%S/%S", n->string, file_name); + if (os_file_path_exists(full_path)) { + result = push_str8_copy(arena, full_path); + break; } } + scratch_end(scratch); } - - scratch_end(scratch); ProfEnd(); - return match_list; + return result; } internal OS_Handle diff --git a/src/linker/lnk_io.h b/src/linker/lnk_io.h index 3e1b1705..76795427 100644 --- a/src/linker/lnk_io.h +++ b/src/linker/lnk_io.h @@ -28,8 +28,6 @@ shared_function uint64_t lnk_write_file(void *raw_handle, uint64_t offset, void // --- IO Functions ------------------------------------------------------------ -internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path); - internal OS_Handle lnk_file_open_with_rename_permissions(String8 path); internal B32 lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file); internal B32 lnk_file_rename(OS_Handle handle, String8 new_name); From 3224c5e0aa8c9598793423721a4734a0cbd157fd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 19:03:25 -0700 Subject: [PATCH 178/302] skip linker info sections during relocation patching, also log a message when encountering an unsupported machine type --- src/linker/lnk.c | 10 ++++++---- src/linker/lnk_obj.c | 6 ++++++ src/linker/lnk_obj.h | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 67f5bdec..2ec33142 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2830,9 +2830,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) LNK_Obj *obj = task->objs[task_id]; COFF_FileHeaderInfo obj_header = obj->header; - COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj_header.section_table_range).str; - String8 symbol_table = str8_substr(obj->data, obj_header.symbol_table_range); - String8 string_table = str8_substr(obj->data, obj_header.string_table_range); + COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj); + String8 symbol_table = lnk_coff_symbol_table_from_obj(obj); + String8 string_table = lnk_coff_string_table_from_obj(obj); U32 closest_sect = 0; U32 closest_reloc = 0; @@ -2841,6 +2841,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) for EachIndex(sect_idx, obj_header.section_count_no_null) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; + if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; } if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } if (section_header->flags & COFF_SectionFlag_CntUninitializedData) { continue; } @@ -2860,7 +2861,8 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) lnk_error_obj(LNK_Error_IllegalRelocation, obj, "unknown relocation type 0x%x", reloc->type); } } else if (obj->header.machine != COFF_MachineType_Unknown) { - NotImplemented; + lnk_not_implemented("relocation patching is not implemented for %S", coff_string_from_machine_type(obj->header.machine)); + continue; } // compute virtual offsets diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index cb1ace28..80383349 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -527,6 +527,12 @@ lnk_coff_string_table_from_obj(LNK_Obj *obj) return str8_substr(obj->data, obj->header.string_table_range); } +internal String8 +lnk_coff_symbol_table_from_obj(LNK_Obj *obj) +{ + return str8_substr(obj->data, obj->header.symbol_table_range); +} + internal COFF_RelocArray lnk_coff_reloc_info_from_section_number(LNK_Obj *obj, U64 section_number) { diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 3f449725..3783f72f 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -119,6 +119,7 @@ internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Ob internal COFF_RelocArray lnk_coff_relocs_from_section_header(LNK_Obj *obj, COFF_SectionHeader *section_header); internal COFF_SectionHeader * lnk_coff_section_table_from_obj(LNK_Obj *obj); internal String8 lnk_coff_string_table_from_obj(LNK_Obj *obj); +internal String8 lnk_coff_symbol_table_from_obj(LNK_Obj *obj); internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out); internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx); From 80967fac120653d52d094aa90ffe0087219c6614 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 9 Sep 2025 19:28:44 -0700 Subject: [PATCH 179/302] pre-parse section names and flag debug info sections --- src/linker/lnk.c | 49 ++++++++++++++--------------- src/linker/lnk.h | 3 +- src/linker/lnk_debug_info.c | 9 ++---- src/linker/lnk_obj.c | 61 +++++++++++++++++++------------------ src/linker/lnk_obj.h | 1 - 5 files changed, 59 insertions(+), 64 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 2ec33142..05f4da83 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2042,10 +2042,9 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer String8 debug_strings = {0}; for EachIndex(sect_idx, obj->header.section_count_no_null) { - if (lnk_is_coff_section_debug(obj, sect_idx)) { - continue; - } COFF_SectionHeader *section_header = §ion_table[sect_idx]; + if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } + String8 section_name = coff_name_from_section_header(string_table, section_header); U64 section_number = sect_idx+1; COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header); @@ -2199,9 +2198,9 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); // is section eligible for walking? - if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } - if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } // divide relocs and push task for each reloc block COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number); @@ -2283,9 +2282,9 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number); // is section eligible for walking? - if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } - if (lnk_is_coff_section_debug(ref_obj, section_number-1)) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } // mark section section_header->flags |= LNK_SECTION_FLAG_IS_LIVE; @@ -2315,8 +2314,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj U32 section_number = sect_idx+1; COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); - - if (lnk_is_coff_section_debug(obj, sect_idx)) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } // remove unreferenced sections if (~section_header->flags & LNK_SECTION_FLAG_IS_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { @@ -2523,7 +2521,8 @@ THREAD_POOL_TASK_FUNC(lnk_flag_debug_symbols_task) symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { - if (lnk_is_coff_section_debug(obj, symbol.section_number-1)) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; } } @@ -2846,7 +2845,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) if (section_header->flags & COFF_SectionFlag_CntUninitializedData) { continue; } // get section bytes (special case debug info because it is not copied to the image) - String8 data = lnk_is_coff_section_debug(obj, sect_idx) ? obj->data : task->image_data; + String8 data = section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO ? obj->data : task->image_data; Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize); String8 section_data = str8_substr(data, section_frange); @@ -2877,7 +2876,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); if (interp == COFF_SymbolValueInterp_Regular) { if (symbol.section_number == lnk_obj_get_removed_section_number(obj)) { - if (!lnk_is_coff_section_debug(obj, sect_idx)) { + if (~section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { String8 sect_name = coff_name_from_section_header(string_table, §ion_table[sect_idx]); lnk_error_obj(LNK_Error_RelocationAgainstRemovedSection, obj, "relocating against symbol that is in a removed section (symbol: %S, reloc-section: %S 0x%llx, reloc-index: 0x%llx)", symbol.name, sect_name, sect_idx+1, reloc_idx); } @@ -3462,7 +3461,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_file_offsets_and_sizes_in_obj_section_headers_ta for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = §ion_table[sect_idx]; B32 patch_section_header = (~sect_header->flags & COFF_SectionFlag_LnkRemove) && - !lnk_is_coff_section_debug(obj, sect_idx); + (~sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO); if (patch_section_header) { LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; @@ -4735,17 +4734,15 @@ lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs LNK_Obj *obj = objs[obj_idx]; COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(obj->data, obj->header.section_table_range.min, 0); for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { - if (lnk_is_coff_section_debug(obj, sect_idx)) { - COFF_SectionHeader *section_header = §ion_table[sect_idx]; - if (~section_header->flags & COFF_SectionFlag_LnkRemove) { - LNK_Lib *lib = lnk_obj_get_lib(obj); - if (lib) { - String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); - String8 obj_name = str8_skip_last_slash(obj->path); - str8_list_pushf(arena, &map, "%S(%S) SECT%X\n", lib_name, obj_name, sect_idx+1); - } else { - str8_list_pushf(arena, &map, "%S SECT%X\n", obj->path, sect_idx+1); - } + COFF_SectionHeader *section_header = §ion_table[sect_idx]; + if (~section_header->flags & COFF_SectionFlag_LnkRemove && section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + LNK_Lib *lib = lnk_obj_get_lib(obj); + if (lib) { + String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); + String8 obj_name = str8_skip_last_slash(obj->path); + str8_list_pushf(arena, &map, "%S(%S) SECT%X\n", lib_name, obj_name, sect_idx+1); + } else { + str8_list_pushf(arena, &map, "%S SECT%X\n", obj->path, sect_idx+1); } } } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 4cf1404c..a3f7909c 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -73,7 +73,8 @@ typedef struct LNK_Inputer #define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" #define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***" -#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) +#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) +#define LNK_SECTION_FLAG_DEBUG_INFO (1 << 1) typedef struct LNK_ImportTables { diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index b2de09a1..1e99fa7f 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2934,12 +2934,9 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *obj_sect_header = &obj_section_table[sect_idx]; - if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) { - continue; - } - if (lnk_is_coff_section_debug(obj, sect_idx)) { - continue; - } + if (obj_sect_header->flags & COFF_SectionFlag_LnkInfo) { continue; } + if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (obj_sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } U64 sect_number; String8 sect_data; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 80383349..d16155be 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -259,6 +259,19 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } } } + + // + // mark debug info sections + // + { + for EachIndex(sect_idx, header.section_count_no_null) { + COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; + String8 sect_name = str8_cstring_capped(sect_header->name, sect_header->name + sizeof(sect_header->name)); + if (str8_starts_with(sect_name, str8_lit(".debug$"))) { + sect_header->flags |= LNK_SECTION_FLAG_DEBUG_INFO; + } + } + } B8 hotpatch = 0; if (header.machine == COFF_MachineType_X64) { @@ -271,25 +284,27 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) Temp scratch = scratch_begin(&arena, 1); CV_Symbol comp_symbol = {0}; - for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { + for EachIndex(sect_idx, header.section_count_no_null) { COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; - String8 name = str8_cstring_capped(sect_header->name, sect_header->name+sizeof(sect_header->name)); - if (str8_match(name, str8_lit(".debug$S"), 0)) { - Temp temp = temp_begin(scratch.arena); - String8 debug_s_data = str8_substr(input->data, rng_1u64(sect_header->foff, sect_header->foff+sect_header->fsize)); - CV_DebugS debug_s = cv_parse_debug_s(temp.arena, debug_s_data); - for (String8Node *symbols_n = debug_s.data_list[CV_C13SubSectionIdxKind_Symbols].first; symbols_n != 0; symbols_n = symbols_n->next) { - CV_SymbolList symbol_list = {0}; - cv_parse_symbol_sub_section_capped(scratch.arena, &symbol_list, 0, symbols_n->string, CV_SymbolAlign, 2); - if (symbol_list.first->data.kind == CV_SymKind_COMPILE3) { - comp_symbol = symbol_list.first->data; - goto found_comp_symbol; - } else if (symbol_list.last->data.kind == CV_SymKind_COMPILE3) { - comp_symbol = symbol_list.last->data; - goto found_comp_symbol; + if (sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + String8 name = str8_cstring_capped(sect_header->name, sect_header->name+sizeof(sect_header->name)); + if (str8_match(name, str8_lit(".debug$S"), 0)) { + Temp temp = temp_begin(scratch.arena); + String8 debug_s_data = str8_substr(input->data, rng_1u64(sect_header->foff, sect_header->foff+sect_header->fsize)); + CV_DebugS debug_s = cv_parse_debug_s(temp.arena, debug_s_data); + for EachNode(symbols_n, String8Node, debug_s.data_list[CV_C13SubSectionIdxKind_Symbols].first) { + CV_SymbolList symbol_list = {0}; + cv_parse_symbol_sub_section_capped(scratch.arena, &symbol_list, 0, symbols_n->string, CV_SymbolAlign, 2); + if (symbol_list.first->data.kind == CV_SymKind_COMPILE3) { + comp_symbol = symbol_list.first->data; + goto found_comp_symbol; + } else if (symbol_list.last->data.kind == CV_SymKind_COMPILE3) { + comp_symbol = symbol_list.last->data; + goto found_comp_symbol; + } } + temp_end(temp); } - temp_end(temp); } } found_comp_symbol:; @@ -556,20 +571,6 @@ lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ return 0; } -internal B32 -lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx) -{ - String8 string_table = str8_substr(obj->data, obj->header.string_table_range); - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx+1); - - String8 full_name = coff_name_from_section_header(string_table, section_header); - String8 name, postfix; - coff_parse_section_name(full_name, &name, &postfix); - - B32 is_debug = str8_match(name, str8_lit(".debug"), 0); - return is_debug; -} - internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx) { diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 3783f72f..9fca1cb5 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -121,7 +121,6 @@ internal COFF_SectionHeader * lnk_coff_section_table_from_obj(LNK_Obj *obj); internal String8 lnk_coff_string_table_from_obj(LNK_Obj *obj); internal String8 lnk_coff_symbol_table_from_obj(LNK_Obj *obj); internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out); -internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx); // --- Helpers ----------------------------------------------------------------- From 3ab9f72c76b42b5777ef34e09c1fb0f48aca74dd Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 16 Sep 2025 11:47:04 -0700 Subject: [PATCH 180/302] readme pass --- README.md | 314 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 173 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 8d8396ec..203f9e5d 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,94 @@ # The RAD Debugger Project -_**Note:** This README does not document usage instructions and tips for the +_**NOTE:** This README does not document usage instructions and tips for the debugger itself, and is intended as a technical overview of the project. The debugger's README, which includes usage instructions and tips, can be found packaged along with debugger releases, or within the `build` folder after a -local copy has been built._ +local copy has been built. You can find pre-built release binaries +[here](https://github.com/EpicGamesExt/raddebugger/releases)._ The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It currently only supports local-machine Windows x64 debugging with PDBs, with plans to expand and port in the future. In the future we'll expand to also support native Linux debugging and DWARF debug info. -The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet- -proof, it'd greatly help out if you submitted the issues you find here, along -with any information you can gather, like dump files (along with the build you -used), instructions to reproduce, test executables, and so on. +The debugger is currently in *ALPHA*. In order to get the debugger +bullet-proof, it'd greatly help out if you submitted the issues you find +[here](https://github.com/EpicGamesExt/raddebugger/issues), along with any +information you can gather, like dump files (along with the build you used), +instructions to reproduce, test executables, and so on. -You can download pre-built binaries for the debugger -[here](https://github.com/EpicGamesExt/raddebugger/releases). +In addition to the debugger, we aim to further improve the toolchain with two +additional related technologies: **(1)** the RAD Debug Info (RDI) format, and +**(2)** the RAD Linker. -The RAD Debugger project aims to simplify the debugger by simplifying and -unifying the underlying debug info format. In that pursuit we've built the RAD -Debug Info (RDI) format, which is what the debugger parses and uses. To work -with existing toolchains, we convert PDB (and eventually PE/ELF files with -embedded DWARF) into the RDI format on-demand. +## The RAD Debug Info (RDI) Format + +The RAD Debug Info (RDI) format is our custom debug information format, which +the debugger parses and uses, rather than the debug information natively +produced by toolchains, like PDB or DWARF. To work with these existing +toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF) +into the RDI format on-demand. The RDI format is currently specified in code, in the files within the -`src/lib_rdi_format` folder. The other relevant folders for working with the -format are: +`src/lib_rdi` folder. In [`rdi.h`](src/lib_rdi/rdi.h) and +[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format +itself are specified. In [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) and +[`rdi_parse.c`](src/lib_rdi/rdi_parse.c), helpers for parsing the format are +included. -- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info. -- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase - layer, or built as an executable with a command line interface frontend. -- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter. -- `rdi_dump`: Our RDI textual dumping utility. +We also have an in-progress library for constructing and serializing RDI data, +located within the `src/lib_rdi_make` folder. -## Development Setup Instructions +Our `radbin` utility (accessible through the debugger too, via the `--bin` +command line argument) is capable of converting native debug information formats +to RDI, and of producing textual dumps of contents stored within RDI files. -**Note: Currently, only x64 Windows development is supported.** +## The RAD Linker -### 1. Installing the Required Tools (MSVC & Windows SDK) +The RAD Linker is a new performance linker for generating x64 PE/COFF binaries. +It is designed to be very fast when creating gigantic executables. It generates +standard PDB files for debugging, but it can also (optionally) natively create +RAD Debug Info too, which is useful both to eliminate on-demand conversion time +when debugging, but also for huge executables that otherwise create broken +PDBs that overflow internal 32-bit tables. + +The RAD Linker is primarily optimized to handle huge linking projects. In our +test cases (where debug info is multiple gigabytes), we see 50% faster link +times. + +The command line syntax is fully compatible with MSVC; you can get a full list +of implemented switches from `/help`. + +Our current designed-for use case for the linker is to help with the +compile-debug cycle of huge projects. We don't yet have support for +dead-code-elimination or link-time-optimizations, but these features are on the +road map. + +By default, the linker spawns as many threads as there are cores, so if you plan +to run multiple linkers in parallel, you can limit the number of thread workers +via `/rad_workers`. + +We also have support for large memory pages, which, when enabled, reduce link +time by another 25%. To link with large pages, you need to explicitly request +them via `/rad_large_pages`. Large pages are off by default, since Windows +support for large pages is a bit buggy; we recommend they only be used in Docker +or VM images where the environment is reset after each link. In a standard +Windows environment, using large pages otherwise will fragment memory quickly, +forcing a reboot. We are working on a Linux port of the linker that will be able +to build with large pages robustly. + +A benchmark of the linker's performance is below: + +![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/a95b382a-76b4-4a4c-b809-b61fe25e667a) + +--- + +# Project Development Setup Instructions + +**NOTE: Currently, only x64 Windows development is supported for the project.** + +## 1. Installing the Required Tools (MSVC & Windows SDK) In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both @@ -48,7 +97,7 @@ the Windows SDK and the MSVC compiler and linker. If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++ Build Tools), you may also build with [Clang](https://releases.llvm.org/). -### 2. Build Environment Setup +## 2. Build Environment Setup Building the codebase can be done in a terminal which is equipped with the ability to call either MSVC or Clang from command line. @@ -92,9 +141,9 @@ You should see the following output: [msvc compile] [default mode, assuming `raddbg` build] metagen_main.c -searching C:\devel\raddebugger/src... 447 files found -parsing metadesk... 14 metadesk files parsed -gathering tables... 93 tables found +searching C:\devel\raddebugger/src... 458 files found +parsing metadesk... 16 metadesk files parsed +gathering tables... 97 tables found generating layer code... raddbg_main.c ``` @@ -112,23 +161,43 @@ build release This build will take significantly longer. -## Short-To-Medium-Term Roadmap +By default, `build.bat` only builds the debugger if no arguments (or just +`release`) are passed, but additional arguments can be passed to build the RAD +Linker, or the `radbin` CLI binary file utility: + +``` +build radlink release +build radbin release +``` + +--- + +# Project Roadmap ### The Initial Alpha Battle-Testing Phase -The first priority for the project is to ensure that the most crucial debugger -components are functioning extremely reliably for local, x64, Windows -debugging. This would include parts like debug info conversion, debug info -loading, process control, stepping, evaluation (correct usage of both location -info and type info), and a robust frontend which ensures the lower level parts -are usable. +The first priority for the project is to ensure that the most crucial components +are functioning extremely reliably for local, x64, Windows development. +For the debugger, this would include parts like debug info conversion, debug +info loading, process control, stepping, evaluation (correct usage of both +location info and type info), and a robust frontend which ensures the lower +level parts are usable. For the linker, this is a matter of reliability and +convergence with existing linker behavior. -We feel that the debugger has already come a long way in all of these respects, -but given the massive set of possible combinations of languages, build -settings, toolchains, used language features, and patterns of generated code, -there are still cases where the debugger has not been tested, and so there are -still issues. So, we feel that the top priority is eliminating these issues, -such that the debugging experience is rock solid. +We feel that we've already come a long way in all of these respects, but given +the massive set of possible combinations of languages, build settings, +toolchains, used language features, and patterns of generated code, we still +expect some issues, and are prioritizing these issues being resolved first. + +We also hope to continue to improve performance in this phase. For the debugger, +this primarily includes frontend performance, introducing caches when economical +to do so, and tightening existing systems up. For the linker, it has been mostly +tuned thus far for giant projects, and so we'd like to improve linking speed for +small-to-mid sized projects as well. + +For the linker, there are also a number of features to come, like +dead-code-elimination (`/opt:ref`), and link-time-optimizations with the help +of `clang` (we won't support LTCG from MSVC, since it is undocumented). ### Local x64 Linux Debugging Phase @@ -171,42 +240,7 @@ But for now, we're mostly focused on those first two phases. --- -# The RAD Linker - -The RAD Linker is a new performance linker for generating x64 PE/COFF binaries. It is designed to be very fast when creating gigantic executables. It generates standard PDB files for debugging, but it can also optionally create RAD Debugger debug info too (useful for huge executables that otherwise create broken PDBs that overflow internal 32-bit tables). - -The RAD Linker is primarily optimized to handle huge linking projects - in our test cases (where debug info is multiple gigabytes), we see 50% faster link times. - -The command line syntax is fully compatible with MSVC and you can get a full list of implemented switches from `/help`. - -Our current designed-for use case for the linker is to help with the compile-debug cycle of huge projects. We don't yet have support for dead-code-elimination or link-time-optimizations, but these features are on the road map. - -By default, the RAD linker spawns as many threads as there are cores, so if you plan to run multiple linkers in parallel, you can limit the number of thread workers via `/rad_workers`. - -We also have support for large memory pages, which, when enabled, reduce link time by -another 25%. To link with large pages, you need to explicitly request them via `/rad_large_pages`. Large pages are off by default, since Windows support for large pages is a bit buggy - we recommend they only be used in Docker or VM images where the environment is reset after each link. In a standard Windows environment, using large pages otherwise will fragment memory quickly forcing a reboot. We are working on a Linux port of the linker that will be able to build with large pages robustly. - -## Short Term Roadmap -- Porting linker to Linux (for Windows executables, just running on Linux). -- Debug info features - - Get DWARF debug info converter up-and-running. - - Smooth out rough edges in RADDBGI builder. - - Improve build speed further (especially for tiny and mid sizes projects). -- Other features to come - - Dead-code-elimination via `/opt:ref`. - - Link Time Optimizations with the help of clang (we won't support LTCG from MSVC compiler since it is undocumented). - -## To build the RAD Linker -- Setup development environment, [see](#Development-Setup-Instructions) -- Run `build radlink release` or if you have clang installed `build radlink release clang`. We favor latter option for better code generation. - -If build was successful linker executable is placed in `build` folder under `radlink.exe`. - -## Benchmarks - -![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/a95b382a-76b4-4a4c-b809-b61fe25e667a) - ---- +# Codebase Introduction ## Top-Level Directory Descriptions @@ -221,7 +255,7 @@ also exist: - `local`: Local files, used for local build configuration input files. Not checked in to version control. -## Codebase Introduction +## Layer Descriptions The codebase is organized into *layers*. Layers are separated either to isolate certain problems, and to allow inclusion into various builds without needing to @@ -249,35 +283,33 @@ so in other words, layers are arranged into a directed acyclic graph. A few layers are built to be used completely independently from the rest of the codebase, as libraries in other codebases and projects. As such, these layers do not depend on any other layers in the codebase. The folders which contain these -layers are prefixed with `lib_`, like `lib_rdi_format`. +layers are prefixed with `lib_`, like `lib_rdi`. A list of the layers in the codebase and their associated namespaces is below: - `async` (`ASYNC_`): Implements a system for asynchronous work to be queued and executed on a thread pool. - `base` (no namespace): Universal, codebase-wide constructs. Strings, math, - memory allocators, helper macros, command-line parsing, and so on. Depends - on no other codebase layers. -- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format. -- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File + memory allocators, helper macros, command-line parsing, and so on. Requires + no other codebase layers. +- `codeview` (`CV_`): Code for parsing and writing the CodeView format. +- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File Format) file format. - `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements asynchronous process control, stepping, and breakpoints for all attached processes. Runs in lockstep with attached processes. When it runs, attached processes are halted. When attached processes are running, it is halted. Driven by a debugger frontend on another thread. -- `dasm_cache` (`DASM_`): An asynchronous disassembly decoder and cache. Users - ask for disassembly for some data, with a particular architecture, and other - various parameters, and threads implemented in this layer decode and cache the - disassembly for that data with those parameters. -- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info - stored in the RDI format. Users ask for debug info for a particular path, and - on separate threads, this layer loads the associated debug info file. If - necessary, it will launch a separate conversion process to convert original - debug info into the RDI format. +- `dasm_cache` (`DASM_`): Asynchronous disassembly computation, and a cache to + store asynchronously produced disassembly artifacts. +- `dbgi` (`DI_`): Asynchronous debug info loading, and a cache for loaded + debug info. Loads RAD Debug Info (RDI) files. Launches separate processes for + on-demand conversion to the RDI format if necessary. Also provides various + asynchronous operations for using debug information, like fuzzy searching + across all records in loaded debug information. - `dbg_engine` (`D_`): Implements the core debugger system, without any graphical components. This contains top-level logic for things like stepping, - launching, freezing threads, mid-run breakpoint addition, some caching layers, - and so on. + launching, freezing threads, mid-run breakpoint addition, some caches, and so + on. - `demon` (`DMN_`): An abstraction layer for local-machine, low-level process control. The abstraction is used to provide a common interface for process control on target platforms. Used to implement part of `ctrl`. @@ -285,15 +317,17 @@ A list of the layers in the codebase and their associated namespaces is below: debugger's purposes, using the underlying `render` abstraction layer. Provides high-level APIs for various draw commands, but takes care of batching them, and so on. -- `eval` (`E_`): Implements a compiler for an expression language built for - evaluation of variables, registers, types, and more, from debugger-attached - processes, debug info, debugger state, and files. Broken into several phases - mostly corresponding to traditional compiler phases - lexer, parser, - type-checker, IR generation, and IR evaluation. +- `dwarf` (`DW_`): Code for parsing the DWARF format. +- `elf` (`ELF_`): Code for parsing the ELF format. +- `eval` (`E_`): A compiler for an expression language, built for evaluation of + variables, registers, types, and more, from debugger-attached processes, + debug info, debugger state, and files. Broken into several phases mostly + corresponding to traditional compiler phases: lexer, parser, type-checker, IR + generation, and IR evaluation. - `eval_visualization` (`EV_`): Implements the core non-graphical evaluation visualization engine, which can be used to visualize evaluations (provided by the `eval` layer) in a number of ways. Implements core data structures and - transforms for the `Watch` view. + transforms for watch tables. - `file_stream` (`FS_`): Provides asynchronous file loading, storing the artifacts inside of the cache implemented by the `hash_store` layer, and hot-reloading the contents of files when they change. Allows callers to map @@ -304,31 +338,29 @@ A list of the layers in the codebase and their associated namespaces is below: layer. - `font_provider` (`FP_`): An abstraction layer for various font file decoding and font rasterization backends. -- `fuzzy_search` (`FZY_`): Provides a fuzzy searching engine for doing - large, asynchronous fuzzy searches. Used by the debugger for implementing - things like the symbol lister or the `Procedures` view, which search across - all loaded debug info records, using fuzzy matching rules. - `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU geometry data, filled by data sourced in the `hash_store` layer's cache. Used for asynchronously preparing data for visualization. - `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a - 128-bit hash of the data. Also implements a 128-bit key cache on top, where - the keys refer to a unique identity, associated with a 128-bit hash, where the - hash may change across time. Used as a general data store by other layers. + 128-bit hash of the data. Also implements a keying system on top, where keys + refer to a unique identity which corresponds to a history of 128-bit hashes. + Used as a general data store by other layers. - `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user programs to work with various features in the debugger. Does not depend on `base`, and can be independently relocated to other codebases. -- `lib_rdi_format` (`RDI_`): Standalone library which defines the core RDI types +- `lib_rdi` (`RDI_`): Standalone library which defines the core RDI types and helper functions for reading and writing the RDI debug info file format. Does not depend on `base`, and can be independently relocated to other codebases. - `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info data. Does not depend on `base`, and can be independently relocated to other codebases. +- `linker` (`LNK_`): The layer which implements the RAD Linker executable + itself. - `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which is the JSON-like (technically a JSON superset) text format used for the - debugger's user and project configuration files, view rules, and metacode, - which is parsed and used to generate code with the `metagen` layer. + debugger's user and project configuration files and metacode, which is parsed + and used to generate code with the `metagen` layer. - `metagen` (`MG_`): A metaprogram which is used to generate primarily code and data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and generates C code which is then included by hand-written C code. Currently, it @@ -337,18 +369,13 @@ A list of the layers in the codebase and their associated namespaces is below: tables, which are then used to produce e.g. C `enum`s and a number of associated data tables. There are also a number of other generation features, like embedding binary files or complex multi-line strings into source code. - This layer cannot depend on any other layer in the codebase directly, - including `base`, because it may be used to generate code for those layers. To - still use `base` and `os` layer features in the `metagen` program, a separate, - duplicate version of `base` and `os` are included in this layer. They are - updated manually, as needed. This is to ensure the stability of the - metaprogram. -- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format. +- `msf` (`MSF_`): Code for parsing and writing the MSF file format. +- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT. - `mule` (no namespace): Test executables for battle testing debugger functionality. - `mutable_text` (`MTX_`): Implements an asynchronously-filled-and-mutated cache for text buffers which are mutated across time. In the debugger, this is - used to implement the `Output` view. + used to implement the `Output` log. - `natvis` (no namespace): NatVis files for type visualization of the codebase's types in other debuggers. - `os/core` (`OS_`): An abstraction layer providing core, non-graphical @@ -357,26 +384,30 @@ A list of the layers in the codebase and their associated namespaces is below: - `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing graphical operating system features under an abstract API, which is implemented per-target-operating-system. -- `path` (`PATH_`): Small helpers for manipulating file path strings. -- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format. -- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable) - file format. +- `pdb` (`PDB_`): Code for parsing and writing the PDB file format. +- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file + format. +- `ptr_graph_cache` (`PG_`): An in-progress layer which will supply + asynchronously-computed pointer graphs, used for graph visualization in the + debugger, including structures like trees and linked lists. +- `radbin` (`RB_`): The layer implementing the `radbin` binary utility + executable. - `raddbg` (`RD_`): The layer which ties everything together for the main - graphical debugger. Implements the debugger's graphical frontend, all of the - debugger-specific UI, the debugger executable's command line interface, and - all of the built-in visualizers. -- `rdi_breakpad_from_pdb` (`P2B_`): Our implementation, using the codebase's RDI - technology, for extracting information from PDBs and generating Breakpad text - dumps. -- `rdi_dump` (no namespace): A dumper utility program for dumping - textualizations of RDI debug info files. -- `rdi_format` (no namespace): A layer which includes the `lib_rdi_format` layer - and bundles it with codebase-specific helpers, to easily include the library - in codebase programs, and have it be integrated with codebase constructs. -- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI - conversion. -- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion. -- `rdi_make` (no namespace): A layer which includes the `lib_rdi_make` layer and + graphical debugger executable. Implements the debugger's graphical frontend, + all of the debugger-specific UI, the debugger executable's command line + interface, and all of the built-in visualizers. +- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with + codebase-specific helpers, to easily include the library in codebase programs, + and have it be integrated with codebase constructs. +- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the + equivalent RDI data. +- `rdi_from_dwarf` (`D2R_`): In-progress code for converting DWARF to the + equivalent RDI data. +- `rdi_from_elf` (`E2R_`)): Code for converting ELF data to the equivalent RDI + data. +- `rdi_from_pdb` (`P2R_`): Code for converting PDB data to the equivalent RDI + data. +- `rdi_make` (`RDIM_`): A layer which includes the `lib_rdi_make` layer and bundles it with codebase-specific helpers, to easily include the library in codebase programs, and have it be integrated with codebase constructs. - `regs` (`REGS_`): Types, helper functions, and metadata for registers on @@ -388,11 +419,12 @@ A list of the layers in the codebase and their associated namespaces is below: as-needed basis. Higher level drawing features are implemented in the `draw` layer. - `scratch` (no namespace): Scratch space for small and transient test programs. -- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU - texture data, filled by data sourced in the `hash_store` layer's cache. Used - for asynchronously preparing data for visualization. -- `text_cache` (`TXT_`): Implements an asynchronously-filled cache for textual - analysis data (tokens, line ranges, and so on), filled by data sourced in the +- `tester` (no namespace): A program used for automated testing. +- `texture_cache` (`TEX_`): An asynchronously-filled cache for GPU texture data, + filled by data sourced in the `hash_store` layer's cache. Used for + asynchronously preparing data for visualization. +- `text_cache` (`TXT_`): An asynchronously-filled cache for textual analysis + data (tokens, line ranges, and so on), filled by data sourced in the `hash_store` layer's cache. Used for asynchronously preparing data for visualization (like for the source code viewer). - `third_party` (no namespace): External code from other projects, which some From c5a1da5c804b7cbd9c8925923c051338ffd50bc1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 16 Sep 2025 11:48:00 -0700 Subject: [PATCH 181/302] bump to 22 --- src/base/base_context_cracking.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index 7edbd59b..50cb84a5 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -159,7 +159,7 @@ #endif #if !defined(BUILD_VERSION_PATCH) -# define BUILD_VERSION_PATCH 21 +# define BUILD_VERSION_PATCH 22 #endif #define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) From 49bcb252d9f0aafebde3784efc3a753a10319b9a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 16 Sep 2025 11:51:10 -0700 Subject: [PATCH 182/302] remove year from license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index ef60e20b..81025cbb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2024 Epic Games Tools +Copyright (c) Epic Games Tools Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in From 443646b356da8ada10fa3e44e0e24f7491c8b983 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 16 Sep 2025 12:28:33 -0700 Subject: [PATCH 183/302] rdi make: fix incorrect base encoding offset initialization when pushing into new location chunk --- src/lib_rdi_make/rdi_make.c | 5 +++-- src/rdi/rdi_local.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 0ccff4fb..6295b5fb 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -4,7 +4,7 @@ //////////////////////////////// //~ rjf: API Implementation Helper Macros -#define RDIM_IdxedChunkListPush(arena, list, chunk_type, element_type, cap_value, result) \ +#define RDIM_IdxedChunkListPush(arena, list, chunk_type, element_type, cap_value, result, ...) \ element_type *result = 0;\ do\ {\ @@ -14,6 +14,7 @@ if(n == 0 || n->count >= n->cap)\ n = rdim_push_array(arena, chunk_type, 1);\ n->cap = cap_value;\ n->base_idx = list->total_count;\ +__VA_ARGS__;\ n->v = rdim_push_array_no_zero(arena, element_type, n->cap);\ RDIM_SLLQueuePush(list->first, list->last, n);\ list->chunk_count += 1;\ @@ -1054,7 +1055,7 @@ rdim_encoded_size_from_location_info(RDIM_LocationInfo *info) RDI_PROC RDIM_Location * rdim_location_chunk_list_push_new(RDIM_Arena *arena, RDIM_LocationChunkList *list, RDI_U64 cap, RDIM_LocationInfo *info) { - RDIM_IdxedChunkListPush(arena, list, RDIM_LocationChunkNode, RDIM_Location, cap, result); + RDIM_IdxedChunkListPush(arena, list, RDIM_LocationChunkNode, RDIM_Location, cap, result, n->base_encoding_off = list->total_encoded_size); { RDI_U64 encoded_size = rdim_encoded_size_from_location_info(info); rdim_memcpy_struct(&result->info, info); diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index 874c35dd..f30651c1 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -167,7 +167,7 @@ rdi_string_from_eval_op(Arena *arena, RDI_EvalOp op) switch(op) { default:{result = push_str8f(arena, "%#x", op);}break; -#define X(name) case RDI_EvalOp_##name:{result = str8_lit("#name");}break; +#define X(name) case RDI_EvalOp_##name:{result = str8_lit(#name);}break; RDI_EvalOp_XList #undef X } @@ -181,7 +181,7 @@ rdi_string_from_eval_type_group(Arena *arena, RDI_EvalTypeGroup eval_type_group) switch(eval_type_group) { default:{result = push_str8f(arena, "%#x", eval_type_group);}break; -#define X(name) case RDI_EvalTypeGroup_##name:{result = str8_lit("#name");}break; +#define X(name) case RDI_EvalTypeGroup_##name:{result = str8_lit(#name);}break; RDI_EvalTypeGroup_XList #undef X } From 99c989a3c368532a1f364119b65c2540990b3a7b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 17 Sep 2025 10:06:13 -0700 Subject: [PATCH 184/302] first pass at setting up base layer async thread path --- project.4coder | 4 +- src/base/base_entry_point.c | 18 ++++++ src/base/base_entry_point.h | 1 + src/file_stream/file_stream.c | 113 ++++++++++++++++++++++++++++++++++ src/file_stream/file_stream.h | 28 +++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) diff --git a/project.4coder b/project.4coder index 1bb5aad9..9dc98bf1 100644 --- a/project.4coder +++ b/project.4coder @@ -46,8 +46,8 @@ load_paths = commands = { //- rjf: [raddbg] - // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 6c9c17f2..36b303f7 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -2,6 +2,8 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) global U64 global_update_tick_idx = 0; +global CondVar async_tick_cond_var = {0}; +global Mutex async_tick_mutex = {0}; internal void main_thread_base_entry_point(int arguments_count, char **arguments) @@ -9,6 +11,10 @@ main_thread_base_entry_point(int arguments_count, char **arguments) Temp scratch = scratch_begin(0, 0); ThreadNameF("[main thread]"); + //- rjf: set up async thread group info + async_tick_cond_var = cond_var_alloc(); + async_tick_mutex = mutex_alloc(); + //- rjf: set up telemetry #if PROFILE_TELEMETRY local_persist char tm_data[MB(64)]; @@ -133,3 +139,15 @@ update(void) #endif return result; } + +internal void +async_thread_entry_point(void *params) +{ + MutexScope(async_tick_mutex) for(;;) + { + cond_var_wait(async_tick_cond_var, async_tick_mutex, max_U64); +#if defined(FILE_STREAM_H) + fs_async_tick(); +#endif + } +} diff --git a/src/base/base_entry_point.h b/src/base/base_entry_point.h index 346df5df..91cffd99 100644 --- a/src/base/base_entry_point.h +++ b/src/base/base_entry_point.h @@ -8,5 +8,6 @@ internal void main_thread_base_entry_point(int argc, char **argv); internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params); internal U64 update_tick_idx(void); internal B32 update(void); +internal void async_thread_entry_point(void *params); #endif // BASE_ENTRY_POINT_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 0fec0e2c..e322ee83 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -244,6 +244,119 @@ fs_properties_from_path(String8 path) return result; } +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void +fs_async_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: gather all requests + local_persist FS_Request *reqs = 0; + local_persist U64 reqs_count = 0; + if(lane_idx() == 0) MutexScope(fs_shared->req_mutex) + { + reqs_count = fs_shared->req_count; + reqs = push_array(scratch.arena, FS_Request, reqs_count); + U64 idx = 0; + for EachNode(r, FS_RequestNode, fs_shared->first_req) + { + MemoryCopyStruct(&reqs[idx], &r->v); + reqs[idx].path = str8_copy(scratch.arena, reqs[idx].path); + idx += 1; + } + arena_clear(fs_shared->req_arena); + fs_shared->first_req = fs_shared->last_req = 0; + fs_shared->req_count = 0; + } + lane_sync(); + + //- rjf: do requests + Rng1U64 range = lane_range(reqs_count); + for EachInRange(req_idx, range) + { + //- rjf: unpack + FS_Request *r = &reqs[req_idx]; + HS_Key key = r->key; + String8 path = r->path; + Rng1U64 range = r->range; + U64 path_hash = fs_little_hash_from_string(path); + U64 path_slot_idx = path_hash%fs_shared->slots_count; + U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count; + FS_Slot *path_slot = &fs_shared->slots[path_slot_idx]; + FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; + + //- rjf: load + ProfBegin("load \"%.*s\"", str8_varg(path)); + FileProperties pre_props = os_properties_from_file_path(path); + U64 range_size = dim_1u64(range); + U64 read_size = Min(pre_props.size - range.min, range_size); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); + U64 data_arena_size = read_size+ARENA_HEADER_SIZE; + data_arena_size += KB(4)-1; + data_arena_size -= data_arena_size%KB(4); + ProfBegin("allocate"); + Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); + ProfEnd(); + ProfBegin("read"); + String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size)); + ProfEnd(); + os_file_close(file); + FileProperties post_props = os_properties_from_file_path(path); + + //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file + B32 read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + read_size == data.size && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + if(!read_good) + { + ProfScope("abort") + { + arena_release(data_arena); + MemoryZeroStruct(&data); + data_arena = 0; + } + } + + //- rjf: submit + else + { + ProfScope("submit") + { + hs_submit_data(key, &data_arena, data); + } + } + + //- rjf: commit info to cache + ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex) + { + FS_Node *node = 0; + for(FS_Node *n = path_slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0)) + { + node = n; + break; + } + } + if(node != 0 && read_good) + { + if(node->props.modified != 0) + { + ins_atomic_u64_inc_eval(&fs_shared->change_gen); + } + node->props = post_props; + } + } + cond_var_broadcast(path_stripe->cv); + } + + scratch_end(scratch); +} + //////////////////////////////// //~ rjf: Streamer Threads diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index b3b4aac2..dae0393b 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -57,6 +57,22 @@ struct FS_Stripe //////////////////////////////// //~ rjf: Shared State Bundle +typedef struct FS_Request FS_Request; +struct FS_Request +{ + FS_Request *next; + HS_Key key; + String8 path; + Rng1U64 range; +}; + +typedef struct FS_RequestNode FS_RequestNode; +struct FS_RequestNode +{ + FS_RequestNode *next; + FS_Request v; +}; + typedef struct FS_Shared FS_Shared; struct FS_Shared { @@ -69,6 +85,13 @@ struct FS_Shared FS_Slot *slots; FS_Stripe *stripes; + // rjf: requests + Mutex req_mutex; + Arena *req_arena; + FS_RequestNode *first_req; + FS_RequestNode *last_req; + U64 req_count; + // rjf: user -> streamer ring buffer U64 u2s_ring_size; U8 *u2s_ring_base; @@ -109,6 +132,11 @@ internal HS_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal FileProperties fs_properties_from_path(String8 path); +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void fs_async_tick(void); + //////////////////////////////// //~ rjf: Streaming Work From 0d15b8670bf8364f41159efe19f09734993fb251 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 17 Sep 2025 14:47:55 -0700 Subject: [PATCH 185/302] eliminate bifurcated rw lock path based on exclusive mode; promote thread operations to base layer, use os layer as impl; first pass on moving file streaming layer to base layer's async wavefront --- src/async/async.c | 12 +- src/async/async.h | 2 +- src/base/base_entry_point.c | 69 +++++- src/base/base_inc.c | 2 +- src/base/base_inc.h | 2 +- src/base/{base_sync.c => base_threads.c} | 42 +++- src/base/{base_sync.h => base_threads.h} | 39 ++- src/ctrl/ctrl_core.c | 76 +++--- src/ctrl/ctrl_core.h | 2 +- src/dasm_cache/dasm_cache.c | 20 +- src/dasm_cache/dasm_cache.h | 2 +- src/dbgi/dbgi.c | 50 ++-- src/dbgi/dbgi.h | 4 +- src/demon/linux/demon_core_linux.c | 4 +- src/demon/win32/demon_core_win32.c | 6 +- src/file_stream/file_stream.c | 287 ++++++----------------- src/file_stream/file_stream.h | 23 -- src/geo_cache/geo_cache.c | 22 +- src/geo_cache/geo_cache.h | 2 +- src/hash_store/hash_store.c | 34 +-- src/hash_store/hash_store.h | 2 +- src/mutable_text/mutable_text.c | 8 +- src/mutable_text/mutable_text.h | 2 +- src/os/core/linux/os_core_linux.c | 91 +++---- src/os/core/linux/os_core_linux.h | 4 +- src/os/core/linux/os_core_linux_old.c | 6 +- src/os/core/linux/os_core_linux_old.h | 4 +- src/os/core/os_core.c | 15 -- src/os/core/os_core.h | 33 +-- src/os/core/win32/os_core_win32.c | 72 +++--- src/os/core/win32/os_core_win32.h | 2 +- src/ptr_graph_cache/ptr_graph_cache.c | 18 +- src/ptr_graph_cache/ptr_graph_cache.h | 4 +- src/radbin/radbin.c | 6 +- src/raddbg/raddbg_main.c | 16 +- src/render/d3d11/render_d3d11.c | 24 +- src/text_cache/text_cache.c | 24 +- src/text_cache/text_cache.h | 2 +- src/texture_cache/texture_cache.c | 22 +- src/texture_cache/texture_cache.h | 2 +- 40 files changed, 450 insertions(+), 607 deletions(-) rename src/base/{base_sync.c => base_threads.c} (64%) rename src/base/{base_sync.h => base_threads.h} (63%) diff --git a/src/async/async.c b/src/async/async.c index 953f34a5..eeef9054 100644 --- a/src/async/async.c +++ b/src/async/async.c @@ -29,10 +29,10 @@ async_init(CmdLine *cmdline) async_shared->work_threads_count = Max(4, os_get_system_info()->logical_processor_count-1); } async_shared->work_threads_count = Max(4, async_shared->work_threads_count); - async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count); + async_shared->work_threads = push_array(arena, Thread, async_shared->work_threads_count); for EachIndex(idx, async_shared->work_threads_count) { - async_shared->work_threads[idx] = os_thread_launch(async_work_thread__entry_point, (void *)idx, 0); + async_shared->work_threads[idx] = thread_launch(async_work_thread__entry_point, (void *)idx); } } @@ -68,7 +68,7 @@ async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params // thread, and skip ring buffer if so. B32 queued_in_ring_buffer = 0; B32 need_to_execute_on_this_thread = 0; - OS_MutexScope(ring->ring_mutex) for(;;) + MutexScope(ring->ring_mutex) for(;;) { U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count)); if(num_available_work_threads == 0 && async_work_thread_depth > 0) @@ -167,12 +167,12 @@ async_pop_work(void) ASYNC_Work work = {0}; B32 done = 0; ASYNC_Priority taken_priority = ASYNC_Priority_Low; - OS_MutexScope(async_shared->ring_mutex) for(;!done;) + MutexScope(async_shared->ring_mutex) for(;!done;) { for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1)) { ASYNC_Ring *ring = &async_shared->rings[priority]; - OS_MutexScope(ring->ring_mutex) + MutexScope(ring->ring_mutex) { U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos; if(unconsumed_size >= sizeof(work)) @@ -274,7 +274,7 @@ internal void async_work_thread__entry_point(void *p) { U64 thread_idx = (U64)p; - ThreadNameF("[async] work thread #%I64u", thread_idx); + ThreadNameF("async_work_thread_%I64u", thread_idx); async_work_thread_idx = thread_idx; for(;;) { diff --git a/src/async/async.h b/src/async/async.h index b7fcc6b6..cf905e5a 100644 --- a/src/async/async.h +++ b/src/async/async.h @@ -104,7 +104,7 @@ struct ASYNC_Shared CondVar ring_cv; // rjf: work threads - OS_Handle *work_threads; + Thread *work_threads; U64 work_threads_count; U64 work_threads_live_count; }; diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 36b303f7..aee68a3e 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -2,18 +2,23 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) global U64 global_update_tick_idx = 0; -global CondVar async_tick_cond_var = {0}; -global Mutex async_tick_mutex = {0}; +global CondVar async_tick_start_cond_var = {0}; +global CondVar async_tick_stop_cond_var = {0}; +global Mutex async_tick_start_mutex = {0}; +global Mutex async_tick_stop_mutex = {0}; +global B32 global_async_exit = 0; internal void main_thread_base_entry_point(int arguments_count, char **arguments) { + ThreadNameF("main_thread"); Temp scratch = scratch_begin(0, 0); - ThreadNameF("[main thread]"); //- rjf: set up async thread group info - async_tick_cond_var = cond_var_alloc(); - async_tick_mutex = mutex_alloc(); + async_tick_start_cond_var = cond_var_alloc(); + async_tick_start_mutex = mutex_alloc(); + async_tick_stop_cond_var = cond_var_alloc(); + async_tick_stop_mutex = mutex_alloc(); //- rjf: set up telemetry #if PROFILE_TELEMETRY @@ -29,7 +34,13 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #endif //- rjf: parse command line - String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, arguments_count, arguments); + String8List command_line_argument_strings = {0}; + { + for EachIndex(idx, arguments_count) + { + str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx])); + } + } CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings); //- rjf: begin captures @@ -37,12 +48,9 @@ main_thread_base_entry_point(int arguments_count, char **arguments) if(capture) { ProfBeginCapture(arguments[0]); + ProfMsg(BUILD_TITLE); } -#if PROFILE_TELEMETRY - tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE); -#endif - //- rjf: initialize all included layers #if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL) async_init(&cmdline); @@ -96,9 +104,42 @@ main_thread_base_entry_point(int arguments_count, char **arguments) rd_init(&cmdline); #endif + //- rjf: launch async threads + Thread *async_threads = 0; + U64 async_threads_count = 0; + { + U64 num_main_threads = 1; +#if defined(CTRL_CORE_H) + num_main_threads += 1; +#endif + U64 num_async_threads = os_get_system_info()->logical_processor_count; + U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads); + num_async_threads -= num_main_threads_clamped; + num_async_threads = Max(1, num_async_threads); + Barrier barrier = barrier_alloc(num_async_threads); + LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads); + async_threads_count = num_async_threads; + async_threads = push_array(scratch.arena, Thread, async_threads_count); + for EachIndex(idx, num_async_threads) + { + lane_ctxs[idx].lane_idx = idx; + lane_ctxs[idx].lane_count = num_async_threads; + lane_ctxs[idx].barrier = barrier; + async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]); + } + } + //- rjf: call into entry point entry_point(&cmdline); + //- rjf: join async threads + ins_atomic_u32_inc_eval(&global_async_exit); + cond_var_broadcast(async_tick_start_cond_var); + for EachIndex(idx, async_threads_count) + { + thread_join(async_threads[idx], max_U64); + } + //- rjf: end captures if(capture) { @@ -143,11 +184,15 @@ update(void) internal void async_thread_entry_point(void *params) { - MutexScope(async_tick_mutex) for(;;) + LaneCtx lctx = *(LaneCtx *)params; + lane_ctx(lctx); + ThreadNameF("async_thread_%I64u", lane_idx()); + for(;!ins_atomic_u32_eval(&global_async_exit);) { - cond_var_wait(async_tick_cond_var, async_tick_mutex, max_U64); + MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); #if defined(FILE_STREAM_H) fs_async_tick(); #endif + cond_var_broadcast(async_tick_stop_cond_var); } } diff --git a/src/base/base_inc.c b/src/base/base_inc.c index dc6cad3c..ec199ac0 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -12,7 +12,7 @@ #include "base_arena.c" #include "base_math.c" #include "base_strings.c" -#include "base_sync.c" +#include "base_threads.c" #include "base_thread_context.c" #include "base_command_line.c" #include "base_markup.c" diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 72d22362..4bf367da 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -14,7 +14,7 @@ #include "base_arena.h" #include "base_math.h" #include "base_strings.h" -#include "base_sync.h" +#include "base_threads.h" #include "base_thread_context.h" #include "base_command_line.h" #include "base_markup.h" diff --git a/src/base/base_sync.c b/src/base/base_threads.c similarity index 64% rename from src/base/base_sync.c rename to src/base/base_threads.c index daa5f462..a992ed6f 100644 --- a/src/base/base_sync.c +++ b/src/base/base_threads.c @@ -1,6 +1,29 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Thread Functions + +internal Thread +thread_launch(ThreadEntryPointFunctionType *f, void *p) +{ + Thread thread = os_thread_launch(f, p); + return thread; +} + +internal B32 +thread_join(Thread thread, U64 endt_us) +{ + B32 result = os_thread_join(thread, endt_us); + return result; +} + +internal void +thread_detach(Thread thread) +{ + os_thread_detach(thread); +} + //////////////////////////////// //~ rjf: Synchronization Primitive Functions @@ -15,20 +38,17 @@ internal void mutex_drop(Mutex mutex) {os_mutex_drop(mutex);} internal RWMutex rw_mutex_alloc(void) {return os_rw_mutex_alloc();} internal void rw_mutex_release(RWMutex mutex) {os_rw_mutex_release(mutex);} -internal void rw_mutex_take_r(RWMutex mutex) {os_rw_mutex_take_r(mutex);} -internal void rw_mutex_drop_r(RWMutex mutex) {os_rw_mutex_drop_r(mutex);} -internal void rw_mutex_take_w(RWMutex mutex) {os_rw_mutex_take_w(mutex);} -internal void rw_mutex_drop_w(RWMutex mutex) {os_rw_mutex_drop_w(mutex);} +internal void rw_mutex_take(RWMutex mutex, B32 write_mode) {os_rw_mutex_take(mutex, write_mode);} +internal void rw_mutex_drop(RWMutex mutex, B32 write_mode) {os_rw_mutex_drop(mutex, write_mode);} //- rjf: condition variables -internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();} -internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);} -internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);} -internal B32 cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us) {return os_cond_var_wait_rw_r(cv, mutex_rw, endt_us);} -internal B32 cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us) {return os_cond_var_wait_rw_w(cv, mutex_rw, endt_us);} -internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);} -internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);} +internal CondVar cond_var_alloc(void) {return os_cond_var_alloc();} +internal void cond_var_release(CondVar cv) {os_cond_var_release(cv);} +internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) {return os_cond_var_wait(cv, mutex, endt_us);} +internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) {return os_cond_var_wait_rw(cv, mutex_rw, write_mode, endt_us);} +internal void cond_var_signal(CondVar cv) {os_cond_var_signal(cv);} +internal void cond_var_broadcast(CondVar cv) {os_cond_var_broadcast(cv);} //- rjf: cross-process semaphores diff --git a/src/base/base_sync.h b/src/base/base_threads.h similarity index 63% rename from src/base/base_sync.h rename to src/base/base_threads.h index c3251037..d33712b5 100644 --- a/src/base/base_sync.h +++ b/src/base/base_threads.h @@ -1,8 +1,18 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef BASE_SYNC_H -#define BASE_SYNC_H +#ifndef BASE_THREADS_H +#define BASE_THREADS_H + +//////////////////////////////// +//~ rjf: Thread Types + +typedef struct Thread Thread; +struct Thread +{ + U64 u64[1]; +}; +typedef void ThreadEntryPointFunctionType(void *p); //////////////////////////////// //~ rjf: Synchronization Primitive Types @@ -37,6 +47,13 @@ struct Barrier U64 u64[1]; }; +//////////////////////////////// +//~ rjf: Thread Functions + +internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p); +internal B32 thread_join(Thread thread, U64 endt_us); +internal void thread_detach(Thread thread); + //////////////////////////////// //~ rjf: Synchronization Primitive Functions @@ -49,18 +66,21 @@ internal void mutex_drop(Mutex mutex); //- rjf: reader/writer mutexes internal RWMutex rw_mutex_alloc(void); internal void rw_mutex_release(RWMutex mutex); -internal void rw_mutex_take_r(RWMutex mutex); -internal void rw_mutex_drop_r(RWMutex mutex); -internal void rw_mutex_take_w(RWMutex mutex); -internal void rw_mutex_drop_w(RWMutex mutex); +internal void rw_mutex_take(RWMutex mutex, B32 write_mode); +internal void rw_mutex_drop(RWMutex mutex, B32 write_mode); +#define rw_mutex_take_r(m) rw_mutex_take((m), (0)) +#define rw_mutex_take_w(m) rw_mutex_take((m), (1)) +#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0)) +#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1)) //- rjf: condition variables internal CondVar cond_var_alloc(void); internal void cond_var_release(CondVar cv); // returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us); -internal B32 cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us); -internal B32 cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us); +#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt)) +#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt)) internal void cond_var_signal(CondVar cv); internal void cond_var_broadcast(CondVar cv); @@ -79,8 +99,9 @@ internal void barrier_wait(Barrier barrier); //- rjf: scope macros #define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex)) +#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode))) #define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex)) #define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex)) #define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex))) -#endif // BASE_SYNC_H +#endif // BASE_THREADS_H diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index ec12c673..aa85862a 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1603,7 +1603,7 @@ ctrl_init(void) ctrl_state->u2csb_ring_mutex = mutex_alloc(); ctrl_state->u2csb_ring_cv = cond_var_alloc(); ctrl_state->ctrl_thread_log = log_alloc(); - ctrl_state->ctrl_thread = os_thread_launch(ctrl_thread__entry_point, 0, 0); + ctrl_state->ctrl_thread = thread_launch(ctrl_thread__entry_point, 0); } //////////////////////////////// @@ -1637,7 +1637,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 HS_Root root = {0}; { B32 node_found = 0; - OS_MutexScopeR(process_stripe->rw_mutex) + MutexScopeR(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { @@ -1649,7 +1649,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 } } } - if(!node_found) OS_MutexScopeW(process_stripe->rw_mutex) + if(!node_found) MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { @@ -1699,7 +1699,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 B32 id_exists = 0; B32 id_stale = 0; B32 id_working = 0; - OS_MutexScopeR(process_stripe->rw_mutex) for(;;) + MutexScopeR(process_stripe->rw_mutex) for(;;) { for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) { @@ -1747,7 +1747,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 if(!id_exists || (id_exists && id_stale && !id_working)) { B32 node_needs_stream = 0; - OS_MutexScopeW(process_stripe->rw_mutex) + MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) { @@ -1796,7 +1796,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 async_push_work(ctrl_mem_stream_work); requested = 1; } - else OS_MutexScopeW(process_stripe->rw_mutex) + else MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) { @@ -2041,7 +2041,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) U64 stripe_idx = slot_idx%cache->stripes_count; CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->next) { @@ -2097,7 +2097,7 @@ ctrl_reg_block_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle handle CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx]; CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx]; void *result = push_array(arena, U8, reg_block_size); - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { // rjf: find existing node CTRL_ThreadRegCacheNode *node = 0; @@ -2203,7 +2203,7 @@ ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_Handle module_handle, U64 v U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->module, module_handle)) { @@ -2269,7 +2269,7 @@ ctrl_entry_point_voff_from_module(CTRL_Handle module_handle) U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->module, module_handle)) { @@ -2289,7 +2289,7 @@ ctrl_tls_vaddr_range_from_module(CTRL_Handle module_handle) U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->module, module_handle)) { @@ -2309,7 +2309,7 @@ ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_Handle module_handle U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->module, module_handle)) { @@ -2329,7 +2329,7 @@ ctrl_raddbg_data_from_module(Arena *arena, CTRL_Handle module_handle) U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->module, module_handle)) { @@ -3460,7 +3460,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 hi B32 node_exists = 0; B32 node_stale = 1; B32 node_working = 0; - OS_MutexScopeR(stripe->rw_mutex) for(;;) + MutexScopeR(stripe->rw_mutex) for(;;) { CTRL_CallStackCacheNode *node = 0; for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) @@ -3499,7 +3499,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 hi //- rjf: [write] node does not exist => create; request if new or stale B32 need_request = (!node_exists || node_stale); CTRL_CallStackCacheNode *node_to_request = 0; - if(can_request && need_request) OS_MutexScopeW(stripe->rw_mutex) + if(can_request && need_request) MutexScopeW(stripe->rw_mutex) { CTRL_CallStackCacheNode *node = 0; for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) @@ -3530,7 +3530,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 hi { async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); } - else OS_MutexScopeW(stripe->rw_mutex) + else MutexScopeW(stripe->rw_mutex) { node_to_request->working_count -= 1; } @@ -3551,7 +3551,7 @@ ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us) U64 reg_gen = ctrl_reg_gen(); U64 mem_gen = ctrl_mem_gen(); CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; - OS_MutexScopeR(cache->rw_mutex) for(;;) + MutexScopeR(cache->rw_mutex) for(;;) { // rjf: unpack cache/time state B32 is_stale = (cache->reg_gen != reg_gen || cache->mem_gen != mem_gen); @@ -3641,7 +3641,7 @@ ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us) Temp scratch = scratch_begin(0, 0); String8 msgs_srlzed_baked = ctrl_serialized_string_from_msg_list(scratch.arena, msgs); B32 good = 0; - OS_MutexScope(ctrl_state->u2c_ring_mutex) for(;;) + MutexScope(ctrl_state->u2c_ring_mutex) for(;;) { U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos); U64 available_size = ctrl_state->u2c_ring_size-unconsumed_size; @@ -3672,7 +3672,7 @@ ctrl_u2c_pop_msgs(Arena *arena) { Temp scratch = scratch_begin(&arena, 1); String8 msgs_srlzed_baked = {0}; - OS_MutexScope(ctrl_state->u2c_ring_mutex) for(;;) + MutexScope(ctrl_state->u2c_ring_mutex) for(;;) { U64 unconsumed_size = (ctrl_state->u2c_ring_write_pos-ctrl_state->u2c_ring_read_pos); if(unconsumed_size >= sizeof(U64)) @@ -3699,7 +3699,7 @@ ctrl_c2u_push_events(CTRL_EventList *events) { if(events->count != 0) ProfScope("ctrl_c2u_push_events") { - OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { ctrl_entity_store_apply_events(ctrl_state->ctrl_thread_entity_store, events); } @@ -3707,7 +3707,7 @@ ctrl_c2u_push_events(CTRL_EventList *events) { Temp scratch = scratch_begin(0, 0); String8 event_srlzed = ctrl_serialized_string_from_event(scratch.arena, &n->v, ctrl_state->c2u_ring_size-sizeof(U64)); - OS_MutexScope(ctrl_state->c2u_ring_mutex) for(;;) + MutexScope(ctrl_state->c2u_ring_mutex) for(;;) { U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos); U64 available_size = ctrl_state->c2u_ring_size-unconsumed_size; @@ -3736,7 +3736,7 @@ ctrl_c2u_pop_events(Arena *arena) ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); CTRL_EventList events = {0}; - OS_MutexScope(ctrl_state->c2u_ring_mutex) for(;;) + MutexScope(ctrl_state->c2u_ring_mutex) for(;;) { U64 unconsumed_size = (ctrl_state->c2u_ring_write_pos-ctrl_state->c2u_ring_read_pos); if(unconsumed_size >= sizeof(U64)) @@ -3766,7 +3766,7 @@ ctrl_c2u_pop_events(Arena *arena) internal void ctrl_thread__entry_point(void *p) { - ThreadNameF("[ctrl] thread"); + ThreadNameF("ctrl_thread"); ProfBeginFunction(); DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin(); log_select(ctrl_state->ctrl_thread_log); @@ -3896,7 +3896,7 @@ ctrl_thread__entry_point(void *p) CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); DI_Key old_dbgi_key = {debug_info_path->string, debug_info_path->timestamp}; di_close(&old_dbgi_key); - OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path_normalized_from_string(scratch.arena, path)); } @@ -4386,7 +4386,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { CTRL_ModuleImageInfoCacheNode *node = 0; for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) @@ -4427,7 +4427,7 @@ ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { CTRL_ModuleImageInfoCacheNode *node = 0; for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) @@ -5068,7 +5068,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, U64 stripe_idx = slot_idx%cache->stripes_count; CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = slot->first, *next = 0; n != 0; n = next) { @@ -5431,7 +5431,7 @@ ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: record (id -> entry points), so that we know custom entry points for this PID CTRL_EntityCtxRWStore *entity_ctx_rw_store = ctrl_state->ctrl_thread_entity_store; - OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) { @@ -6869,7 +6869,7 @@ internal B32 ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) { B32 good = 0; - OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; @@ -6892,7 +6892,7 @@ ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 internal void ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) { - OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; if(unconsumed_size >= sizeof(*out_key)+sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated)) @@ -7045,7 +7045,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) } //- rjf: commit new info to cache - OS_MutexScopeW(process_stripe->rw_mutex) + MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { @@ -7093,7 +7093,7 @@ internal B32 ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us) { B32 good = 0; - OS_MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) + MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; U64 available_size = ctrl_state->u2csb_ring_size - unconsumed_size; @@ -7119,7 +7119,7 @@ ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us) internal void ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread) { - OS_MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) + MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; if(unconsumed_size >= sizeof(*out_thread)) @@ -7150,7 +7150,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) //- rjf: produce mini entity context for just this process CTRL_EntityCtx *entity_ctx = push_array(scratch.arena, CTRL_EntityCtx, 1); - OS_MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { CTRL_EntityCtx *src_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_EntityCtx *dst_ctx = entity_ctx; @@ -7263,7 +7263,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) { B32 found = 0; B32 committed = 0; - OS_MutexScopeW(stripe->rw_mutex) for(;;) + MutexScopeW(stripe->rw_mutex) for(;;) { // rjf: try to find node & commit for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) @@ -7311,7 +7311,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work) } //- rjf: mark work as done - OS_MutexScopeW(stripe->rw_mutex) for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) + MutexScopeW(stripe->rw_mutex) for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) { if(ctrl_handle_match(n->thread, thread_handle)) { @@ -7345,7 +7345,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) CTRL_Handle *threads = 0; CTRL_Handle *threads_processes = 0; Arch *threads_arches = 0; - OS_MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { CTRL_EntityCtx *ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_EntityArray thread_entities = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Thread); @@ -7434,7 +7434,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; if(tree.root != &ctrl_call_stack_tree_node_nil) { - OS_MutexScopeW(cache->rw_mutex) for(;;) + MutexScopeW(cache->rw_mutex) for(;;) { if(cache->scope_touch_count == 0) { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index c9a996d7..1ba02bc7 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -870,7 +870,7 @@ struct CTRL_State // rjf: ctrl thread state U64 ctrl_thread_run_state; String8 ctrl_thread_log_path; - OS_Handle ctrl_thread; + Thread ctrl_thread; Log *ctrl_thread_log; RWMutex ctrl_thread_entity_ctx_rw_mutex; CTRL_EntityCtxRWStore *ctrl_thread_entity_store; diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 1fb6dcc5..6cd83d9a 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -277,7 +277,7 @@ dasm_init(void) dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size); dasm_shared->u2p_ring_cv = cond_var_alloc(); dasm_shared->u2p_ring_mutex = mutex_alloc(); - dasm_shared->evictor_detector_thread = os_thread_launch(dasm_evictor_detector_thread__entry_point, 0, 0); + dasm_shared->evictor_detector_thread = thread_launch(dasm_evictor_detector_thread__entry_point, 0); } //////////////////////////////// @@ -308,7 +308,7 @@ dasm_scope_close(DASM_Scope *scope) U64 stripe_idx = slot_idx%dasm_shared->stripes_count; DASM_Slot *slot = &dasm_shared->slots[slot_idx]; DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -353,7 +353,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) //- rjf: try to get existing results B32 found = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -373,7 +373,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) B32 node_is_new = 0; U64 *node_working_count = 0; HS_Root root = {0}; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { DASM_Node *node = 0; for(DASM_Node *n = slot->first; n != 0; n = n->next) @@ -450,7 +450,7 @@ internal B32 dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us) { B32 good = 0; - OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) + MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; @@ -485,7 +485,7 @@ dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us) internal void dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out) { - OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) + MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64)) @@ -722,7 +722,7 @@ ASYNC_WORK_DEF(dasm_parse_work) } //- rjf: commit results to cache - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -757,7 +757,7 @@ ASYNC_WORK_DEF(dasm_parse_work) internal void dasm_evictor_detector_thread__entry_point(void *p) { - ThreadNameF("[dasm] evictor/detector thread"); + ThreadNameF("dasm_evictor_detector_thread"); for(;;) { U64 change_gen = fs_change_gen(); @@ -773,7 +773,7 @@ dasm_evictor_detector_thread__entry_point(void *p) DASM_Slot *slot = &dasm_shared->slots[slot_idx]; DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -794,7 +794,7 @@ dasm_evictor_detector_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 5423ddb2..898089ed 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -263,7 +263,7 @@ struct DASM_Shared Mutex u2p_ring_mutex; // rjf: evictor/detector thread - OS_Handle evictor_detector_thread; + Thread evictor_detector_thread; }; //////////////////////////////// diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 49aec576..aff0da46 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -238,9 +238,9 @@ di_init(void) di_shared->search_threads[idx].ring_cv = cond_var_alloc(); di_shared->search_threads[idx].ring_size = KB(64); di_shared->search_threads[idx].ring_base = push_array_no_zero(arena, U8, di_shared->search_threads[idx].ring_size); - di_shared->search_threads[idx].thread = os_thread_launch(di_search_thread__entry_point, (void *)idx, 0); + di_shared->search_threads[idx].thread = thread_launch(di_search_thread__entry_point, (void *)idx); } - di_shared->search_evictor_thread = os_thread_launch(di_search_evictor_thread__entry_point, 0, 0); + di_shared->search_evictor_thread = thread_launch(di_search_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -468,7 +468,7 @@ di_open(DI_Key *key) DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; log_infof("open_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp); - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { //- rjf: find existing node DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); @@ -529,7 +529,7 @@ di_close(DI_Key *key) DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; log_infof("close_debug_info: {\"%S\", 0x%I64x}\n", key->path, key->min_timestamp); - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { //- rjf: find existing node DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); @@ -591,7 +591,7 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us) U64 stripe_idx = slot_idx%di_shared->stripes_count; DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; - ProfScope("grab node") OS_MutexScopeR(stripe->rw_mutex) for(;;) + ProfScope("grab node") MutexScopeR(stripe->rw_mutex) for(;;) { //- rjf: find existing node DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, key); @@ -662,7 +662,7 @@ di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams U64 stripe_idx = slot_idx%di_shared->search_stripes_count; DI_SearchSlot * slot = &di_shared->search_slots[slot_idx]; DI_SearchStripe * stripe = &di_shared->search_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) for(;;) + MutexScopeW(stripe->rw_mutex) for(;;) { // rjf: map key -> node DI_SearchNode *node = 0; @@ -753,7 +753,7 @@ internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us) { B32 sent = 0; - OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) + MutexScope(di_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; U64 available_size = di_shared->u2p_ring_size - unconsumed_size; @@ -782,7 +782,7 @@ di_u2p_enqueue_key(DI_Key *key, U64 endt_us) internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) { - OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) + MutexScope(di_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; if(unconsumed_size >= sizeof(out_key->path.size) + sizeof(out_key->min_timestamp)) @@ -801,7 +801,7 @@ di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) internal void di_p2u_push_event(DI_Event *event) { - OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) + MutexScope(di_shared->p2u_ring_mutex) for(;;) { U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); U64 available_size = di_shared->p2u_ring_size-unconsumed_size; @@ -822,7 +822,7 @@ internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us) { DI_EventList events = {0}; - OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) + MutexScope(di_shared->p2u_ring_mutex) for(;;) { U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) @@ -1111,7 +1111,7 @@ ASYNC_WORK_DEF(di_parse_work) //////////////////////////// //- rjf: commit parsed info to cache // - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); if(node != 0) @@ -1153,7 +1153,7 @@ di_u2s_enqueue_req(U128 key, U64 endt_us) B32 result = 0; U64 thread_idx = key.u64[0]%di_shared->search_threads_count; DI_SearchThread *thread = &di_shared->search_threads[thread_idx]; - OS_MutexScope(thread->ring_mutex) for(;;) + MutexScope(thread->ring_mutex) for(;;) { U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; U64 available_size = thread->ring_size - unconsumed_size; @@ -1181,7 +1181,7 @@ di_u2s_dequeue_req(U64 thread_idx) { U128 key = {0}; DI_SearchThread *thread = &di_shared->search_threads[thread_idx]; - OS_MutexScope(thread->ring_mutex) for(;;) + MutexScope(thread->ring_mutex) for(;;) { U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; if(unconsumed_size >= sizeof(key)) @@ -1272,7 +1272,7 @@ ASYNC_WORK_DEF(di_search_work) //- rjf: every so often, check the key's write gen - if it has been bumped, then cancel if(idx%100 == 0) { - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(DI_SearchNode *n = slot->first; n != 0; n = n->next) { @@ -1385,7 +1385,7 @@ internal void di_search_thread__entry_point(void *p) { U64 thread_idx = (U64)p; - ThreadNameF("[di] search thread #%I64u", thread_idx); + ThreadNameF("di_search_thread_%I64u", thread_idx); for(;;) { Temp scratch = scratch_begin(0, 0); @@ -1402,7 +1402,7 @@ di_search_thread__entry_point(void *p) String8 query = {0}; DI_SearchParams params = {0}; U64 initial_bucket_write_gen = 0; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { for(DI_SearchNode *n = slot->first; n != 0; n = n->next) { @@ -1512,7 +1512,7 @@ di_search_thread__entry_point(void *p) //- rjf: commit to cache - wait on scope touches if(arena != 0) { - OS_MutexScopeW(stripe->rw_mutex) for(;;) + MutexScopeW(stripe->rw_mutex) for(;;) { B32 found = 0; B32 done = 0; @@ -1553,7 +1553,7 @@ di_search_thread__entry_point(void *p) internal void di_search_evictor_thread__entry_point(void *p) { - ThreadNameF("[di] search evictor thread"); + ThreadNameF("di_search_evictor_thread"); for(;;) { for(U64 slot_idx = 0; slot_idx < di_shared->search_slots_count; slot_idx += 1) @@ -1562,7 +1562,7 @@ di_search_evictor_thread__entry_point(void *p) DI_SearchSlot *slot = &di_shared->search_slots[slot_idx]; DI_SearchStripe *stripe = &di_shared->search_stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(DI_SearchNode *n = slot->first; n != 0; n = n->next) { @@ -1573,7 +1573,7 @@ di_search_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(DI_SearchNode *n = slot->first, *next = 0; n != 0; n = next) { @@ -1642,7 +1642,7 @@ di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys) } // rjf: store parameters if needed - if(store->params_hash != params_hash) OS_MutexScopeW(store->params_rw_mutex) + if(store->params_hash != params_hash) MutexScopeW(store->params_rw_mutex) { arena_clear(store->params_arena); store->params_hash = params_hash; @@ -1738,7 +1738,7 @@ di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us) if(completed_params_hash != store->params_hash && node->req_count == ins_atomic_u64_eval(&node->cmp_count)) { B32 sent = 0; - OS_MutexScope(store->u2m_ring_mutex) for(;;) + MutexScope(store->u2m_ring_mutex) for(;;) { U64 unconsumed_size = store->u2m_ring_write_pos - store->u2m_ring_read_pos; U64 available_size = store->u2m_ring_size - unconsumed_size; @@ -1770,7 +1770,7 @@ di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us) // rjf: if this node's state is stale, wait for it if we need to if(os_now_microseconds() < endt_us && node->req_params_hash != completed_params_hash) { - OS_MutexScopeR(store->match_rw_mutex) for(;;) + MutexScopeR(store->match_rw_mutex) for(;;) { if(node->req_params_hash == ins_atomic_u64_eval(&node->cmp_params_hash)) { @@ -1805,7 +1805,7 @@ ASYNC_WORK_DEF(di_match_work) DI_MatchNameNode *node = 0; U64 alloc_gen = 0; String8 name = {0}; - ProfScope("get next name") OS_MutexScope(store->u2m_ring_mutex) for(;;) + ProfScope("get next name") MutexScope(store->u2m_ring_mutex) for(;;) { U64 unconsumed_size = store->u2m_ring_write_pos - store->u2m_ring_read_pos; if(unconsumed_size >= sizeof(U64)) @@ -1824,7 +1824,7 @@ ASYNC_WORK_DEF(di_match_work) //- rjf: read parameters U64 params_hash = 0; DI_KeyArray params_keys = {0}; - ProfScope("read parameters") OS_MutexScopeR(store->params_rw_mutex) + ProfScope("read parameters") MutexScopeR(store->params_rw_mutex) { params_keys = di_key_array_copy(scratch.arena, &store->params_keys); params_hash = store->params_hash; diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 48545d26..10f59b27 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -248,7 +248,7 @@ struct DI_TCTX typedef struct DI_SearchThread DI_SearchThread; struct DI_SearchThread { - OS_Handle thread; + Thread thread; Mutex ring_mutex; CondVar ring_cv; U64 ring_size; @@ -386,7 +386,7 @@ struct DI_Shared // rjf: search threads U64 search_threads_count; DI_SearchThread *search_threads; - OS_Handle search_evictor_thread; + Thread search_evictor_thread; }; //////////////////////////////// diff --git a/src/demon/linux/demon_core_linux.c b/src/demon/linux/demon_core_linux.c index 4fed12a3..8f613189 100644 --- a/src/demon/linux/demon_core_linux.c +++ b/src/demon/linux/demon_core_linux.c @@ -922,7 +922,7 @@ dmn_ctrl_begin(void) internal void dmn_ctrl_exclusive_access_begin(void) { - OS_MutexScope(dmn_lnx_state->access_mutex) + MutexScope(dmn_lnx_state->access_mutex) { dmn_lnx_state->access_run_state = 1; } @@ -931,7 +931,7 @@ dmn_ctrl_exclusive_access_begin(void) internal void dmn_ctrl_exclusive_access_end(void) { - OS_MutexScope(dmn_lnx_state->access_mutex) + MutexScope(dmn_lnx_state->access_mutex) { dmn_lnx_state->access_run_state = 0; } diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index a1a023e2..5c93e2d2 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -866,7 +866,7 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) MemoryZero(zmm_d, sizeof(*zmm_d)); } } - + // CET / Shadow Stack if(xstate_mask & XSTATE_MASK_CET_U) { @@ -1204,7 +1204,7 @@ dmn_ctrl_begin(void) internal void dmn_ctrl_exclusive_access_begin(void) { - OS_MutexScope(dmn_w32_shared->access_mutex) + MutexScope(dmn_w32_shared->access_mutex) { dmn_w32_shared->access_run_state = 1; } @@ -1213,7 +1213,7 @@ dmn_ctrl_exclusive_access_begin(void) internal void dmn_ctrl_exclusive_access_end(void) { - OS_MutexScope(dmn_w32_shared->access_mutex) + MutexScope(dmn_w32_shared->access_mutex) { dmn_w32_shared->access_run_state = 0; } diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index e322ee83..c4af2cf2 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -52,11 +52,8 @@ fs_init(void) fs_shared->stripes[idx].cv = cond_var_alloc(); fs_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); } - fs_shared->u2s_ring_size = KB(64); - fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size); - fs_shared->u2s_ring_cv = cond_var_alloc(); - fs_shared->u2s_ring_mutex = mutex_alloc(); - fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0); + fs_shared->req_mutex = mutex_alloc(); + fs_shared->req_arena = arena_alloc(); } //////////////////////////////// @@ -84,23 +81,13 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) FS_Slot *path_slot = &fs_shared->slots[path_slot_idx]; FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; - //- rjf: get root for this path + //- rjf: get root for this path - on 1st try (read mode), try to read, on 2nd try (write mode), create node HS_Root root = {0}; - OS_MutexScopeR(path_stripe->rw_mutex) + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { B32 node_found = 0; - for(FS_Node *n = path_slot->first; n != 0; n = n->next) + RWMutexScope(path_stripe->rw_mutex, write_mode) { - if(str8_match(n->path, path, 0)) - { - node_found = 1; - root = n->root; - break; - } - } - if(!node_found) OS_MutexScopeRWPromote(path_stripe->rw_mutex) - { - B32 node_found = 0; for(FS_Node *n = path_slot->first; n != 0; n = n->next) { if(str8_match(n->path, path, 0)) @@ -110,7 +97,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) break; } } - if(!node_found) + if(write_mode && !node_found) { FS_Node *node = push_array(path_stripe->arena, FS_Node, 1); SLLQueuePush(path_slot->first, path_slot->last, node); @@ -121,6 +108,10 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) root = node->root; } } + if(node_found) + { + break; + } } //- rjf: build a key for this path/range combo @@ -131,7 +122,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) if(u128_match(hs_hash_from_key(key, 0), u128_zero())) { // rjf: loop: request, check for results, return until we can't - OS_MutexScopeW(path_stripe->rw_mutex) for(;;) + RWMutexScope(path_stripe->rw_mutex, 1) for(;;) { // rjf: path -> node FS_Node *node = 0; @@ -172,22 +163,27 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) range_node->id = key.id; } - // rjf: try to send stream request - if(ins_atomic_u64_eval(&range_node->working_count) == 0 && - fs_u2s_enqueue_req(key, range, path, endt_us)) + // rjf: push request + if(range_node->working_count == 0) { - ins_atomic_u64_inc_eval(&range_node->working_count); - DeferLoop(rw_mutex_drop_w(path_stripe->rw_mutex), rw_mutex_take_w(path_stripe->rw_mutex)) + range_node->working_count += 1; + MutexScope(fs_shared->req_mutex) { - async_push_work(fs_stream_work, .working_counter = &range_node->working_count); + FS_RequestNode *n = push_array(fs_shared->req_arena, FS_RequestNode, 1); + SLLQueuePush(fs_shared->first_req, fs_shared->last_req, n); + fs_shared->req_count += 1; + n->v.key = key; + n->v.path = str8_copy(fs_shared->req_arena, path); + n->v.range = range; } + cond_var_broadcast(async_tick_start_cond_var); } // rjf: have time to wait? -> wait on this stripe; otherwise exit B32 have_results = !u128_match(hs_hash_from_key(key, 0), u128_zero()); if(!have_results && os_now_microseconds() < endt_us) { - cond_var_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us); + cond_var_wait_rw(path_stripe->cv, path_stripe->rw_mutex, 1, endt_us); } else { @@ -229,7 +225,7 @@ fs_properties_from_path(String8 path) U64 stripe_idx = slot_idx%fs_shared->stripes_count; FS_Slot *slot = &fs_shared->slots[slot_idx]; FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(FS_Node *n = slot->first; n != 0; n = n->next) { @@ -252,6 +248,51 @@ fs_async_tick(void) { Temp scratch = scratch_begin(0, 0); + //- rjf: do detection pass + { + U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; + Rng1U64 range = lane_range(fs_shared->stripes_count); + for EachInRange(stripe_idx, range) + { + FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; + MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) + { + U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; + FS_Slot *slot = &fs_shared->slots[slot_idx]; + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + FileProperties props = os_properties_from_file_path(n->path); + if(props.modified != n->props.modified) + { + for(U64 range_slot_idx = 0; range_slot_idx < n->slots_count; range_slot_idx += 1) + { + for(FS_RangeNode *range_n = n->slots[range_slot_idx].first; + range_n != 0; + range_n = range_n->next) + { + HS_Key key = hs_key_make(n->root, range_n->id); + if(ins_atomic_u64_eval(&range_n->working_count) == 0) + { + ins_atomic_u64_inc_eval(&range_n->working_count); + MutexScope(fs_shared->req_mutex) + { + FS_RequestNode *req_n = push_array(fs_shared->req_arena, FS_RequestNode, 1); + SLLQueuePush(fs_shared->first_req, fs_shared->last_req, req_n); + fs_shared->req_count += 1; + req_n->v.key = key; + req_n->v.path = str8_copy(fs_shared->req_arena, n->path); + req_n->v.range = range; + } + cond_var_broadcast(async_tick_start_cond_var); + } + } + } + } + } + } + } + } + //- rjf: gather all requests local_persist FS_Request *reqs = 0; local_persist U64 reqs_count = 0; @@ -331,7 +372,7 @@ fs_async_tick(void) } //- rjf: commit info to cache - ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex) + ProfScope("commit to cache") MutexScopeW(path_stripe->rw_mutex) { FS_Node *node = 0; for(FS_Node *n = path_slot->first; n != 0; n = n->next) @@ -356,191 +397,3 @@ fs_async_tick(void) scratch_end(scratch); } - -//////////////////////////////// -//~ rjf: Streamer Threads - -internal B32 -fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us) -{ - B32 result = 0; - path.size = Min(path.size, fs_shared->u2s_ring_size); - OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;) - { - U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; - U64 available_size = fs_shared->u2s_ring_size - unconsumed_size; - U64 needed_size = sizeof(key) + sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size; - if(available_size >= needed_size) - { - result = 1; - fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &key); - fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min); - fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max); - fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size); - fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size); - break; - } - cond_var_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us); - } - if(result) - { - cond_var_broadcast(fs_shared->u2s_ring_cv); - } - return result; -} - -internal void -fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out) -{ - OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;) - { - U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; - if(unconsumed_size >= sizeof(*key_out) + sizeof(U64)*2 + sizeof(U64)) - { - fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, key_out); - fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &range_out->min); - fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &range_out->max); - fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size); - path_out->str = push_array(arena, U8, path_out->size); - fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size); - break; - } - cond_var_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64); - } - cond_var_broadcast(fs_shared->u2s_ring_cv); -} - -ASYNC_WORK_DEF(fs_stream_work) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //- rjf: get next request - HS_Key key = {0}; - Rng1U64 range = {0}; - String8 path = {0}; - fs_u2s_dequeue_req(scratch.arena, &key, &range, &path); - - //- rjf: unpack request - U64 path_hash = fs_little_hash_from_string(path); - U64 path_slot_idx = path_hash%fs_shared->slots_count; - U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count; - FS_Slot *path_slot = &fs_shared->slots[path_slot_idx]; - FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; - - //- rjf: load - ProfBegin("load \"%.*s\"", str8_varg(path)); - FileProperties pre_props = os_properties_from_file_path(path); - U64 range_size = dim_1u64(range); - U64 read_size = Min(pre_props.size - range.min, range_size); - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); - B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); - U64 data_arena_size = read_size+ARENA_HEADER_SIZE; - data_arena_size += KB(4)-1; - data_arena_size -= data_arena_size%KB(4); - ProfBegin("allocate"); - Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); - ProfEnd(); - ProfBegin("read"); - String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size)); - ProfEnd(); - os_file_close(file); - FileProperties post_props = os_properties_from_file_path(path); - - //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file - B32 read_good = (pre_props.modified == post_props.modified && - pre_props.size == post_props.size && - read_size == data.size && - (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); - if(!read_good) - { - ProfScope("abort") - { - arena_release(data_arena); - MemoryZeroStruct(&data); - data_arena = 0; - } - } - - //- rjf: submit - else - { - ProfScope("submit") - { - hs_submit_data(key, &data_arena, data); - } - } - - //- rjf: commit info to cache - ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex) - { - FS_Node *node = 0; - for(FS_Node *n = path_slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, 0)) - { - node = n; - break; - } - } - if(node != 0 && read_good) - { - if(node->props.modified != 0) - { - ins_atomic_u64_inc_eval(&fs_shared->change_gen); - } - node->props = post_props; - } - } - cond_var_broadcast(path_stripe->cv); - - ProfEnd(); - scratch_end(scratch); - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Change Detector Thread - -internal void -fs_detector_thread__entry_point(void *p) -{ - ThreadNameF("[fs] detector thread"); - for(;;) - { - U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; - for(U64 stripe_idx = 0; stripe_idx < fs_shared->stripes_count; stripe_idx += 1) - { - FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) - { - U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; - FS_Slot *slot = &fs_shared->slots[slot_idx]; - for(FS_Node *n = slot->first; n != 0; n = n->next) - { - FileProperties props = os_properties_from_file_path(n->path); - if(props.modified != n->props.modified) - { - for(U64 range_slot_idx = 0; range_slot_idx < n->slots_count; range_slot_idx += 1) - { - for(FS_RangeNode *range_n = n->slots[range_slot_idx].first; - range_n != 0; - range_n = range_n->next) - { - HS_Key key = hs_key_make(n->root, range_n->id); - if(ins_atomic_u64_eval(&range_n->working_count) == 0 && - fs_u2s_enqueue_req(key, r1u64(key.id.u128[0].u64[0], key.id.u128[0].u64[1]), n->path, os_now_microseconds()+100000)) - { - ins_atomic_u64_inc_eval(&range_n->working_count); - async_push_work(fs_stream_work, .working_counter = &range_n->working_count); - } - } - } - } - } - } - } - os_sleep_milliseconds(100); - } -} diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index dae0393b..e549fa52 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -91,17 +91,6 @@ struct FS_Shared FS_RequestNode *first_req; FS_RequestNode *last_req; U64 req_count; - - // rjf: user -> streamer ring buffer - U64 u2s_ring_size; - U8 *u2s_ring_base; - U64 u2s_ring_write_pos; - U64 u2s_ring_read_pos; - CondVar u2s_ring_cv; - Mutex u2s_ring_mutex; - - // rjf: change detector threads - OS_Handle detector_thread; }; //////////////////////////////// @@ -137,16 +126,4 @@ internal FileProperties fs_properties_from_path(String8 path); internal void fs_async_tick(void); -//////////////////////////////// -//~ rjf: Streaming Work - -internal B32 fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us); -internal void fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out); -ASYNC_WORK_DEF(fs_stream_work); - -//////////////////////////////// -//~ rjf: Change Detector Thread - -internal void fs_detector_thread__entry_point(void *p); - #endif // FILE_STREAM_H diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 4aced2ba..f42e152d 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -28,7 +28,7 @@ geo_init(void) geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); geo_shared->u2x_ring_cv = cond_var_alloc(); geo_shared->u2x_ring_mutex = mutex_alloc(); - geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0); + geo_shared->evictor_thread = thread_launch(geo_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -76,7 +76,7 @@ geo_scope_close(GEO_Scope *scope) U64 stripe_idx = slot_idx%geo_shared->stripes_count; GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { @@ -126,7 +126,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; B32 found = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { @@ -142,7 +142,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) B32 node_is_new = 0; if(!found) { - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { GEO_Node *node = 0; for(GEO_Node *n = slot->first; n != 0; n = n->next) @@ -203,7 +203,7 @@ internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us) { B32 good = 0; - OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) + MutexScope(geo_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; U64 available_size = geo_shared->u2x_ring_size-unconsumed_size; @@ -229,7 +229,7 @@ geo_u2x_enqueue_req(U128 hash, U64 endt_us) internal void geo_u2x_dequeue_req(U128 *hash_out) { - OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) + MutexScope(geo_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; if(unconsumed_size >= sizeof(*hash_out)) @@ -259,7 +259,7 @@ ASYNC_WORK_DEF(geo_xfer_work) //- rjf: take task B32 got_task = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { @@ -286,7 +286,7 @@ ASYNC_WORK_DEF(geo_xfer_work) } //- rjf: commit results to cache - if(got_task) OS_MutexScopeW(stripe->rw_mutex) + if(got_task) MutexScopeW(stripe->rw_mutex) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { @@ -311,7 +311,7 @@ ASYNC_WORK_DEF(geo_xfer_work) internal void geo_evictor_thread__entry_point(void *p) { - ThreadNameF("[geo] evictor thread"); + ThreadNameF("geo_evictor_thread"); for(;;) { U64 check_time_us = os_now_microseconds(); @@ -324,7 +324,7 @@ geo_evictor_thread__entry_point(void *p) GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { @@ -339,7 +339,7 @@ geo_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index 1d3f0bf3..24dd4941 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -88,7 +88,7 @@ struct GEO_Shared Mutex u2x_ring_mutex; // rjf: evictor thread - OS_Handle evictor_thread; + Thread evictor_thread; }; //////////////////////////////// diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index e3d934e5..09c65180 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -103,7 +103,7 @@ hs_init(void) stripe->rw_mutex = rw_mutex_alloc(); stripe->cv = cond_var_alloc(); } - hs_shared->evictor_thread = os_thread_launch(hs_evictor_thread__entry_point, 0, 0); + hs_shared->evictor_thread = thread_launch(hs_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -118,7 +118,7 @@ hs_root_alloc(void) U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { HS_RootNode *node = hs_shared->root_stripes_free_nodes[stripe_idx]; if(node != 0) @@ -148,7 +148,7 @@ hs_root_release(HS_Root root) //- rjf: release root node, grab its arena / ID list Arena *root_arena = 0; HS_RootIDChunkList root_ids = {0}; - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { for(HS_RootNode *n = slot->first; n != 0; n = n->next) { @@ -175,7 +175,7 @@ hs_root_release(HS_Root root) U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - OS_MutexScopeW(key_stripe->rw_mutex) + MutexScopeW(key_stripe->rw_mutex) { for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) { @@ -189,7 +189,7 @@ hs_root_release(HS_Root root) U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; HS_Slot *hash_slot = &hs_shared->slots[hash_slot_idx]; HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; - OS_MutexScopeR(hash_stripe->rw_mutex) + MutexScopeR(hash_stripe->rw_mutex) { for(HS_Node *n = hash_slot->first; n != 0; n = n->next) { @@ -231,7 +231,7 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; //- rjf: commit data to cache - if already there, just bump key refcount - ProfScope("commit data to cache - if already there, just bump key refcount") OS_MutexScopeW(stripe->rw_mutex) + ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) { HS_Node *existing_node = 0; for(HS_Node *n = slot->first; n != 0; n = n->next) @@ -279,7 +279,7 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) //- rjf: commit this hash to key cache U128 key_expired_hash = {0}; - ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex) + ProfScope("commit this hash to key cache") MutexScopeW(key_stripe->rw_mutex) { // rjf: find existing key B32 key_is_new = 0; @@ -329,7 +329,7 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) U64 root_stripe_idx = root_slot_idx%hs_shared->root_stripes_count; HS_RootSlot *root_slot = &hs_shared->root_slots[root_slot_idx]; HS_Stripe *root_stripe = &hs_shared->root_stripes[root_stripe_idx]; - OS_MutexScopeW(root_stripe->rw_mutex) + MutexScopeW(root_stripe->rw_mutex) { for(HS_RootNode *n = root_slot->first; n != 0; n = n->next) { @@ -362,7 +362,7 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; HS_Slot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx]; - OS_MutexScopeR(old_hash_stripe->rw_mutex) + MutexScopeR(old_hash_stripe->rw_mutex) { for(HS_Node *n = old_hash_slot->first; n != 0; n = n->next) { @@ -414,7 +414,7 @@ hs_scope_close(HS_Scope *scope) U64 stripe_idx = slot_idx%hs_shared->stripes_count; HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(HS_Node *n = slot->first; n != 0; n = n->next) { @@ -458,7 +458,7 @@ hs_hash_downstream_inc(U128 hash) U64 stripe_idx = slot_idx%hs_shared->stripes_count; HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(HS_Node *n = slot->first; n != 0; n = n->next) { @@ -478,7 +478,7 @@ hs_hash_downstream_dec(U128 hash) U64 stripe_idx = slot_idx%hs_shared->stripes_count; HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(HS_Node *n = slot->first; n != 0; n = n->next) { @@ -503,7 +503,7 @@ hs_hash_from_key(HS_Key key, U64 rewind_count) U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - OS_MutexScopeR(key_stripe->rw_mutex) + MutexScopeR(key_stripe->rw_mutex) { for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) { @@ -526,7 +526,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash) U64 stripe_idx = slot_idx%hs_shared->stripes_count; HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(HS_Node *n = slot->first; n != 0; n = n->next) { @@ -548,7 +548,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash) internal void hs_evictor_thread__entry_point(void *p) { - ThreadNameF("[hs] evictor thread"); + ThreadNameF("hs_evictor_thread"); for(;;) { for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1) @@ -557,7 +557,7 @@ hs_evictor_thread__entry_point(void *p) HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(HS_Node *n = slot->first; n != 0; n = n->next) { @@ -571,7 +571,7 @@ hs_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index 6bde1a44..97971ee4 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -208,7 +208,7 @@ struct HS_Shared U64 root_id_gen; // rjf: evictor thread - OS_Handle evictor_thread; + Thread evictor_thread; }; //////////////////////////////// diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index e052d5d5..10643b89 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -30,7 +30,7 @@ mtx_init(void) mtx_shared->mut_threads[idx].ring_base = push_array_no_zero(arena, U8, mtx_shared->mut_threads[idx].ring_size); mtx_shared->mut_threads[idx].cv = cond_var_alloc(); mtx_shared->mut_threads[idx].mutex = mutex_alloc(); - mtx_shared->mut_threads[idx].thread = os_thread_launch(mtx_mut_thread__entry_point, &mtx_shared->mut_threads[idx], 0); + mtx_shared->mut_threads[idx].thread = thread_launch(mtx_mut_thread__entry_point, &mtx_shared->mut_threads[idx]); } } @@ -52,7 +52,7 @@ internal void mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) { // TODO(rjf): if op.replace is too big, need to split into multiple edits - OS_MutexScope(thread->mutex) for(;;) + MutexScope(thread->mutex) for(;;) { U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; U64 available_size = thread->ring_size - unconsumed_size; @@ -73,7 +73,7 @@ mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out) { - OS_MutexScope(thread->mutex) for(;;) + MutexScope(thread->mutex) for(;;) { U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; if(unconsumed_size >= sizeof(*buffer_key_out) + sizeof(op_out->range) + sizeof(op_out->replace.size)) @@ -94,7 +94,7 @@ internal void mtx_mut_thread__entry_point(void *p) { MTX_MutThread *mut_thread = (MTX_MutThread *)p; - ThreadNameF("[mtx] mut thread #%I64u", (U64)(mut_thread - mtx_shared->mut_threads)); + ThreadNameF("mtx_mut_thread_%I64u", (U64)(mut_thread - mtx_shared->mut_threads)); for(;;) { Temp scratch = scratch_begin(0, 0); diff --git a/src/mutable_text/mutable_text.h b/src/mutable_text/mutable_text.h index 2f985e85..3957f561 100644 --- a/src/mutable_text/mutable_text.h +++ b/src/mutable_text/mutable_text.h @@ -49,7 +49,7 @@ struct MTX_MutThread U64 ring_write_pos; CondVar cv; Mutex mutex; - OS_Handle thread; + Thread thread; }; //////////////////////////////// diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 94210eab..9e01d5ef 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -121,7 +121,7 @@ internal void * os_lnx_thread_entry_point(void *ptr) { OS_LNX_Entity *entity = (OS_LNX_Entity *)ptr; - OS_ThreadFunctionType *func = entity->thread.func; + ThreadEntryPointFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; supplement_thread_base_entry_point(func, thread_ptr); return 0; @@ -801,7 +801,7 @@ os_process_kill(OS_Handle handle) //~ rjf: @os_hooks Threads (Implemented Per-OS) internal OS_Handle -os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) +os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params) { OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread); entity->thread.func = func; @@ -911,31 +911,22 @@ os_rw_mutex_release(OS_Handle rw_mutex) } internal void -os_rw_mutex_take_r(OS_Handle rw_mutex) +os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode) { if(os_handle_match(rw_mutex, os_handle_zero())) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_rdlock(&entity->rwmutex_handle); + if(write_mode) + { + pthread_rwlock_wrlock(&entity->rwmutex_handle); + } + else + { + pthread_rwlock_rdlock(&entity->rwmutex_handle); + } } internal void -os_rw_mutex_drop_r(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_unlock(&entity->rwmutex_handle); -} - -internal void -os_rw_mutex_take_w(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_wrlock(&entity->rwmutex_handle); -} - -internal void -os_rw_mutex_drop_w(OS_Handle rw_mutex) +os_rw_mutex_drop(OS_Handle rw_mutex, B32 write_mode) { if(os_handle_match(rw_mutex, os_handle_zero())) { return; } OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; @@ -995,7 +986,7 @@ os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) } internal B32 -os_cond_var_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) +os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_us) { // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack // this together, but this would probably just be a lot better if we just @@ -1016,49 +1007,27 @@ os_cond_var_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); if(wait_result != ETIMEDOUT) { - pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); + if(write_mode) + { + pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); + } + else + { + pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); + } result = 1; break; } if(wait_result == ETIMEDOUT) { - pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); - break; - } - } - pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); - return result; -} - -internal B32 -os_cond_var_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) -{ - // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack - // this together, but this would probably just be a lot better if we just - // implemented the primitives ourselves with e.g. futexes - // - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0]; - struct timespec endt_timespec; - endt_timespec.tv_sec = endt_us/Million(1); - endt_timespec.tv_nsec = Thousand(1) * (endt_us - (endt_us/Million(1))*Million(1)); - B32 result = 0; - pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle); - pthread_rwlock_unlock(&rw_mutex_entity->rwmutex_handle); - for(;;) - { - int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); - if(wait_result != ETIMEDOUT) - { - pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); - result = 1; - break; - } - if(wait_result == ETIMEDOUT) - { - pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); + if(write_mode) + { + pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); + } + else + { + pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); + } break; } } @@ -1229,7 +1198,7 @@ os_library_close(OS_Handle lib) //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) internal void -os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr) +os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr) { // rjf: push handler to chain OS_LNX_SafeCallChain chain = {0}; diff --git a/src/os/core/linux/os_core_linux.h b/src/os/core/linux/os_core_linux.h index 4b345a4b..7b335fbb 100644 --- a/src/os/core/linux/os_core_linux.h +++ b/src/os/core/linux/os_core_linux.h @@ -54,7 +54,7 @@ typedef struct OS_LNX_SafeCallChain OS_LNX_SafeCallChain; struct OS_LNX_SafeCallChain { OS_LNX_SafeCallChain *next; - OS_ThreadFunctionType *fail_handler; + ThreadEntryPointFunctionType *fail_handler; void *ptr; }; @@ -81,7 +81,7 @@ struct OS_LNX_Entity struct { pthread_t handle; - OS_ThreadFunctionType *func; + ThreadEntryPointFunctionType *func; void *ptr; } thread; pthread_mutex_t mutex_handle; diff --git a/src/os/core/linux/os_core_linux_old.c b/src/os/core/linux/os_core_linux_old.c index 3e3ae763..4d492f06 100644 --- a/src/os/core/linux/os_core_linux_old.c +++ b/src/os/core/linux/os_core_linux_old.c @@ -783,7 +783,7 @@ lnx_free_entity(LNX_Entity *entity){ internal void* lnx_thread_base(void *ptr){ LNX_Entity *entity = (LNX_Entity*)ptr; - OS_ThreadFunctionType *func = entity->thread.func; + ThreadEntryPointFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; TCTX tctx_; @@ -1377,7 +1377,7 @@ os_launch_process(OS_LaunchOptions *options){ //~ rjf: @os_hooks Threads (Implemented Per-OS) internal OS_Handle -os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params){ +os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params){ // entity LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Thread); entity->reference_mask = 0x3; @@ -1642,7 +1642,7 @@ os_library_close(OS_Handle lib) //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) internal void -os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){ +os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr){ LNX_SafeCallChain chain = {0}; SLLStackPush(lnx_safe_call_chain, &chain); chain.fail_handler = fail_handler; diff --git a/src/os/core/linux/os_core_linux_old.h b/src/os/core/linux/os_core_linux_old.h index efec7159..cf133b2a 100644 --- a/src/os/core/linux/os_core_linux_old.h +++ b/src/os/core/linux/os_core_linux_old.h @@ -48,7 +48,7 @@ struct LNX_Entity{ volatile U32 reference_mask; union{ struct{ - OS_ThreadFunctionType *func; + ThreadEntryPointFunctionType *func; void *ptr; pthread_t handle; } thread; @@ -62,7 +62,7 @@ struct LNX_Entity{ struct LNX_SafeCallChain{ LNX_SafeCallChain *next; - OS_ThreadFunctionType *fail_handler; + ThreadEntryPointFunctionType *fail_handler; void *ptr; }; diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index e4cb49e6..04ede12a 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -40,21 +40,6 @@ os_handle_array_from_list(Arena *arena, OS_HandleList *list) return result; } -//////////////////////////////// -//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) - -internal String8List -os_string_list_from_argcv(Arena *arena, int argc, char **argv) -{ - String8List result = {0}; - for(int i = 0; i < argc; i += 1) - { - String8 str = str8_cstring(argv[i]); - str8_list_push(arena, &result, str); - } - return result; -} - //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, Implemented Once) diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 7737602c..656ab4a4 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -128,11 +128,6 @@ struct OS_ProcessLaunchParams OS_Handle stdin_file; }; -//////////////////////////////// -//~ rjf: Thread Types - -typedef void OS_ThreadFunctionType(void *ptr); - //////////////////////////////// //~ rjf: Handle Type Functions (Helpers, Implemented Once) @@ -141,11 +136,6 @@ internal B32 os_handle_match(OS_Handle a, OS_Handle b); internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle); internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list); -//////////////////////////////// -//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) - -internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv); - //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, Implemented Once) @@ -262,9 +252,9 @@ internal B32 os_process_kill(OS_Handle handle); //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params); -internal B32 os_thread_join(OS_Handle handle, U64 endt_us); -internal void os_thread_detach(OS_Handle handle); +internal Thread os_thread_launch(ThreadEntryPointFunctionType *f, void *p); +internal B32 os_thread_join(Thread handle, U64 endt_us); +internal void os_thread_detach(Thread handle); //////////////////////////////// //~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) @@ -278,18 +268,15 @@ internal void os_mutex_drop(Mutex mutex); //- rjf: reader/writer mutexes internal RWMutex os_rw_mutex_alloc(void); internal void os_rw_mutex_release(RWMutex mutex); -internal void os_rw_mutex_take_r(RWMutex mutex); -internal void os_rw_mutex_drop_r(RWMutex mutex); -internal void os_rw_mutex_take_w(RWMutex mutex); -internal void os_rw_mutex_drop_w(RWMutex mutex); +internal void os_rw_mutex_take(RWMutex mutex, B32 write_mode); +internal void os_rw_mutex_drop(RWMutex mutex, B32 write_mode); //- rjf: condition variables internal CondVar os_cond_var_alloc(void); internal void os_cond_var_release(CondVar cv); // returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout internal B32 os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us); -internal B32 os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us); -internal B32 os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us); +internal B32 os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us); internal void os_cond_var_signal(CondVar cv); internal void os_cond_var_broadcast(CondVar cv); @@ -306,12 +293,6 @@ internal Barrier os_barrier_alloc(U64 count); internal void os_barrier_release(Barrier barrier); internal void os_barrier_wait(Barrier barrier); -//- rjf: scope macros -#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) -#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex)) -#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex)) -#define OS_MutexScopeRWPromote(mutex) DeferLoop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex))) - //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) @@ -322,7 +303,7 @@ internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name); //////////////////////////////// //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) -internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr); +internal void os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr); //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index d90d68ff..0e29fad9 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -144,7 +144,7 @@ internal DWORD os_w32_thread_entry_point(void *ptr) { OS_W32_Entity *entity = (OS_W32_Entity *)ptr; - OS_ThreadFunctionType *func = entity->thread.func; + ThreadEntryPointFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; supplement_thread_base_entry_point(func, thread_ptr); return 0; @@ -1103,19 +1103,19 @@ os_process_detach(OS_Handle handle) //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle -os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) +internal Thread +os_thread_launch(ThreadEntryPointFunctionType *f, void *p) { OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Thread); - entity->thread.func = func; - entity->thread.ptr = ptr; + entity->thread.func = f; + entity->thread.ptr = p; entity->thread.handle = CreateThread(0, 0, os_w32_thread_entry_point, entity, 0, &entity->thread.tid); - OS_Handle result = {IntFromPtr(entity)}; + Thread result = {IntFromPtr(entity)}; return result; } internal B32 -os_thread_join(OS_Handle handle, U64 endt_us) +os_thread_join(Thread handle, U64 endt_us) { DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); OS_W32_Entity *entity = (OS_W32_Entity *)PtrFromInt(handle.u64[0]); @@ -1130,7 +1130,7 @@ os_thread_join(OS_Handle handle, U64 endt_us) } internal void -os_thread_detach(OS_Handle thread) +os_thread_detach(Thread thread) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]); if(entity != 0) @@ -1194,31 +1194,31 @@ os_rw_mutex_release(RWMutex rw_mutex) } internal void -os_rw_mutex_take_r(RWMutex rw_mutex) +os_rw_mutex_take(RWMutex rw_mutex, B32 write_mode) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - AcquireSRWLockShared(&entity->rw_mutex); + if(write_mode) + { + AcquireSRWLockExclusive(&entity->rw_mutex); + } + else + { + AcquireSRWLockShared(&entity->rw_mutex); + } } internal void -os_rw_mutex_drop_r(RWMutex rw_mutex) +os_rw_mutex_drop(RWMutex rw_mutex, B32 write_mode) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - ReleaseSRWLockShared(&entity->rw_mutex); -} - -internal void -os_rw_mutex_take_w(RWMutex rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - AcquireSRWLockExclusive(&entity->rw_mutex); -} - -internal void -os_rw_mutex_drop_w(RWMutex rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - ReleaseSRWLockExclusive(&entity->rw_mutex); + if(write_mode) + { + ReleaseSRWLockExclusive(&entity->rw_mutex); + } + else + { + ReleaseSRWLockShared(&entity->rw_mutex); + } } //- rjf: condition variables @@ -1254,7 +1254,7 @@ os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us) } internal B32 -os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us) +os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us) { U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); BOOL result = 0; @@ -1263,21 +1263,7 @@ os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us) OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, - CONDITION_VARIABLE_LOCKMODE_SHARED); - } - return result; -} - -internal B32 -os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - BOOL result = 0; - if(sleep_ms > 0) - { - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); - result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0); + write_mode ? 0 : CONDITION_VARIABLE_LOCKMODE_SHARED); } return result; } @@ -1413,7 +1399,7 @@ os_library_close(OS_Handle lib) //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) internal void -os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr) +os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr) { __try { diff --git a/src/os/core/win32/os_core_win32.h b/src/os/core/win32/os_core_win32.h index 8a7f65e8..777961c0 100644 --- a/src/os/core/win32/os_core_win32.h +++ b/src/os/core/win32/os_core_win32.h @@ -62,7 +62,7 @@ struct OS_W32_Entity { struct { - OS_ThreadFunctionType *func; + ThreadEntryPointFunctionType *func; void *ptr; HANDLE handle; DWORD tid; diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 7d52ab78..37e9b554 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -25,12 +25,12 @@ ptg_init(void) ptg_shared->u2b_ring_cv = cond_var_alloc(); ptg_shared->u2b_ring_mutex = mutex_alloc(); ptg_shared->builder_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4); - ptg_shared->builder_threads = push_array(arena, OS_Handle, ptg_shared->builder_thread_count); + ptg_shared->builder_threads = push_array(arena, Thread, ptg_shared->builder_thread_count); for(U64 idx = 0; idx < ptg_shared->builder_thread_count; idx += 1) { - ptg_shared->builder_threads[idx] = os_thread_launch(ptg_builder_thread__entry_point, (void *)idx, 0); + ptg_shared->builder_threads[idx] = thread_launch(ptg_builder_thread__entry_point, (void *)idx); } - ptg_shared->evictor_thread = os_thread_launch(ptg_evictor_thread__entry_point, 0, 0); + ptg_shared->evictor_thread = thread_launch(ptg_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -122,7 +122,7 @@ internal B32 ptg_u2b_enqueue_req(PTG_Key *key, U64 endt_us) { B32 good = 0; - OS_MutexScope(ptg_shared->u2b_ring_mutex) for(;;) + MutexScope(ptg_shared->u2b_ring_mutex) for(;;) { U64 unconsumed_size = ptg_shared->u2b_ring_write_pos-ptg_shared->u2b_ring_read_pos; U64 available_size = ptg_shared->u2b_ring_size-unconsumed_size; @@ -148,7 +148,7 @@ ptg_u2b_enqueue_req(PTG_Key *key, U64 endt_us) internal void ptg_u2b_dequeue_req(PTG_Key *key_out) { - OS_MutexScope(ptg_shared->u2b_ring_mutex) for(;;) + MutexScope(ptg_shared->u2b_ring_mutex) for(;;) { U64 unconsumed_size = ptg_shared->u2b_ring_write_pos-ptg_shared->u2b_ring_read_pos; if(unconsumed_size >= sizeof(*key_out)) @@ -180,7 +180,7 @@ ptg_builder_thread__entry_point(void *p) //- rjf: take task B32 got_task = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) { @@ -200,7 +200,7 @@ ptg_builder_thread__entry_point(void *p) //- rjf: commit results to cache - if(got_task) OS_MutexScopeW(stripe->rw_mutex) + if(got_task) MutexScopeW(stripe->rw_mutex) { for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) { @@ -236,7 +236,7 @@ ptg_evictor_thread__entry_point(void *p) PTG_GraphSlot *slot = &ptg_shared->slots[slot_idx]; PTG_GraphStripe *stripe = &ptg_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) { @@ -251,7 +251,7 @@ ptg_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(PTG_GraphNode *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/ptr_graph_cache/ptr_graph_cache.h b/src/ptr_graph_cache/ptr_graph_cache.h index 37e18ce9..43befd6b 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.h +++ b/src/ptr_graph_cache/ptr_graph_cache.h @@ -181,10 +181,10 @@ struct PTG_Shared // rjf: builder threads U64 builder_thread_count; - OS_Handle *builder_threads; + Thread *builder_threads; // rjf: evictor thread - OS_Handle evictor_thread; + Thread evictor_thread; }; //////////////////////////////// diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index fc59c69c..64bde605 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -23,7 +23,7 @@ rb_entry_point(CmdLine *cmdline) threads_count = threads_count_from_cmdline; } } - OS_Handle *threads = push_array(scratch.arena, OS_Handle, threads_count); + Thread *threads = push_array(scratch.arena, Thread, threads_count); RB_ThreadParams *threads_params = push_array(scratch.arena, RB_ThreadParams, threads_count); Barrier barrier = barrier_alloc(threads_count); for EachIndex(idx, threads_count) @@ -32,11 +32,11 @@ rb_entry_point(CmdLine *cmdline) threads_params[idx].lane_ctx.lane_idx = idx; threads_params[idx].lane_ctx.lane_count = threads_count; threads_params[idx].lane_ctx.barrier = barrier; - threads[idx] = os_thread_launch(rb_thread_entry_point, &threads_params[idx], 0); + threads[idx] = thread_launch(rb_thread_entry_point, &threads_params[idx]); } for EachIndex(idx, threads_count) { - os_thread_join(threads[idx], max_U64); + thread_join(threads[idx], max_U64); } scratch_end(scratch); } diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 588673d3..eeda6184 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -357,7 +357,7 @@ global CondVar ipc_s2m_ring_cv = {0}; internal void ipc_signaler_thread__entry_point(void *p) { - ThreadNameF("[rd] ipc signaler thread"); + ThreadNameF("rd_ipc_signaler_thread"); for(;;) { if(os_semaphore_take(ipc_sender2main_signal_semaphore, max_U64)) @@ -367,7 +367,7 @@ ipc_signaler_thread__entry_point(void *p) IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base; String8 msg = str8((U8 *)(ipc_info+1), ipc_info->msg_size); msg.size = Min(msg.size, IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo)); - OS_MutexScope(ipc_s2m_ring_mutex) for(;;) + MutexScope(ipc_s2m_ring_mutex) for(;;) { U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; U64 available_size = (sizeof(ipc_s2m_ring_buffer) - unconsumed_size); @@ -535,7 +535,7 @@ entry_point(CmdLine *cmd_line) if(ipc_sender2main_shared_memory_base != 0) { MemoryZeroStruct(ipc_info); - os_thread_launch(ipc_signaler_thread__entry_point, 0, 0); + thread_launch(ipc_signaler_thread__entry_point, 0); } scratch_end(scratch); @@ -551,7 +551,7 @@ entry_point(CmdLine *cmd_line) Temp scratch = scratch_begin(0, 0); B32 consumed = 0; String8 msg = {0}; - OS_MutexScope(ipc_s2m_ring_mutex) + MutexScope(ipc_s2m_ring_mutex) { U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; if(unconsumed_size >= sizeof(U64)) @@ -711,7 +711,13 @@ entry_point(CmdLine *cmd_line) IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base; U8 *buffer = (U8 *)(ipc_info+1); U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); - String8List parts = os_string_list_from_argcv(scratch.arena, cmd_line->argc - 1, cmd_line->argv + 1); + String8List parts = {0}; + { + for EachIndex(idx, cmd_line->argc-1) + { + str8_list_push(scratch.arena, &parts, str8_cstring(cmd_line->argv[idx+1])); + } + } StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; String8 msg = str8_list_join(scratch.arena, &parts, &join); ipc_info->msg_size = Min(buffer_max, msg.size); diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c index ac9e8a54..444199cf 100644 --- a/src/render/d3d11/render_d3d11.c +++ b/src/render/d3d11/render_d3d11.c @@ -487,7 +487,7 @@ r_window_equip(OS_Handle handle) { ProfBeginFunction(); R_Handle result = {0}; - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { //- rjf: allocate per-window-state R_D3D11_Window *window = r_d3d11_state->first_free_window; @@ -559,7 +559,7 @@ r_hook void r_window_unequip(OS_Handle handle, R_Handle equip_handle) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Window *window = r_d3d11_window_from_handle(equip_handle); window->stage_color_srv->lpVtbl->Release(window->stage_color_srv); @@ -588,7 +588,7 @@ r_tex2d_alloc(R_ResourceKind kind, Vec2S32 size, R_Tex2DFormat format, void *dat //- rjf: allocate R_D3D11_Tex2D *texture = 0; - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { texture = r_d3d11_state->first_free_tex2d; if(texture == 0) @@ -675,7 +675,7 @@ r_hook void r_tex2d_release(R_Handle handle) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); if(texture != &r_d3d11_tex2d_nil) @@ -711,7 +711,7 @@ r_hook void r_fill_tex2d_region(R_Handle handle, Rng2S32 subrect, void *data) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); if(texture != &r_d3d11_tex2d_nil) @@ -739,7 +739,7 @@ r_buffer_alloc(R_ResourceKind kind, U64 size, void *data) //- rjf: allocate R_D3D11_Buffer *buffer = 0; - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { buffer = r_d3d11_state->first_free_buffer; if(buffer == 0) @@ -798,7 +798,7 @@ r_hook void r_buffer_release(R_Handle handle) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Buffer *buffer = r_d3d11_buffer_from_handle(handle); SLLStackPush(r_d3d11_state->first_to_free_buffer, buffer); @@ -811,7 +811,7 @@ r_buffer_release(R_Handle handle) r_hook void r_begin_frame(void) { - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { // NOTE(rjf): no-op } @@ -820,7 +820,7 @@ r_begin_frame(void) r_hook void r_end_frame(void) { - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { for(R_D3D11_FlushBuffer *buffer = r_d3d11_state->first_buffer_to_flush; buffer != 0; buffer = buffer->next) { @@ -858,7 +858,7 @@ r_hook void r_window_begin_frame(OS_Handle window, R_Handle window_equip) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Window *wnd = r_d3d11_window_from_handle(window_equip); ID3D11DeviceContext1 *d_ctx = r_d3d11_state->device_ctx; @@ -990,7 +990,7 @@ r_hook void r_window_end_frame(OS_Handle window, R_Handle window_equip) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Window *wnd = r_d3d11_window_from_handle(window_equip); ID3D11DeviceContext1 *d_ctx = r_d3d11_state->device_ctx; @@ -1060,7 +1060,7 @@ r_hook void r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes) { ProfBeginFunction(); - OS_MutexScopeW(r_d3d11_state->device_rw_mutex) + MutexScopeW(r_d3d11_state->device_rw_mutex) { //////////////////////////// //- rjf: unpack arguments diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 15c2f21e..0a17218a 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1614,7 +1614,7 @@ txt_init(void) txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); txt_shared->u2p_ring_cv = cond_var_alloc(); txt_shared->u2p_ring_mutex = mutex_alloc(); - txt_shared->evictor_thread = os_thread_launch(txt_evictor_thread__entry_point, 0, 0); + txt_shared->evictor_thread = thread_launch(txt_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -1662,7 +1662,7 @@ txt_scope_close(TXT_Scope *scope) U64 stripe_idx = slot_idx%txt_shared->stripes_count; TXT_Slot *slot = &txt_shared->slots[slot_idx]; TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -1713,7 +1713,7 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) TXT_Slot *slot = &txt_shared->slots[slot_idx]; TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; B32 found = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -1731,7 +1731,7 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) B32 node_is_new = 0; if(!found) { - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { TXT_Node *node = 0; for(TXT_Node *n = slot->first; n != 0; n = n->next) @@ -2157,7 +2157,7 @@ internal B32 txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us) { B32 good = 0; - OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) + MutexScope(txt_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; U64 available_size = txt_shared->u2p_ring_size - unconsumed_size; @@ -2184,7 +2184,7 @@ txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us) internal void txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out) { - OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) + MutexScope(txt_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; if(unconsumed_size >= sizeof(*hash_out) + sizeof(*lang_out)) @@ -2216,7 +2216,7 @@ ASYNC_WORK_DEF(txt_parse_work) //- rjf: take task B32 got_task = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -2245,7 +2245,7 @@ ASYNC_WORK_DEF(txt_parse_work) //- rjf: grab pointers to working counters U64 *bytes_processed_ptr = 0; U64 *bytes_to_process_ptr = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -2482,7 +2482,7 @@ ASYNC_WORK_DEF(txt_parse_work) } //- rjf: commit results to cache - if(got_task) OS_MutexScopeW(stripe->rw_mutex) + if(got_task) MutexScopeW(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -2511,7 +2511,7 @@ ASYNC_WORK_DEF(txt_parse_work) internal void txt_evictor_thread__entry_point(void *p) { - ThreadNameF("[txt] evictor thread"); + ThreadNameF("txt_evictor_thread"); for(;;) { U64 check_time_us = os_now_microseconds(); @@ -2524,7 +2524,7 @@ txt_evictor_thread__entry_point(void *p) TXT_Slot *slot = &txt_shared->slots[slot_idx]; TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { @@ -2539,7 +2539,7 @@ txt_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index db86ee70..e08494ff 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -252,7 +252,7 @@ struct TXT_Shared Mutex u2p_ring_mutex; // rjf: evictor thread - OS_Handle evictor_thread; + Thread evictor_thread; }; //////////////////////////////// diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 71976f5b..a837f599 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -41,7 +41,7 @@ tex_init(void) tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); tex_shared->u2x_ring_cv = cond_var_alloc(); tex_shared->u2x_ring_mutex = mutex_alloc(); - tex_shared->evictor_thread = os_thread_launch(tex_evictor_thread__entry_point, 0, 0); + tex_shared->evictor_thread = thread_launch(tex_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -89,7 +89,7 @@ tex_scope_close(TEX_Scope *scope) U64 stripe_idx = slot_idx%tex_shared->stripes_count; TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TEX_Node *n = slot->first; n != 0; n = n->next) { @@ -140,7 +140,7 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; B32 found = 0; B32 stale = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TEX_Node *n = slot->first; n != 0; n = n->next) { @@ -156,7 +156,7 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog B32 node_is_new = 0; if(!found) { - OS_MutexScopeW(stripe->rw_mutex) + MutexScopeW(stripe->rw_mutex) { TEX_Node *node = 0; for(TEX_Node *n = slot->first; n != 0; n = n->next) @@ -222,7 +222,7 @@ internal B32 tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) { B32 good = 0; - OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) + MutexScope(tex_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; U64 available_size = tex_shared->u2x_ring_size-unconsumed_size; @@ -249,7 +249,7 @@ tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) internal void tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) { - OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) + MutexScope(tex_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; if(unconsumed_size >= sizeof(*hash_out)+sizeof(*top_out)) @@ -281,7 +281,7 @@ ASYNC_WORK_DEF(tex_xfer_work) //- rjf: take task B32 got_task = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TEX_Node *n = slot->first; n != 0; n = n->next) { @@ -308,7 +308,7 @@ ASYNC_WORK_DEF(tex_xfer_work) } //- rjf: commit results to cache - if(got_task) OS_MutexScopeW(stripe->rw_mutex) + if(got_task) MutexScopeW(stripe->rw_mutex) { for(TEX_Node *n = slot->first; n != 0; n = n->next) { @@ -333,7 +333,7 @@ ASYNC_WORK_DEF(tex_xfer_work) internal void tex_evictor_thread__entry_point(void *p) { - ThreadNameF("[tex] evictor thread"); + ThreadNameF("tex_evictor_thread"); for(;;) { U64 check_time_us = os_now_microseconds(); @@ -346,7 +346,7 @@ tex_evictor_thread__entry_point(void *p) TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; B32 slot_has_work = 0; - OS_MutexScopeR(stripe->rw_mutex) + MutexScopeR(stripe->rw_mutex) { for(TEX_Node *n = slot->first; n != 0; n = n->next) { @@ -361,7 +361,7 @@ tex_evictor_thread__entry_point(void *p) } } } - if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + if(slot_has_work) MutexScopeW(stripe->rw_mutex) { for(TEX_Node *n = slot->first, *next = 0; n != 0; n = next) { diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 7d547a59..818a3406 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -100,7 +100,7 @@ struct TEX_Shared Mutex u2x_ring_mutex; // rjf: evictor thread - OS_Handle evictor_thread; + Thread evictor_thread; }; //////////////////////////////// From 6abdadcccbd24af05e26bd644b5129a7d91b64b8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 17 Sep 2025 14:50:06 -0700 Subject: [PATCH 186/302] garbage collect window states on quit as well --- src/raddbg/raddbg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index e05c43d1..ac3cea31 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -17276,7 +17276,7 @@ rd_frame(void) { next = ws->hash_next; RD_Cfg *cfg = rd_cfg_from_id(ws->cfg_id); - if(cfg == &rd_nil_cfg || ws->last_frame_index_touched < rd_state->frame_index) + if(cfg == &rd_nil_cfg || ws->last_frame_index_touched < rd_state->frame_index || rd_state->quit) { ui_state_release(ws->ui); r_window_unequip(ws->os, ws->r); From 7d7edd7cf7b71967cc04c0c607aa5d74ecf404b3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 17 Sep 2025 15:21:24 -0700 Subject: [PATCH 187/302] renormalize line endings --- src/base/base_entry_point.c | 2 +- src/base/base_strings.c | 222 +++++++++++++++++----------------- src/file_stream/file_stream.c | 4 +- src/file_stream/file_stream.h | 4 +- 4 files changed, 116 insertions(+), 116 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index aee68a3e..3d84e7e9 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -191,7 +191,7 @@ async_thread_entry_point(void *params) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); #if defined(FILE_STREAM_H) - fs_async_tick(); + fs_tick(); #endif cond_var_broadcast(async_tick_stop_cond_var); } diff --git a/src/base/base_strings.c b/src/base/base_strings.c index d2ea3244..960fb163 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -397,7 +397,7 @@ str8_is_before(String8 a, String8 b) //~ rjf: String Slicing internal String8 -str8_substr(String8 str, Rng1U64 range) +str8_substr(String8 str, Rng1U64 range) { range.min = ClampTop(range.min, str.size); range.max = ClampTop(range.max, str.size); @@ -407,14 +407,14 @@ str8_substr(String8 str, Rng1U64 range) } internal String8 -str8_prefix(String8 str, U64 size) +str8_prefix(String8 str, U64 size) { str.size = ClampTop(size, str.size); return str; } internal String8 -str8_skip(String8 str, U64 amt) +str8_skip(String8 str, U64 amt) { amt = ClampTop(amt, str.size); str.str += amt; @@ -423,7 +423,7 @@ str8_skip(String8 str, U64 amt) } internal String8 -str8_postfix(String8 str, U64 size) +str8_postfix(String8 str, U64 size) { size = ClampTop(size, str.size); str.str = (str.str + str.size) - size; @@ -432,7 +432,7 @@ str8_postfix(String8 str, U64 size) } internal String8 -str8_chop(String8 str, U64 amt) +str8_chop(String8 str, U64 amt) { amt = ClampTop(amt, str.size); str.size -= amt; @@ -555,12 +555,12 @@ push_cstr(Arena *arena, String8 str) //- rjf: string -> integer internal S64 -sign_from_str8(String8 string, String8 *string_tail) +sign_from_str8(String8 string, String8 *string_tail) { // count negative signs U64 neg_count = 0; U64 i = 0; - for(; i < string.size; i += 1) + for(; i < string.size; i += 1) { if (string.str[i] == '-'){ neg_count += 1; @@ -579,18 +579,18 @@ sign_from_str8(String8 string, String8 *string_tail) } internal B32 -str8_is_integer(String8 string, U32 radix) +str8_is_integer(String8 string, U32 radix) { B32 result = 0; - if(string.size > 0) + if(string.size > 0) { - if(1 < radix && radix <= 16) + if(1 < radix && radix <= 16) { result = 1; - for(U64 i = 0; i < string.size; i += 1) + for(U64 i = 0; i < string.size; i += 1) { U8 c = string.str[i]; - if(!(c < 0x80) || integer_symbol_reverse[c] >= radix) + if(!(c < 0x80) || integer_symbol_reverse[c] >= radix) { result = 0; break; @@ -602,12 +602,12 @@ str8_is_integer(String8 string, U32 radix) } internal U64 -u64_from_str8(String8 string, U32 radix) +u64_from_str8(String8 string, U32 radix) { U64 x = 0; - if(1 < radix && radix <= 16) + if(1 < radix && radix <= 16) { - for(U64 i = 0; i < string.size; i += 1) + for(U64 i = 0; i < string.size; i += 1) { x *= radix; x += integer_symbol_reverse[string.str[i]&0x7F]; @@ -617,7 +617,7 @@ u64_from_str8(String8 string, U32 radix) } internal S64 -s64_from_str8(String8 string, U32 radix) +s64_from_str8(String8 string, U32 radix) { S64 sign = sign_from_str8(string, &string); S64 x = (S64)u64_from_str8(string, radix) * sign; @@ -642,11 +642,11 @@ s32_from_str8(String8 string, U32 radix) internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x) -{ - // rjf: unpack radix / prefix size based on string prefix - U64 radix = 0; - U64 prefix_size = 0; - { +{ + // rjf: unpack radix / prefix size based on string prefix + U64 radix = 0; + U64 prefix_size = 0; + { // hex if(str8_match(str8_prefix(string, 2), str8_lit("0x"), StringMatchFlag_CaseInsensitive)) { @@ -667,16 +667,16 @@ try_u64_from_str8_c_rules(String8 string, U64 *x) { radix = 10, prefix_size = 0; } - } - - // rjf: convert if we can + } + + // rjf: convert if we can String8 integer = str8_skip(string, prefix_size); B32 is_integer = str8_is_integer(integer, radix); if(is_integer) { *x = u64_from_str8(integer, radix); - } - + } + return is_integer; } @@ -696,8 +696,8 @@ try_s64_from_str8_c_rules(String8 string, S64 *x) internal String8 str8_from_memory_size(Arena *arena, U64 size) { - String8 result = {0}; - { + String8 result = {0}; + { if(size < KB(1)) { result = push_str8f(arena, "%llu Bytes", size); @@ -717,8 +717,8 @@ str8_from_memory_size(Arena *arena, U64 size) else { result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100); - } - } + } + } return result; } @@ -973,7 +973,7 @@ f64_from_str8(String8 string) //~ rjf: String List Construction Functions internal String8Node * -str8_list_push_node(String8List *list, String8Node *node) +str8_list_push_node(String8List *list, String8Node *node) { SLLQueuePush(list->first, list->last, node); list->node_count += 1; @@ -982,7 +982,7 @@ str8_list_push_node(String8List *list, String8Node *node) } internal String8Node * -str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string) +str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string) { SLLQueuePush(list->first, list->last, node); list->node_count += 1; @@ -992,7 +992,7 @@ str8_list_push_node_set_string(String8List *list, String8Node *node, String8 str } internal String8Node * -str8_list_push_node_front(String8List *list, String8Node *node) +str8_list_push_node_front(String8List *list, String8Node *node) { SLLQueuePushFront(list->first, list->last, node); list->node_count += 1; @@ -1001,7 +1001,7 @@ str8_list_push_node_front(String8List *list, String8Node *node) } internal String8Node * -str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string) +str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string) { SLLQueuePushFront(list->first, list->last, node); list->node_count += 1; @@ -1011,7 +1011,7 @@ str8_list_push_node_front_set_string(String8List *list, String8Node *node, Strin } internal String8Node * -str8_list_push(Arena *arena, String8List *list, String8 string) +str8_list_push(Arena *arena, String8List *list, String8 string) { String8Node *node = push_array_no_zero(arena, String8Node, 1); str8_list_push_node_set_string(list, node, string); @@ -1019,7 +1019,7 @@ str8_list_push(Arena *arena, String8List *list, String8 string) } internal String8Node * -str8_list_push_front(Arena *arena, String8List *list, String8 string) +str8_list_push_front(Arena *arena, String8List *list, String8 string) { String8Node *node = push_array_no_zero(arena, String8Node, 1); str8_list_push_node_front_set_string(list, node, string); @@ -1027,18 +1027,18 @@ str8_list_push_front(Arena *arena, String8List *list, String8 string) } internal void -str8_list_concat_in_place(String8List *list, String8List *to_push) +str8_list_concat_in_place(String8List *list, String8List *to_push) { - if(to_push->node_count != 0) + if(to_push->node_count != 0) { - if(list->last) + if(list->last) { list->node_count += to_push->node_count; list->total_size += to_push->total_size; list->last->next = to_push->first; list->last = to_push->last; } - else + else { *list = *to_push; } @@ -1070,7 +1070,7 @@ str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align){ } internal String8Node* -str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) +str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) { va_list args; va_start(args, fmt); @@ -1081,7 +1081,7 @@ str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) } internal String8Node* -str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...) +str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...) { va_list args; va_start(args, fmt); @@ -1092,10 +1092,10 @@ str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...) } internal String8List -str8_list_copy(Arena *arena, String8List *list) +str8_list_copy(Arena *arena, String8List *list) { String8List result = {0}; - for(String8Node *node = list->first; node != 0; node = node->next) + for(String8Node *node = list->first; node != 0; node = node->next) { String8Node *new_node = push_array_no_zero(arena, String8Node, 1); String8 new_string = push_str8_copy(arena, node->string); @@ -1108,34 +1108,34 @@ str8_list_copy(Arena *arena, String8List *list) //~ rjf: String Splitting & Joining internal String8List -str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags) +str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags) { String8List list = {0}; B32 keep_empties = (flags & StringSplitFlag_KeepEmpties); U8 *ptr = string.str; U8 *opl = string.str + string.size; - for(;ptr < opl;) + for(;ptr < opl;) { U8 *first = ptr; - for(;ptr < opl; ptr += 1) + for(;ptr < opl; ptr += 1) { U8 c = *ptr; B32 is_split = 0; - for(U64 i = 0; i < split_char_count; i += 1) + for(U64 i = 0; i < split_char_count; i += 1) { - if(split_chars[i] == c) + if(split_chars[i] == c) { is_split = 1; break; } } - if(is_split) + if(is_split) { break; } } String8 string = str8_range(first, ptr); - if(keep_empties || string.size > 0) + if(keep_empties || string.size > 0) { str8_list_push(arena, &list, string); } @@ -1145,22 +1145,22 @@ str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, } internal String8List -str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags) +str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags) { String8List list = str8_split(arena, string, split_chars.str, split_chars.size, flags); return list; } internal String8 -str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params) +str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params) { StringJoin join = {0}; - if(optional_params != 0) + if(optional_params != 0) { MemoryCopyStruct(&join, optional_params); } U64 sep_count = 0; - if(list->node_count > 0) + if(list->node_count > 0) { sep_count = list->node_count - 1; } @@ -1171,11 +1171,11 @@ str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params) ptr += join.pre.size; for(String8Node *node = list->first; node != 0; - node = node->next) + node = node->next) { MemoryCopy(ptr, node->string.str, node->string.size); ptr += node->string.size; - if(node->next != 0) + if(node->next != 0) { MemoryCopy(ptr, join.sep.str, join.sep.size); ptr += join.sep.size; @@ -1218,7 +1218,7 @@ internal String8Array str8_array_from_list(Arena *arena, String8List *list) { String8Array array; - array.count = list->node_count; + array.count = list->node_count; array.v = push_array_no_zero(arena, String8, array.count); U64 idx = 0; for(String8Node *n = list->first; n != 0; n = n->next, idx += 1) @@ -1410,13 +1410,13 @@ str8_split_path(Arena *arena, String8 string) internal void str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style) { - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(0, 0); typedef struct String8MetaNode String8MetaNode; struct String8MetaNode { String8MetaNode *next; String8Node *node; - }; + }; String8MetaNode *stack = 0; String8MetaNode *free_meta_node = 0; String8Node *first = path->first; @@ -1796,13 +1796,13 @@ path_replace_file_extension(Arena *arena, String8 file_name, String8 ext) //////////////////////////////// //~ rjf: UTF-8 & UTF-16 Decoding/Encoding -read_only global U8 utf8_class[32] = +read_only global U8 utf8_class[32] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; internal UnicodeDecode -utf8_decode(U8 *str, U64 max) +utf8_decode(U8 *str, U64 max) { UnicodeDecode result = {1, max_U32}; U8 byte = str[0]; @@ -1863,12 +1863,12 @@ utf8_decode(U8 *str, U64 max) } internal UnicodeDecode -utf16_decode(U16 *str, U64 max) +utf16_decode(U16 *str, U64 max) { UnicodeDecode result = {1, max_U32}; result.codepoint = str[0]; result.inc = 1; - if(max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000) + if(max > 1 && 0xD800 <= str[0] && str[0] < 0xDC00 && 0xDC00 <= str[1] && str[1] < 0xE000) { result.codepoint = ((str[0] - 0xD800) << 10) | ((str[1] - 0xDC00) + 0x10000); result.inc = 2; @@ -1877,28 +1877,28 @@ utf16_decode(U16 *str, U64 max) } internal U32 -utf8_encode(U8 *str, U32 codepoint) +utf8_encode(U8 *str, U32 codepoint) { U32 inc = 0; - if(codepoint <= 0x7F) + if(codepoint <= 0x7F) { str[0] = (U8)codepoint; inc = 1; } - else if(codepoint <= 0x7FF) + else if(codepoint <= 0x7FF) { str[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5); str[1] = bit8 | (codepoint & bitmask6); inc = 2; } - else if(codepoint <= 0xFFFF) + else if(codepoint <= 0xFFFF) { str[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4); str[1] = bit8 | ((codepoint >> 6) & bitmask6); str[2] = bit8 | ( codepoint & bitmask6); inc = 3; } - else if(codepoint <= 0x10FFFF) + else if(codepoint <= 0x10FFFF) { str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3); str[1] = bit8 | ((codepoint >> 12) & bitmask6); @@ -1906,7 +1906,7 @@ utf8_encode(U8 *str, U32 codepoint) str[3] = bit8 | ( codepoint & bitmask6); inc = 4; } - else + else { str[0] = '?'; inc = 1; @@ -1915,18 +1915,18 @@ utf8_encode(U8 *str, U32 codepoint) } internal U32 -utf16_encode(U16 *str, U32 codepoint) +utf16_encode(U16 *str, U32 codepoint) { U32 inc = 1; - if(codepoint == max_U32) + if(codepoint == max_U32) { str[0] = (U16)'?'; } - else if(codepoint < 0x10000) + else if(codepoint < 0x10000) { str[0] = (U16)codepoint; } - else + else { U32 v = codepoint - 0x10000; str[0] = safe_cast_u16(0xD800 + (v >> 10)); @@ -2053,7 +2053,7 @@ StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_c internal OperatingSystem operating_system_from_string(String8 string) { - for EachElement(idx, g_os_enum_map) + for EachElement(idx, g_os_enum_map) { if(str8_match(g_os_enum_map[idx].string, string, StringMatchFlag_CaseInsensitive)) { @@ -2064,9 +2064,9 @@ operating_system_from_string(String8 string) } internal String8 -string_from_dimension(Dimension dimension) +string_from_dimension(Dimension dimension) { - read_only local_persist String8 strings[] = + read_only local_persist String8 strings[] = { str8_lit_comp("X"), str8_lit_comp("Y"), @@ -2074,7 +2074,7 @@ string_from_dimension(Dimension dimension) str8_lit_comp("W"), }; String8 result = str8_lit("error"); - if((U32)dimension < 4) + if((U32)dimension < 4) { result = strings[dimension]; } @@ -2082,15 +2082,15 @@ string_from_dimension(Dimension dimension) } internal String8 -string_from_side(Side side) +string_from_side(Side side) { - local_persist String8 strings[] = + local_persist String8 strings[] = { str8_lit_comp("Min"), str8_lit_comp("Max"), }; String8 result = str8_lit("error"); - if((U32)side < 2) + if((U32)side < 2) { result = strings[side]; } @@ -2109,26 +2109,26 @@ string_from_operating_system(OperatingSystem os) } internal String8 -string_from_arch(Arch arch) -{ - String8 result = {0}; - switch(arch) - { - case Arch_Null: {result = str8_lit("Null");}break; - case Arch_x64: {result = str8_lit("x64");}break; - case Arch_x86: {result = str8_lit("x86");}break; - case Arch_arm64: {result = str8_lit("arm64");}break; - case Arch_arm32: {result = str8_lit("arm32");}break; - case Arch_COUNT: - {result = str8_lit("Invalid");}break; - } +string_from_arch(Arch arch) +{ + String8 result = {0}; + switch(arch) + { + case Arch_Null: {result = str8_lit("Null");}break; + case Arch_x64: {result = str8_lit("x64");}break; + case Arch_x86: {result = str8_lit("x86");}break; + case Arch_arm64: {result = str8_lit("arm64");}break; + case Arch_arm32: {result = str8_lit("arm32");}break; + case Arch_COUNT: + {result = str8_lit("Invalid");}break; + } return result; } internal String8 -string_from_week_day(WeekDay week_day) +string_from_week_day(WeekDay week_day) { - read_only local_persist String8 strings[] = + read_only local_persist String8 strings[] = { str8_lit_comp("Sun"), str8_lit_comp("Mon"), @@ -2139,7 +2139,7 @@ string_from_week_day(WeekDay week_day) str8_lit_comp("Sat"), }; String8 result = str8_lit("Err"); - if((U32)week_day < WeekDay_COUNT) + if((U32)week_day < WeekDay_COUNT) { result = strings[week_day]; } @@ -2147,9 +2147,9 @@ string_from_week_day(WeekDay week_day) } internal String8 -string_from_month(Month month) +string_from_month(Month month) { - read_only local_persist String8 strings[] = + read_only local_persist String8 strings[] = { str8_lit_comp("Jan"), str8_lit_comp("Feb"), @@ -2165,7 +2165,7 @@ string_from_month(Month month) str8_lit_comp("Dec"), }; String8 result = str8_lit("Err"); - if((U32)month < Month_COUNT) + if((U32)month < Month_COUNT) { result = strings[month]; } @@ -2173,16 +2173,16 @@ string_from_month(Month month) } internal String8 -string_from_date_time(Arena *arena, DateTime *date_time) +string_from_date_time(Arena *arena, DateTime *date_time) { char *mon_str = (char*)string_from_month(date_time->month).str; U32 adjusted_hour = date_time->hour%12; - if(adjusted_hour == 0) + if(adjusted_hour == 0) { adjusted_hour = 12; } char *ampm = "am"; - if(date_time->hour >= 12) + if(date_time->hour >= 12) { ampm = "pm"; } @@ -2193,7 +2193,7 @@ string_from_date_time(Arena *arena, DateTime *date_time) } internal String8 -string_from_date_time__file_name(Arena *arena, DateTime *date_time) +string_from_date_time__file_name(Arena *arena, DateTime *date_time) { char *mon_str = (char*)string_from_month(date_time->month).str; String8 result = str8f(arena, "%d-%s-%0d--%02d-%02d-%02d", @@ -2203,22 +2203,22 @@ string_from_date_time__file_name(Arena *arena, DateTime *date_time) } internal String8 -string_from_elapsed_time(Arena *arena, DateTime dt) +string_from_elapsed_time(Arena *arena, DateTime dt) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; - if(dt.year) + if(dt.year) { str8_list_pushf(scratch.arena, &list, "%dy", dt.year); str8_list_pushf(scratch.arena, &list, "%um", dt.mon); str8_list_pushf(scratch.arena, &list, "%ud", dt.day); - } - else if(dt.mon) + } + else if(dt.mon) { str8_list_pushf(scratch.arena, &list, "%um", dt.mon); str8_list_pushf(scratch.arena, &list, "%ud", dt.day); - } - else if (dt.day) + } + else if (dt.day) { str8_list_pushf(scratch.arena, &list, "%ud", dt.day); } @@ -2850,7 +2850,7 @@ str8_compar(String8 a, String8 b, B32 ignore_case) return cmp; } -internal int str8_compar_ignore_case(const void *a, const void *b) +internal int str8_compar_ignore_case(const void *a, const void *b) { return str8_compar(*(String8*)a, *(String8*)b, 1); } diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index c4af2cf2..a90656cf 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -241,10 +241,10 @@ fs_properties_from_path(String8 path) } //////////////////////////////// -//~ rjf: Asynchronous Tick +//~ rjf: Tick internal void -fs_async_tick(void) +fs_tick(void) { Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index e549fa52..8bd6ba3b 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -122,8 +122,8 @@ internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal FileProperties fs_properties_from_path(String8 path); //////////////////////////////// -//~ rjf: Asynchronous Tick +//~ rjf: Tick -internal void fs_async_tick(void); +internal void fs_tick(void); #endif // FILE_STREAM_H From 4e1ebe5a6b3921a74df3ec0c7c13ac223382be4d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 13:15:38 -0700 Subject: [PATCH 188/302] change import stub symbol characteristic to search alias to skip them on subsequent searches --- src/linker/lnk.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 05f4da83..f760f0c2 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -465,13 +465,10 @@ lnk_make_null_obj(Arena *arena) COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_Unknown); // push null symbol - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External); + COFF_ObjSymbol *null_abs = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External); // push import stub - { - COFF_ObjSymbol *tag = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_IMPORT_STUB), 0, COFF_SymStorageClass_Static); - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_AntiDependency, tag); - } + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_SearchAlias, null_abs); // push .debug$T sections with null leaf String8 null_debug_data; From 98eaf67dd866c31913049b815978f2c9cc5c0a30 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 13:16:30 -0700 Subject: [PATCH 189/302] while symbol table is being built sort weak and undefined symbols to separate chunk lists to speed up library search --- src/linker/lnk_symbol_table.c | 90 +++++++++++++++++++++-------------- src/linker/lnk_symbol_table.h | 3 ++ 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 94bc4ddb..3a66719e 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -86,6 +86,12 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * return result; } +internal void +lnk_symbol_hash_trie_chunk_list_concat_in_place(LNK_SymbolHashTrieChunkList *list, LNK_SymbolHashTrieChunkList *to_concat) +{ + SLLConcatInPlace(list, to_concat); +} + internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { @@ -382,7 +388,7 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, if (curr_trie == 0) { // init node - LNK_SymbolHashTrie *new_trie = lnk_symbol_hash_trie_chunk_list_push(arena, chunks, 512); + LNK_SymbolHashTrie *new_trie = lnk_symbol_hash_trie_chunk_list_push(arena, chunks, 0x1000); new_trie->name = &symbol->name; new_trie->symbol = symbol; MemoryZeroArray(new_trie->child); @@ -542,17 +548,25 @@ lnk_symbol_table_hasher(String8 string) internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena) { - LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); - symtab->arena = arena; - symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); + LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); + symtab->arena = arena; + symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); + symtab->weak_undef_chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); return symtab; } internal void lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) { - U64 hash = lnk_symbol_table_hasher(symbol->name); - lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunks[worker_id], &symtab->root, hash, symbol); + U64 hash = lnk_symbol_table_hasher(symbol->name); + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol); + LNK_SymbolHashTrieChunkList *chunks; + if (interp == COFF_SymbolValueInterp_Weak || interp == COFF_SymbolValueInterp_Undefined) { + chunks = &symtab->weak_undef_chunks[worker_id]; + } else { + chunks = &symtab->chunks[worker_id]; + } + lnk_symbol_hash_trie_insert_or_replace(arena, chunks, &symtab->root, hash, symbol); } internal void @@ -702,34 +716,34 @@ exit:; internal THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) { - LNK_ReplaceWeakSymbolsWithDefaultSymbolTask *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id]; - for EachIndex(i, chunk->count) { - LNK_Symbol *symbol = chunk->v[i].symbol; - LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); - COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_ObjSymbolRef resolve = {0}; - if (lnk_resolve_weak_symbol(symtab, symbol_ref, &resolve)) { - COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); - COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); - if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); - if (symbol_ref.obj->header.is_big_obj) { - COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; - symbol32->section_number = COFF_Symbol_UndefinedSection; - symbol32->value = 0; - symbol32->storage_class = COFF_SymStorageClass_External; + LNK_SymbolTable *symtab = raw_task; + for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); + COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + LNK_ObjSymbolRef resolve = {0}; + if (lnk_resolve_weak_symbol(symtab, symbol_ref, &resolve)) { + COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); + COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); + if (resolve_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); + if (symbol_ref.obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; + symbol32->section_number = COFF_Symbol_UndefinedSection; + symbol32->value = 0; + symbol32->storage_class = COFF_SymStorageClass_External; + } else { + COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; + symbol16->section_number = COFF_Symbol_UndefinedSection; + symbol16->value = 0; + symbol16->storage_class = COFF_SymStorageClass_External; + } } else { - COFF_Symbol16 *symbol16 = symbol_parsed.raw_symbol; - symbol16->section_number = COFF_Symbol_UndefinedSection; - symbol16->value = 0; - symbol16->storage_class = COFF_SymStorageClass_External; + symbol->refs->v = resolve; } - } else { - symbol->refs->v = resolve; } } } @@ -740,11 +754,13 @@ internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) { ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); - tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_with_default_symbol_task, &(LNK_ReplaceWeakSymbolsWithDefaultSymbolTask){ .symtab = symtab, .chunks = chunks }); - scratch_end(scratch); + + tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_replace_weak_with_default_symbol_task, symtab, "Replace Weak With Default Symbols"); + + for EachIndex(i, tp->worker_count) { + lnk_symbol_hash_trie_chunk_list_concat_in_place(&symtab->chunks[i], &symtab->weak_undef_chunks[i]); + } + ProfEnd(); } diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index afa4ebd5..190d649d 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -76,6 +76,7 @@ typedef struct LNK_SymbolTable TP_Arena *arena; LNK_SymbolHashTrie *root; LNK_SymbolHashTrieChunkList *chunks; + LNK_SymbolHashTrieChunkList *weak_undef_chunks; } LNK_SymbolTable; // --- Workers Contexts -------------------------------------------------------- @@ -102,6 +103,8 @@ internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *lis // --- Symbol Hash Trie -------------------------------------------------------- +internal LNK_SymbolHashTrie * lnk_symbol_hash_tire_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList *list, U64 cap); +internal void lnk_symbol_hash_trie_chunk_list_concat_in_place(LNK_SymbolHashTrieChunkList *list, LNK_SymbolHashTrieChunkList *to_concat); internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *symbol); internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name); internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie); From ded932e3ba8890358cfdfa5ce43adea4b09a8b5e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 13:17:14 -0700 Subject: [PATCH 190/302] skip library searches for import stubs --- src/linker/lnk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f760f0c2..9a98fc9b 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1640,6 +1640,9 @@ lnk_link_inputs(TP_Context *tp, LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); + // skip lib search + import_symbol->is_lib_member_linked = 1; + // find DLL with import symbols B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; From 0b5dd92a873c09d922e6b70a321866d69ac22b0d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 13:17:33 -0700 Subject: [PATCH 191/302] minor tweaks --- src/linker/lnk.c | 35 +++++++++++++++++++---------------- src/linker/lnk_lib.c | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 9a98fc9b..21d2ff2a 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1478,7 +1478,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } -internal void +internal force_inline void lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, U32 member_idx) { B32 is_first_set = lnk_lib_set_link_symbol(lib, member_idx, link_symbol); @@ -1496,12 +1496,13 @@ lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Sym internal THREAD_POOL_TASK_FUNC(lnk_search_lib_task) { - LNK_SearchLibTask *task = raw_task; - LNK_Lib *lib = task->lib; - LNK_SymbolTable *symtab = task->symtab; - LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id]; + LNK_SearchLibTask *task = raw_task; + LNK_Lib *lib = task->lib; + LNK_SymbolTable *symtab = task->symtab; + B32 search_anti_deps = task->search_anti_deps; + LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id]; - for (LNK_SymbolHashTrieChunk *c = symtab->chunks[task_id].first; c != 0; c = c->next) { + for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) { for EachIndex(i, c->count) { LNK_Symbol *symbol = c->v[i].symbol; if (symbol->is_lib_member_linked) { continue; } @@ -1521,15 +1522,17 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task) if (lnk_search_lib(lib, symbol->name, &member_idx)) { lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); } - } else if (task->search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_ObjSymbolRef dep_symbol = {0}; - if (lnk_resolve_weak_symbol(symtab, symbol_ref, &dep_symbol)) { - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - U32 member_idx; - if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { - lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } else if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + if (search_anti_deps) { + LNK_ObjSymbolRef dep_symbol = {0}; + if (lnk_resolve_weak_symbol(symtab, symbol_ref, &dep_symbol)) { + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(lib, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member(arena, member_ref_list, symbol, lib, member_idx); + } } } } @@ -1555,7 +1558,7 @@ lnk_link_inputs(TP_Context *tp, for (U64 resolved_members_count = 0; ; resolved_members_count = 0) { lnk_load_inputs(tp, arena, config, inputer, symtab, link); - for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) { + for EachNode(lib_n, LNK_LibNode, link->libs.first) { ProfBeginV("Search %S", str8_skip_last_slash(lib_n->data.path)); do { lnk_load_inputs(tp, arena, config, inputer, symtab, link); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index bcf06da7..2bd417e4 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -262,7 +262,7 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) return is_first_set; } -internal B32 +internal force_inline B32 lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out) { U64 symbol_idx = str8_array_bsearch(lib->symbol_names, symbol_name); From 8a46ee0ad2089db570949ad88cc1e6636688b08d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 13:23:16 -0700 Subject: [PATCH 192/302] return full path to the first matched file --- src/linker/lnk_io.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk_io.c b/src/linker/lnk_io.c index 49172cfe..1125c884 100644 --- a/src/linker/lnk_io.c +++ b/src/linker/lnk_io.c @@ -52,11 +52,20 @@ internal String8 lnk_find_first_file(Arena *arena, String8List dir_list, String8 path) { ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); String8 result = {0}; if (os_file_path_exists(path)) { - result = path; + PathStyle path_style = path_style_from_str8(path); + if (path_style == PathStyle_Relative) { + String8 current_path = os_get_current_path(scratch.arena); + String8List l = {0}; + str8_list_push(scratch.arena, &l, current_path); + str8_list_push(scratch.arena, &l, path); + result = str8_path_list_join_by_style(arena, &l, PathStyle_SystemAbsolute); + } else { + result = path; + } } else { - Temp scratch = scratch_begin(&arena, 1); String8 file_name = str8_skip_last_slash(path); for EachNode(n, String8Node, dir_list.first) { String8 full_path = push_str8f(scratch.arena, "%S/%S", n->string, file_name); @@ -65,8 +74,8 @@ lnk_find_first_file(Arena *arena, String8List dir_list, String8 path) break; } } - scratch_end(scratch); } + scratch_end(scratch); ProfEnd(); return result; } From d4ac5ede779c507e701166930747a6a3542f5aba Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 11 Sep 2025 14:09:26 -0700 Subject: [PATCH 193/302] assign correct removed section type --- src/linker/lnk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 21d2ff2a..1cc0d52b 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2563,7 +2563,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) value = parsed_symlink.value; } else { // COMDAT section may have static symbols which are now invalid to relocate against - section_number = LNK_REMOVED_SECTION_NUMBER_32; + section_number = lnk_obj_get_removed_section_number(obj); value = max_U32; task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; } @@ -2711,10 +2711,10 @@ THREAD_POOL_TASK_FUNC(lnk_patch_regular_symbols_task) COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); LNK_SectionContrib *sc = task->sect_map[obj_idx][symbol.section_number-1]; - U16 section_number; + U32 section_number; U32 value; if (sc == task->null_sc) { - section_number = LNK_REMOVED_SECTION_NUMBER_16; + section_number = lnk_obj_get_removed_section_number(obj); value = max_U32; } else { section_number = safe_cast_u32(sc->u.sect_idx + 1); From 630c3b42a7a2d7b9fd9924203ecc6aaa3ee2bd11 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sat, 13 Sep 2025 01:35:56 -0700 Subject: [PATCH 194/302] do lightweight import gathering while resolving links --- src/coff/coff.h | 1 + src/linker/lnk.c | 226 ++++++++++++++++++---------------- src/linker/lnk.h | 32 ++--- src/linker/lnk_lib.c | 31 ++--- src/linker/lnk_lib.h | 21 ++-- src/linker/lnk_symbol_table.c | 8 +- src/linker/lnk_symbol_table.h | 3 +- 7 files changed, 160 insertions(+), 162 deletions(-) diff --git a/src/coff/coff.h b/src/coff/coff.h index 0cd16897..69b72ff3 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -294,6 +294,7 @@ typedef struct COFF_Symbol32 typedef U32 COFF_WeakExtType; enum { + COFF_WeakExt_Null = 0, COFF_WeakExt_NoLibrary = 1, COFF_WeakExt_SearchLibrary = 2, COFF_WeakExt_SearchAlias = 3, diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1cc0d52b..788a42ed 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -468,7 +468,7 @@ lnk_make_null_obj(Arena *arena) COFF_ObjSymbol *null_abs = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit(LNK_NULL_SYMBOL), 0, COFF_SymStorageClass_External); // push import stub - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_SearchAlias, null_abs); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit(LNK_IMPORT_STUB), COFF_WeakExt_Null, null_abs); // push .debug$T sections with null leaf String8 null_debug_data; @@ -1198,8 +1198,8 @@ internal int lnk_lib_member_ref_is_before(void *raw_a, void *raw_b) { LNK_LibMemberRef **a = raw_a, **b = raw_b; - LNK_Symbol *a_pull_in_ref = (*a)->lib->was_member_linked[(*a)->member_idx]; - LNK_Symbol *b_pull_in_ref = (*b)->lib->was_member_linked[(*b)->member_idx]; + LNK_Symbol *a_pull_in_ref = (*a)->lib->member_links[(*a)->member_idx]; + LNK_Symbol *b_pull_in_ref = (*b)->lib->member_links[(*b)->member_idx]; return lnk_symbol_is_before(a_pull_in_ref, b_pull_in_ref); } @@ -1478,17 +1478,14 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } -internal force_inline void +internal void lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Symbol *link_symbol, LNK_Lib *lib, U32 member_idx) { - B32 is_first_set = lnk_lib_set_link_symbol(lib, member_idx, link_symbol); - if (is_first_set) { - link_symbol->is_lib_member_linked = 1; - + B32 was_linked = lnk_lib_set_link_symbol(lib, member_idx, link_symbol); + if (was_linked) { LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1); - member_ref->lib = lib; - member_ref->member_idx = member_idx; - + member_ref->lib = lib; + member_ref->member_idx = member_idx; lnk_lib_member_ref_list_push_node(queued_members, member_ref); } } @@ -1502,10 +1499,9 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task) B32 search_anti_deps = task->search_anti_deps; LNK_LibMemberRefList *member_ref_list = &task->member_ref_lists[task_id]; - for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) { + for EachNode(c, LNK_SymbolHashTrieChunk, symtab->search_chunks[task_id].first) { for EachIndex(i, c->count) { LNK_Symbol *symbol = c->v[i].symbol; - if (symbol->is_lib_member_linked) { continue; } LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); @@ -1548,31 +1544,33 @@ lnk_link_inputs(TP_Context *tp, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, - LNK_Link *link, - LNK_ImportTables *imps) + LNK_Link *link) { ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); - B32 search_anti_deps = 0; + LNK_LibMemberRefList *member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count); + B32 search_anti_deps = 0; for (U64 resolved_members_count = 0; ; resolved_members_count = 0) { lnk_load_inputs(tp, arena, config, inputer, symtab, link); for EachNode(lib_n, LNK_LibNode, link->libs.first) { - ProfBeginV("Search %S", str8_skip_last_slash(lib_n->data.path)); + LNK_Lib *lib = &lib_n->data; + + ProfBeginV("Search %S", str8_skip_last_slash(lib->path)); do { lnk_load_inputs(tp, arena, config, inputer, symtab, link); + // search symbols in lib + MemoryZeroTyped(member_ref_lists, tp->worker_count); + tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &(LNK_SearchLibTask){ .search_anti_deps = search_anti_deps, .lib = lib, .symtab = symtab, .member_ref_lists = member_ref_lists }); + LNK_LibMemberRefList queued_members = {0}; - { - LNK_SearchLibTask task = { .search_anti_deps = search_anti_deps, .lib = &lib_n->data, .symtab = symtab }; - task.member_ref_lists = push_array(scratch.arena, LNK_LibMemberRefList, tp->worker_count); - tp_for_parallel(tp, arena, tp->worker_count, lnk_search_lib_task, &task); - lnk_lib_member_ref_list_concat_in_place_array(&queued_members, task.member_ref_lists, tp->worker_count); - } + lnk_lib_member_ref_list_concat_in_place_array(&queued_members, member_ref_lists, tp->worker_count); // sort library member refs to match the order of their appearance in obj symbol tables LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members); + //qsort(member_refs, queued_members.count, sizeof(member_refs[0]), lnk_lib_member_ref_compar); radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before); if (queued_members.count) { @@ -1583,7 +1581,7 @@ lnk_link_inputs(TP_Context *tp, LNK_LibMemberRef *member_ref = member_refs[i]; LNK_Lib *lib = member_ref->lib; - LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; + LNK_Symbol *link_symbol = lib->member_links[member_ref->member_idx]; COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); COFF_DataType member_type = coff_data_type_from_data(member_info.data); @@ -1602,70 +1600,50 @@ lnk_link_inputs(TP_Context *tp, // push inputs for lib member refs for EachIndex(i, queued_members.count) { - LNK_LibMemberRef *member_ref = member_refs[i]; - LNK_Lib *lib = member_ref->lib; - LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; + LNK_LibMemberRef *member_ref = member_refs[i]; + U64 member_idx = member_ref->member_idx; - // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); + // parse member info + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_idx]); COFF_DataType member_type = coff_data_type_from_data(member_info.data); String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name); switch (member_type) { case COFF_DataType_Import: { - COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(member_info.data); + LNK_Symbol *link_symbol = lib->member_links[member_idx]; - // import machine compat check - if (import_header.machine != config->machine) { - LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol); - lnk_error_obj(LNK_Error_IncompatibleMachine, - ref.obj, - "symbol %S pulls-in import from %S for an incompatible machine %S (expected machine %S)", - link_symbol->name, - str8_chop_last_slash(lib->path), - coff_string_from_machine_type(import_header.machine), - coff_string_from_machine_type(config->machine)); - break; + LNK_Symbol *import_symbols[2] = {0}; + if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) { + import_symbols[0] = link_symbol; + import_symbols[1] = lnk_symbol_table_search(symtab, str8_skip(link_symbol->name, str8_lit("__imp_").size)); + } else { + Temp temp = temp_begin(scratch.arena); + String8 imp_name = push_str8f(temp.arena, "__imp_%S", link_symbol->name); + import_symbols[0] = lnk_symbol_table_search(symtab, imp_name); + import_symbols[1] = link_symbol; + temp_end(temp); } - // was import already created? - LNK_Symbol *is_import_loaded = lnk_symbol_table_search(symtab, link_symbol->name); - if (is_import_loaded) { - COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(is_import_loaded); - if (interp != COFF_SymbolValueInterp_Undefined) { - break; - } + for EachIndex(i, ArrayCount(import_symbols)) { + LNK_Symbol *import_symbol = import_symbols[i]; + if (import_symbol == 0) { continue; } + + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + + // same import symbol must never be queued more than once, if it is, there is a bug in the link set logic + AssertAlways(import_symbol->refs != import_stub->refs); + + // replace the import symbol with a stub, which is later replaced with the real import symbol once import obj is ready + import_symbol->refs = import_stub->refs; } - // create import stub symbol (later replaced with actual import) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_ObjSymbolRef import_symbol_ref = lnk_ref_from_symbol(import_stub); - LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); - lnk_symbol_table_push(symtab, import_symbol); - - // skip lib search - import_symbol->is_lib_member_linked = 1; - - // find DLL with import symbols - B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); - String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; - HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; - PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); - - // create record for a first time-DLL - if (import_symbols == 0) { - import_symbols = push_array(imps->arena, PE_MakeImportList, 1); - str8_list_push(imps->arena, dll_names, import_header.dll_name); - hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols); - } - - // push make import info - pe_make_import_header_list_push(imps->arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }); + // push import member for import obj generation + lnk_lib_member_ref_list_push_node(&link->imports, member_ref); } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { if (lib->type == COFF_Archive_Thin) { - // obj path in thin archive is relative to the directory with archive + // obj path in thin archive is relative to the directory with lib String8List obj_path_list = {0}; str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); str8_list_push(scratch.arena, &obj_path_list, member_name); @@ -1747,18 +1725,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer link->last_cmd_lib = &config->input_list[LNK_Input_Lib].first; link->try_to_resolve_entry_point = 1; - // - // init import hash tables - // - LNK_ImportTables *imps = 0; - { - Arena *imps_arena = arena_alloc(); - imps = push_array(imps_arena, LNK_ImportTables, 1); - imps->arena = imps_arena; - imps->static_imports = hash_table_init(imps->arena, 0x1000); - imps->delayed_imports = hash_table_init(imps->arena, 0x1000); - } - // input :null_obj String8 null_obj = lnk_make_null_obj(inputer->arena); lnk_inputer_push_obj_linkgen(inputer, 0, str8_lit("* Null *"), null_obj); @@ -1774,7 +1740,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } // link inputer - lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); + lnk_link_inputs(tp, arena, config, inputer, symtab, link); // TODO: need to figure out under what condition to include load config //lnk_include_symbol(config, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME), 0); @@ -1786,11 +1752,64 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } - // make and input delayed imports + // + // make imports + // { - String8List delayed_dll_names = imps->delayed_dll_names; - HashTable *delayed_imports_ht = imps->delayed_imports; + HashTable *static_imports_ht = hash_table_init(scratch.arena, 0x1000); + HashTable *delayed_imports_ht = hash_table_init(scratch.arena, 0x1000); + String8List delayed_dll_names = {0}; + String8List static_dll_names = {0}; + + for EachNode(member_ref, LNK_LibMemberRef, link->imports.first) { + LNK_Lib *lib = member_ref->lib; + U64 member_idx = member_ref->member_idx; + LNK_Symbol *link_symbol = lib->member_links[member_idx]; + + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_idx]); + COFF_DataType member_type = coff_data_type_from_data(member_info.data); + String8 member_name = coff_decode_member_name(lib->long_names, member_info.header.name); + COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(member_info.data); + + // import machine compat check + if (import_header.machine != config->machine) { + LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol); + lnk_error_obj(LNK_Error_IncompatibleMachine, + ref.obj, + "symbol %S pulls-in import from %S with an incompatible machine %S (expected machine %S)", + link_symbol->name, + str8_chop_last_slash(lib->path), + coff_string_from_machine_type(import_header.machine), + coff_string_from_machine_type(config->machine)); + break; + } + + // find DLL with import symbols + B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); + String8List *dll_names = is_delay_load ? &delayed_dll_names : &static_dll_names; + HashTable *imports_ht = is_delay_load ? delayed_imports_ht : static_imports_ht; + PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + + // create record for a first time-DLL + if (import_symbols == 0) { + import_symbols = push_array(scratch.arena, PE_MakeImportList, 1); + str8_list_push(scratch.arena, dll_names, import_header.dll_name); + hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols); + } + + B32 make_jump_thunk = 1; + if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) { + LNK_Symbol *thunk_symbol = lnk_symbol_table_search(symtab, str8_skip(link_symbol->name, str8_lit("__imp_").size)); + make_jump_thunk = thunk_symbol != 0; + } + + // push make import info + pe_make_import_header_list_push(scratch.arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = make_jump_thunk }); + } AssertAlways(delayed_dll_names.node_count == delayed_imports_ht->count); + AssertAlways(static_dll_names.node_count == static_imports_ht->count); + + // make and input delayed imports if (delayed_imports_ht->count) { ProfBegin("Build Delay Import Table"); @@ -1813,13 +1832,8 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } - } - // make and input static imports - { - String8List static_dll_names = imps->static_dll_names; - HashTable *static_imports_ht = imps->static_imports; - AssertAlways(static_dll_names.node_count == static_imports_ht->count); + // make and input static imports if (static_imports_ht->count) { ProfBegin("Build Static Import Table"); @@ -1840,6 +1854,15 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } + + // warn about unused delayloads + if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) { + for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { + if (!hash_table_search_path_raw(delayed_imports_ht, dll_name_n->string)) { + lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string); + } + } + } } if (config->export_symbol_list.count) { @@ -1967,7 +1990,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer // // link linker made objs // - lnk_link_inputs(tp, arena, config, inputer, symtab, link, imps); + lnk_link_inputs(tp, arena, config, inputer, symtab, link); // // finalize symbol table @@ -2104,17 +2127,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer ProfEnd(); } - // - // warn about unused delayloads - // - if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) { - for (String8Node *dll_name_n = config->delay_load_dll_list.first; dll_name_n != 0; dll_name_n = dll_name_n->next) { - if (!hash_table_search_path_raw(imps->delayed_imports, dll_name_n->string)) { - lnk_error(LNK_Warning_UnusedDelayLoadDll, "/DELAYLOAD: %S found no imports", dll_name_n->string); - } - } - } - // // discard COMDAT sections that are not referenced // diff --git a/src/linker/lnk.h b/src/linker/lnk.h index a3f7909c..31443404 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -7,8 +7,8 @@ typedef struct LNK_LibMemberRef { - LNK_Lib *lib; - U32 member_idx; + LNK_Lib *lib; + U32 member_idx; struct LNK_LibMemberRef *next; } LNK_LibMemberRef; @@ -76,25 +76,17 @@ typedef struct LNK_Inputer #define LNK_SECTION_FLAG_IS_LIVE (1 << 0) #define LNK_SECTION_FLAG_DEBUG_INFO (1 << 1) -typedef struct LNK_ImportTables -{ - Arena *arena; - String8List delayed_dll_names; - String8List static_dll_names; - HashTable *static_imports; - HashTable *delayed_imports; -} LNK_ImportTables; - typedef struct LNK_Link { - LNK_ObjList objs; - LNK_LibList libs; - LNK_ObjNode **last_symbol_input; - LNK_IncludeSymbolNode **last_include; - String8Node **last_cmd_lib; - String8Node **last_default_lib; - String8Node **last_obj_lib; - B32 try_to_resolve_entry_point; + LNK_ObjList objs; + LNK_LibList libs; + LNK_ObjNode **last_symbol_input; + LNK_IncludeSymbolNode **last_include; + String8Node **last_cmd_lib; + String8Node **last_default_lib; + String8Node **last_obj_lib; + LNK_LibMemberRefList imports; + B32 try_to_resolve_entry_point; } LNK_Link; // -- Image Layout ------------------------------------------------------------ @@ -299,7 +291,7 @@ internal LNK_LibMemberRef ** lnk_array_from_lib_member_list(Arena *arena, LNK_Li internal LNK_ObjNode * lnk_load_objs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, U64 *objs_count_out); internal void lnk_load_libs (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_Link *link); -internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link, LNK_ImportTables *imps); +internal void lnk_link_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab, LNK_Link *link); internal LNK_Link * lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer *inputer, LNK_SymbolTable *symtab); // --- Optimizations ----------------------------------------------------------- diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 2bd417e4..cd4f5e82 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -137,10 +137,11 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L lib_out->path = push_str8_copy(arena, path); lib_out->data = data; lib_out->type = type; + lib_out->member_count = member_count; lib_out->symbol_count = Min(symbol_count, symbol_names.count); // TODO: warn about mismatched number of symbol names and symbol count in the header lib_out->member_offsets = member_offsets; lib_out->symbol_indices = symbol_indices; - lib_out->was_member_linked = push_array(arena, LNK_Symbol *, member_count); + lib_out->member_links = push_array(arena, LNK_Symbol *, member_count); lib_out->symbol_names = symbol_names; lib_out->long_names = parse.long_names; lib_out->input_idx = input_idx; @@ -225,41 +226,33 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) { local_persist LNK_Symbol null_symbol; - B32 is_first_set; + LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol); - LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); - - for (;;) { - is_first_set = (slot == 0); + B32 was_linked = (slot == 0); + for (LNK_Symbol *leader = link_symbol;;) { // update slot symbol if it is empty or link symbol comes before symbol in the slot if (slot && slot != &null_symbol) { - if (!str8_starts_with(link_symbol->name, str8_lit("__imp_")) && str8_starts_with(slot->name, str8_lit("__imp_"))) { - // replace import address symbol with jump thunk symbol - slot = link_symbol; - is_first_set = 1; - } else if (str8_starts_with(link_symbol->name, str8_lit("__imp_")) && !str8_starts_with(slot->name, str8_lit("__imp_"))) { - // no need to replace - } else if (lnk_symbol_is_before(slot, link_symbol)) { - slot = link_symbol; + if (lnk_symbol_is_before(slot, leader)) { + leader = slot; } } else { - slot = link_symbol; + leader = link_symbol; } // try to insert back updated slot symbol - LNK_Symbol *was_replaced = ins_atomic_ptr_eval_cond_assign(&lib->was_member_linked[member_idx], slot, &null_symbol); + LNK_Symbol *swap = ins_atomic_ptr_eval_cond_assign(&lib->member_links[member_idx], leader, &null_symbol); // exit if slot symbol was null - if (was_replaced == &null_symbol) { + if (swap == &null_symbol) { break; } // reload slot symbol - slot = ins_atomic_ptr_eval_assign(&lib->was_member_linked[member_idx], &null_symbol); + slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol); } - return is_first_set; + return was_linked; } internal force_inline B32 diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 826b507f..0cbdd673 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -5,16 +5,17 @@ typedef struct LNK_Lib { - String8 path; - String8 data; - COFF_ArchiveType type; - U32 symbol_count; - U32 *member_offsets; - U16 *symbol_indices; - LNK_Symbol **was_member_linked; - String8Array symbol_names; - String8 long_names; - U64 input_idx; + String8 path; + String8 data; + COFF_ArchiveType type; + U32 member_count; + U32 symbol_count; + U32 *member_offsets; + U16 *symbol_indices; + LNK_Symbol **member_links; + String8Array symbol_names; + String8 long_names; + U64 input_idx; } LNK_Lib; typedef struct LNK_LibNode diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 3a66719e..175c5e54 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -551,7 +551,7 @@ lnk_symbol_table_init(TP_Arena *arena) LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); symtab->arena = arena; symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); - symtab->weak_undef_chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); + symtab->search_chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); return symtab; } @@ -562,7 +562,7 @@ lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol); LNK_SymbolHashTrieChunkList *chunks; if (interp == COFF_SymbolValueInterp_Weak || interp == COFF_SymbolValueInterp_Undefined) { - chunks = &symtab->weak_undef_chunks[worker_id]; + chunks = &symtab->search_chunks[worker_id]; } else { chunks = &symtab->chunks[worker_id]; } @@ -717,7 +717,7 @@ internal THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) { LNK_SymbolTable *symtab = raw_task; - for EachNode(c, LNK_SymbolHashTrieChunk, symtab->weak_undef_chunks[task_id].first) { + for EachNode(c, LNK_SymbolHashTrieChunk, symtab->search_chunks[task_id].first) { for EachIndex(i, c->count) { LNK_Symbol *symbol = c->v[i].symbol; LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); @@ -758,7 +758,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab) tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_replace_weak_with_default_symbol_task, symtab, "Replace Weak With Default Symbols"); for EachIndex(i, tp->worker_count) { - lnk_symbol_hash_trie_chunk_list_concat_in_place(&symtab->chunks[i], &symtab->weak_undef_chunks[i]); + lnk_symbol_hash_trie_chunk_list_concat_in_place(&symtab->chunks[i], &symtab->search_chunks[i]); } ProfEnd(); diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 190d649d..7ca55350 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -20,7 +20,6 @@ typedef struct LNK_ObjSymbolRefNode typedef struct LNK_Symbol { String8 name; - B8 is_lib_member_linked; LNK_ObjSymbolRefNode *refs; } LNK_Symbol; @@ -76,7 +75,7 @@ typedef struct LNK_SymbolTable TP_Arena *arena; LNK_SymbolHashTrie *root; LNK_SymbolHashTrieChunkList *chunks; - LNK_SymbolHashTrieChunkList *weak_undef_chunks; + LNK_SymbolHashTrieChunkList *search_chunks; } LNK_SymbolTable; // --- Workers Contexts -------------------------------------------------------- From cc8fdc6c6fe87efb4fc95aee3a5c7532f0049533 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 16:00:09 -0700 Subject: [PATCH 195/302] order check for COMDATs with any property --- src/linker/lnk_symbol_table.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 175c5e54..dc9f37a0 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -273,12 +273,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) switch (src_select) { case COFF_ComdatSelect_Null: case COFF_ComdatSelect_Any: { - if (src_section_length == dst_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - // both COMDATs are valid but to get smaller exe pick smallest - can_replace = 0; - } + can_replace = lnk_obj_is_before(src_obj, dst_obj); } break; case COFF_ComdatSelect_NoDuplicates: { lnk_error_multiply_defined_symbol(dst, src); From 5a12513306dc1a4ab41ca9ab2bce90075a6ab585 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:40:48 -0700 Subject: [PATCH 196/302] parallelize section garbage collection currently we tag pointers to solve ABA problem however if the list has more than max_U16 items, the tag will overflow and cause serious issues. To fix this, we need to use 64-bit tags together with 128-bit interlocked compare-exchange intrinsic --- src/linker/lnk.c | 373 ++++++++++++++++++++++++------------ src/linker/lnk.h | 44 ++++- src/linker/lnk_debug_info.c | 6 +- src/linker/lnk_obj.c | 4 +- 4 files changed, 299 insertions(+), 128 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 788a42ed..e1383e3e 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2069,7 +2069,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer for EachIndex(sect_idx, obj->header.section_count_no_null) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; - if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; } String8 section_name = coff_name_from_section_header(string_table, section_header); U64 section_number = sect_idx+1; @@ -2161,23 +2161,234 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer return link; } +internal void +lnk_reloc_refs_list_push_node(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_node) +{ + U64 node_tag = UnpackPointerTag(tagged_node); + LNK_RelocRefsNode *node = UnpackPointer(tagged_node); + + node->next = list->head; + list->head = PackPointer(node, node_tag); +} + +internal LNK_RelocRefsNode * +lnk_reloc_refs_list_pop_node(LNK_RelocRefsList *list) +{ + LNK_RelocRefsNode *result = list->head; + + if (list->head) { + LNK_RelocRefsNode *head = UnpackPointer(list->head); + list->head = head->next; + } + + return result; +} + +internal LNK_RelocRefsNode * +lnk_reloc_refs_list_push(Arena *arena, LNK_RelocRefsList *list, LNK_RelocRefs *v) +{ + LNK_RelocRefsNode *node = push_array(arena, LNK_RelocRefsNode, 1); + node->v = v; + lnk_reloc_refs_list_push_node(list, node); + return node; +} + +internal LNK_RelocRefsNode * +lnk_reloc_refs_list_pop_node_atomic(LNK_RelocRefsList *list) +{ + LNK_RelocRefsNode *tagged_node; + for (;;) { + tagged_node = list->head; + if (tagged_node == 0) { break; } + + LNK_RelocRefsNode *head = UnpackPointer(tagged_node); + LNK_RelocRefsNode *tagged_next = head->next; + + void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_next, tagged_node); + if (swap == tagged_node) { break; } + } + return tagged_node; +} + +internal void +lnk_reloc_refs_list_push_node_atomic(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_node) +{ + tagged_node = BumpPointerTag(tagged_node); + for (;;) { + LNK_RelocRefsNode *old_head = list->head; + LNK_RelocRefsNode *node = UnpackPointer(tagged_node); + node->next = old_head; + void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_node, old_head); + if (swap == old_head) { break; } + } +} + +internal void +lnk_reloc_refs_list_concat_in_place(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_first, LNK_RelocRefsNode *tagged_last) +{ + tagged_first = BumpPointerTag(tagged_first); + for (;;) { + LNK_RelocRefsNode *old_head = list->head; + LNK_RelocRefsNode *last = UnpackPointer(tagged_last); + last->next = old_head; + void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_first, old_head); + if (swap == old_head) { break;} + } +} + +internal +THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0,0); + + LNK_OptRefTask *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + + LNK_RelocRefsList free_list = {0}; + for (;;) { + // update active thread count + ins_atomic_u32_inc_eval(&task->active_thread_count); + + for (;;) { + // pop head node + LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(&task->reloc_refs); + if (!node) { break; } + + LNK_RelocRefsNode *reloc_refs_node = UnpackPointer(node); + LNK_RelocRefs *reloc_refs = reloc_refs_node->v; + + LNK_RelocRefsNode *first_node = 0, *last_node = 0; + for EachIndex(reloc_idx, reloc_refs->relocs.count) { + COFF_Reloc *reloc = &reloc_refs->relocs.v[reloc_idx]; + LNK_ObjSymbolRef reloc_defn = (LNK_ObjSymbolRef){ .obj = reloc_refs->obj, .symbol_idx = reloc->isymbol }; + COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_defn.obj, reloc_defn.symbol_idx); + COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed); + + LNK_ObjSymbolRef ref_symbol = reloc_defn; + for (;;) { + COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); + COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); + + LNK_ObjSymbolRef next_ref = {0}; + if (ref_interp == COFF_SymbolValueInterp_Regular) { + LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); + if (symlink) { + ref_symbol = lnk_ref_from_symbol(symlink); + } + break; + } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { + if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = lnk_ref_from_symbol(defn); + } else { + MemoryZeroStruct(&ref_symbol); + break; + } + } else if (ref_interp == COFF_SymbolValueInterp_Weak) { + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = lnk_ref_from_symbol(defn); + } else { + break; + } + + if (MemoryMatchStruct(&next_ref, &ref_symbol)) { + MemoryZeroStruct(&ref_symbol); + break; + } + ref_symbol = next_ref; + } + + // skip unresolved symbol + if (ref_symbol.obj == 0) { continue; } + + COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); + COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); + LNK_Obj *ref_obj = ref_symbol.obj; + + if (ref_interp == COFF_SymbolValueInterp_Regular) { + // make section number list (reloc section + associates) + U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); + section_number_list->data = ref_parsed.section_number; + section_number_list->next = ref_obj->associated_sections[ref_parsed.section_number]; + + // push section headers relocations to the task stack + for EachNode(section_number_n, U32Node, section_number_list) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number_n->data); + + // is section eligible for walking? + if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_LIVE) { continue; } + + // mark section live + section_header->flags |= LNK_SECTION_FLAG_LIVE; + + LNK_RelocRefsNode *tagged_node; + if (free_list.head) { + tagged_node = lnk_reloc_refs_list_pop_node(&free_list); + tagged_node = BumpPointerTag(tagged_node); + } else { + tagged_node = push_array(scratch.arena, LNK_RelocRefsNode, 1); + tagged_node->v = push_array(scratch.arena, LNK_RelocRefs, 1); + } + + LNK_RelocRefsNode *node = UnpackPointer(tagged_node); + node->v->obj = ref_obj; + node->v->relocs = lnk_coff_reloc_info_from_section_number(ref_obj, section_number_n->data); + + if (first_node == 0) { + first_node = tagged_node; + last_node = tagged_node; + } else { + node->next = first_node; + first_node = tagged_node; + } + } + } + } + + lnk_reloc_refs_list_push_node(&free_list, node); + + if (first_node && last_node) { + lnk_reloc_refs_list_concat_in_place(&task->reloc_refs, first_node, last_node); + } + } + + // are all threads done walking? + U32 active_thread_count = ins_atomic_u32_dec_eval(&task->active_thread_count); + if (active_thread_count == 0 && task->reloc_refs.head == 0) { + break; + } + + // comprehensive solution to the waiting problem + for (; ins_atomic_ptr_eval(&task->reloc_refs.head) == 0; ) { + // was signaled to exit? + if (ins_atomic_u64_eval(&task->active_thread_count) == 0) { goto exit; } + } + } + exit:; + + scratch_end(scratch); + ProfEnd(); +} + internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); - struct Task { struct Task *next; LNK_Obj *obj; COFF_RelocArray relocs; U32 section_number; }; - struct Task *task_stack = 0; - const U64 RELOCS_PER_TASK = 1024; + LNK_RelocRefsList reloc_refs = {0}; // // reset live flag on sections // - for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + for EachNode(obj_n, LNK_ObjNode, objs.first) { for EachIndex(sect_idx, obj_n->data.header.section_count_no_null) { COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(&obj_n->data, sect_idx+1); - section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; + section_header->flags &= ~LNK_SECTION_FLAG_LIVE; } } @@ -2192,42 +2403,43 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj } // push tasks for each root symbol - for (LNK_IncludeSymbolNode *root_n = config->include_symbol_list.first; root_n != 0; root_n = root_n->next) { + for EachNode(root_n, LNK_IncludeSymbolNode, config->include_symbol_list.first) { LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name); LNK_ObjSymbolRef root_ref = lnk_ref_from_symbol(root); - struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root_ref.obj; - t->relocs.count = 1; - t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root_ref.symbol_idx; + LNK_RelocRefs *r = push_array(scratch.arena, LNK_RelocRefs, 1); + r->obj = root_ref.obj; + r->relocs.count = 1; + r->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); + r->relocs.v[0].isymbol = root_ref.symbol_idx; - SLLStackPush(task_stack, t); + lnk_reloc_refs_list_push(scratch.arena, &reloc_refs, r); } // push task for every non-COMDAT section - for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + for EachNode(obj_n, LNK_ObjNode, objs.first) { LNK_Obj *obj = &obj_n->data; for EachIndex(sect_idx, obj->header.section_count_no_null) { U32 section_number = sect_idx+1; COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); // is section eligible for walking? - if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } if (section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } + if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; } // divide relocs and push task for each reloc block - COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number); - U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); - struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); + COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number); + U64 new_task_count = CeilIntegerDiv(relocs.count, LNK_RELOCS_PER_TASK); + LNK_RelocRefs *new_tasks = push_array(scratch.arena, LNK_RelocRefs, new_task_count); for EachIndex(new_task_idx, new_task_count) { - struct Task *t = new_tasks + new_task_idx; - t->obj = obj; - t->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); - t->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); - t->section_number = section_number; - SLLStackPush(task_stack, t); + LNK_RelocRefs *r = new_tasks + new_task_idx; + r->obj = obj; + r->relocs.count = Min(LNK_RELOCS_PER_TASK, relocs.count - (new_task_idx * LNK_RELOCS_PER_TASK)); + r->relocs.v = relocs.v + (new_task_idx * LNK_RELOCS_PER_TASK); + + lnk_reloc_refs_list_push(scratch.arena, &reloc_refs, r); } } } @@ -2236,119 +2448,38 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj // // walk relocations and mark referenced sections with live flag // - for (; task_stack; ) { - struct Task *t = task_stack; SLLStackPop(task_stack); - for EachIndex(reloc_idx, t->relocs.count) { - COFF_Reloc *reloc = &t->relocs.v[reloc_idx]; - LNK_ObjSymbolRef reloc_defn = (LNK_ObjSymbolRef){ .obj = t->obj, .symbol_idx = reloc->isymbol }; - COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_defn.obj, reloc_defn.symbol_idx); - COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed); - - LNK_ObjSymbolRef ref_symbol = reloc_defn; - for (;;) { - COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); - COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); - - LNK_ObjSymbolRef next_ref = {0}; - if (ref_interp == COFF_SymbolValueInterp_Regular) { - LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); - if (symlink) { - ref_symbol = lnk_ref_from_symbol(symlink); - } - break; - } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { - if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = lnk_ref_from_symbol(defn); - } else { - MemoryZeroStruct(&ref_symbol); - break; - } - } else if (ref_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); - next_ref = lnk_ref_from_symbol(defn); - } else { - break; - } - - if (MemoryMatchStruct(&next_ref, &ref_symbol)) { - MemoryZeroStruct(&ref_symbol); - break; - } - ref_symbol = next_ref; - } - - // skip unresolved symbol - if (ref_symbol.obj == 0) { continue; } - - COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx); - COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed); - LNK_Obj *ref_obj = ref_symbol.obj; - - if (ref_interp == COFF_SymbolValueInterp_Regular) { - // make section number list (reloc section + associates) - U32Node *section_number_list = push_array(scratch.arena, U32Node, 1); - section_number_list->data = ref_parsed.section_number; - section_number_list->next = ref_obj->associated_sections[ref_parsed.section_number]; - - // push section headers relocations to the task stack - for (U32Node *section_number_n = section_number_list; section_number_n != 0; section_number_n = section_number_n->next) { - U32 section_number = section_number_n->data; - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number); - - // is section eligible for walking? - if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - if (section_header->flags & LNK_SECTION_FLAG_IS_LIVE) { continue; } - if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } - - // mark section - section_header->flags |= LNK_SECTION_FLAG_IS_LIVE; - - // divide relocs and push task for each reloc block - COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(ref_obj, section_number); - U64 new_task_count = CeilIntegerDiv(relocs.count, RELOCS_PER_TASK); - struct Task *new_tasks = push_array(scratch.arena, struct Task, new_task_count); - for EachIndex(new_task_idx, new_task_count) { - struct Task *n = new_tasks + new_task_idx; - n->obj = ref_obj; - n->relocs.count = Min(RELOCS_PER_TASK, relocs.count - (new_task_idx * RELOCS_PER_TASK)); - n->relocs.v = relocs.v + (new_task_idx * RELOCS_PER_TASK); - n->section_number = section_number; - SLLStackPush(task_stack, n); - } - } - } - } - } + LNK_OptRefTask task = {0}; + task.symtab = symtab; + task.reloc_refs = reloc_refs; + tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_walk_relocs_and_mark_ref_sections_task, &task, "Mark Live Sections"); ProfBegin("Remove Unreachable Sections"); - for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + for EachNode(obj_n, LNK_ObjNode, objs.first) { LNK_Obj *obj = &obj_n->data; for EachIndex(sect_idx, obj->header.section_count_no_null) { U32 section_number = sect_idx+1; COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); - if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } + if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; } // remove unreferenced sections - if (~section_header->flags & LNK_SECTION_FLAG_IS_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { + if (~section_header->flags & LNK_SECTION_FLAG_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) { section_header->flags |= COFF_SectionFlag_LnkRemove; } // remove associated sections if (section_header->flags & COFF_SectionFlag_LnkRemove) { - for (U32Node *section_number_n = obj->associated_sections[section_number]; section_number_n != 0; section_number_n = section_number_n->next) { - U32 section_number = section_number_n->data; - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); + for EachNode(section_number_n, U32Node, obj->associated_sections[section_number]) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number_n->data); section_header->flags |= COFF_SectionFlag_LnkRemove; } } - + // TODO: Reset reserved flag so it does not get propagated to the image sections. // We need to mask out reserved flags when gathering section definitions to actually // prevent propagation. - section_header->flags &= ~LNK_SECTION_FLAG_IS_LIVE; + section_header->flags &= ~LNK_SECTION_FLAG_LIVE; } } ProfEnd(); @@ -2537,7 +2668,7 @@ THREAD_POOL_TASK_FUNC(lnk_flag_debug_symbols_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); - if (section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1; } } @@ -2860,7 +2991,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) if (section_header->flags & COFF_SectionFlag_CntUninitializedData) { continue; } // get section bytes (special case debug info because it is not copied to the image) - String8 data = section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO ? obj->data : task->image_data; + String8 data = section_header->flags & LNK_SECTION_FLAG_DEBUG ? obj->data : task->image_data; Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize); String8 section_data = str8_substr(data, section_frange); @@ -2891,7 +3022,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); if (interp == COFF_SymbolValueInterp_Regular) { if (symbol.section_number == lnk_obj_get_removed_section_number(obj)) { - if (~section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + if (~section_header->flags & LNK_SECTION_FLAG_DEBUG) { String8 sect_name = coff_name_from_section_header(string_table, §ion_table[sect_idx]); lnk_error_obj(LNK_Error_RelocationAgainstRemovedSection, obj, "relocating against symbol that is in a removed section (symbol: %S, reloc-section: %S 0x%llx, reloc-index: 0x%llx)", symbol.name, sect_name, sect_idx+1, reloc_idx); } @@ -3476,7 +3607,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_file_offsets_and_sizes_in_obj_section_headers_ta for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = §ion_table[sect_idx]; B32 patch_section_header = (~sect_header->flags & COFF_SectionFlag_LnkRemove) && - (~sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO); + (~sect_header->flags & LNK_SECTION_FLAG_DEBUG); if (patch_section_header) { LNK_SectionContrib *sc = task->sect_map[obj_idx][sect_idx]; LNK_Section *sect = task->image_sects.v[sc->u.sect_idx]; @@ -4750,7 +4881,7 @@ lnk_build_rad_map(Arena *arena, String8 image_data, LNK_Config *config, U64 objs COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(obj->data, obj->header.section_table_range.min, 0); for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *section_header = §ion_table[sect_idx]; - if (~section_header->flags & COFF_SectionFlag_LnkRemove && section_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + if (~section_header->flags & COFF_SectionFlag_LnkRemove && section_header->flags & LNK_SECTION_FLAG_DEBUG) { LNK_Lib *lib = lnk_obj_get_lib(obj); if (lib) { String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(lib->path)); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 31443404..cf7bfe0a 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -73,8 +73,8 @@ typedef struct LNK_Inputer #define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***" #define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***" -#define LNK_SECTION_FLAG_IS_LIVE (1 << 0) -#define LNK_SECTION_FLAG_DEBUG_INFO (1 << 1) +#define LNK_SECTION_FLAG_LIVE (1 << 0) +#define LNK_SECTION_FLAG_DEBUG (1 << 1) typedef struct LNK_Link { @@ -118,6 +118,39 @@ typedef struct LNK_CommonBlockContrib } u; } LNK_CommonBlockContrib; +// --- Ref --------------------------------------------------------------------- + +#define PointerBitSize 64u +#define PointerFreeBitsSize 16u + +#define PointerTagBitSize PointerFreeBitsSize +#define PointerTagMask ((1ull << (PointerTagBitSize)) - 1u) +#define PointerTagShift (PointerBitSize - PointerTagBitSize) + +#define PackPointer(ptr, tag) (void *)(IntFromPtr(ptr) | (((tag) & PointerTagMask) << PointerTagShift)) +#define UnpackPointerTag(ptr) ((IntFromPtr(ptr) >> PointerTagShift) & PointerTagMask) +#define UnpackPointer(ptr) (void *)(IntFromPtr(ptr) & ~(PointerTagMask << PointerTagShift)) +#define BumpPointerTag(ptr) PackPointer(UnpackPointer(ptr), UnpackPointerTag(ptr) + 1) + +#define LNK_RELOCS_PER_TASK 0x1000 + +typedef struct LNK_RelocRefs +{ + LNK_Obj *obj; + COFF_RelocArray relocs; +} LNK_RelocRefs; + +typedef struct LNK_RelocRefsNode +{ + LNK_RelocRefs *v; + struct LNK_RelocRefsNode *next; +} LNK_RelocRefsNode; + +typedef struct LNK_RelocRefsList +{ + LNK_RelocRefsNode *head; +} LNK_RelocRefsList; + // --- Base Reloc -------------------------------------------------------------- typedef struct LNK_BaseRelocPage @@ -156,6 +189,13 @@ typedef struct LNK_LibMemberRefList *member_ref_lists; } LNK_SearchLibTask; +typedef struct +{ + LNK_SymbolTable *symtab; + U32 active_thread_count; + LNK_RelocRefsList reloc_refs; +} LNK_OptRefTask; + typedef struct { LNK_SymbolTable *symtab; diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 1e99fa7f..f0fdf62d 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2934,9 +2934,9 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *obj_sect_header = &obj_section_table[sect_idx]; - if (obj_sect_header->flags & COFF_SectionFlag_LnkInfo) { continue; } - if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) { continue; } - if (obj_sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { continue; } + if (obj_sect_header->flags & COFF_SectionFlag_LnkInfo) { continue; } + if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + if (obj_sect_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; } U64 sect_number; String8 sect_data; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index d16155be..aa3362d7 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -268,7 +268,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; String8 sect_name = str8_cstring_capped(sect_header->name, sect_header->name + sizeof(sect_header->name)); if (str8_starts_with(sect_name, str8_lit(".debug$"))) { - sect_header->flags |= LNK_SECTION_FLAG_DEBUG_INFO; + sect_header->flags |= LNK_SECTION_FLAG_DEBUG; } } } @@ -286,7 +286,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) CV_Symbol comp_symbol = {0}; for EachIndex(sect_idx, header.section_count_no_null) { COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; - if (sect_header->flags & LNK_SECTION_FLAG_DEBUG_INFO) { + if (sect_header->flags & LNK_SECTION_FLAG_DEBUG) { String8 name = str8_cstring_capped(sect_header->name, sect_header->name+sizeof(sect_header->name)); if (str8_match(name, str8_lit(".debug$S"), 0)) { Temp temp = temp_begin(scratch.arena); From fe63983d4a9ce46f230a2f5e0061957326ad67d1 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:41:06 -0700 Subject: [PATCH 197/302] u32 decrement intrinsic --- src/base/base_core.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index 34a0cb64..c705f532 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -209,15 +209,16 @@ # define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c) # define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c)) # define ins_atomic_u32_eval(x) *((volatile U32 *)(x)) -# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x) +# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)(x)) +# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((volatile LONG *)(x)) # define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c)) # define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c)) -# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c) +# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), (c)) # else # error Atomic intrinsics not defined for this compiler / architecture combination. # endif #elif COMPILER_CLANG || COMPILER_GCC -# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST) +# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) # define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) # define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1) # define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1) @@ -226,8 +227,9 @@ # define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) # define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) # define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1) +# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1) # define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c)) -# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST) +# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) # define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) #else # error Atomic intrinsics not defined for this compiler / architecture. From b646e1cd43efdb07a6f58c84d78c9ba833745644 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:47:33 -0700 Subject: [PATCH 198/302] fix compiler errors --- src/coff/coff_obj_writer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index 419fc398..ccfc4f47 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -73,8 +73,8 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) // long name if (s->name.size > sizeof(name.short_name)) { U64 string_table_offset = string_table.total_size; - str8_list_push(scratch.arena, &string.table, s->name); - str8_list_push(scratch.arena, &string.table, str8_lit("\0")); + str8_list_push(scratch.arena, &string_table, s->name); + str8_list_push(scratch.arena, &string_table, str8_lit("\0")); name.long_name.zeroes = 0; name.long_name.string_table_offset = safe_cast_u32(string_table_offset); @@ -169,7 +169,7 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) String8 sect_name = s->name; if (sect_name.size > sizeof(d->name)) { U64 sect_name_off = string_table.total_size; - str8_list_push_cstr(scratch.arena, &string_table, sect_name); + str8_list_push(scratch.arena, &string_table, push_cstr(scratch.arena, sect_name)); sect_name = push_str8f(scratch.arena, "/%u", sect_name_off); AssertAlways(sect_name.size <= sizeof(d->name)); From 28aec349fdeb8e29fbb73a53b10bbc713c14cdf3 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:54:19 -0700 Subject: [PATCH 199/302] update readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 203f9e5d..84191fd3 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ of implemented switches from `/help`. Our current designed-for use case for the linker is to help with the compile-debug cycle of huge projects. We don't yet have support for -dead-code-elimination or link-time-optimizations, but these features are on the -road map. +link-time-optimizations, but this feature is on the road map. By default, the linker spawns as many threads as there are cores, so if you plan to run multiple linkers in parallel, you can limit the number of thread workers From c653410af52e0a5ee46f4ab383a344d7a393a8f6 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:57:37 -0700 Subject: [PATCH 200/302] stub /errorreportlevel --- src/linker/lnk_config.c | 6 +++++- src/linker/lnk_config.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 8a1bb9a6..8e8a5ce8 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -35,7 +35,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = { LNK_CmdSwitch_DynamicBase, 0, "DYNAMICBASE", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, 0, "EMITVOLATILEMETADATA", "", "" }, { LNK_CmdSwitch_Entry, 1, "ENTRY", ":FUNCTION", "" }, - { LNK_CmdSwitch_Null, 0, "ERRORREPORT", "", "Deprecated starting Windows Vista." }, + { LNK_CmdSwitch_ErrorReport, 0, "ERRORREPORT", "", "Deprecated starting Windows Vista." }, { LNK_CmdSwitch_Export, 1, "EXPORT", ":SYMBOL", "" }, { LNK_CmdSwitch_NotImplemented, 0, "EXPORTADMIN", "", "" }, { LNK_CmdSwitch_FastFail, 0, "FASTFAIL", "", "Not used." }, @@ -1293,6 +1293,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List config->entry_point_name = new_entry_point_name; } break; + case LNK_CmdSwitch_ErrorReport: { + // not supported -- ignore + } break; + case LNK_CmdSwitch_Export: { PE_ExportParse export_parse = {0}; if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) { diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 5c81ab44..0b82edc3 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -45,6 +45,7 @@ typedef enum LNK_CmdSwitch_DynamicBase, LNK_CmdSwitch_Dump, LNK_CmdSwitch_Entry, + LNK_CmdSwitch_ErrorReport, LNK_CmdSwitch_Export, LNK_CmdSwitch_FastFail, LNK_CmdSwitch_FileAlign, @@ -101,7 +102,6 @@ typedef enum LNK_CmdSwitch_DisallowLib, LNK_CmdSwitch_EditAndContinue, LNK_CmdSwitch_EmitVolatileMetadata, - LNK_CmdSwitch_ErrorReport, LNK_CmdSwitch_ExportAdmin, LNK_CmdSwitch_FastGenProfile, LNK_CmdSwitch_FailIfMismatch, From 0b154cef46dc9bccfd2d9ebd6d71e1b39b9dc661 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 21:59:56 -0700 Subject: [PATCH 201/302] stub /brepro --- src/linker/lnk_config.c | 5 +++++ src/linker/lnk_config.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 8e8a5ce8..688b3915 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -15,6 +15,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = { LNK_CmdSwitch_NotImplemented, 0, "ASSEMBLYMODULE", "", "" }, // .NET { LNK_CmdSwitch_NotImplemented, 0, "ASSEMBLYRESOURCE", "", "" }, // .NET { LNK_CmdSwitch_Base, 0, "BASE", "{ADDRESS[,SIZE]|@FILENAME,KEY}", "" }, + { LNK_CmdSwitch_Brepro, 0, "BREPRO", "", "Not supported" }, { LNK_CmdSwitch_NotImplemented, 0, "CLRIMAGETYPE", "", "" }, // .NET { LNK_CmdSwitch_NotImplemented, 0, "CLRLOADEROPTIMIZATION","", "" }, // .NET { LNK_CmdSwitch_NotImplemented, 0, "CLRSUPPORTLASTERROR", "", "" }, // .NET @@ -1215,6 +1216,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List } } break; + case LNK_CmdSwitch_Brepro: { + // not supported -- ignore + } break; + case LNK_CmdSwitch_Debug: { if (value_strings.node_count == 0) { config->debug_mode = LNK_DebugMode_Full; diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 0b82edc3..86cc075e 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -37,6 +37,7 @@ typedef enum LNK_CmdSwitch_AlternateName, LNK_CmdSwitch_AppContainer, LNK_CmdSwitch_Base, + LNK_CmdSwitch_Brepro, LNK_CmdSwitch_Debug, LNK_CmdSwitch_DefaultLib, LNK_CmdSwitch_Delay, From e33a95bfe25f91331be7fab4499635adc6f82e7d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 16 Sep 2025 22:06:39 -0700 Subject: [PATCH 202/302] do not embed time stamp with /brepro --- src/linker/lnk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e1383e3e..9c91ba89 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -154,7 +154,9 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_LargeAddressAware, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbAltPath, "%%_RAD_PDB_PATH%%"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_PdbPageSize, "%u", KB(4)); - lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); + if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Brepro)) { + lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_TimeStamp, "%u", os_get_process_start_time_unix()); + } lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Age, "%u", 1); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, ""); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DoMerge, ""); From 0c1010b72dfb138542e0de52cabf605a1afe5494 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 17 Sep 2025 16:38:14 -0700 Subject: [PATCH 203/302] move hash store eviction to base layer async wavefront; start dasm transition --- src/base/base_entry_point.c | 3 + src/dasm_cache/dasm_cache.c | 263 ++++++++++++++++++++++++++++++++++++ src/dasm_cache/dasm_cache.h | 40 ++++-- src/hash_store/hash_store.c | 63 ++++----- src/hash_store/hash_store.h | 7 +- 5 files changed, 327 insertions(+), 49 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 3d84e7e9..bef24678 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -190,6 +190,9 @@ async_thread_entry_point(void *params) for(;!ins_atomic_u32_eval(&global_async_exit);) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); +#if defined(HASH_STORE_H) + hs_tick(); +#endif #if defined(FILE_STREAM_H) fs_tick(); #endif diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 6cd83d9a..319e5127 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -443,6 +443,269 @@ dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U1 return result; } +//////////////////////////////// +//~ rjf: Ticks + +#if 0 +internal void +dasm_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + DI_Scope *di_scope = di_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + + //- rjf: gather all requests + local_persist DASM_Request *reqs = 0; + local_persist U64 reqs_count = 0; + if(lane_idx() == 0) MutexScope(dasm_shared->req_mutex) + { + reqs_count = dasm_shared->req_count; + reqs = push_array(scratch.arena, DASM_Request, reqs_count); + U64 idx = 0; + for EachNode(r, DASM_RequestNode, dasm_shared->first_req) + { + MemoryCopyStruct(&reqs[idx], &r->v); + reqs[idx].params.dbgi_key = di_key_copy(scratch.arena, &reqs[idx].params.dbgi_key); + idx += 1; + } + arena_clear(dasm_shared->req_arena); + dasm_shared->first_req = dasm_shared->last_req = 0; + dasm_shared->req_count = 0; + } + lane_sync(); + + //- rjf: do requests + Rng1U64 range = lane_range(reqs_count); + for EachInRange(req_idx, range) + { + //- rjf: unpack + DASM_Request *r = &reqs[req_idx]; + HS_Root root = r->root; + U128 hash = r->hash; + DASM_Params params = r->params; + String8 data = hs_data_from_hash(hs_scope, hash); + U64 change_gen = fs_change_gen(); + U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; + U64 stripe_idx = slot_idx%dasm_shared->stripes_count; + DASM_Slot *slot = &dasm_shared->slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; + + //- rjf: get dbg info + RDI_Parsed *rdi = &rdi_parsed_nil; + if(params.dbgi_key.path.size != 0) + { + rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); + } + + //- rjf: data * arch * addr * dbg -> decode artifacts + DASM_LineChunkList line_list = {0}; + String8List inst_strings = {0}; + switch(params.arch) + { + default:{}break; + + //- rjf: x86/x64 decoding + case Arch_x64: + case Arch_x86: + { + // rjf: disassemble + RDI_SourceFile *last_file = &rdi_nil_element_union.source_file; + RDI_Line *last_line = 0; + for(U64 off = 0; off < data.size;) + { + // rjf: disassemble one instruction + DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax); + if(inst.size == 0) + { + break; + } + + // rjf: push strings derived from voff -> line info + if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines) && + rdi != &rdi_parsed_nil) + { + U64 voff = (params.vaddr+off) - params.base_vaddr; + U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff); + RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx); + RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx); + RDI_ParsedLineTable unit_line_info = {0}; + rdi_parsed_from_line_table(rdi, line_table, &unit_line_info); + U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff); + if(line_info_idx < unit_line_info.count) + { + RDI_Line *line = &unit_line_info.lines[line_info_idx]; + RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx); + String8 file_normalized_full_path = {0}; + file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); + if(file != last_file) + { + if(params.style_flags & DASM_StyleFlag_SourceFilesNames && + file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0) + { + String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0) + { + String8 inst_string = str8_lit(">"); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + last_file = file; + } + if(line && line != last_line && file->normal_full_path_string_idx != 0 && + params.style_flags & DASM_StyleFlag_SourceLines && + file_normalized_full_path.size != 0) + { + FileProperties props = os_properties_from_file_path(file_normalized_full_path); + if(props.modified != 0) + { + // TODO(rjf): need redirection path - this may map to a different path on the local machine, + // need frontend to communicate path remapping info to this layer + HS_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); + U64 endt_us = max_U64; + U128 hash = {0}; + TXT_TextInfo text_info = {0}; + for(;os_now_microseconds() <= endt_us;) + { + text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + if(!u128_match(hash, u128_zero())) + { + break; + } + } + if(0 < line->line_num && line->line_num < text_info.lines_count) + { + String8 data = hs_data_from_hash(hs_scope, hash); + String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); + if(line_text.size != 0) + { + String8 inst_string = push_str8f(scratch.arena, "> %S", line_text); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + } + } + last_line = line; + } + } + } + + // rjf: push line + String8 addr_part = {0}; + if(params.style_flags & DASM_StyleFlag_Addresses) + { + addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &rdi_parsed_nil ? " " : "", params.vaddr+off); + } + String8 code_bytes_part = {0}; + if(params.style_flags & DASM_StyleFlag_CodeBytes) + { + String8List code_bytes_strings = {0}; + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{")); + for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1) + { + if(byte_idx < inst.size) + { + str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : ""); + } + else if(byte_idx < 8) + { + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + } + } + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); + } + String8 symbol_part = {0}; + if(inst.jump_dest_vaddr != 0 && rdi != &rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) + { + RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr); + if(scope_idx != 0) + { + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + RDI_U32 procedure_idx = scope->proc_idx; + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx); + String8 procedure_name = {0}; + procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); + if(procedure_name.size != 0) + { + symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name); + } + } + } + String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part); + DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line); + str8_list_push(scratch.arena, &inst_strings, inst_string); + + // rjf: increment + off += inst.size; + } + }break; + } + + //- rjf: artifacts -> value bundle + Arena *info_arena = 0; + DASM_Info info = {0}; + { + //- rjf: produce joined text + Arena *text_arena = arena_alloc(); + StringJoin text_join = {0}; + text_join.sep = str8_lit("\n"); + String8 text = str8_list_join(text_arena, &inst_strings, &text_join); + + //- rjf: produce unique key for this disassembly's text + HS_Key text_key = hs_key_make(root, hs_id_make(0, 0)); + + //- rjf: submit text data to hash store + U128 text_hash = hs_submit_data(text_key, &text_arena, text); + + //- rjf: produce value bundle + info_arena = arena_alloc(); + info.text_key = text_key; + info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list); + } + + //- rjf: commit results to cache + RWMutexScope(stripe->rw_mutex, 1) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms)) + { + n->info_arena = info_arena; + MemoryCopyStruct(&n->info, &info); + if(rdi != &rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) + { + n->change_gen = change_gen; + } + else + { + n->change_gen = 0; + } + break; + } + } + } + } + + txt_scope_close(txt_scope); + di_scope_close(di_scope); + hs_scope_close(hs_scope); + scratch_end(scratch); +} +#endif + //////////////////////////////// //~ rjf: Parse Threads diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 898089ed..4cde946b 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -100,6 +100,24 @@ struct DASM_Params DI_Key dbgi_key; }; +//////////////////////////////// +//~ rjf: Disassembly Request Bundle + +typedef struct DASM_Request DASM_Request; +struct DASM_Request +{ + HS_Root root; + U128 hash; + DASM_Params params; +}; + +typedef struct DASM_RequestNode DASM_RequestNode; +struct DASM_RequestNode +{ + DASM_RequestNode *next; + DASM_Request v; +}; + //////////////////////////////// //~ rjf: Disassembly Text Line Types @@ -143,16 +161,6 @@ struct DASM_LineArray U64 count; }; -//////////////////////////////// -//~ rjf: Disassembly Result Bundle - -typedef struct DASM_Result DASM_Result; -struct DASM_Result -{ - String8 text; - DASM_LineArray lines; -}; - //////////////////////////////// //~ rjf: Value Bundle Type @@ -254,6 +262,13 @@ struct DASM_Shared DASM_Slot *slots; DASM_Stripe *stripes; + // rjf: requests + Mutex req_mutex; + Arena *req_arena; + DASM_RequestNode *first_req; + DASM_RequestNode *last_req; + U64 req_count; + // rjf: user -> parse thread U64 u2p_ring_size; U8 *u2p_ring_base; @@ -313,6 +328,11 @@ internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_No internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out); +//////////////////////////////// +//~ rjf: Ticks + +internal void dasm_tick(void); + //////////////////////////////// //~ rjf: Parse Threads diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 09c65180..8adccdfd 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -103,7 +103,6 @@ hs_init(void) stripe->rw_mutex = rw_mutex_alloc(); stripe->cv = cond_var_alloc(); } - hs_shared->evictor_thread = thread_launch(hs_evictor_thread__entry_point, 0); } //////////////////////////////// @@ -543,54 +542,50 @@ hs_data_from_hash(HS_Scope *scope, U128 hash) } //////////////////////////////// -//~ rjf: Evictor Thread +//~ rjf: Tick internal void -hs_evictor_thread__entry_point(void *p) +hs_tick(void) { - ThreadNameF("hs_evictor_thread"); - for(;;) + Rng1U64 range = lane_range(hs_shared->slots_count); + for EachInRange(slot_idx, range) { - for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1) + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + MutexScopeR(stripe->rw_mutex) { - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) + for(HS_Node *n = slot->first; n != 0; n = n->next) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) { - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) - { - slot_has_work = 1; - break; - } + slot_has_work = 1; + break; } } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) + } + if(slot_has_work) MutexScopeW(stripe->rw_mutex) + { + for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) { - for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) + next = n->next; + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) { - next = n->next; - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + DLLRemove(slot->first, slot->last, n); + SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); + if(n->arena != 0) { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); - if(n->arena != 0) - { - arena_release(n->arena); - } + arena_release(n->arena); } } } } - os_sleep_milliseconds(1000); } } diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index 97971ee4..488b8730 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -206,9 +206,6 @@ struct HS_Shared HS_Stripe *root_stripes; HS_RootNode **root_stripes_free_nodes; U64 root_id_gen; - - // rjf: evictor thread - Thread evictor_thread; }; //////////////////////////////// @@ -263,8 +260,8 @@ internal U128 hs_hash_from_key(HS_Key key, U64 rewind_count); internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash); //////////////////////////////// -//~ rjf: Evictor Thread +//~ rjf: Tick -internal void hs_evictor_thread__entry_point(void *p); +internal void hs_tick(void); #endif // HASH_STORE_H From 7c08d6846b8901a9deb7ffb8e1a9f3ed443784ac Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 11:18:36 -0700 Subject: [PATCH 204/302] dasm cache in new async wavefront --- src/base/base_entry_point.c | 3 + src/dasm_cache/dasm_cache.c | 572 ++++++++-------------------------- src/dasm_cache/dasm_cache.h | 23 -- src/file_stream/file_stream.c | 3 +- src/hash_store/hash_store.c | 2 + 5 files changed, 140 insertions(+), 463 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index bef24678..d2d1e966 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -195,6 +195,9 @@ async_thread_entry_point(void *params) #endif #if defined(FILE_STREAM_H) fs_tick(); +#endif +#if defined(DASM_CACHE_H) + dasm_tick(); #endif cond_var_broadcast(async_tick_stop_cond_var); } diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 319e5127..c6b10a54 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -273,11 +273,8 @@ dasm_init(void) dasm_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); dasm_shared->stripes[idx].cv = cond_var_alloc(); } - dasm_shared->u2p_ring_size = KB(64); - dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size); - dasm_shared->u2p_ring_cv = cond_var_alloc(); - dasm_shared->u2p_ring_mutex = mutex_alloc(); - dasm_shared->evictor_detector_thread = thread_launch(dasm_evictor_detector_thread__entry_point, 0); + dasm_shared->req_mutex = mutex_alloc(); + dasm_shared->req_arena = arena_alloc(); } //////////////////////////////// @@ -351,42 +348,27 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) DASM_Slot *slot = &dasm_shared->slots[slot_idx]; DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - //- rjf: try to get existing results - B32 found = 0; - MutexScopeR(stripe->rw_mutex) + //- rjf: try to get existing results; create node if needed + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params)) - { - MemoryCopyStruct(&info, &n->info); - found = 1; - dasm_scope_touch_node__stripe_r_guarded(scope, n); - break; - } - } - } - - //- rjf: miss -> kick off work to fill cache - if(!found) - { - B32 node_is_new = 0; - U64 *node_working_count = 0; - HS_Root root = {0}; - MutexScopeW(stripe->rw_mutex) + B32 found = 0; + RWMutexScope(stripe->rw_mutex, write_mode) { + // rjf: find existing node DASM_Node *node = 0; for(DASM_Node *n = slot->first; n != 0; n = n->next) { if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params)) { node = n; + found = 1; break; } } - if(node == 0) + + // rjf: [write mode] allocate node if needed, and kick off request + if(write_mode && node == 0) { - // rjf: allocate node node = stripe->free_node; if(node) { @@ -397,26 +379,36 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) node = push_array_no_zero(stripe->arena, DASM_Node, 1); } MemoryZeroStruct(node); - - // rjf: fill node DLLPushBack(slot->first, slot->last, node); node->hash = hash; MemoryCopyStruct(&node->params, params); node->root = hs_root_alloc(); // TODO(rjf): need to make this releasable - currently all exe_paths just leak node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); - - // rjf: gather work kickoff params - node_is_new = 1; ins_atomic_u64_inc_eval(&node->working_count); - node_working_count = &node->working_count; - root = node->root; + MutexScope(dasm_shared->req_mutex) + { + DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); + SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); + dasm_shared->req_count += 1; + req_n->v.root = node->root; + req_n->v.hash = hash; + MemoryCopyStruct(&req_n->v.params, params); + req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); + } + cond_var_broadcast(async_tick_start_cond_var); + } + + // rjf: nonzero node, request if needed - touch & return results + if(node != 0) + { + dasm_scope_touch_node__stripe_r_guarded(scope, node); + MemoryCopyStruct(&info, &node->info); } } - if(node_is_new) + if(found) { - dasm_u2p_enqueue_req(root, hash, params, max_U64); - async_push_work(dasm_parse_work, .working_counter = node_working_count); + break; } } } @@ -446,14 +438,88 @@ dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U1 //////////////////////////////// //~ rjf: Ticks -#if 0 internal void dasm_tick(void) { + ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); - DI_Scope *di_scope = di_scope_open(); - TXT_Scope *txt_scope = txt_scope_open(); + + //- rjf: do detection pass + { + U64 change_gen = fs_change_gen(); + U64 check_time_us = os_now_microseconds(); + U64 check_time_user_clocks = update_tick_idx(); + U64 evict_threshold_us = 10*1000000; + U64 retry_threshold_us = 1*1000000; + U64 evict_threshold_user_clocks = 10; + U64 retry_threshold_user_clocks = 10; + Rng1U64 range = lane_range(dasm_shared->slots_count); + for EachInRange(slot_idx, range) + { + U64 stripe_idx = slot_idx%dasm_shared->stripes_count; + DASM_Slot *slot = &dasm_shared->slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + MutexScopeR(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + ins_atomic_u64_eval(&n->working_count) == 0) + { + slot_has_work = 1; + break; + } + if(n->change_gen != 0 && n->change_gen != change_gen && + n->last_time_requested_us+retry_threshold_us <= check_time_us && + n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) MutexScopeW(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(n->scope_ref_count == 0 && + n->last_time_touched_us+evict_threshold_us <= check_time_us && + n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + ins_atomic_u64_eval(&n->working_count) == 0) + { + DLLRemove(slot->first, slot->last, n); + if(n->info_arena != 0) + { + arena_release(n->info_arena); + } + SLLStackPush(stripe->free_node, n); + } + if(n->change_gen != 0 && n->change_gen != change_gen && + n->last_time_requested_us+retry_threshold_us <= check_time_us && + n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) + { + MutexScope(dasm_shared->req_mutex) + { + DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); + SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); + dasm_shared->req_count += 1; + req_n->v.root = n->root; + req_n->v.hash = n->hash; + req_n->v.params = n->params; + req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); + } + n->last_time_requested_us = os_now_microseconds(); + n->last_user_clock_idx_requested = check_time_user_clocks; + ins_atomic_u64_inc_eval(&n->working_count); + } + } + } + } + } //- rjf: gather all requests local_persist DASM_Request *reqs = 0; @@ -479,7 +545,12 @@ dasm_tick(void) Rng1U64 range = lane_range(reqs_count); for EachInRange(req_idx, range) { + HS_Scope *hs_scope = hs_scope_open(); + DI_Scope *di_scope = di_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + //- rjf: unpack + B32 stale = 0; DASM_Request *r = &reqs[req_idx]; HS_Root root = r->root; U128 hash = r->hash; @@ -497,6 +568,7 @@ dasm_tick(void) { rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); } + stale = (stale || (rdi == &rdi_parsed_nil)); //- rjf: data * arch * addr * dbg -> decode artifacts DASM_LineChunkList line_list = {0}; @@ -572,15 +644,8 @@ dasm_tick(void) TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; - TXT_TextInfo text_info = {0}; - for(;os_now_microseconds() <= endt_us;) - { - text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); - if(!u128_match(hash, u128_zero())) - { - break; - } - } + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + stale = (stale || u128_match(hash, u128_zero())); if(0 < line->line_num && line->line_num < text_info.lines_count) { String8 data = hs_data_from_hash(hs_scope, hash); @@ -657,6 +722,7 @@ dasm_tick(void) //- rjf: artifacts -> value bundle Arena *info_arena = 0; DASM_Info info = {0}; + if(!stale) { //- rjf: produce joined text Arena *text_arena = arena_alloc(); @@ -677,7 +743,7 @@ dasm_tick(void) } //- rjf: commit results to cache - RWMutexScope(stripe->rw_mutex, 1) + if(!stale) RWMutexScope(stripe->rw_mutex, 1) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -693,401 +759,29 @@ dasm_tick(void) { n->change_gen = 0; } + ins_atomic_u64_dec_eval(&n->working_count); break; } } } - } - - txt_scope_close(txt_scope); - di_scope_close(di_scope); - hs_scope_close(hs_scope); - scratch_end(scratch); -} -#endif - -//////////////////////////////// -//~ rjf: Parse Threads - -internal B32 -dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us) -{ - B32 good = 0; - MutexScope(dasm_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; - U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(root)+sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64)) - { - good = 1; - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &root); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->vaddr); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->arch); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->style_flags); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->syntax); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->base_vaddr); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size); - dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(dasm_shared->u2p_ring_cv); - } - return good; -} - -internal void -dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out) -{ - MutexScope(dasm_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64)) - { - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, root_out); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, hash_out); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->vaddr); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->arch); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->style_flags); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->syntax); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->base_vaddr); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.path.size); - params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size); - dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp); - break; - } - cond_var_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64); - } - cond_var_broadcast(dasm_shared->u2p_ring_cv); -} - -ASYNC_WORK_DEF(dasm_parse_work) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); - DI_Scope *di_scope = di_scope_open(); - TXT_Scope *txt_scope = txt_scope_open(); - - //- rjf: get next request - HS_Root root = {0}; - U128 hash = {0}; - DASM_Params params = {0}; - dasm_u2p_dequeue_req(scratch.arena, &root, &hash, ¶ms); - U64 change_gen = fs_change_gen(); - - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - - //- rjf: get dbg info - RDI_Parsed *rdi = &rdi_parsed_nil; - if(params.dbgi_key.path.size != 0) - { - rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, max_U64); - } - - //- rjf: hash -> data - String8 data = hs_data_from_hash(hs_scope, hash); - - //- rjf: data * arch * addr * dbg -> decode artifacts - DASM_LineChunkList line_list = {0}; - String8List inst_strings = {0}; - { - switch(params.arch) - { - default:{}break; - - //- rjf: x86/x64 decoding - case Arch_x64: - case Arch_x86: - { - // rjf: disassemble - RDI_SourceFile *last_file = &rdi_nil_element_union.source_file; - RDI_Line *last_line = 0; - for(U64 off = 0; off < data.size;) - { - // rjf: disassemble one instruction - DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax); - if(inst.size == 0) - { - break; - } - - // rjf: push strings derived from voff -> line info - if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines)) - { - if(rdi != &rdi_parsed_nil) - { - U64 voff = (params.vaddr+off) - params.base_vaddr; - U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff); - RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx); - RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx); - RDI_ParsedLineTable unit_line_info = {0}; - rdi_parsed_from_line_table(rdi, line_table, &unit_line_info); - U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff); - if(line_info_idx < unit_line_info.count) - { - RDI_Line *line = &unit_line_info.lines[line_info_idx]; - RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx); - String8 file_normalized_full_path = {0}; - file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); - if(file != last_file) - { - if(params.style_flags & DASM_StyleFlag_SourceFilesNames && - file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0) - { - String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0) - { - String8 inst_string = str8_lit(">"); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - last_file = file; - } - if(line && line != last_line && file->normal_full_path_string_idx != 0 && - params.style_flags & DASM_StyleFlag_SourceLines && - file_normalized_full_path.size != 0) - { - FileProperties props = os_properties_from_file_path(file_normalized_full_path); - if(props.modified != 0) - { - // TODO(rjf): need redirection path - this may map to a different path on the local machine, - // need frontend to communicate path remapping info to this layer - HS_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); - TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); - U64 endt_us = max_U64; - U128 hash = {0}; - TXT_TextInfo text_info = {0}; - for(;os_now_microseconds() <= endt_us;) - { - text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); - if(!u128_match(hash, u128_zero())) - { - break; - } - } - if(0 < line->line_num && line->line_num < text_info.lines_count) - { - String8 data = hs_data_from_hash(hs_scope, hash); - String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); - if(line_text.size != 0) - { - String8 inst_string = push_str8f(scratch.arena, "> %S", line_text); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - } - } - last_line = line; - } - } - } - } - - // rjf: push line - String8 addr_part = {0}; - if(params.style_flags & DASM_StyleFlag_Addresses) - { - addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &rdi_parsed_nil ? " " : "", params.vaddr+off); - } - String8 code_bytes_part = {0}; - if(params.style_flags & DASM_StyleFlag_CodeBytes) - { - String8List code_bytes_strings = {0}; - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{")); - for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1) - { - if(byte_idx < inst.size) - { - str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : ""); - } - else if(byte_idx < 8) - { - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); - } - } - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); - code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); - } - String8 symbol_part = {0}; - if(inst.jump_dest_vaddr != 0 && rdi != &rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) - { - RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr); - if(scope_idx != 0) - { - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - RDI_U32 procedure_idx = scope->proc_idx; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx); - String8 procedure_name = {0}; - procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); - if(procedure_name.size != 0) - { - symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name); - } - } - } - String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part); - DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line); - str8_list_push(scratch.arena, &inst_strings, inst_string); - - // rjf: increment - off += inst.size; - } - }break; - } - } - - //- rjf: artifacts -> value bundle - Arena *info_arena = 0; - DASM_Info info = {0}; - { - //- rjf: produce joined text - Arena *text_arena = arena_alloc(); - StringJoin text_join = {0}; - text_join.sep = str8_lit("\n"); - String8 text = str8_list_join(text_arena, &inst_strings, &text_join); - //- rjf: produce unique key for this disassembly's text - HS_Key text_key = hs_key_make(root, hs_id_make(0, 0)); - - //- rjf: submit text data to hash store - U128 text_hash = hs_submit_data(text_key, &text_arena, text); - - //- rjf: produce value bundle - info_arena = arena_alloc(); - info.text_key = text_key; - info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list); - } - - //- rjf: commit results to cache - MutexScopeW(stripe->rw_mutex) - { - for(DASM_Node *n = slot->first; n != 0; n = n->next) + //- rjf: re-request if stale + MutexScope(dasm_shared->req_mutex) { - if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms)) - { - n->info_arena = info_arena; - MemoryCopyStruct(&n->info, &info); - if(rdi != &rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) - { - n->change_gen = change_gen; - } - else - { - n->change_gen = 0; - } - break; - } + DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); + SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); + dasm_shared->req_count += 1; + req_n->v.root = root; + req_n->v.hash = hash; + req_n->v.params = params; + req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); } + + txt_scope_close(txt_scope); + di_scope_close(di_scope); + hs_scope_close(hs_scope); } - txt_scope_close(txt_scope); - di_scope_close(di_scope); - hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Evictor/Detector Thread - -internal void -dasm_evictor_detector_thread__entry_point(void *p) -{ - ThreadNameF("dasm_evictor_detector_thread"); - for(;;) - { - U64 change_gen = fs_change_gen(); - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 10*1000000; - U64 retry_threshold_us = 1*1000000; - U64 evict_threshold_user_clocks = 10; - U64 retry_threshold_user_clocks = 10; - for(U64 slot_idx = 0; slot_idx < dasm_shared->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - ins_atomic_u64_eval(&n->working_count) == 0) - { - slot_has_work = 1; - break; - } - if(n->change_gen != 0 && n->change_gen != change_gen && - n->last_time_requested_us+retry_threshold_us <= check_time_us && - n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - ins_atomic_u64_eval(&n->working_count) == 0) - { - DLLRemove(slot->first, slot->last, n); - if(n->info_arena != 0) - { - arena_release(n->info_arena); - } - SLLStackPush(stripe->free_node, n); - } - if(n->change_gen != 0 && n->change_gen != change_gen && - n->last_time_requested_us+retry_threshold_us <= check_time_us && - n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) - { - if(dasm_u2p_enqueue_req(n->root, n->hash, &n->params, max_U64)) - { - async_push_work(dasm_parse_work); - n->last_time_requested_us = os_now_microseconds(); - n->last_user_clock_idx_requested = check_time_user_clocks; - } - } - } - } - } - os_sleep_milliseconds(100); - } } diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 4cde946b..855cf348 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -268,17 +268,6 @@ struct DASM_Shared DASM_RequestNode *first_req; DASM_RequestNode *last_req; U64 req_count; - - // rjf: user -> parse thread - U64 u2p_ring_size; - U8 *u2p_ring_base; - U64 u2p_ring_write_pos; - U64 u2p_ring_read_pos; - CondVar u2p_ring_cv; - Mutex u2p_ring_mutex; - - // rjf: evictor/detector thread - Thread evictor_detector_thread; }; //////////////////////////////// @@ -333,16 +322,4 @@ internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM internal void dasm_tick(void); -//////////////////////////////// -//~ rjf: Parse Threads - -internal B32 dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us); -internal void dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out); -ASYNC_WORK_DEF(dasm_parse_work); - -//////////////////////////////// -//~ rjf: Evictor/Detector Thread - -internal void dasm_evictor_detector_thread__entry_point(void *p); - #endif // DASM_CACHE_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index a90656cf..d7a0dd02 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -246,6 +246,7 @@ fs_properties_from_path(String8 path) internal void fs_tick(void) { + ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); //- rjf: do detection pass @@ -283,7 +284,6 @@ fs_tick(void) req_n->v.path = str8_copy(fs_shared->req_arena, n->path); req_n->v.range = range; } - cond_var_broadcast(async_tick_start_cond_var); } } } @@ -396,4 +396,5 @@ fs_tick(void) } scratch_end(scratch); + ProfEnd(); } diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 8adccdfd..48555c7c 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -547,6 +547,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash) internal void hs_tick(void) { + ProfBeginFunction(); Rng1U64 range = lane_range(hs_shared->slots_count); for EachInRange(slot_idx, range) { @@ -588,4 +589,5 @@ hs_tick(void) } } } + ProfEnd(); } From 364e15491c63fa123b5ee3f3ad259b80c7ebcfdf Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 14:19:00 -0700 Subject: [PATCH 205/302] switch from static lane distribution in file/dasm to dynamic counter --- src/base/base_entry_point.c | 1 + src/dasm_cache/dasm_cache.c | 14 ++++++++--- src/dasm_cache/dasm_cache.h | 3 +++ src/file_stream/file_stream.c | 11 +++++++-- src/file_stream/file_stream.h | 3 +++ src/hash_store/hash_store.c | 46 +++++++++++++++++------------------ src/hash_store/hash_store.h | 30 ++++++++++++++--------- 7 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index d2d1e966..a0de2ba9 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -6,6 +6,7 @@ global CondVar async_tick_start_cond_var = {0}; global CondVar async_tick_stop_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; +global U64 async_wait_timeout = 0; global B32 global_async_exit = 0; internal void diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index c6b10a54..a3754f7d 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -538,13 +538,20 @@ dasm_tick(void) arena_clear(dasm_shared->req_arena); dasm_shared->first_req = dasm_shared->last_req = 0; dasm_shared->req_count = 0; + dasm_shared->lane_req_take_counter = 0; } lane_sync(); //- rjf: do requests - Rng1U64 range = lane_range(reqs_count); - for EachInRange(req_idx, range) + for(;;) { + //- rjf: get next request + U64 req_num = ins_atomic_u64_inc_eval(&dasm_shared->lane_req_take_counter); + if(req_num < 1 || reqs_count < req_num) + { + break; + } + U64 req_idx = req_num-1; HS_Scope *hs_scope = hs_scope_open(); DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); @@ -766,7 +773,7 @@ dasm_tick(void) } //- rjf: re-request if stale - MutexScope(dasm_shared->req_mutex) + if(stale) MutexScope(dasm_shared->req_mutex) { DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); @@ -781,6 +788,7 @@ dasm_tick(void) di_scope_close(di_scope); hs_scope_close(hs_scope); } + lane_sync(); scratch_end(scratch); ProfEnd(); diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 855cf348..26690ec6 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -268,6 +268,9 @@ struct DASM_Shared DASM_RequestNode *first_req; DASM_RequestNode *last_req; U64 req_count; + + // rjf: request take counter + U64 lane_req_take_counter; }; //////////////////////////////// diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index d7a0dd02..488a1552 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -310,14 +310,20 @@ fs_tick(void) arena_clear(fs_shared->req_arena); fs_shared->first_req = fs_shared->last_req = 0; fs_shared->req_count = 0; + fs_shared->lane_req_take_counter = 0; } lane_sync(); //- rjf: do requests - Rng1U64 range = lane_range(reqs_count); - for EachInRange(req_idx, range) + for(;;) { //- rjf: unpack + U64 req_num = ins_atomic_u64_inc_eval(&fs_shared->lane_req_take_counter); + if(req_num < 1 || reqs_count < req_num) + { + break; + } + U64 req_idx = req_num-1; FS_Request *r = &reqs[req_idx]; HS_Key key = r->key; String8 path = r->path; @@ -394,6 +400,7 @@ fs_tick(void) } cond_var_broadcast(path_stripe->cv); } + lane_sync(); scratch_end(scratch); ProfEnd(); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 8bd6ba3b..ad084ca5 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -91,6 +91,9 @@ struct FS_Shared FS_RequestNode *first_req; FS_RequestNode *last_req; U64 req_count; + + // rjf: request take counter + U64 lane_req_take_counter; }; //////////////////////////////// diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 48555c7c..7f7771fd 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -69,9 +69,9 @@ hs_init(void) hs_shared->arena = arena; hs_shared->slots_count = 4096; hs_shared->stripes_count = Min(hs_shared->slots_count, os_get_system_info()->logical_processor_count); - hs_shared->slots = push_array(arena, HS_Slot, hs_shared->slots_count); + hs_shared->slots = push_array(arena, HS_BlobSlot, hs_shared->slots_count); hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count); - hs_shared->stripes_free_nodes = push_array(arena, HS_Node *, hs_shared->stripes_count); + hs_shared->stripes_free_nodes = push_array(arena, HS_BlobNode *, hs_shared->stripes_count); for(U64 idx = 0; idx < hs_shared->stripes_count; idx += 1) { HS_Stripe *stripe = &hs_shared->stripes[idx]; @@ -186,11 +186,11 @@ hs_root_release(HS_Root root) U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; U64 hash_slot_idx = hash.u64[1]%hs_shared->slots_count; U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; - HS_Slot *hash_slot = &hs_shared->slots[hash_slot_idx]; + HS_BlobSlot *hash_slot = &hs_shared->slots[hash_slot_idx]; HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; MutexScopeR(hash_stripe->rw_mutex) { - for(HS_Node *n = hash_slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = hash_slot->first; n != 0; n = n->next) { if(u128_match(n->hash, hash)) { @@ -226,14 +226,14 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) U128 hash = hs_hash_from_data(data); U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; //- rjf: commit data to cache - if already there, just bump key refcount ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) { - HS_Node *existing_node = 0; - for(HS_Node *n = slot->first; n != 0; n = n->next) + HS_BlobNode *existing_node = 0; + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { if(u128_match(n->hash, hash)) { @@ -243,14 +243,14 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) } if(existing_node == 0) { - HS_Node *node = hs_shared->stripes_free_nodes[stripe_idx]; + HS_BlobNode *node = hs_shared->stripes_free_nodes[stripe_idx]; if(node) { SLLStackPop(hs_shared->stripes_free_nodes[stripe_idx]); } else { - node = push_array(stripe->arena, HS_Node, 1); + node = push_array(stripe->arena, HS_BlobNode, 1); } node->hash = hash; if(data_arena != 0) @@ -359,11 +359,11 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) { U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count; U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; - HS_Slot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; + HS_BlobSlot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx]; MutexScopeR(old_hash_stripe->rw_mutex) { - for(HS_Node *n = old_hash_slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = old_hash_slot->first; n != 0; n = n->next) { if(u128_match(n->hash, key_expired_hash)) { @@ -411,11 +411,11 @@ hs_scope_close(HS_Scope *scope) next = touch->next; U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { if(u128_match(hash, n->hash)) { @@ -430,7 +430,7 @@ hs_scope_close(HS_Scope *scope) } internal void -hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node) +hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_BlobNode *node) { HS_Touch *touch = hs_tctx->free_touch; ins_atomic_u64_inc_eval(&node->scope_ref_count); @@ -455,11 +455,11 @@ hs_hash_downstream_inc(U128 hash) { U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { if(u128_match(hash, n->hash)) { @@ -475,11 +475,11 @@ hs_hash_downstream_dec(U128 hash) { U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { if(u128_match(hash, n->hash)) { @@ -523,11 +523,11 @@ hs_data_from_hash(HS_Scope *scope, U128 hash) String8 result = {0}; U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { if(u128_match(n->hash, hash)) { @@ -552,12 +552,12 @@ hs_tick(void) for EachInRange(slot_idx, range) { U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; B32 slot_has_work = 0; MutexScopeR(stripe->rw_mutex) { - for(HS_Node *n = slot->first; n != 0; n = n->next) + for(HS_BlobNode *n = slot->first; n != 0; n = n->next) { U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); @@ -571,7 +571,7 @@ hs_tick(void) } if(slot_has_work) MutexScopeW(stripe->rw_mutex) { - for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) + for(HS_BlobNode *n = slot->first, *next = 0; n != 0; n = next) { next = n->next; U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index 488b8730..73dce513 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -64,7 +64,7 @@ struct HS_Key }; //////////////////////////////// -//~ rjf: Cache Types +//~ rjf: Root Cache Types typedef struct HS_RootIDChunkNode HS_RootIDChunkNode; struct HS_RootIDChunkNode @@ -101,6 +101,9 @@ struct HS_RootSlot HS_RootNode *last; }; +//////////////////////////////// +//~ rjf: Key Cache Types + #define HS_KEY_HASH_HISTORY_COUNT 64 #define HS_KEY_HASH_HISTORY_STRONG_REF_COUNT 2 @@ -121,11 +124,14 @@ struct HS_KeySlot HS_KeyNode *last; }; -typedef struct HS_Node HS_Node; -struct HS_Node +//////////////////////////////// +//~ rjf: Content Blob Cache Types + +typedef struct HS_BlobNode HS_BlobNode; +struct HS_BlobNode { - HS_Node *next; - HS_Node *prev; + HS_BlobNode *next; + HS_BlobNode *prev; U128 hash; Arena *arena; String8 data; @@ -134,11 +140,11 @@ struct HS_Node U64 downstream_ref_count; }; -typedef struct HS_Slot HS_Slot; -struct HS_Slot +typedef struct HS_BlobSlot HS_BlobSlot; +struct HS_BlobSlot { - HS_Node *first; - HS_Node *last; + HS_BlobNode *first; + HS_BlobNode *last; }; typedef struct HS_Stripe HS_Stripe; @@ -188,9 +194,9 @@ struct HS_Shared // rjf: main data cache U64 slots_count; U64 stripes_count; - HS_Slot *slots; + HS_BlobSlot *slots; HS_Stripe *stripes; - HS_Node **stripes_free_nodes; + HS_BlobNode **stripes_free_nodes; // rjf: key cache U64 key_slots_count; @@ -245,7 +251,7 @@ internal U128 hs_submit_data(HS_Key key, Arena **data_arena, String8 data); internal HS_Scope *hs_scope_open(void); internal void hs_scope_close(HS_Scope *scope); -internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node); +internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_BlobNode *node); //////////////////////////////// //~ rjf: Downstream Accesses From 5381307e900d4c6e060b0676f4828a30f2d4429b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 14:42:25 -0700 Subject: [PATCH 206/302] hash_store -> content --- src/base/base_entry_point.c | 8 +- src/content/content.c | 593 ++++++++++++++++++ .../hash_store.h => content/content.h} | 186 +++--- src/ctrl/ctrl_core.c | 44 +- src/ctrl/ctrl_core.h | 10 +- src/dasm_cache/dasm_cache.c | 24 +- src/dasm_cache/dasm_cache.h | 8 +- src/dbg_engine/dbg_engine_core.c | 4 +- src/dbg_engine/dbg_engine_core.h | 2 +- src/file_stream/file_stream.c | 28 +- src/file_stream/file_stream.h | 8 +- src/geo_cache/geo_cache.c | 12 +- src/geo_cache/geo_cache.h | 2 +- src/hash_store/hash_store.c | 593 ------------------ src/mutable_text/mutable_text.c | 20 +- src/mutable_text/mutable_text.h | 6 +- src/ptr_graph_cache/ptr_graph_cache.c | 4 +- src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 2 +- src/raddbg/raddbg_core.c | 122 ++-- src/raddbg/raddbg_core.h | 12 +- src/raddbg/raddbg_main.c | 4 +- src/raddbg/raddbg_views.c | 32 +- src/tester/tester_main.c | 8 +- src/text_cache/text_cache.c | 16 +- src/text_cache/text_cache.h | 2 +- src/texture_cache/texture_cache.c | 12 +- src/texture_cache/texture_cache.h | 2 +- 29 files changed, 884 insertions(+), 884 deletions(-) create mode 100644 src/content/content.c rename src/{hash_store/hash_store.h => content/content.h} (54%) delete mode 100644 src/hash_store/hash_store.c diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index a0de2ba9..7b7bec00 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -56,8 +56,8 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL) async_init(&cmdline); #endif -#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) - hs_init(); +#if defined(CONTENT_H) && !defined(C_INIT_MANUAL) + c_init(); #endif #if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) fs_init(); @@ -191,8 +191,8 @@ async_thread_entry_point(void *params) for(;!ins_atomic_u32_eval(&global_async_exit);) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); -#if defined(HASH_STORE_H) - hs_tick(); +#if defined(CONTENT_H) + c_tick(); #endif #if defined(FILE_STREAM_H) fs_tick(); diff --git a/src/content/content.c b/src/content/content.c new file mode 100644 index 00000000..b0fe33fc --- /dev/null +++ b/src/content/content.c @@ -0,0 +1,593 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#undef LAYER_COLOR +#define LAYER_COLOR 0x684123ff + +//////////////////////////////// +//~ rjf: Basic Helpers + +#if !defined(XXH_IMPLEMENTATION) +# define XXH_IMPLEMENTATION +# define XXH_STATIC_LINKING_ONLY +# include "third_party/xxHash/xxhash.h" +#endif + +internal U64 +c_little_hash_from_data(String8 data) +{ + U64 result = XXH3_64bits(data.str, data.size); + return result; +} + +internal U128 +c_hash_from_data(String8 data) +{ + U128 u128 = {0}; + XXH128_hash_t hash = XXH3_128bits(data.str, data.size); + MemoryCopy(&u128, &hash, sizeof(u128)); + return u128; +} + +internal C_ID +c_id_make(U64 u64_0, U64 u64_1) +{ + C_ID id; + id.u128[0].u64[0] = u64_0; + id.u128[0].u64[1] = u64_1; + return id; +} + +internal B32 +c_id_match(C_ID a, C_ID b) +{ + B32 result = MemoryMatchStruct(&a, &b); + return result; +} + +internal C_Key +c_key_make(C_Root root, C_ID id) +{ + C_Key key = {root, 0, id}; + return key; +} + +internal B32 +c_key_match(C_Key a, C_Key b) +{ + return (MemoryMatchStruct(&a.root, &b.root) && c_id_match(a.id, b.id)); +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +c_init(void) +{ + Arena *arena = arena_alloc(); + c_shared = push_array(arena, C_Shared, 1); + c_shared->arena = arena; + c_shared->slots_count = 4096; + c_shared->stripes_count = Min(c_shared->slots_count, os_get_system_info()->logical_processor_count); + c_shared->slots = push_array(arena, C_BlobSlot, c_shared->slots_count); + c_shared->stripes = push_array(arena, C_Stripe, c_shared->stripes_count); + c_shared->stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->stripes_count); + for(U64 idx = 0; idx < c_shared->stripes_count; idx += 1) + { + C_Stripe *stripe = &c_shared->stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); + } + c_shared->key_slots_count = 4096; + c_shared->key_stripes_count = Min(c_shared->key_slots_count, os_get_system_info()->logical_processor_count); + c_shared->key_slots = push_array(arena, C_KeySlot, c_shared->key_slots_count); + c_shared->key_stripes = push_array(arena, C_Stripe, c_shared->key_stripes_count); + c_shared->key_stripes_free_nodes = push_array(arena, C_KeyNode *, c_shared->key_stripes_count); + for(U64 idx = 0; idx < c_shared->key_stripes_count; idx += 1) + { + C_Stripe *stripe = &c_shared->key_stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); + } + c_shared->root_slots_count = 4096; + c_shared->root_stripes_count = Min(c_shared->root_slots_count, os_get_system_info()->logical_processor_count); + c_shared->root_slots = push_array(arena, C_RootSlot, c_shared->root_slots_count); + c_shared->root_stripes = push_array(arena, C_Stripe, c_shared->root_stripes_count); + c_shared->root_stripes_free_nodes = push_array(arena, C_RootNode *, c_shared->root_stripes_count); + for(U64 idx = 0; idx < c_shared->root_stripes_count; idx += 1) + { + C_Stripe *stripe = &c_shared->root_stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = rw_mutex_alloc(); + stripe->cv = cond_var_alloc(); + } +} + +//////////////////////////////// +//~ rjf: Root Allocation/Deallocation + +internal C_Root +c_root_alloc(void) +{ + C_Root root = {0}; + root.u64[0] = ins_atomic_u64_inc_eval(&c_shared->root_id_gen); + U64 slot_idx = root.u64[0]%c_shared->root_slots_count; + U64 stripe_idx = slot_idx%c_shared->root_stripes_count; + C_RootSlot *slot = &c_shared->root_slots[slot_idx]; + C_Stripe *stripe = &c_shared->root_stripes[stripe_idx]; + MutexScopeW(stripe->rw_mutex) + { + C_RootNode *node = c_shared->root_stripes_free_nodes[stripe_idx]; + if(node != 0) + { + SLLStackPop(c_shared->root_stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array(stripe->arena, C_RootNode, 1); + } + DLLPushBack(slot->first, slot->last, node); + node->root = root; + node->arena = arena_alloc(); + } + return root; +} + +internal void +c_root_release(C_Root root) +{ + //- rjf: unpack root + U64 slot_idx = root.u64[0]%c_shared->root_slots_count; + U64 stripe_idx = slot_idx%c_shared->root_stripes_count; + C_RootSlot *slot = &c_shared->root_slots[slot_idx]; + C_Stripe *stripe = &c_shared->root_stripes[stripe_idx]; + + //- rjf: release root node, grab its arena / ID list + Arena *root_arena = 0; + C_RootIDChunkList root_ids = {0}; + MutexScopeW(stripe->rw_mutex) + { + for(C_RootNode *n = slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&root, &n->root)) + { + DLLRemove(slot->first, slot->last, n); + root_arena = n->arena; + root_ids = n->ids; + SLLStackPush(c_shared->root_stripes_free_nodes[stripe_idx], n); + break; + } + } + } + + //- rjf: release all IDs + for(C_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next) + { + for EachIndex(chunk_idx, id_chunk_n->count) + { + C_ID id = id_chunk_n->v[chunk_idx]; + C_Key key = c_key_make(root, id); + U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%c_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; + C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; + C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; + MutexScopeW(key_stripe->rw_mutex) + { + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key)) + { + // rjf: release reference to all hashes + for(U64 history_idx = 0; history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) + { + U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; + U64 hash_slot_idx = hash.u64[1]%c_shared->slots_count; + U64 hash_stripe_idx = hash_slot_idx%c_shared->stripes_count; + C_BlobSlot *hash_slot = &c_shared->slots[hash_slot_idx]; + C_Stripe *hash_stripe = &c_shared->stripes[hash_stripe_idx]; + MutexScopeR(hash_stripe->rw_mutex) + { + for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + + // rjf: release key node + DLLRemove(key_slot->first, key_slot->last, n); + SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n); + break; + } + } + } + } + } +} + +//////////////////////////////// +//~ rjf: Cache Submission + +internal U128 +c_submit_data(C_Key key, Arena **data_arena, String8 data) +{ + U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%c_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; + C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; + C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; + U128 hash = c_hash_from_data(data); + U64 slot_idx = hash.u64[1]%c_shared->slots_count; + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + + //- rjf: commit data to cache - if already there, just bump key refcount + ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) + { + C_BlobNode *existing_node = 0; + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + existing_node = n; + break; + } + } + if(existing_node == 0) + { + C_BlobNode *node = c_shared->stripes_free_nodes[stripe_idx]; + if(node) + { + SLLStackPop(c_shared->stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array(stripe->arena, C_BlobNode, 1); + } + node->hash = hash; + if(data_arena != 0) + { + node->arena = *data_arena; + } + node->data = data; + node->scope_ref_count = 0; + node->key_ref_count = 1; + DLLPushBack(slot->first, slot->last, node); + } + else + { + existing_node->key_ref_count += 1; + if(data_arena != 0) + { + arena_release(*data_arena); + } + } + if(data_arena != 0) + { + *data_arena = 0; + } + } + + //- rjf: commit this hash to key cache + U128 key_expired_hash = {0}; + ProfScope("commit this hash to key cache") MutexScopeW(key_stripe->rw_mutex) + { + // rjf: find existing key + B32 key_is_new = 0; + C_KeyNode *key_node = 0; + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key)) + { + key_node = n; + break; + } + } + + // rjf: create key node if it doesn't exist + if(!key_node) + { + key_is_new = 1; + key_node = c_shared->key_stripes_free_nodes[key_stripe_idx]; + if(key_node) + { + SLLStackPop(c_shared->key_stripes_free_nodes[key_stripe_idx]); + } + else + { + key_node = push_array(key_stripe->arena, C_KeyNode, 1); + } + key_node->key = key; + DLLPushBack(key_slot->first, key_slot->last, key_node); + } + + // rjf: push hash into key's history + if(key_node) + { + if(key_node->hash_history_gen >= C_KEY_HASH_HISTORY_STRONG_REF_COUNT) + { + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-C_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; + } + key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; + key_node->hash_history_gen += 1; + } + + // rjf: key is new -> add this key to the associated root + if(key_is_new) + { + U64 root_hash = c_little_hash_from_data(str8_struct(&key.root)); + U64 root_slot_idx = root_hash%c_shared->root_slots_count; + U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; + C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; + C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx]; + MutexScopeW(root_stripe->rw_mutex) + { + for(C_RootNode *n = root_slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&n->root, &key.root)) + { + C_RootIDChunkNode *chunk = n->ids.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(n->arena, C_RootIDChunkNode, 1); + SLLQueuePush(n->ids.first, n->ids.last, chunk); + n->ids.chunk_count += 1; + chunk->cap = 1024; + chunk->v = push_array_no_zero(n->arena, C_ID, chunk->cap); + } + chunk->v[chunk->count] = key.id; + chunk->count += 1; + n->ids.total_count += 1; + break; + } + } + } + } + } + + //- rjf: decrement key ref count of expired hash + ProfScope("decrement key ref count of expired hash") + if(!u128_match(key_expired_hash, u128_zero())) + { + U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->slots_count; + U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->stripes_count; + C_BlobSlot *old_hash_slot = &c_shared->slots[old_hash_slot_idx]; + C_Stripe *old_hash_stripe = &c_shared->stripes[old_hash_stripe_idx]; + MutexScopeR(old_hash_stripe->rw_mutex) + { + for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, key_expired_hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + + return hash; +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal C_Scope * +c_scope_open(void) +{ + if(c_tctx == 0) + { + Arena *arena = arena_alloc(); + c_tctx = push_array(arena, C_TCTX, 1); + c_tctx->arena = arena; + } + C_Scope *scope = c_tctx->free_scope; + if(scope) + { + SLLStackPop(c_tctx->free_scope); + } + else + { + scope = push_array_no_zero(c_tctx->arena, C_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +c_scope_close(C_Scope *scope) +{ + for(C_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) + { + U128 hash = touch->hash; + next = touch->next; + U64 slot_idx = hash.u64[1]%c_shared->slots_count; + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + MutexScopeR(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(c_tctx->free_touch, touch); + } + SLLStackPush(c_tctx->free_scope, scope); +} + +internal void +c_scope_touch_node__stripe_r_guarded(C_Scope *scope, C_BlobNode *node) +{ + C_Touch *touch = c_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + if(touch != 0) + { + SLLStackPop(c_tctx->free_touch); + } + else + { + touch = push_array_no_zero(c_tctx->arena, C_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Downstream Accesses + +internal void +c_hash_downstream_inc(U128 hash) +{ + U64 slot_idx = hash.u64[1]%c_shared->slots_count; + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + MutexScopeR(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_inc_eval(&n->downstream_ref_count); + break; + } + } + } +} + +internal void +c_hash_downstream_dec(U128 hash) +{ + U64 slot_idx = hash.u64[1]%c_shared->slots_count; + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + MutexScopeR(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->downstream_ref_count); + break; + } + } + } +} + +//////////////////////////////// +//~ rjf: Cache Lookup + +internal U128 +c_hash_from_key(C_Key key, U64 rewind_count) +{ + U128 result = {0}; + U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%c_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; + C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; + C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; + MutexScopeR(key_stripe->rw_mutex) + { + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count) + { + result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)]; + break; + } + } + } + return result; +} + +internal String8 +c_data_from_hash(C_Scope *scope, U128 hash) +{ + ProfBeginFunction(); + String8 result = {0}; + U64 slot_idx = hash.u64[1]%c_shared->slots_count; + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + MutexScopeR(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + result = n->data; + c_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Tick + +internal void +c_tick(void) +{ + ProfBeginFunction(); + Rng1U64 range = lane_range(c_shared->slots_count); + for EachInRange(slot_idx, range) + { + U64 stripe_idx = slot_idx%c_shared->stripes_count; + C_BlobSlot *slot = &c_shared->slots[slot_idx]; + C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + B32 slot_has_work = 0; + MutexScopeR(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first; n != 0; n = n->next) + { + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) MutexScopeW(stripe->rw_mutex) + { + for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(c_shared->stripes_free_nodes[stripe_idx], n); + if(n->arena != 0) + { + arena_release(n->arena); + } + } + } + } + } + ProfEnd(); +} diff --git a/src/hash_store/hash_store.h b/src/content/content.h similarity index 54% rename from src/hash_store/hash_store.h rename to src/content/content.h index 73dce513..6a0ecd5f 100644 --- a/src/hash_store/hash_store.h +++ b/src/content/content.h @@ -1,8 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef HASH_STORE_H -#define HASH_STORE_H +#ifndef CONTENT_H +#define CONTENT_H //////////////////////////////// //~ NOTE(rjf): Hash Store Notes (2025/05/18) @@ -43,95 +43,95 @@ //////////////////////////////// //~ rjf: Key Types -typedef struct HS_Root HS_Root; -struct HS_Root +typedef struct C_Root C_Root; +struct C_Root { U64 u64[1]; }; -typedef struct HS_ID HS_ID; -struct HS_ID +typedef struct C_ID C_ID; +struct C_ID { U128 u128[1]; }; -typedef struct HS_Key HS_Key; -struct HS_Key +typedef struct C_Key C_Key; +struct C_Key { - HS_Root root; + C_Root root; U64 _padding_; - HS_ID id; + C_ID id; }; //////////////////////////////// //~ rjf: Root Cache Types -typedef struct HS_RootIDChunkNode HS_RootIDChunkNode; -struct HS_RootIDChunkNode +typedef struct C_RootIDChunkNode C_RootIDChunkNode; +struct C_RootIDChunkNode { - HS_RootIDChunkNode *next; - HS_ID *v; + C_RootIDChunkNode *next; + C_ID *v; U64 count; U64 cap; }; -typedef struct HS_RootIDChunkList HS_RootIDChunkList; -struct HS_RootIDChunkList +typedef struct C_RootIDChunkList C_RootIDChunkList; +struct C_RootIDChunkList { - HS_RootIDChunkNode *first; - HS_RootIDChunkNode *last; + C_RootIDChunkNode *first; + C_RootIDChunkNode *last; U64 chunk_count; U64 total_count; }; -typedef struct HS_RootNode HS_RootNode; -struct HS_RootNode +typedef struct C_RootNode C_RootNode; +struct C_RootNode { - HS_RootNode *next; - HS_RootNode *prev; + C_RootNode *next; + C_RootNode *prev; Arena *arena; - HS_Root root; - HS_RootIDChunkList ids; + C_Root root; + C_RootIDChunkList ids; }; -typedef struct HS_RootSlot HS_RootSlot; -struct HS_RootSlot +typedef struct C_RootSlot C_RootSlot; +struct C_RootSlot { - HS_RootNode *first; - HS_RootNode *last; + C_RootNode *first; + C_RootNode *last; }; //////////////////////////////// //~ rjf: Key Cache Types -#define HS_KEY_HASH_HISTORY_COUNT 64 -#define HS_KEY_HASH_HISTORY_STRONG_REF_COUNT 2 +#define C_KEY_HASH_HISTORY_COUNT 64 +#define C_KEY_HASH_HISTORY_STRONG_REF_COUNT 2 -typedef struct HS_KeyNode HS_KeyNode; -struct HS_KeyNode +typedef struct C_KeyNode C_KeyNode; +struct C_KeyNode { - HS_KeyNode *next; - HS_KeyNode *prev; - HS_Key key; - U128 hash_history[HS_KEY_HASH_HISTORY_COUNT]; + C_KeyNode *next; + C_KeyNode *prev; + C_Key key; + U128 hash_history[C_KEY_HASH_HISTORY_COUNT]; U64 hash_history_gen; }; -typedef struct HS_KeySlot HS_KeySlot; -struct HS_KeySlot +typedef struct C_KeySlot C_KeySlot; +struct C_KeySlot { - HS_KeyNode *first; - HS_KeyNode *last; + C_KeyNode *first; + C_KeyNode *last; }; //////////////////////////////// //~ rjf: Content Blob Cache Types -typedef struct HS_BlobNode HS_BlobNode; -struct HS_BlobNode +typedef struct C_BlobNode C_BlobNode; +struct C_BlobNode { - HS_BlobNode *next; - HS_BlobNode *prev; + C_BlobNode *next; + C_BlobNode *prev; U128 hash; Arena *arena; String8 data; @@ -140,15 +140,15 @@ struct HS_BlobNode U64 downstream_ref_count; }; -typedef struct HS_BlobSlot HS_BlobSlot; -struct HS_BlobSlot +typedef struct C_BlobSlot C_BlobSlot; +struct C_BlobSlot { - HS_BlobNode *first; - HS_BlobNode *last; + C_BlobNode *first; + C_BlobNode *last; }; -typedef struct HS_Stripe HS_Stripe; -struct HS_Stripe +typedef struct C_Stripe C_Stripe; +struct C_Stripe { Arena *arena; RWMutex rw_mutex; @@ -158,116 +158,116 @@ struct HS_Stripe //////////////////////////////// //~ rjf: Scoped Access -typedef struct HS_Touch HS_Touch; -struct HS_Touch +typedef struct C_Touch C_Touch; +struct C_Touch { - HS_Touch *next; + C_Touch *next; U128 hash; }; -typedef struct HS_Scope HS_Scope; -struct HS_Scope +typedef struct C_Scope C_Scope; +struct C_Scope { - HS_Scope *next; - HS_Touch *top_touch; + C_Scope *next; + C_Touch *top_touch; }; //////////////////////////////// //~ rjf: Thread Context -typedef struct HS_TCTX HS_TCTX; -struct HS_TCTX +typedef struct C_TCTX C_TCTX; +struct C_TCTX { Arena *arena; - HS_Scope *free_scope; - HS_Touch *free_touch; + C_Scope *free_scope; + C_Touch *free_touch; }; //////////////////////////////// //~ rjf: Shared State -typedef struct HS_Shared HS_Shared; -struct HS_Shared +typedef struct C_Shared C_Shared; +struct C_Shared { Arena *arena; // rjf: main data cache U64 slots_count; U64 stripes_count; - HS_BlobSlot *slots; - HS_Stripe *stripes; - HS_BlobNode **stripes_free_nodes; + C_BlobSlot *slots; + C_Stripe *stripes; + C_BlobNode **stripes_free_nodes; // rjf: key cache U64 key_slots_count; U64 key_stripes_count; - HS_KeySlot *key_slots; - HS_Stripe *key_stripes; - HS_KeyNode **key_stripes_free_nodes; + C_KeySlot *key_slots; + C_Stripe *key_stripes; + C_KeyNode **key_stripes_free_nodes; // rjf: root cache U64 root_slots_count; U64 root_stripes_count; - HS_RootSlot *root_slots; - HS_Stripe *root_stripes; - HS_RootNode **root_stripes_free_nodes; + C_RootSlot *root_slots; + C_Stripe *root_stripes; + C_RootNode **root_stripes_free_nodes; U64 root_id_gen; }; //////////////////////////////// //~ rjf: Globals -thread_static HS_TCTX *hs_tctx = 0; -global HS_Shared *hs_shared = 0; +thread_static C_TCTX *c_tctx = 0; +global C_Shared *c_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers -internal U64 hs_little_hash_from_data(String8 data); -internal U128 hs_hash_from_data(String8 data); -internal HS_ID hs_id_make(U64 u64_0, U64 u64_1); -internal B32 hs_id_match(HS_ID a, HS_ID b); -internal HS_Key hs_key_make(HS_Root root, HS_ID id); -internal B32 hs_key_match(HS_Key a, HS_Key b); +internal U64 c_little_hash_from_data(String8 data); +internal U128 c_hash_from_data(String8 data); +internal C_ID c_id_make(U64 u64_0, U64 u64_1); +internal B32 c_id_match(C_ID a, C_ID b); +internal C_Key c_key_make(C_Root root, C_ID id); +internal B32 c_key_match(C_Key a, C_Key b); //////////////////////////////// //~ rjf: Main Layer Initialization -internal void hs_init(void); +internal void c_init(void); //////////////////////////////// //~ rjf: Root Allocation/Deallocation -internal HS_Root hs_root_alloc(void); -internal void hs_root_release(HS_Root root); +internal C_Root c_root_alloc(void); +internal void c_root_release(C_Root root); //////////////////////////////// //~ rjf: Cache Submission -internal U128 hs_submit_data(HS_Key key, Arena **data_arena, String8 data); +internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data); //////////////////////////////// //~ rjf: Scoped Access -internal HS_Scope *hs_scope_open(void); -internal void hs_scope_close(HS_Scope *scope); -internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_BlobNode *node); +internal C_Scope *c_scope_open(void); +internal void c_scope_close(C_Scope *scope); +internal void c_scope_touch_node__stripe_r_guarded(C_Scope *scope, C_BlobNode *node); //////////////////////////////// //~ rjf: Downstream Accesses -internal void hs_hash_downstream_inc(U128 hash); -internal void hs_hash_downstream_dec(U128 hash); +internal void c_hash_downstream_inc(U128 hash); +internal void c_hash_downstream_dec(U128 hash); //////////////////////////////// //~ rjf: Cache Lookups -internal U128 hs_hash_from_key(HS_Key key, U64 rewind_count); -internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash); +internal U128 c_hash_from_key(C_Key key, U64 rewind_count); +internal String8 c_data_from_hash(C_Scope *scope, U128 hash); //////////////////////////////// //~ rjf: Tick -internal void hs_tick(void); +internal void c_tick(void); -#endif // HASH_STORE_H +#endif // CONTENT_H diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index aa85862a..a2412766 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1620,7 +1620,7 @@ ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) //- rjf: process memory cache key reading -internal HS_Key +internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) { CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; @@ -1634,7 +1634,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 //- rjf: get the hash store root for this process; construct process node if it // doesn't exist - HS_Root root = {0}; + C_Root root = {0}; { B32 node_found = 0; MutexScopeR(process_stripe->rw_mutex) @@ -1667,7 +1667,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 DLLPushBack(process_slot->first, process_slot->last, node); node->arena = node_arena; node->handle = process; - node->root = hs_root_alloc(); + node->root = c_root_alloc(); node->range_hash_slots_count = 1024; node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); root = node->root; @@ -1676,7 +1676,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 } //- rjf: form ID for this process memory query - HS_ID id = {0}; + C_ID id = {0}; { id.u128[0].u64[0] = vaddr_range.min & 0x00ffffffffffffffull; id.u128[0].u64[1] = vaddr_range.max & 0x00ffffffffffffffull; @@ -1685,10 +1685,10 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 id.u128[0].u64[0] |= (1ull << 63); } } - U64 range_hash = hs_little_hash_from_data(str8_struct(&id)); + U64 range_hash = c_little_hash_from_data(str8_struct(&id)); //- rjf: form full key - HS_Key key = hs_key_make(root, id); + C_Key key = c_key_make(root, id); //- rjf: loop: try to look for current results, request if not there, wait if we can, repeat until we can't U64 mem_gen = ctrl_mem_gen(); @@ -1709,7 +1709,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(hs_id_match(n->id, id)) + if(c_id_match(n->id, id)) { id_exists = 1; id_stale = (n->mem_gen < mem_gen); @@ -1758,7 +1758,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 CTRL_ProcessMemoryRangeHashNode *range_n = 0; for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(hs_id_match(n->id, id)) + if(c_id_match(n->id, id)) { range_n = n; break; @@ -1807,7 +1807,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 CTRL_ProcessMemoryRangeHashNode *range_n = 0; for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(hs_id_match(n->id, id)) + if(c_id_match(n->id, id)) { n->working_count -= 1; break; @@ -1851,7 +1851,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn range.max <= 0x000FFFFFFFFFFFFFull) { Temp scratch = scratch_begin(&arena, 1); - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; //- rjf: unpack address range, prepare per-touched-page info @@ -1868,9 +1868,9 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn { U64 page_base_vaddr = page_range.min + page_idx*page_size; B32 page_is_stale = 0; - HS_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); - U128 page_hash = hs_hash_from_key(page_key, 0); - U128 page_last_hash = hs_hash_from_key(page_key, 1); + C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); + U128 page_hash = c_hash_from_key(page_key, 0); + U128 page_last_hash = c_hash_from_key(page_key, 1); result.stale = (result.stale || page_is_stale); page_hashes[page_idx] = page_hash; page_last_hashes[page_idx] = page_last_hash; @@ -1889,7 +1889,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) { // rjf: read data for this page - String8 data = hs_data_from_hash(scope, page_hashes[page_idx]); + String8 data = c_data_from_hash(scope, page_hashes[page_idx]); Rng1U64 data_vaddr_range = r1u64(page_range.min + page_idx*page_size, page_range.min + page_idx*page_size+data.size); // rjf: skip/chop bytes which are irrelevant for the actual requested read @@ -1925,7 +1925,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn // fill out changed flags if(!u128_match(page_hashes[page_idx], page_last_hashes[page_idx])) ProfScope("hashes don't match; diff each byte") { - String8 last_data = hs_data_from_hash(scope, page_last_hashes[page_idx]); + String8 last_data = c_data_from_hash(scope, page_last_hashes[page_idx]); String8 in_range_last_data = last_data; if(page_idx == page_count-1 && data_vaddr_range.max > range.max) { @@ -1977,7 +1977,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn } } - hs_scope_close(scope); + c_scope_close(scope); scratch_end(scratch); } ProfEnd(); @@ -6866,7 +6866,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: user -> memory stream communication internal B32 -ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) +ctrl_u2ms_enqueue_req(C_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) { B32 good = 0; MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) @@ -6890,7 +6890,7 @@ ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 } internal void -ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) +ctrl_u2ms_dequeue_req(C_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) { MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { @@ -6917,7 +6917,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; //- rjf: unpack next request - HS_Key key = {0}; + C_Key key = {0}; CTRL_Handle process = {0}; Rng1U64 vaddr_range = {0}; B32 zero_terminated = 0; @@ -6932,7 +6932,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; //- rjf: unpack address range hash cache key - U64 range_hash = hs_little_hash_from_data(str8_struct(&key.id)); + U64 range_hash = c_little_hash_from_data(str8_struct(&key.id)); //- rjf: clamp vaddr range Rng1U64 vaddr_range_clamped = vaddr_range; @@ -7037,7 +7037,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) U128 hash = {0}; if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) { - hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + hash = c_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); } else if(range_arena != 0) { @@ -7055,7 +7055,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) { - if(hs_id_match(range_n->id, key.id)) + if(c_id_match(range_n->id, key.id)) { if(pre_read_mem_gen == post_read_mem_gen) { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 1ba02bc7..d4464238 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -545,7 +545,7 @@ struct CTRL_ProcessMemoryRangeHashNode // rjf: key Rng1U64 vaddr_range; B32 zero_terminated; - HS_ID id; + C_ID id; // rjf: staleness info U64 mem_gen; @@ -570,7 +570,7 @@ struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode *prev; Arena *arena; CTRL_Handle handle; - HS_Root root; + C_Root root; U64 range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; }; @@ -1076,7 +1076,7 @@ internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); //~ rjf: Process Memory Functions //- rjf: process memory cache key reading -internal HS_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); +internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); @@ -1206,8 +1206,8 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //~ rjf: Asynchronous Memory Streaming Functions //- rjf: user -> memory stream communication -internal B32 ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); -internal void ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); +internal B32 ctrl_u2ms_enqueue_req(C_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); +internal void ctrl_u2ms_dequeue_req(C_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); //- rjf: entry point ASYNC_WORK_DEF(ctrl_mem_stream_work); diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index a3754f7d..ba351817 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -382,7 +382,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) DLLPushBack(slot->first, slot->last, node); node->hash = hash; MemoryCopyStruct(&node->params, params); - node->root = hs_root_alloc(); + node->root = c_root_alloc(); // TODO(rjf): need to make this releasable - currently all exe_paths just leak node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); ins_atomic_u64_inc_eval(&node->working_count); @@ -416,12 +416,12 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } internal DASM_Info -dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out) +dasm_info_from_key_params(DASM_Scope *scope, C_Key key, DASM_Params *params, U128 *hash_out) { DASM_Info result = {0}; - for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { - U128 hash = hs_hash_from_key(key, rewind_idx); + U128 hash = c_hash_from_key(key, rewind_idx); result = dasm_info_from_hash_params(scope, hash, params); if(result.lines.count != 0) { @@ -552,17 +552,17 @@ dasm_tick(void) break; } U64 req_idx = req_num-1; - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); //- rjf: unpack B32 stale = 0; DASM_Request *r = &reqs[req_idx]; - HS_Root root = r->root; + C_Root root = r->root; U128 hash = r->hash; DASM_Params params = r->params; - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); U64 change_gen = fs_change_gen(); U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; U64 stripe_idx = slot_idx%dasm_shared->stripes_count; @@ -647,7 +647,7 @@ dasm_tick(void) { // TODO(rjf): need redirection path - this may map to a different path on the local machine, // need frontend to communicate path remapping info to this layer - HS_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); + C_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; @@ -655,7 +655,7 @@ dasm_tick(void) stale = (stale || u128_match(hash, u128_zero())); if(0 < line->line_num && line->line_num < text_info.lines_count) { - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); if(line_text.size != 0) { @@ -738,10 +738,10 @@ dasm_tick(void) String8 text = str8_list_join(text_arena, &inst_strings, &text_join); //- rjf: produce unique key for this disassembly's text - HS_Key text_key = hs_key_make(root, hs_id_make(0, 0)); + C_Key text_key = c_key_make(root, c_id_make(0, 0)); //- rjf: submit text data to hash store - U128 text_hash = hs_submit_data(text_key, &text_arena, text); + U128 text_hash = c_submit_data(text_key, &text_arena, text); //- rjf: produce value bundle info_arena = arena_alloc(); @@ -786,7 +786,7 @@ dasm_tick(void) txt_scope_close(txt_scope); di_scope_close(di_scope); - hs_scope_close(hs_scope); + c_scope_close(c_scope); } lane_sync(); diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 26690ec6..2818119a 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -106,7 +106,7 @@ struct DASM_Params typedef struct DASM_Request DASM_Request; struct DASM_Request { - HS_Root root; + C_Root root; U128 hash; DASM_Params params; }; @@ -167,7 +167,7 @@ struct DASM_LineArray typedef struct DASM_Info DASM_Info; struct DASM_Info { - HS_Key text_key; + C_Key text_key; DASM_LineArray lines; }; @@ -186,7 +186,7 @@ struct DASM_Node DASM_Params params; // rjf: root - HS_Root root; + C_Root root; // rjf: generations U64 change_gen; @@ -318,7 +318,7 @@ internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_No //~ rjf: Cache Lookups internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params); -internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out); +internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, C_Key key, DASM_Params *params, U128 *hash_out); //////////////////////////////// //~ rjf: Ticks diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index e72a46aa..c44c70e6 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1421,8 +1421,8 @@ d_init(void) d_state = push_array(arena, D_State, 1); d_state->arena = arena; d_state->cmds_arena = arena_alloc(); - d_state->output_log_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); - hs_submit_data(d_state->output_log_key, 0, str8_zero()); + d_state->output_log_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); + c_submit_data(d_state->output_log_key, 0, str8_zero()); d_state->ctrl_entity_store = ctrl_entity_ctx_rw_store_alloc(); d_state->ctrl_stop_arena = arena_alloc(); d_state->ctrl_msg_arena = arena_alloc(); diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index e6e535db..9b7aeafc 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -283,7 +283,7 @@ struct D_State D_CmdList cmds; // rjf: output log key - HS_Key output_log_key; + C_Key output_log_key; // rjf: per-run caches U64 tls_base_cache_reggen_idx; diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 488a1552..88869e33 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -27,7 +27,7 @@ fs_big_hash_from_string_range(String8 string, Rng1U64 range) MemoryCopy(buffer, string.str, string.size); MemoryCopy(buffer + string.size, &range.min, sizeof(range.min)); MemoryCopy(buffer + string.size + sizeof(range.min), &range.max, sizeof(range.max)); - U128 hash = hs_hash_from_data(str8(buffer, buffer_size)); + U128 hash = c_hash_from_data(str8(buffer, buffer_size)); scratch_end(scratch); return hash; } @@ -68,7 +68,7 @@ fs_change_gen(void) //////////////////////////////// //~ rjf: Cache Interaction -internal HS_Key +internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { Temp scratch = scratch_begin(0, 0); @@ -82,7 +82,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; //- rjf: get root for this path - on 1st try (read mode), try to read, on 2nd try (write mode), create node - HS_Root root = {0}; + C_Root root = {0}; for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { B32 node_found = 0; @@ -102,7 +102,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) FS_Node *node = push_array(path_stripe->arena, FS_Node, 1); SLLQueuePush(path_slot->first, path_slot->last, node); node->path = push_str8_copy(path_stripe->arena, path); - node->root = hs_root_alloc(); + node->root = c_root_alloc(); node->slots_count = 64; node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count); root = node->root; @@ -115,11 +115,11 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) } //- rjf: build a key for this path/range combo - HS_Key key = hs_key_make(root, hs_id_make(range.min, range.max)); + C_Key key = c_key_make(root, c_id_make(range.min, range.max)); //- rjf: if the most recent hash for this key is zero, then try to submit a new // request to pull it in. - if(u128_match(hs_hash_from_key(key, 0), u128_zero())) + if(u128_match(c_hash_from_key(key, 0), u128_zero())) { // rjf: loop: request, check for results, return until we can't RWMutexScope(path_stripe->rw_mutex, 1) for(;;) @@ -148,7 +148,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) FS_RangeNode *range_node = 0; for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next) { - if(hs_id_match(n->id, key.id)) + if(c_id_match(n->id, key.id)) { range_node = n; break; @@ -180,7 +180,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) } // rjf: have time to wait? -> wait on this stripe; otherwise exit - B32 have_results = !u128_match(hs_hash_from_key(key, 0), u128_zero()); + B32 have_results = !u128_match(c_hash_from_key(key, 0), u128_zero()); if(!have_results && os_now_microseconds() < endt_us) { cond_var_wait_rw(path_stripe->cv, path_stripe->rw_mutex, 1, endt_us); @@ -201,10 +201,10 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { U128 hash = {0}; { - HS_Key key = fs_key_from_path_range(path, range, endt_us); - for EachIndex(rewind_idx, HS_KEY_HASH_HISTORY_COUNT) + C_Key key = fs_key_from_path_range(path, range, endt_us); + for EachIndex(rewind_idx, C_KEY_HASH_HISTORY_COUNT) { - hash = hs_hash_from_key(key, rewind_idx); + hash = c_hash_from_key(key, rewind_idx); if(!u128_match(hash, u128_zero())) { break; @@ -271,7 +271,7 @@ fs_tick(void) range_n != 0; range_n = range_n->next) { - HS_Key key = hs_key_make(n->root, range_n->id); + C_Key key = c_key_make(n->root, range_n->id); if(ins_atomic_u64_eval(&range_n->working_count) == 0) { ins_atomic_u64_inc_eval(&range_n->working_count); @@ -325,7 +325,7 @@ fs_tick(void) } U64 req_idx = req_num-1; FS_Request *r = &reqs[req_idx]; - HS_Key key = r->key; + C_Key key = r->key; String8 path = r->path; Rng1U64 range = r->range; U64 path_hash = fs_little_hash_from_string(path); @@ -373,7 +373,7 @@ fs_tick(void) { ProfScope("submit") { - hs_submit_data(key, &data_arena, data); + c_submit_data(key, &data_arena, data); } } diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index ad084ca5..dbee2562 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -11,7 +11,7 @@ typedef struct FS_RangeNode FS_RangeNode; struct FS_RangeNode { FS_RangeNode *next; - HS_ID id; + C_ID id; U64 working_count; }; @@ -32,7 +32,7 @@ struct FS_Node FileProperties props; // rjf: hash store root - HS_Root root; + C_Root root; // rjf: sub-table of per-requested-file-range info U64 slots_count; @@ -61,7 +61,7 @@ typedef struct FS_Request FS_Request; struct FS_Request { FS_Request *next; - HS_Key key; + C_Key key; String8 path; Rng1U64 range; }; @@ -120,7 +120,7 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Cache Interaction -internal HS_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); +internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal FileProperties fs_properties_from_path(String8 path); diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index f42e152d..6c20b6ba 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -181,12 +181,12 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) } internal R_Handle -geo_buffer_from_key(GEO_Scope *scope, HS_Key key) +geo_buffer_from_key(GEO_Scope *scope, C_Key key) { R_Handle handle = {0}; - for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { - U128 hash = hs_hash_from_key(key, rewind_idx); + U128 hash = c_hash_from_key(key, rewind_idx); handle = geo_buffer_from_hash(scope, hash); if(!r_handle_match(handle, r_handle_zero())) { @@ -245,7 +245,7 @@ geo_u2x_dequeue_req(U128 *hash_out) ASYNC_WORK_DEF(geo_xfer_work) { ProfBeginFunction(); - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); //- rjf: decode U128 hash = {0}; @@ -275,7 +275,7 @@ ASYNC_WORK_DEF(geo_xfer_work) String8 data = {0}; if(got_task) { - data = hs_data_from_hash(scope, hash); + data = c_data_from_hash(scope, hash); } //- rjf: data -> buffer @@ -300,7 +300,7 @@ ASYNC_WORK_DEF(geo_xfer_work) } } - hs_scope_close(scope); + c_scope_close(scope); ProfEnd(); return 0; } diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index 24dd4941..fd85e300 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -118,7 +118,7 @@ internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node //~ rjf: Cache Lookups internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash); -internal R_Handle geo_buffer_from_key(GEO_Scope *scope, HS_Key key); +internal R_Handle geo_buffer_from_key(GEO_Scope *scope, C_Key key); //////////////////////////////// //~ rjf: Transfer Threads diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c deleted file mode 100644 index 7f7771fd..00000000 --- a/src/hash_store/hash_store.c +++ /dev/null @@ -1,593 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#undef LAYER_COLOR -#define LAYER_COLOR 0x684123ff - -//////////////////////////////// -//~ rjf: Basic Helpers - -#if !defined(XXH_IMPLEMENTATION) -# define XXH_IMPLEMENTATION -# define XXH_STATIC_LINKING_ONLY -# include "third_party/xxHash/xxhash.h" -#endif - -internal U64 -hs_little_hash_from_data(String8 data) -{ - U64 result = XXH3_64bits(data.str, data.size); - return result; -} - -internal U128 -hs_hash_from_data(String8 data) -{ - U128 u128 = {0}; - XXH128_hash_t hash = XXH3_128bits(data.str, data.size); - MemoryCopy(&u128, &hash, sizeof(u128)); - return u128; -} - -internal HS_ID -hs_id_make(U64 u64_0, U64 u64_1) -{ - HS_ID id; - id.u128[0].u64[0] = u64_0; - id.u128[0].u64[1] = u64_1; - return id; -} - -internal B32 -hs_id_match(HS_ID a, HS_ID b) -{ - B32 result = MemoryMatchStruct(&a, &b); - return result; -} - -internal HS_Key -hs_key_make(HS_Root root, HS_ID id) -{ - HS_Key key = {root, 0, id}; - return key; -} - -internal B32 -hs_key_match(HS_Key a, HS_Key b) -{ - return (MemoryMatchStruct(&a.root, &b.root) && hs_id_match(a.id, b.id)); -} - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -hs_init(void) -{ - Arena *arena = arena_alloc(); - hs_shared = push_array(arena, HS_Shared, 1); - hs_shared->arena = arena; - hs_shared->slots_count = 4096; - hs_shared->stripes_count = Min(hs_shared->slots_count, os_get_system_info()->logical_processor_count); - hs_shared->slots = push_array(arena, HS_BlobSlot, hs_shared->slots_count); - hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count); - hs_shared->stripes_free_nodes = push_array(arena, HS_BlobNode *, hs_shared->stripes_count); - for(U64 idx = 0; idx < hs_shared->stripes_count; idx += 1) - { - HS_Stripe *stripe = &hs_shared->stripes[idx]; - stripe->arena = arena_alloc(); - stripe->rw_mutex = rw_mutex_alloc(); - stripe->cv = cond_var_alloc(); - } - hs_shared->key_slots_count = 4096; - hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_get_system_info()->logical_processor_count); - hs_shared->key_slots = push_array(arena, HS_KeySlot, hs_shared->key_slots_count); - hs_shared->key_stripes = push_array(arena, HS_Stripe, hs_shared->key_stripes_count); - hs_shared->key_stripes_free_nodes = push_array(arena, HS_KeyNode *, hs_shared->key_stripes_count); - for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1) - { - HS_Stripe *stripe = &hs_shared->key_stripes[idx]; - stripe->arena = arena_alloc(); - stripe->rw_mutex = rw_mutex_alloc(); - stripe->cv = cond_var_alloc(); - } - hs_shared->root_slots_count = 4096; - hs_shared->root_stripes_count = Min(hs_shared->root_slots_count, os_get_system_info()->logical_processor_count); - hs_shared->root_slots = push_array(arena, HS_RootSlot, hs_shared->root_slots_count); - hs_shared->root_stripes = push_array(arena, HS_Stripe, hs_shared->root_stripes_count); - hs_shared->root_stripes_free_nodes = push_array(arena, HS_RootNode *, hs_shared->root_stripes_count); - for(U64 idx = 0; idx < hs_shared->root_stripes_count; idx += 1) - { - HS_Stripe *stripe = &hs_shared->root_stripes[idx]; - stripe->arena = arena_alloc(); - stripe->rw_mutex = rw_mutex_alloc(); - stripe->cv = cond_var_alloc(); - } -} - -//////////////////////////////// -//~ rjf: Root Allocation/Deallocation - -internal HS_Root -hs_root_alloc(void) -{ - HS_Root root = {0}; - root.u64[0] = ins_atomic_u64_inc_eval(&hs_shared->root_id_gen); - U64 slot_idx = root.u64[0]%hs_shared->root_slots_count; - U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; - HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; - MutexScopeW(stripe->rw_mutex) - { - HS_RootNode *node = hs_shared->root_stripes_free_nodes[stripe_idx]; - if(node != 0) - { - SLLStackPop(hs_shared->root_stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array(stripe->arena, HS_RootNode, 1); - } - DLLPushBack(slot->first, slot->last, node); - node->root = root; - node->arena = arena_alloc(); - } - return root; -} - -internal void -hs_root_release(HS_Root root) -{ - //- rjf: unpack root - U64 slot_idx = root.u64[0]%hs_shared->root_slots_count; - U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; - HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; - - //- rjf: release root node, grab its arena / ID list - Arena *root_arena = 0; - HS_RootIDChunkList root_ids = {0}; - MutexScopeW(stripe->rw_mutex) - { - for(HS_RootNode *n = slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&root, &n->root)) - { - DLLRemove(slot->first, slot->last, n); - root_arena = n->arena; - root_ids = n->ids; - SLLStackPush(hs_shared->root_stripes_free_nodes[stripe_idx], n); - break; - } - } - } - - //- rjf: release all IDs - for(HS_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next) - { - for EachIndex(chunk_idx, id_chunk_n->count) - { - HS_ID id = id_chunk_n->v[chunk_idx]; - HS_Key key = hs_key_make(root, id); - U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); - U64 key_slot_idx = key_hash%hs_shared->key_slots_count; - U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; - HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; - HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - MutexScopeW(key_stripe->rw_mutex) - { - for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(hs_key_match(n->key, key)) - { - // rjf: release reference to all hashes - for(U64 history_idx = 0; history_idx < HS_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) - { - U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; - U64 hash_slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; - HS_BlobSlot *hash_slot = &hs_shared->slots[hash_slot_idx]; - HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; - MutexScopeR(hash_stripe->rw_mutex) - { - for(HS_BlobNode *n = hash_slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - ins_atomic_u64_dec_eval(&n->key_ref_count); - break; - } - } - } - } - - // rjf: release key node - DLLRemove(key_slot->first, key_slot->last, n); - SLLStackPush(hs_shared->key_stripes_free_nodes[key_stripe_idx], n); - break; - } - } - } - } - } -} - -//////////////////////////////// -//~ rjf: Cache Submission - -internal U128 -hs_submit_data(HS_Key key, Arena **data_arena, String8 data) -{ - U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); - U64 key_slot_idx = key_hash%hs_shared->key_slots_count; - U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; - HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; - HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - U128 hash = hs_hash_from_data(data); - U64 slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - - //- rjf: commit data to cache - if already there, just bump key refcount - ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) - { - HS_BlobNode *existing_node = 0; - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - existing_node = n; - break; - } - } - if(existing_node == 0) - { - HS_BlobNode *node = hs_shared->stripes_free_nodes[stripe_idx]; - if(node) - { - SLLStackPop(hs_shared->stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array(stripe->arena, HS_BlobNode, 1); - } - node->hash = hash; - if(data_arena != 0) - { - node->arena = *data_arena; - } - node->data = data; - node->scope_ref_count = 0; - node->key_ref_count = 1; - DLLPushBack(slot->first, slot->last, node); - } - else - { - existing_node->key_ref_count += 1; - if(data_arena != 0) - { - arena_release(*data_arena); - } - } - if(data_arena != 0) - { - *data_arena = 0; - } - } - - //- rjf: commit this hash to key cache - U128 key_expired_hash = {0}; - ProfScope("commit this hash to key cache") MutexScopeW(key_stripe->rw_mutex) - { - // rjf: find existing key - B32 key_is_new = 0; - HS_KeyNode *key_node = 0; - for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(hs_key_match(n->key, key)) - { - key_node = n; - break; - } - } - - // rjf: create key node if it doesn't exist - if(!key_node) - { - key_is_new = 1; - key_node = hs_shared->key_stripes_free_nodes[key_stripe_idx]; - if(key_node) - { - SLLStackPop(hs_shared->key_stripes_free_nodes[key_stripe_idx]); - } - else - { - key_node = push_array(key_stripe->arena, HS_KeyNode, 1); - } - key_node->key = key; - DLLPushBack(key_slot->first, key_slot->last, key_node); - } - - // rjf: push hash into key's history - if(key_node) - { - if(key_node->hash_history_gen >= HS_KEY_HASH_HISTORY_STRONG_REF_COUNT) - { - key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-HS_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; - } - key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; - key_node->hash_history_gen += 1; - } - - // rjf: key is new -> add this key to the associated root - if(key_is_new) - { - U64 root_hash = hs_little_hash_from_data(str8_struct(&key.root)); - U64 root_slot_idx = root_hash%hs_shared->root_slots_count; - U64 root_stripe_idx = root_slot_idx%hs_shared->root_stripes_count; - HS_RootSlot *root_slot = &hs_shared->root_slots[root_slot_idx]; - HS_Stripe *root_stripe = &hs_shared->root_stripes[root_stripe_idx]; - MutexScopeW(root_stripe->rw_mutex) - { - for(HS_RootNode *n = root_slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&n->root, &key.root)) - { - HS_RootIDChunkNode *chunk = n->ids.last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(n->arena, HS_RootIDChunkNode, 1); - SLLQueuePush(n->ids.first, n->ids.last, chunk); - n->ids.chunk_count += 1; - chunk->cap = 1024; - chunk->v = push_array_no_zero(n->arena, HS_ID, chunk->cap); - } - chunk->v[chunk->count] = key.id; - chunk->count += 1; - n->ids.total_count += 1; - break; - } - } - } - } - } - - //- rjf: decrement key ref count of expired hash - ProfScope("decrement key ref count of expired hash") - if(!u128_match(key_expired_hash, u128_zero())) - { - U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count; - U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; - HS_BlobSlot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; - HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx]; - MutexScopeR(old_hash_stripe->rw_mutex) - { - for(HS_BlobNode *n = old_hash_slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, key_expired_hash)) - { - ins_atomic_u64_dec_eval(&n->key_ref_count); - break; - } - } - } - } - - return hash; -} - -//////////////////////////////// -//~ rjf: Scoped Access - -internal HS_Scope * -hs_scope_open(void) -{ - if(hs_tctx == 0) - { - Arena *arena = arena_alloc(); - hs_tctx = push_array(arena, HS_TCTX, 1); - hs_tctx->arena = arena; - } - HS_Scope *scope = hs_tctx->free_scope; - if(scope) - { - SLLStackPop(hs_tctx->free_scope); - } - else - { - scope = push_array_no_zero(hs_tctx->arena, HS_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -hs_scope_close(HS_Scope *scope) -{ - for(HS_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - U128 hash = touch->hash; - next = touch->next; - U64 slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - SLLStackPush(hs_tctx->free_touch, touch); - } - SLLStackPush(hs_tctx->free_scope, scope); -} - -internal void -hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_BlobNode *node) -{ - HS_Touch *touch = hs_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - if(touch != 0) - { - SLLStackPop(hs_tctx->free_touch); - } - else - { - touch = push_array_no_zero(hs_tctx->arena, HS_Touch, 1); - } - MemoryZeroStruct(touch); - touch->hash = node->hash; - SLLStackPush(scope->top_touch, touch); -} - -//////////////////////////////// -//~ rjf: Downstream Accesses - -internal void -hs_hash_downstream_inc(U128 hash) -{ - U64 slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - ins_atomic_u64_inc_eval(&n->downstream_ref_count); - break; - } - } - } -} - -internal void -hs_hash_downstream_dec(U128 hash) -{ - U64 slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - ins_atomic_u64_dec_eval(&n->downstream_ref_count); - break; - } - } - } -} - -//////////////////////////////// -//~ rjf: Cache Lookup - -internal U128 -hs_hash_from_key(HS_Key key, U64 rewind_count) -{ - U128 result = {0}; - U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); - U64 key_slot_idx = key_hash%hs_shared->key_slots_count; - U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; - HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; - HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - MutexScopeR(key_stripe->rw_mutex) - { - for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(hs_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count) - { - result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)]; - break; - } - } - } - return result; -} - -internal String8 -hs_data_from_hash(HS_Scope *scope, U128 hash) -{ - ProfBeginFunction(); - String8 result = {0}; - U64 slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - result = n->data; - hs_scope_touch_node__stripe_r_guarded(scope, n); - break; - } - } - } - ProfEnd(); - return result; -} - -//////////////////////////////// -//~ rjf: Tick - -internal void -hs_tick(void) -{ - ProfBeginFunction(); - Rng1U64 range = lane_range(hs_shared->slots_count); - for EachInRange(slot_idx, range) - { - U64 stripe_idx = slot_idx%hs_shared->stripes_count; - HS_BlobSlot *slot = &hs_shared->slots[slot_idx]; - HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first; n != 0; n = n->next) - { - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(HS_BlobNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) - { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); - if(n->arena != 0) - { - arena_release(n->arena); - } - } - } - } - } - ProfEnd(); -} diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index 10643b89..e8da7022 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -38,9 +38,9 @@ mtx_init(void) //~ rjf: Buffer Operations internal void -mtx_push_op(HS_Key buffer_key, MTX_Op op) +mtx_push_op(C_Key buffer_key, MTX_Op op) { - U64 hash = hs_little_hash_from_data(str8_struct(&buffer_key)); + U64 hash = c_little_hash_from_data(str8_struct(&buffer_key)); MTX_MutThread *thread = &mtx_shared->mut_threads[hash%mtx_shared->mut_threads_count]; mtx_enqueue_op(thread, buffer_key, op); } @@ -49,7 +49,7 @@ mtx_push_op(HS_Key buffer_key, MTX_Op op) //~ rjf: Mutation Threads internal void -mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) +mtx_enqueue_op(MTX_MutThread *thread, C_Key buffer_key, MTX_Op op) { // TODO(rjf): if op.replace is too big, need to split into multiple edits MutexScope(thread->mutex) for(;;) @@ -71,7 +71,7 @@ mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) } internal void -mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out) +mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, C_Key *buffer_key_out, MTX_Op *op_out) { MutexScope(thread->mutex) for(;;) { @@ -98,16 +98,16 @@ mtx_mut_thread__entry_point(void *p) for(;;) { Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); //- rjf: get next op - HS_Key buffer_key = {0}; + C_Key buffer_key = {0}; MTX_Op op = {0}; mtx_dequeue_op(scratch.arena, mut_thread, &buffer_key, &op); //- rjf: get buffer's current data - U128 hash = hs_hash_from_key(buffer_key, 0); - String8 data = hs_data_from_hash(hs_scope, hash); + U128 hash = c_hash_from_key(buffer_key, 0); + String8 data = c_data_from_hash(c_scope, hash); //- rjf: clamp op by data op.range.min = Min(op.range.min, data.size); @@ -134,10 +134,10 @@ mtx_mut_thread__entry_point(void *p) MemoryCopy(new_data_base+pre_replace_data.size+op.replace.size, post_replace_data.str, post_replace_data.size); } String8 new_data = str8(new_data_base, new_data_size); - hs_submit_data(buffer_key, &arena, new_data); + c_submit_data(buffer_key, &arena, new_data); } - hs_scope_close(hs_scope); + c_scope_close(c_scope); scratch_end(scratch); } } diff --git a/src/mutable_text/mutable_text.h b/src/mutable_text/mutable_text.h index 3957f561..1ff03ce9 100644 --- a/src/mutable_text/mutable_text.h +++ b/src/mutable_text/mutable_text.h @@ -84,13 +84,13 @@ internal void mtx_init(void); //////////////////////////////// //~ rjf: Buffer Operations -internal void mtx_push_op(HS_Key buffer_key, MTX_Op op); +internal void mtx_push_op(C_Key buffer_key, MTX_Op op); //////////////////////////////// //~ rjf: Mutation Threads -internal void mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op); -internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out); +internal void mtx_enqueue_op(MTX_MutThread *thread, C_Key buffer_key, MTX_Op op); +internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, C_Key *buffer_key_out, MTX_Op *op_out); internal void mtx_mut_thread__entry_point(void *p); #endif // MUTABLE_TEXT_H diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 37e9b554..2526c67b 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -166,7 +166,7 @@ ptg_builder_thread__entry_point(void *p) { for(;;) { - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); //- rjf: get next key PTG_Key key = {0}; @@ -214,7 +214,7 @@ ptg_builder_thread__entry_point(void *p) } } - hs_scope_close(scope); + c_scope_close(scope); } } diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 59dbf0e3..140275af 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -517,7 +517,7 @@ Rng1U64 rd_reg_slot_range_table[47] = {OffsetOf(RD_Regs, file_path), OffsetOf(RD_Regs, file_path) + sizeof(String8)}, {OffsetOf(RD_Regs, cursor), OffsetOf(RD_Regs, cursor) + sizeof(TxtPt)}, {OffsetOf(RD_Regs, mark), OffsetOf(RD_Regs, mark) + sizeof(TxtPt)}, -{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(HS_Key)}, +{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(C_Key)}, {OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)}, {OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)}, {OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI_Key)}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index d54928ee..14e419f0 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -463,7 +463,7 @@ U64 inline_depth; String8 file_path; TxtPt cursor; TxtPt mark; -HS_Key text_key; +C_Key text_key; TXT_LangKind lang_kind; D_LineList lines; DI_Key dbgi_key; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 7248a67a..b1175fde 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -733,7 +733,7 @@ RD_RegTable: {String8 file_path FilePath } {TxtPt cursor Cursor } {TxtPt mark Mark } - {HS_Key text_key TextKey } + {C_Key text_key TextKey } {TXT_LangKind lang_kind LangKind } {D_LineList lines Lines } {DI_Key dbgi_key DbgiKey } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index ac3cea31..f0609721 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1746,13 +1746,13 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) //- rjf: reads from hash store key case E_SpaceKind_HashStoreKey: { - HS_Root root = {space.u64_0}; - HS_ID id = {space.u128}; - HS_Key key = hs_key_make(root, id); - U128 hash = hs_hash_from_key(key, 0); - HS_Scope *scope = hs_scope_open(); + C_Root root = {space.u64_0}; + C_ID id = {space.u128}; + C_Key key = c_key_make(root, id); + U128 hash = c_hash_from_key(key, 0); + C_Scope *scope = c_scope_open(); { - String8 data = hs_data_from_hash(scope, hash); + String8 data = c_data_from_hash(scope, hash); Rng1U64 legal_range = r1u64(0, data.size); Rng1U64 read_range = intersect_1u64(range, legal_range); if(read_range.min < read_range.max) @@ -1761,7 +1761,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, data.str + read_range.min, dim_1u64(read_range)); } } - hs_scope_close(scope); + c_scope_close(scope); }break; //- rjf: file reads @@ -1779,13 +1779,13 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) containing_range.max -= containing_range.max%chunk_size; // rjf: map to hash - HS_Key key = fs_key_from_path_range(file_path, containing_range, 0); - U128 hash = hs_hash_from_key(key, 0); + C_Key key = fs_key_from_path_range(file_path, containing_range, 0); + U128 hash = c_hash_from_key(key, 0); // rjf: look up from hash store - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); { - String8 data = hs_data_from_hash(scope, hash); + String8 data = c_data_from_hash(scope, hash); Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size); Rng1U64 read_range = intersect_1u64(range, legal_range); if(read_range.min < read_range.max) @@ -1794,7 +1794,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range)); } } - hs_scope_close(scope); + c_scope_close(scope); }break; //- rjf: interior control entity reads (inside process address space or thread register block) @@ -2137,17 +2137,17 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) //- rjf: asynchronous streamed reads -> hashes from spaces -internal HS_Key +internal C_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) { - HS_Key result = {0}; + C_Key result = {0}; switch(space.kind) { case E_SpaceKind_HashStoreKey: { - HS_Root root = {space.u64_0}; - HS_ID id = {space.u128}; - result = hs_key_make(root, id); + C_Root root = {space.u64_0}; + C_ID id = {space.u128}; + result = c_key_make(root, id); }break; case E_SpaceKind_File: { @@ -2177,16 +2177,16 @@ rd_whole_range_from_eval_space(E_Space space) { case E_SpaceKind_HashStoreKey: { - HS_Root root = {space.u64_0}; - HS_ID id = {space.u128}; - HS_Key key = hs_key_make(root, id); - U128 hash = hs_hash_from_key(key, 0); - HS_Scope *hs_scope = hs_scope_open(); + C_Root root = {space.u64_0}; + C_ID id = {space.u128}; + C_Key key = c_key_make(root, id); + U128 hash = c_hash_from_key(key, 0); + C_Scope *c_scope = c_scope_open(); { - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); result = r1u64(0, data.size); } - hs_scope_close(hs_scope); + c_scope_close(c_scope); }break; case E_SpaceKind_File: { @@ -2872,17 +2872,17 @@ rd_view_ui(Rng2F32 rect) // rjf: unpack view's target expression & hash E_Eval eval = e_eval_from_string(expr_string); Rng1U64 range = r1u64(0, 1024); - HS_Key key = rd_key_from_eval_space_range(eval.space, range, 0); - U128 hash = hs_hash_from_key(key, 0); + C_Key key = rd_key_from_eval_space_range(eval.space, range, 0); + U128 hash = c_hash_from_key(key, 0); // rjf: determine if hash's blob is ready, and which viewer to use B32 data_is_ready = 0; String8 new_view_name = {0}; { - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); if(!u128_match(hash, u128_zero())) { - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); U64 num_utf8_bytes = 0; U64 num_unknown_bytes = 0; for(U64 idx = 0; idx < data.size && idx < range.max;) @@ -2911,7 +2911,7 @@ rd_view_ui(Rng2F32 rect) new_view_name = str8_lit("memory"); } } - hs_scope_close(hs_scope); + c_scope_close(c_scope); } // rjf: if we don't have a viewer, just use the memory viewer. @@ -5993,7 +5993,7 @@ rd_window_frame(void) //- rjf: @window_frame_part compute window's theme // { - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); //- rjf: try to find theme settings from the project, then the user. RD_CfgList colors_cfgs = {0}; @@ -6039,7 +6039,7 @@ rd_window_frame(void) } //- rjf: map the theme config to the associated tree (either from a preset, or from a file) - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme_cfg->first->string); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme_cfg->first->string); if(colors_cfgs.count == 0 && theme_tree == &md_nil_node) { theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; @@ -6110,7 +6110,7 @@ rd_window_frame(void) } } - hs_scope_close(hs_scope); + c_scope_close(c_scope); } ////////////////////////////// @@ -10205,7 +10205,7 @@ rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) //- rjf: colors internal MD_Node * -rd_theme_tree_from_name(Arena *arena, HS_Scope *scope, String8 theme_name) +rd_theme_tree_from_name(Arena *arena, C_Scope *scope, String8 theme_name) { Temp scratch = scratch_begin(&arena, 1); MD_Node *theme_tree = &md_nil_node; @@ -10228,7 +10228,7 @@ rd_theme_tree_from_name(Arena *arena, HS_Scope *scope, String8 theme_name) endt_us = os_now_microseconds()+50000; } U128 hash = fs_hash_from_path_range(path, r1u64(0, max_U64), endt_us); - String8 data = hs_data_from_hash(scope, hash); + String8 data = c_data_from_hash(scope, hash); theme_tree = md_tree_from_string(arena, data); } } @@ -10864,10 +10864,10 @@ rd_init(CmdLine *cmdln) rd_state->user_path_arena = arena_alloc(); rd_state->project_path_arena = arena_alloc(); rd_state->theme_path_arena = arena_alloc(); - rd_state->user_cfg_string_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); - rd_state->project_cfg_string_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); - rd_state->cmdln_cfg_string_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); - rd_state->transient_cfg_string_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); + rd_state->user_cfg_string_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); + rd_state->project_cfg_string_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); + rd_state->cmdln_cfg_string_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); + rd_state->transient_cfg_string_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); for(U64 idx = 0; idx < ArrayCount(rd_state->frame_arenas); idx += 1) { rd_state->frame_arenas[idx] = arena_alloc(); @@ -11272,7 +11272,7 @@ rd_frame(void) { struct { - HS_Key key; + C_Key key; String8 name; } table[] = @@ -11288,7 +11288,7 @@ rd_frame(void) String8 data = rd_string_from_cfg_tree(arena, str8_zero(), rd_cfg_child_from_string(rd_state->root_cfg, table[idx].name)); - hs_submit_data(table[idx].key, &arena, data); + c_submit_data(table[idx].key, &arena, data); } } #endif @@ -12459,10 +12459,10 @@ rd_frame(void) //- rjf: add macro for output log { - HS_Scope *hs_scope = hs_scope_open(); - HS_Key key = d_state->output_log_key; - U128 hash = hs_hash_from_key(key, 0); - String8 data = hs_data_from_hash(hs_scope, hash); + C_Scope *c_scope = c_scope_open(); + C_Key key = d_state->output_log_key; + U128 hash = c_hash_from_key(key, 0); + String8 data = c_data_from_hash(c_scope, hash); E_Space space = e_space_make(E_SpaceKind_HashStoreKey); space.u64_0 = key.root.u64[0]; space.u128 = key.id.u128[0]; @@ -12471,7 +12471,7 @@ rd_frame(void) expr->mode = E_Mode_Offset; expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("output"), expr); - hs_scope_close(hs_scope); + c_scope_close(c_scope); } //- rjf: (DEBUG) add macro for cfg strings @@ -12479,7 +12479,7 @@ rd_frame(void) { struct { - HS_Key key; + C_Key key; String8 name; } table[] = @@ -12491,10 +12491,10 @@ rd_frame(void) }; for EachElement(idx, table) { - HS_Scope *hs_scope = hs_scope_open(); - HS_Key key = table[idx].key; - U128 hash = hs_hash_from_key(key, 0); - String8 data = hs_data_from_hash(hs_scope, hash); + C_Scope *c_scope = c_scope_open(); + C_Key key = table[idx].key; + U128 hash = c_hash_from_key(key, 0); + String8 data = c_data_from_hash(c_scope, hash); E_Space space = e_space_make(E_SpaceKind_HashStoreKey); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); space.u64_0 = key.root.u64[0]; @@ -12503,7 +12503,7 @@ rd_frame(void) expr->mode = E_Mode_Offset; expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); e_string2expr_map_insert(scratch.arena, macro_map, table[idx].name, expr); - hs_scope_close(hs_scope); + c_scope_close(c_scope); } } #endif @@ -15936,10 +15936,10 @@ rd_frame(void) }break; case RD_CmdKind_AddThemeColor: { - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme->first->string); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme->first->string); if(theme_tree == &md_nil_node) { rd_cfg_new_replace(theme, rd_theme_preset_display_string_table[RD_ThemePreset_DefaultDark]); @@ -15948,11 +15948,11 @@ rd_frame(void) rd_cfg_new(color, str8_lit("tags")); RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); rd_cfg_new(value, str8_lit("0xffffffff")); - hs_scope_close(hs_scope); + c_scope_close(c_scope); }break; case RD_CmdKind_ForkTheme: { - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); for(RD_CfgNode *n = colors.first; n != 0; n = n->next) @@ -15961,7 +15961,7 @@ rd_frame(void) } RD_Cfg *theme_cfg = rd_cfg_child_from_string(parent, str8_lit("theme")); String8 theme_name = theme_cfg->first->string; - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme_name); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme_name); if(theme_tree == &md_nil_node) { theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; @@ -15978,7 +15978,7 @@ rd_frame(void) } } rd_cfg_release(theme_cfg); - hs_scope_close(hs_scope); + c_scope_close(c_scope); }break; case RD_CmdKind_SaveTheme: case RD_CmdKind_SaveAndSetTheme: @@ -16091,15 +16091,15 @@ rd_frame(void) case RD_CmdKind_GoToNameAtCursor: case RD_CmdKind_ToggleWatchExpressionAtCursor: { - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); RD_Regs *regs = rd_regs(); - HS_Key text_key = regs->text_key; + C_Key text_key = regs->text_key; TXT_LangKind lang_kind = regs->lang_kind; TxtRng range = txt_rng(regs->cursor, regs->mark); U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, text_key, lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); Rng1U64 expr_off_range = {0}; if(range.min.column != range.max.column) { @@ -16115,7 +16115,7 @@ rd_frame(void) RD_CmdKind_GoToName), .string = expr); txt_scope_close(txt_scope); - hs_scope_close(hs_scope); + c_scope_close(c_scope); }break; case RD_CmdKind_SetNextStatement: { diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index f56ec8ed..6aa379ec 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -571,10 +571,10 @@ struct RD_State F32 tooltip_animation_rate; // rjf: serialized config debug string keys - HS_Key user_cfg_string_key; - HS_Key project_cfg_string_key; - HS_Key cmdln_cfg_string_key; - HS_Key transient_cfg_string_key; + C_Key user_cfg_string_key; + C_Key project_cfg_string_key; + C_Key cmdln_cfg_string_key; + C_Key transient_cfg_string_key; // rjf: schema table MD_NodePtrList *schemas; @@ -898,7 +898,7 @@ internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range internal B32 rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range); //- rjf: asynchronous streamed reads -> hashes from spaces -internal HS_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated); +internal C_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated); //- rjf: space -> entire range internal Rng1U64 rd_whole_range_from_eval_space(E_Space space); @@ -988,7 +988,7 @@ internal void rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs); //~ rjf: Colors, Fonts, Config //- rjf: colors -internal MD_Node *rd_theme_tree_from_name(Arena *arena, HS_Scope *scope, String8 theme_name); +internal MD_Node *rd_theme_tree_from_name(Arena *arena, C_Scope *scope, String8 theme_name); internal Vec4F32 rd_rgba_from_code_color_slot(RD_CodeColorSlot slot); internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind(TXT_TokenKind kind); internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string); diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index eeda6184..27ad88a6 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -225,7 +225,7 @@ #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" #include "mdesk/mdesk.h" -#include "hash_store/hash_store.h" +#include "content/content.h" #include "file_stream/file_stream.h" #include "text_cache/text_cache.h" #include "mutable_text/mutable_text.h" @@ -274,7 +274,7 @@ #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" #include "mdesk/mdesk.c" -#include "hash_store/hash_store.c" +#include "content/content.c" #include "file_stream/file_stream.c" #include "text_cache/text_cache.c" #include "mutable_text/mutable_text.c" diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 73b687d9..43a17b9e 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1944,8 +1944,8 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); dr_fstrs_push_new(arena, &fstrs, ¶ms, name); { - HS_Scope *hs_scope = hs_scope_open(); - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, name); + C_Scope *c_scope = c_scope_open(); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, name); U64 color_idx = 0; for(MD_Node *n = theme_tree; color_idx < 4 && !md_node_is_nil(n); n = md_node_rec_depth_first_pre(n, theme_tree).next) { @@ -1973,7 +1973,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla } } } - hs_scope_close(hs_scope); + c_scope_close(c_scope); } result.eval_fstrs = fstrs; }break; @@ -2025,7 +2025,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) RD_CodeViewState *cv = rd_view_state(RD_CodeViewState); rd_code_view_init(cv); Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); ////////////////////////////// @@ -2091,7 +2091,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) } U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); + String8 data = c_data_from_hash(c_scope, hash); B32 file_is_missing = (rd_regs()->file_path.size != 0 && os_properties_from_file_path(rd_regs()->file_path).modified == 0); B32 key_has_data = !u128_match(hash, u128_zero()) && info.lines_count; ProfEnd(); @@ -2251,7 +2251,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) rd_store_view_param_s64(str8_lit("mark_column"), rd_regs()->mark.column); txt_scope_close(txt_scope); - hs_scope_close(hs_scope); + c_scope_close(c_scope); scratch_end(scratch); } @@ -2291,7 +2291,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) } RD_CodeViewState *cv = &dv->cv; Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); DASM_Scope *dasm_scope = dasm_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); @@ -2399,7 +2399,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) syntax = DASM_Syntax_ATT; } } - HS_Key dasm_key = rd_key_from_eval_space_range(space, range, 0); + C_Key dasm_key = rd_key_from_eval_space_range(space, range, 0); U128 dasm_data_hash = {0}; DASM_Params dasm_params = {0}; { @@ -2415,7 +2415,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) rd_regs()->lang_kind = txt_lang_kind_from_arch(arch); U128 dasm_text_hash = {0}; TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); - String8 dasm_text_data = hs_data_from_hash(hs_scope, dasm_text_hash); + String8 dasm_text_data = c_data_from_hash(c_scope, dasm_text_hash); B32 has_disasm = (dasm_info.lines.count != 0 && dasm_text_info.lines_count != 0); B32 is_loading = (!has_disasm && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); @@ -2497,7 +2497,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) txt_scope_close(txt_scope); dasm_scope_close(dasm_scope); - hs_scope_close(hs_scope); + c_scope_close(c_scope); scratch_end(scratch); } @@ -3826,7 +3826,7 @@ EV_EXPAND_RULE_INFO_FUNCTION_DEF(bitmap) RD_VIEW_UI_FUNCTION_DEF(bitmap) { Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); + C_Scope *c_scope = c_scope_open(); TEX_Scope *tex_scope = tex_scope_open(); ////////////////////////////// @@ -3874,11 +3874,11 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) ////////////////////////////// //- rjf: map expression artifacts -> texture // - HS_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); + C_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); TEX_Topology topology = tex_topology_make(dim, fmt); U128 data_hash = {0}; R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology, &data_hash); - String8 data = hs_data_from_hash(hs_scope, data_hash); + String8 data = c_data_from_hash(c_scope, data_hash); ////////////////////////////// //- rjf: equip loading info @@ -4031,7 +4031,7 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) rd_store_view_param_f32(str8_lit("x"), view_center_pos.x); rd_store_view_param_f32(str8_lit("y"), view_center_pos.y); - hs_scope_close(hs_scope); + c_scope_close(c_scope); tex_scope_close(tex_scope); scratch_end(scratch); } @@ -4364,8 +4364,8 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d) U64 base_offset = eval_range.min; Rng1U64 idxs_range = r1u64(base_offset, base_offset+count*sizeof(U32)); Rng1U64 vtxs_range = r1u64(vtx_base_off, vtx_base_off+vtx_size); - HS_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); - HS_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); + C_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); + C_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); R_Handle idxs_buffer = geo_buffer_from_key(geo_scope, idxs_key); R_Handle vtxs_buffer = geo_buffer_from_key(geo_scope, vtxs_key); diff --git a/src/tester/tester_main.c b/src/tester/tester_main.c index 604ca440..b221159e 100644 --- a/src/tester/tester_main.c +++ b/src/tester/tester_main.c @@ -14,7 +14,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" -#include "hash_store/hash_store.h" +#include "content/content.h" #include "rdi_format/rdi_format_local.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" @@ -23,7 +23,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" -#include "hash_store/hash_store.c" +#include "content/content.c" #include "rdi_format/rdi_format_local.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" @@ -148,7 +148,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) Temp scratch = scratch_begin(0, 0); String8 path = n->string; String8 data = os_data_from_file_path(scratch.arena, path); - rdi_hashes[idx] = hs_hash_from_data(data); + rdi_hashes[idx] = c_hash_from_data(data); rdi_paths_array[idx] = path; scratch_end(scratch); } @@ -160,7 +160,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) Temp scratch = scratch_begin(0, 0); String8 path = n->string; String8 data = os_data_from_file_path(scratch.arena, path); - dump_hashes[idx] = hs_hash_from_data(data); + dump_hashes[idx] = c_hash_from_data(data); dump_paths_array[idx] = path; scratch_end(scratch); } diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 0a17218a..4de63258 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1771,12 +1771,12 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) } internal TXT_TextInfo -txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out) +txt_text_info_from_key_lang(TXT_Scope *scope, C_Key key, TXT_LangKind lang, U128 *hash_out) { TXT_TextInfo result = {0}; - for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { - U128 hash = hs_hash_from_key(key, rewind_idx); + U128 hash = c_hash_from_key(key, rewind_idx); result = txt_text_info_from_hash_lang(scope, hash, lang); if(result.lines_count != 0) { @@ -2206,7 +2206,7 @@ ASYNC_WORK_DEF(txt_parse_work) U128 hash = {0}; TXT_LangKind lang = TXT_LangKind_Null; txt_u2p_dequeue_req(&hash, &lang); - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); //- rjf: unpack hash U64 slot_idx = hash.u64[1]%txt_shared->slots_count; @@ -2232,7 +2232,7 @@ ASYNC_WORK_DEF(txt_parse_work) String8 data = {0}; if(got_task) { - data = hs_data_from_hash(scope, hash); + data = c_data_from_hash(scope, hash); } //- rjf: data -> text info @@ -2488,7 +2488,7 @@ ASYNC_WORK_DEF(txt_parse_work) { if(u128_match(n->hash, hash) && n->lang == lang) { - hs_hash_downstream_inc(n->hash); + c_hash_downstream_inc(n->hash); n->arena = info_arena; info.bytes_processed = n->info.bytes_processed; info.bytes_to_process = n->info.bytes_to_process; @@ -2500,7 +2500,7 @@ ASYNC_WORK_DEF(txt_parse_work) } } - hs_scope_close(scope); + c_scope_close(scope); ProfEnd(); return 0; } @@ -2551,7 +2551,7 @@ txt_evictor_thread__entry_point(void *p) n->is_working == 0) { DLLRemove(slot->first, slot->last, n); - hs_hash_downstream_dec(n->hash); + c_hash_downstream_dec(n->hash); if(n->arena != 0) { arena_release(n->arena); diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index e08494ff..dac93a8c 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -308,7 +308,7 @@ internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node //~ rjf: Cache Lookups internal TXT_TextInfo txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang); -internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out); +internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, C_Key key, TXT_LangKind lang, U128 *hash_out); //////////////////////////////// //~ rjf: Text Info Extractor Helpers diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index a837f599..46413d63 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -196,12 +196,12 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog } internal R_Handle -tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out) +tex_texture_from_key_topology(TEX_Scope *scope, C_Key key, TEX_Topology topology, U128 *hash_out) { R_Handle handle = {0}; - for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { - U128 hash = hs_hash_from_key(key, rewind_idx); + U128 hash = c_hash_from_key(key, rewind_idx); handle = tex_texture_from_hash_topology(scope, hash, topology); if(!r_handle_match(handle, r_handle_zero())) { @@ -266,7 +266,7 @@ tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) ASYNC_WORK_DEF(tex_xfer_work) { ProfBeginFunction(); - HS_Scope *scope = hs_scope_open(); + C_Scope *scope = c_scope_open(); //- rjf: decode U128 hash = {0}; @@ -297,7 +297,7 @@ ASYNC_WORK_DEF(tex_xfer_work) String8 data = {0}; if(got_task) { - data = hs_data_from_hash(scope, hash); + data = c_data_from_hash(scope, hash); } //- rjf: data * topology -> texture @@ -322,7 +322,7 @@ ASYNC_WORK_DEF(tex_xfer_work) } } - hs_scope_close(scope); + c_scope_close(scope); ProfEnd(); return 0; } diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 818a3406..b91007b3 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -135,7 +135,7 @@ internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node //~ rjf: Cache Lookups internal R_Handle tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology); -internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out); +internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, C_Key key, TEX_Topology topology, U128 *hash_out); //////////////////////////////// //~ rjf: Transfer Threads From 1b93dbd4bd3a8a15220f604cd656e873492b0368 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 15:21:22 -0700 Subject: [PATCH 207/302] promote content scope to base layer, rename as 'access'; generalize based just on list of scope refcounts, + optional cvs; eliminate c_scope; replace dasm_scope with access as well --- src/base/base_thread_context.c | 55 ++++++++++ src/base/base_thread_context.h | 28 +++++ src/content/content.c | 150 +++++++------------------- src/content/content.h | 50 ++------- src/ctrl/ctrl_core.c | 8 +- src/dasm_cache/dasm_cache.c | 74 ++----------- src/dasm_cache/dasm_cache.h | 30 +----- src/geo_cache/geo_cache.c | 6 +- src/mutable_text/mutable_text.c | 6 +- src/ptr_graph_cache/ptr_graph_cache.c | 4 +- src/raddbg/raddbg_core.c | 58 +++++----- src/raddbg/raddbg_core.h | 2 +- src/raddbg/raddbg_views.c | 28 +++-- src/text_cache/text_cache.c | 6 +- src/texture_cache/texture_cache.c | 6 +- 15 files changed, 203 insertions(+), 308 deletions(-) diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index c13123fa..465fcb37 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -130,3 +130,58 @@ tctx_read_srcloc(char **file_name, U64 *line_number) *file_name = tctx->file_name; *line_number = tctx->line_number; } + +//////////////////////////////// +//~ rjf: Touch Scope Functions + +internal Access * +access_open(void) +{ + if(tctx_thread_local->access_arena == 0) + { + tctx_thread_local->access_arena = arena_alloc(); + } + Access *access = tctx_thread_local->free_access; + if(access != 0) + { + SLLStackPop(tctx_thread_local->free_access); + } + else + { + access = push_array_no_zero(tctx_thread_local->access_arena, Access, 1); + } + MemoryZeroStruct(access); + return access; +} + +internal void +access_close(Access *access) +{ + for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next) + { + next = touch->next; + ins_atomic_u64_dec_eval(touch->touch_count); + if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); } + SLLStackPush(tctx_thread_local->free_touch, touch); + } + SLLStackPush(tctx_thread_local->free_access, access); +} + +internal void +access_touch(Access *access, U64 *touch_count, CondVar cv) +{ + ins_atomic_u64_inc_eval(touch_count); + Touch *touch = tctx_thread_local->free_touch; + if(touch != 0) + { + SLLStackPop(tctx_thread_local->free_touch); + } + else + { + touch = push_array_no_zero(tctx_thread_local->access_arena, Touch, 1); + } + MemoryZeroStruct(touch); + SLLStackPush(access->top_touch, touch); + touch->cv = cv; + touch->touch_count = touch_count; +} diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 0f6952aa..cfd9e18b 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -15,6 +15,24 @@ struct LaneCtx Barrier barrier; }; +//////////////////////////////// +//~ rjf: Access Scopes + +typedef struct Touch Touch; +struct Touch +{ + Touch *next; + U64 *touch_count; + CondVar cv; +}; + +typedef struct Access Access; +struct Access +{ + Access *next; + Touch *top_touch; +}; + //////////////////////////////// //~ rjf: Base Per-Thread State Bundle @@ -34,6 +52,11 @@ struct TCTX // rjf: source location info char *file_name; U64 line_number; + + // rjf: accesses + Arena *access_arena; + Access *free_access; + Touch *free_touch; }; //////////////////////////////// @@ -69,4 +92,9 @@ internal void tctx_write_srcloc(char *file_name, U64 line_number); internal void tctx_read_srcloc(char **file_name, U64 *line_number); #define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) +//- rjf: access scopes +internal Access *access_open(void); +internal void access_close(Access *access); +internal void access_touch(Access *access, U64 *touch_count, CondVar cv); + #endif // BASE_THREAD_CONTEXT_H diff --git a/src/content/content.c b/src/content/content.c index b0fe33fc..4995f600 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -67,14 +67,14 @@ c_init(void) Arena *arena = arena_alloc(); c_shared = push_array(arena, C_Shared, 1); c_shared->arena = arena; - c_shared->slots_count = 4096; - c_shared->stripes_count = Min(c_shared->slots_count, os_get_system_info()->logical_processor_count); - c_shared->slots = push_array(arena, C_BlobSlot, c_shared->slots_count); - c_shared->stripes = push_array(arena, C_Stripe, c_shared->stripes_count); - c_shared->stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->stripes_count); - for(U64 idx = 0; idx < c_shared->stripes_count; idx += 1) + c_shared->blob_slots_count = 16384; + c_shared->blob_stripes_count = Min(c_shared->blob_slots_count, os_get_system_info()->logical_processor_count); + c_shared->blob_slots = push_array(arena, C_BlobSlot, c_shared->blob_slots_count); + c_shared->blob_stripes = push_array(arena, C_Stripe, c_shared->blob_stripes_count); + c_shared->blob_stripes_free_nodes = push_array(arena, C_BlobNode *, c_shared->blob_stripes_count); + for(U64 idx = 0; idx < c_shared->blob_stripes_count; idx += 1) { - C_Stripe *stripe = &c_shared->stripes[idx]; + C_Stripe *stripe = &c_shared->blob_stripes[idx]; stripe->arena = arena_alloc(); stripe->rw_mutex = rw_mutex_alloc(); stripe->cv = cond_var_alloc(); @@ -184,10 +184,10 @@ c_root_release(C_Root root) for(U64 history_idx = 0; history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) { U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; - U64 hash_slot_idx = hash.u64[1]%c_shared->slots_count; - U64 hash_stripe_idx = hash_slot_idx%c_shared->stripes_count; - C_BlobSlot *hash_slot = &c_shared->slots[hash_slot_idx]; - C_Stripe *hash_stripe = &c_shared->stripes[hash_stripe_idx]; + U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx]; + C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx]; MutexScopeR(hash_stripe->rw_mutex) { for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next) @@ -224,10 +224,10 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; U128 hash = c_hash_from_data(data); - U64 slot_idx = hash.u64[1]%c_shared->slots_count; - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; //- rjf: commit data to cache - if already there, just bump key refcount ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex) @@ -243,10 +243,10 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) } if(existing_node == 0) { - C_BlobNode *node = c_shared->stripes_free_nodes[stripe_idx]; + C_BlobNode *node = c_shared->blob_stripes_free_nodes[stripe_idx]; if(node) { - SLLStackPop(c_shared->stripes_free_nodes[stripe_idx]); + SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]); } else { @@ -357,10 +357,10 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) ProfScope("decrement key ref count of expired hash") if(!u128_match(key_expired_hash, u128_zero())) { - U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->slots_count; - U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->stripes_count; - C_BlobSlot *old_hash_slot = &c_shared->slots[old_hash_slot_idx]; - C_Stripe *old_hash_stripe = &c_shared->stripes[old_hash_stripe_idx]; + U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count; + U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx]; + C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx]; MutexScopeR(old_hash_stripe->rw_mutex) { for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next) @@ -377,86 +377,16 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) return hash; } -//////////////////////////////// -//~ rjf: Scoped Access - -internal C_Scope * -c_scope_open(void) -{ - if(c_tctx == 0) - { - Arena *arena = arena_alloc(); - c_tctx = push_array(arena, C_TCTX, 1); - c_tctx->arena = arena; - } - C_Scope *scope = c_tctx->free_scope; - if(scope) - { - SLLStackPop(c_tctx->free_scope); - } - else - { - scope = push_array_no_zero(c_tctx->arena, C_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -c_scope_close(C_Scope *scope) -{ - for(C_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - U128 hash = touch->hash; - next = touch->next; - U64 slot_idx = hash.u64[1]%c_shared->slots_count; - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(C_BlobNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - SLLStackPush(c_tctx->free_touch, touch); - } - SLLStackPush(c_tctx->free_scope, scope); -} - -internal void -c_scope_touch_node__stripe_r_guarded(C_Scope *scope, C_BlobNode *node) -{ - C_Touch *touch = c_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - if(touch != 0) - { - SLLStackPop(c_tctx->free_touch); - } - else - { - touch = push_array_no_zero(c_tctx->arena, C_Touch, 1); - } - MemoryZeroStruct(touch); - touch->hash = node->hash; - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Downstream Accesses internal void c_hash_downstream_inc(U128 hash) { - U64 slot_idx = hash.u64[1]%c_shared->slots_count; - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { for(C_BlobNode *n = slot->first; n != 0; n = n->next) @@ -473,10 +403,10 @@ c_hash_downstream_inc(U128 hash) internal void c_hash_downstream_dec(U128 hash) { - U64 slot_idx = hash.u64[1]%c_shared->slots_count; - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { for(C_BlobNode *n = slot->first; n != 0; n = n->next) @@ -517,14 +447,14 @@ c_hash_from_key(C_Key key, U64 rewind_count) } internal String8 -c_data_from_hash(C_Scope *scope, U128 hash) +c_data_from_hash(Access *access, U128 hash) { ProfBeginFunction(); String8 result = {0}; - U64 slot_idx = hash.u64[1]%c_shared->slots_count; - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; MutexScopeR(stripe->rw_mutex) { for(C_BlobNode *n = slot->first; n != 0; n = n->next) @@ -532,7 +462,7 @@ c_data_from_hash(C_Scope *scope, U128 hash) if(u128_match(n->hash, hash)) { result = n->data; - c_scope_touch_node__stripe_r_guarded(scope, n); + access_touch(access, &n->scope_ref_count, stripe->cv); break; } } @@ -548,12 +478,12 @@ internal void c_tick(void) { ProfBeginFunction(); - Rng1U64 range = lane_range(c_shared->slots_count); + Rng1U64 range = lane_range(c_shared->blob_slots_count); for EachInRange(slot_idx, range) { - U64 stripe_idx = slot_idx%c_shared->stripes_count; - C_BlobSlot *slot = &c_shared->slots[slot_idx]; - C_Stripe *stripe = &c_shared->stripes[stripe_idx]; + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; B32 slot_has_work = 0; MutexScopeR(stripe->rw_mutex) { @@ -580,7 +510,7 @@ c_tick(void) if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) { DLLRemove(slot->first, slot->last, n); - SLLStackPush(c_shared->stripes_free_nodes[stripe_idx], n); + SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n); if(n->arena != 0) { arena_release(n->arena); diff --git a/src/content/content.h b/src/content/content.h index 6a0ecd5f..b91ad606 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -155,34 +155,6 @@ struct C_Stripe CondVar cv; }; -//////////////////////////////// -//~ rjf: Scoped Access - -typedef struct C_Touch C_Touch; -struct C_Touch -{ - C_Touch *next; - U128 hash; -}; - -typedef struct C_Scope C_Scope; -struct C_Scope -{ - C_Scope *next; - C_Touch *top_touch; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct C_TCTX C_TCTX; -struct C_TCTX -{ - Arena *arena; - C_Scope *free_scope; - C_Touch *free_touch; -}; - //////////////////////////////// //~ rjf: Shared State @@ -191,12 +163,12 @@ struct C_Shared { Arena *arena; - // rjf: main data cache - U64 slots_count; - U64 stripes_count; - C_BlobSlot *slots; - C_Stripe *stripes; - C_BlobNode **stripes_free_nodes; + // rjf: main data blob cache + U64 blob_slots_count; + U64 blob_stripes_count; + C_BlobSlot *blob_slots; + C_Stripe *blob_stripes; + C_BlobNode **blob_stripes_free_nodes; // rjf: key cache U64 key_slots_count; @@ -217,7 +189,6 @@ struct C_Shared //////////////////////////////// //~ rjf: Globals -thread_static C_TCTX *c_tctx = 0; global C_Shared *c_shared = 0; //////////////////////////////// @@ -246,13 +217,6 @@ internal void c_root_release(C_Root root); internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data); -//////////////////////////////// -//~ rjf: Scoped Access - -internal C_Scope *c_scope_open(void); -internal void c_scope_close(C_Scope *scope); -internal void c_scope_touch_node__stripe_r_guarded(C_Scope *scope, C_BlobNode *node); - //////////////////////////////// //~ rjf: Downstream Accesses @@ -263,7 +227,7 @@ internal void c_hash_downstream_dec(U128 hash); //~ rjf: Cache Lookups internal U128 c_hash_from_key(C_Key key, U64 rewind_count); -internal String8 c_data_from_hash(C_Scope *scope, U128 hash); +internal String8 c_data_from_hash(Access *access, U128 hash); //////////////////////////////// //~ rjf: Tick diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index a2412766..9456ddc6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1851,7 +1851,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn range.max <= 0x000FFFFFFFFFFFFFull) { Temp scratch = scratch_begin(&arena, 1); - C_Scope *scope = c_scope_open(); + Access *access = access_open(); CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; //- rjf: unpack address range, prepare per-touched-page info @@ -1889,7 +1889,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) { // rjf: read data for this page - String8 data = c_data_from_hash(scope, page_hashes[page_idx]); + String8 data = c_data_from_hash(access, page_hashes[page_idx]); Rng1U64 data_vaddr_range = r1u64(page_range.min + page_idx*page_size, page_range.min + page_idx*page_size+data.size); // rjf: skip/chop bytes which are irrelevant for the actual requested read @@ -1925,7 +1925,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn // fill out changed flags if(!u128_match(page_hashes[page_idx], page_last_hashes[page_idx])) ProfScope("hashes don't match; diff each byte") { - String8 last_data = c_data_from_hash(scope, page_last_hashes[page_idx]); + String8 last_data = c_data_from_hash(access, page_last_hashes[page_idx]); String8 in_range_last_data = last_data; if(page_idx == page_count-1 && data_vaddr_range.max > range.max) { @@ -1977,7 +1977,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn } } - c_scope_close(scope); + access_close(access); scratch_end(scratch); } ProfEnd(); diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index ba351817..991a067e 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -277,67 +277,11 @@ dasm_init(void) dasm_shared->req_arena = arena_alloc(); } -//////////////////////////////// -//~ rjf: Scoped Access - -internal DASM_Scope * -dasm_scope_open(void) -{ - if(dasm_tctx == 0) - { - Arena *arena = arena_alloc(); - dasm_tctx = push_array(arena, DASM_TCTX, 1); - dasm_tctx->arena = arena; - } - U64 base_pos = arena_pos(dasm_tctx->arena); - DASM_Scope *scope = push_array(dasm_tctx->arena, DASM_Scope, 1); - scope->base_pos = base_pos; - return scope; -} - -internal void -dasm_scope_close(DASM_Scope *scope) -{ - for(DASM_Touch *t = scope->top_touch, *next = 0; t != 0; t = next) - { - next = t->next; - U64 slot_idx = t->hash.u64[1]%dasm_shared->slots_count; - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(t->hash, n->hash) && dasm_params_match(&t->params, &n->params)) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - } - arena_pop_to(dasm_tctx->arena, scope->base_pos); -} - -internal void -dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node) -{ - DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1); - ins_atomic_u64_inc_eval(&node->scope_ref_count); - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); - touch->hash = node->hash; - MemoryCopyStruct(&touch->params, &node->params); - touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key); - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Cache Lookups internal DASM_Info -dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) +dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) { DASM_Info info = {0}; if(!u128_match(hash, u128_zero())) @@ -402,7 +346,9 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) // rjf: nonzero node, request if needed - touch & return results if(node != 0) { - dasm_scope_touch_node__stripe_r_guarded(scope, node); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); + access_touch(access, &node->scope_ref_count, stripe->cv); MemoryCopyStruct(&info, &node->info); } } @@ -416,13 +362,13 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } internal DASM_Info -dasm_info_from_key_params(DASM_Scope *scope, C_Key key, DASM_Params *params, U128 *hash_out) +dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out) { DASM_Info result = {0}; for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { U128 hash = c_hash_from_key(key, rewind_idx); - result = dasm_info_from_hash_params(scope, hash, params); + result = dasm_info_from_hash_params(access, hash, params); if(result.lines.count != 0) { if(hash_out) @@ -552,7 +498,7 @@ dasm_tick(void) break; } U64 req_idx = req_num-1; - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); @@ -562,7 +508,7 @@ dasm_tick(void) C_Root root = r->root; U128 hash = r->hash; DASM_Params params = r->params; - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); U64 change_gen = fs_change_gen(); U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; U64 stripe_idx = slot_idx%dasm_shared->stripes_count; @@ -655,7 +601,7 @@ dasm_tick(void) stale = (stale || u128_match(hash, u128_zero())); if(0 < line->line_num && line->line_num < text_info.lines_count) { - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); if(line_text.size != 0) { @@ -786,7 +732,7 @@ dasm_tick(void) txt_scope_close(txt_scope); di_scope_close(di_scope); - c_scope_close(c_scope); + access_close(access); } lane_sync(); diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 2818119a..890a4bd0 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -220,25 +220,6 @@ struct DASM_Stripe DASM_Node *free_node; }; -//////////////////////////////// -//~ rjf: Scoped Access Types - -typedef struct DASM_Touch DASM_Touch; -struct DASM_Touch -{ - DASM_Touch *next; - U128 hash; - DASM_Params params; -}; - -typedef struct DASM_Scope DASM_Scope; -struct DASM_Scope -{ - DASM_Scope *next; - DASM_Touch *top_touch; - U64 base_pos; -}; - //////////////////////////////// //~ rjf: Thread Context @@ -307,18 +288,11 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); internal void dasm_init(void); -//////////////////////////////// -//~ rjf: Scoped Access - -internal DASM_Scope *dasm_scope_open(void); -internal void dasm_scope_close(DASM_Scope *scope); -internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node); - //////////////////////////////// //~ rjf: Cache Lookups -internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params); -internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, C_Key key, DASM_Params *params, U128 *hash_out); +internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); +internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); //////////////////////////////// //~ rjf: Ticks diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 6c20b6ba..589f1ccf 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -245,7 +245,7 @@ geo_u2x_dequeue_req(U128 *hash_out) ASYNC_WORK_DEF(geo_xfer_work) { ProfBeginFunction(); - C_Scope *scope = c_scope_open(); + Access *access = access_open(); //- rjf: decode U128 hash = {0}; @@ -275,7 +275,7 @@ ASYNC_WORK_DEF(geo_xfer_work) String8 data = {0}; if(got_task) { - data = c_data_from_hash(scope, hash); + data = c_data_from_hash(access, hash); } //- rjf: data -> buffer @@ -300,7 +300,7 @@ ASYNC_WORK_DEF(geo_xfer_work) } } - c_scope_close(scope); + access_close(access); ProfEnd(); return 0; } diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index e8da7022..7768a672 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -98,7 +98,7 @@ mtx_mut_thread__entry_point(void *p) for(;;) { Temp scratch = scratch_begin(0, 0); - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); //- rjf: get next op C_Key buffer_key = {0}; @@ -107,7 +107,7 @@ mtx_mut_thread__entry_point(void *p) //- rjf: get buffer's current data U128 hash = c_hash_from_key(buffer_key, 0); - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); //- rjf: clamp op by data op.range.min = Min(op.range.min, data.size); @@ -137,7 +137,7 @@ mtx_mut_thread__entry_point(void *p) c_submit_data(buffer_key, &arena, new_data); } - c_scope_close(c_scope); + access_close(access); scratch_end(scratch); } } diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 2526c67b..7db6944c 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -166,7 +166,7 @@ ptg_builder_thread__entry_point(void *p) { for(;;) { - C_Scope *scope = c_scope_open(); + Access *access = access_open(); //- rjf: get next key PTG_Key key = {0}; @@ -214,7 +214,7 @@ ptg_builder_thread__entry_point(void *p) } } - c_scope_close(scope); + access_close(access); } } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index f0609721..eff206bc 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1750,9 +1750,9 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) C_ID id = {space.u128}; C_Key key = c_key_make(root, id); U128 hash = c_hash_from_key(key, 0); - C_Scope *scope = c_scope_open(); + Access *access = access_open(); { - String8 data = c_data_from_hash(scope, hash); + String8 data = c_data_from_hash(access, hash); Rng1U64 legal_range = r1u64(0, data.size); Rng1U64 read_range = intersect_1u64(range, legal_range); if(read_range.min < read_range.max) @@ -1761,7 +1761,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, data.str + read_range.min, dim_1u64(read_range)); } } - c_scope_close(scope); + access_close(access); }break; //- rjf: file reads @@ -1783,9 +1783,9 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) U128 hash = c_hash_from_key(key, 0); // rjf: look up from hash store - C_Scope *scope = c_scope_open(); + Access *access = access_open(); { - String8 data = c_data_from_hash(scope, hash); + String8 data = c_data_from_hash(access, hash); Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size); Rng1U64 read_range = intersect_1u64(range, legal_range); if(read_range.min < read_range.max) @@ -1794,7 +1794,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range)); } } - c_scope_close(scope); + access_close(access); }break; //- rjf: interior control entity reads (inside process address space or thread register block) @@ -2181,12 +2181,12 @@ rd_whole_range_from_eval_space(E_Space space) C_ID id = {space.u128}; C_Key key = c_key_make(root, id); U128 hash = c_hash_from_key(key, 0); - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); { - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); result = r1u64(0, data.size); } - c_scope_close(c_scope); + access_close(access); }break; case E_SpaceKind_File: { @@ -2879,10 +2879,10 @@ rd_view_ui(Rng2F32 rect) B32 data_is_ready = 0; String8 new_view_name = {0}; { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); if(!u128_match(hash, u128_zero())) { - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); U64 num_utf8_bytes = 0; U64 num_unknown_bytes = 0; for(U64 idx = 0; idx < data.size && idx < range.max;) @@ -2911,7 +2911,7 @@ rd_view_ui(Rng2F32 rect) new_view_name = str8_lit("memory"); } } - c_scope_close(c_scope); + access_close(access); } // rjf: if we don't have a viewer, just use the memory viewer. @@ -5993,7 +5993,7 @@ rd_window_frame(void) //- rjf: @window_frame_part compute window's theme // { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); //- rjf: try to find theme settings from the project, then the user. RD_CfgList colors_cfgs = {0}; @@ -6039,7 +6039,7 @@ rd_window_frame(void) } //- rjf: map the theme config to the associated tree (either from a preset, or from a file) - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme_cfg->first->string); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, theme_cfg->first->string); if(colors_cfgs.count == 0 && theme_tree == &md_nil_node) { theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; @@ -6110,7 +6110,7 @@ rd_window_frame(void) } } - c_scope_close(c_scope); + access_close(access); } ////////////////////////////// @@ -10205,7 +10205,7 @@ rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) //- rjf: colors internal MD_Node * -rd_theme_tree_from_name(Arena *arena, C_Scope *scope, String8 theme_name) +rd_theme_tree_from_name(Arena *arena, Access *access, String8 theme_name) { Temp scratch = scratch_begin(&arena, 1); MD_Node *theme_tree = &md_nil_node; @@ -10228,7 +10228,7 @@ rd_theme_tree_from_name(Arena *arena, C_Scope *scope, String8 theme_name) endt_us = os_now_microseconds()+50000; } U128 hash = fs_hash_from_path_range(path, r1u64(0, max_U64), endt_us); - String8 data = c_data_from_hash(scope, hash); + String8 data = c_data_from_hash(access, hash); theme_tree = md_tree_from_string(arena, data); } } @@ -12459,10 +12459,10 @@ rd_frame(void) //- rjf: add macro for output log { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); C_Key key = d_state->output_log_key; U128 hash = c_hash_from_key(key, 0); - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); E_Space space = e_space_make(E_SpaceKind_HashStoreKey); space.u64_0 = key.root.u64[0]; space.u128 = key.id.u128[0]; @@ -12471,7 +12471,7 @@ rd_frame(void) expr->mode = E_Mode_Offset; expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("output"), expr); - c_scope_close(c_scope); + access_close(access); } //- rjf: (DEBUG) add macro for cfg strings @@ -15936,10 +15936,10 @@ rd_frame(void) }break; case RD_CmdKind_AddThemeColor: { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme->first->string); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, theme->first->string); if(theme_tree == &md_nil_node) { rd_cfg_new_replace(theme, rd_theme_preset_display_string_table[RD_ThemePreset_DefaultDark]); @@ -15948,11 +15948,11 @@ rd_frame(void) rd_cfg_new(color, str8_lit("tags")); RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); rd_cfg_new(value, str8_lit("0xffffffff")); - c_scope_close(c_scope); + access_close(access); }break; case RD_CmdKind_ForkTheme: { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); for(RD_CfgNode *n = colors.first; n != 0; n = n->next) @@ -15961,7 +15961,7 @@ rd_frame(void) } RD_Cfg *theme_cfg = rd_cfg_child_from_string(parent, str8_lit("theme")); String8 theme_name = theme_cfg->first->string; - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, theme_name); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, theme_name); if(theme_tree == &md_nil_node) { theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; @@ -15978,7 +15978,7 @@ rd_frame(void) } } rd_cfg_release(theme_cfg); - c_scope_close(c_scope); + access_close(access); }break; case RD_CmdKind_SaveTheme: case RD_CmdKind_SaveAndSetTheme: @@ -16091,7 +16091,7 @@ rd_frame(void) case RD_CmdKind_GoToNameAtCursor: case RD_CmdKind_ToggleWatchExpressionAtCursor: { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); TXT_Scope *txt_scope = txt_scope_open(); RD_Regs *regs = rd_regs(); C_Key text_key = regs->text_key; @@ -16099,7 +16099,7 @@ rd_frame(void) TxtRng range = txt_rng(regs->cursor, regs->mark); U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, text_key, lang_kind, &hash); - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); Rng1U64 expr_off_range = {0}; if(range.min.column != range.max.column) { @@ -16115,7 +16115,7 @@ rd_frame(void) RD_CmdKind_GoToName), .string = expr); txt_scope_close(txt_scope); - c_scope_close(c_scope); + access_close(access); }break; case RD_CmdKind_SetNextStatement: { diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 6aa379ec..2d0d87af 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -988,7 +988,7 @@ internal void rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs); //~ rjf: Colors, Fonts, Config //- rjf: colors -internal MD_Node *rd_theme_tree_from_name(Arena *arena, C_Scope *scope, String8 theme_name); +internal MD_Node *rd_theme_tree_from_name(Arena *arena, Access *access, String8 theme_name); internal Vec4F32 rd_rgba_from_code_color_slot(RD_CodeColorSlot slot); internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind(TXT_TokenKind kind); internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 43a17b9e..74df242d 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1944,8 +1944,8 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); dr_fstrs_push_new(arena, &fstrs, ¶ms, name); { - C_Scope *c_scope = c_scope_open(); - MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, c_scope, name); + Access *access = access_open(); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, access, name); U64 color_idx = 0; for(MD_Node *n = theme_tree; color_idx < 4 && !md_node_is_nil(n); n = md_node_rec_depth_first_pre(n, theme_tree).next) { @@ -1973,7 +1973,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla } } } - c_scope_close(c_scope); + access_close(access); } result.eval_fstrs = fstrs; }break; @@ -2025,7 +2025,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) RD_CodeViewState *cv = rd_view_state(RD_CodeViewState); rd_code_view_init(cv); Temp scratch = scratch_begin(0, 0); - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); TXT_Scope *txt_scope = txt_scope_open(); ////////////////////////////// @@ -2091,7 +2091,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) } U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &hash); - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); B32 file_is_missing = (rd_regs()->file_path.size != 0 && os_properties_from_file_path(rd_regs()->file_path).modified == 0); B32 key_has_data = !u128_match(hash, u128_zero()) && info.lines_count; ProfEnd(); @@ -2251,7 +2251,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) rd_store_view_param_s64(str8_lit("mark_column"), rd_regs()->mark.column); txt_scope_close(txt_scope); - c_scope_close(c_scope); + access_close(access); scratch_end(scratch); } @@ -2291,8 +2291,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) } RD_CodeViewState *cv = &dv->cv; Temp scratch = scratch_begin(0, 0); - C_Scope *c_scope = c_scope_open(); - DASM_Scope *dasm_scope = dasm_scope_open(); + Access *access = access_open(); TXT_Scope *txt_scope = txt_scope_open(); ////////////////////////////// @@ -2410,12 +2409,12 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) dasm_params.base_vaddr = base_vaddr; dasm_params.dbgi_key = dbgi_key; } - DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); + DASM_Info dasm_info = dasm_info_from_key_params(access, dasm_key, &dasm_params, &dasm_data_hash); rd_regs()->text_key = dasm_info.text_key; rd_regs()->lang_kind = txt_lang_kind_from_arch(arch); U128 dasm_text_hash = {0}; TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); - String8 dasm_text_data = c_data_from_hash(c_scope, dasm_text_hash); + String8 dasm_text_data = c_data_from_hash(access, dasm_text_hash); B32 has_disasm = (dasm_info.lines.count != 0 && dasm_text_info.lines_count != 0); B32 is_loading = (!has_disasm && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); @@ -2496,8 +2495,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) dv->mark = rd_regs()->mark; txt_scope_close(txt_scope); - dasm_scope_close(dasm_scope); - c_scope_close(c_scope); + access_close(access); scratch_end(scratch); } @@ -3826,7 +3824,7 @@ EV_EXPAND_RULE_INFO_FUNCTION_DEF(bitmap) RD_VIEW_UI_FUNCTION_DEF(bitmap) { Temp scratch = scratch_begin(0, 0); - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); TEX_Scope *tex_scope = tex_scope_open(); ////////////////////////////// @@ -3878,7 +3876,7 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) TEX_Topology topology = tex_topology_make(dim, fmt); U128 data_hash = {0}; R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology, &data_hash); - String8 data = c_data_from_hash(c_scope, data_hash); + String8 data = c_data_from_hash(access, data_hash); ////////////////////////////// //- rjf: equip loading info @@ -4031,8 +4029,8 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) rd_store_view_param_f32(str8_lit("x"), view_center_pos.x); rd_store_view_param_f32(str8_lit("y"), view_center_pos.y); - c_scope_close(c_scope); tex_scope_close(tex_scope); + access_close(access); scratch_end(scratch); } diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 4de63258..81508930 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -2206,7 +2206,7 @@ ASYNC_WORK_DEF(txt_parse_work) U128 hash = {0}; TXT_LangKind lang = TXT_LangKind_Null; txt_u2p_dequeue_req(&hash, &lang); - C_Scope *scope = c_scope_open(); + Access *access = access_open(); //- rjf: unpack hash U64 slot_idx = hash.u64[1]%txt_shared->slots_count; @@ -2232,7 +2232,7 @@ ASYNC_WORK_DEF(txt_parse_work) String8 data = {0}; if(got_task) { - data = c_data_from_hash(scope, hash); + data = c_data_from_hash(access, hash); } //- rjf: data -> text info @@ -2500,7 +2500,7 @@ ASYNC_WORK_DEF(txt_parse_work) } } - c_scope_close(scope); + access_close(access); ProfEnd(); return 0; } diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 46413d63..54d3e55c 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -266,7 +266,7 @@ tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) ASYNC_WORK_DEF(tex_xfer_work) { ProfBeginFunction(); - C_Scope *scope = c_scope_open(); + Access *access = access_open(); //- rjf: decode U128 hash = {0}; @@ -297,7 +297,7 @@ ASYNC_WORK_DEF(tex_xfer_work) String8 data = {0}; if(got_task) { - data = c_data_from_hash(scope, hash); + data = c_data_from_hash(access, hash); } //- rjf: data * topology -> texture @@ -322,7 +322,7 @@ ASYNC_WORK_DEF(tex_xfer_work) } } - c_scope_close(scope); + access_close(access); ProfEnd(); return 0; } From 2131e792a1b5b3a6951aff4cf3076132da43cfb8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 15:25:11 -0700 Subject: [PATCH 208/302] eliminate text cache scope; fold into base layer's 'access' construct --- src/dasm_cache/dasm_cache.c | 4 +- src/raddbg/raddbg_core.c | 4 +- src/raddbg/raddbg_views.c | 8 +--- src/text_cache/text_cache.c | 92 +++---------------------------------- src/text_cache/text_cache.h | 46 +------------------ 5 files changed, 12 insertions(+), 142 deletions(-) diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 991a067e..601f0497 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -500,7 +500,6 @@ dasm_tick(void) U64 req_idx = req_num-1; Access *access = access_open(); DI_Scope *di_scope = di_scope_open(); - TXT_Scope *txt_scope = txt_scope_open(); //- rjf: unpack B32 stale = 0; @@ -597,7 +596,7 @@ dasm_tick(void) TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; - TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + TXT_TextInfo text_info = txt_text_info_from_key_lang(access, key, lang_kind, &hash); stale = (stale || u128_match(hash, u128_zero())); if(0 < line->line_num && line->line_num < text_info.lines_count) { @@ -730,7 +729,6 @@ dasm_tick(void) req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); } - txt_scope_close(txt_scope); di_scope_close(di_scope); access_close(access); } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index eff206bc..1e1dce0d 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -16092,13 +16092,12 @@ rd_frame(void) case RD_CmdKind_ToggleWatchExpressionAtCursor: { Access *access = access_open(); - TXT_Scope *txt_scope = txt_scope_open(); RD_Regs *regs = rd_regs(); C_Key text_key = regs->text_key; TXT_LangKind lang_kind = regs->lang_kind; TxtRng range = txt_rng(regs->cursor, regs->mark); U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, text_key, lang_kind, &hash); + TXT_TextInfo info = txt_text_info_from_key_lang(access, text_key, lang_kind, &hash); String8 data = c_data_from_hash(access, hash); Rng1U64 expr_off_range = {0}; if(range.min.column != range.max.column) @@ -16114,7 +16113,6 @@ rd_frame(void) kind == RD_CmdKind_ToggleWatchExpressionAtCursor ? RD_CmdKind_ToggleWatchExpression : RD_CmdKind_GoToName), .string = expr); - txt_scope_close(txt_scope); access_close(access); }break; case RD_CmdKind_SetNextStatement: diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 74df242d..cd17f550 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2026,7 +2026,6 @@ RD_VIEW_UI_FUNCTION_DEF(text) rd_code_view_init(cv); Temp scratch = scratch_begin(0, 0); Access *access = access_open(); - TXT_Scope *txt_scope = txt_scope_open(); ////////////////////////////// //- rjf: set up invariants @@ -2090,7 +2089,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) rd_regs()->lang_kind = txt_lang_kind_from_extension(lang); } U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &hash); + TXT_TextInfo info = txt_text_info_from_key_lang(access, rd_regs()->text_key, rd_regs()->lang_kind, &hash); String8 data = c_data_from_hash(access, hash); B32 file_is_missing = (rd_regs()->file_path.size != 0 && os_properties_from_file_path(rd_regs()->file_path).modified == 0); B32 key_has_data = !u128_match(hash, u128_zero()) && info.lines_count; @@ -2250,7 +2249,6 @@ RD_VIEW_UI_FUNCTION_DEF(text) rd_store_view_param_s64(str8_lit("mark_line"), rd_regs()->mark.line); rd_store_view_param_s64(str8_lit("mark_column"), rd_regs()->mark.column); - txt_scope_close(txt_scope); access_close(access); scratch_end(scratch); } @@ -2292,7 +2290,6 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) RD_CodeViewState *cv = &dv->cv; Temp scratch = scratch_begin(0, 0); Access *access = access_open(); - TXT_Scope *txt_scope = txt_scope_open(); ////////////////////////////// //- rjf: if disassembly views are not parameterized by anything, they @@ -2413,7 +2410,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) rd_regs()->text_key = dasm_info.text_key; rd_regs()->lang_kind = txt_lang_kind_from_arch(arch); U128 dasm_text_hash = {0}; - TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); + TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(access, rd_regs()->text_key, rd_regs()->lang_kind, &dasm_text_hash); String8 dasm_text_data = c_data_from_hash(access, dasm_text_hash); B32 has_disasm = (dasm_info.lines.count != 0 && dasm_text_info.lines_count != 0); B32 is_loading = (!has_disasm && dim_1u64(range) != 0 && eval.msgs.max_kind == E_MsgKind_Null && (space.kind != RD_EvalSpaceKind_CtrlEntity || space_entity != &ctrl_entity_nil)); @@ -2494,7 +2491,6 @@ RD_VIEW_UI_FUNCTION_DEF(disasm) dv->cursor = rd_regs()->cursor; dv->mark = rd_regs()->mark; - txt_scope_close(txt_scope); access_close(access); scratch_end(scratch); } diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 81508930..554c8dd1 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1617,93 +1617,11 @@ txt_init(void) txt_shared->evictor_thread = thread_launch(txt_evictor_thread__entry_point, 0); } -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void -txt_tctx_ensure_inited(void) -{ - if(txt_tctx == 0) - { - Arena *arena = arena_alloc(); - txt_tctx = push_array(arena, TXT_TCTX, 1); - txt_tctx->arena = arena; - } -} - -//////////////////////////////// -//~ rjf: Scoped Access - -internal TXT_Scope * -txt_scope_open(void) -{ - txt_tctx_ensure_inited(); - TXT_Scope *scope = txt_tctx->free_scope; - if(scope) - { - SLLStackPop(txt_tctx->free_scope); - } - else - { - scope = push_array_no_zero(txt_tctx->arena, TXT_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -txt_scope_close(TXT_Scope *scope) -{ - for(TXT_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - U128 hash = touch->hash; - next = touch->next; - U64 slot_idx = hash.u64[1]%txt_shared->slots_count; - U64 stripe_idx = slot_idx%txt_shared->stripes_count; - TXT_Slot *slot = &txt_shared->slots[slot_idx]; - TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && touch->lang == n->lang) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - SLLStackPush(txt_tctx->free_touch, touch); - } - SLLStackPush(txt_tctx->free_scope, scope); -} - -internal void -txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node) -{ - TXT_Touch *touch = txt_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); - if(touch != 0) - { - SLLStackPop(txt_tctx->free_touch); - } - else - { - touch = push_array_no_zero(txt_tctx->arena, TXT_Touch, 1); - } - MemoryZeroStruct(touch); - touch->hash = node->hash; - touch->lang = node->lang; - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Cache Lookups internal TXT_TextInfo -txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) +txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) { TXT_TextInfo info = {0}; if(!u128_match(hash, u128_zero())) @@ -1723,7 +1641,9 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) info.bytes_processed = ins_atomic_u64_eval(&n->info.bytes_processed); info.bytes_to_process = ins_atomic_u64_eval(&n->info.bytes_to_process); found = 1; - txt_scope_touch_node__stripe_r_guarded(scope, n); + ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); + access_touch(access, &n->scope_ref_count, stripe->cv); break; } } @@ -1771,13 +1691,13 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) } internal TXT_TextInfo -txt_text_info_from_key_lang(TXT_Scope *scope, C_Key key, TXT_LangKind lang, U128 *hash_out) +txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out) { TXT_TextInfo result = {0}; for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { U128 hash = c_hash_from_key(key, rewind_idx); - result = txt_text_info_from_hash_lang(scope, hash, lang); + result = txt_text_info_from_hash_lang(access, hash, lang); if(result.lines_count != 0) { if(hash_out) diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index dac93a8c..abf41f24 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -196,35 +196,6 @@ struct TXT_Stripe CondVar cv; }; -//////////////////////////////// -//~ rjf: Scoped Access - -typedef struct TXT_Touch TXT_Touch; -struct TXT_Touch -{ - TXT_Touch *next; - U128 hash; - TXT_LangKind lang; -}; - -typedef struct TXT_Scope TXT_Scope; -struct TXT_Scope -{ - TXT_Scope *next; - TXT_Touch *top_touch; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct TXT_TCTX TXT_TCTX; -struct TXT_TCTX -{ - Arena *arena; - TXT_Scope *free_scope; - TXT_Touch *free_touch; -}; - //////////////////////////////// //~ rjf: Shared State @@ -259,7 +230,6 @@ struct TXT_Shared //~ rjf: Globals read_only global TXT_ScopeNode txt_scope_node_nil = {0}; -thread_static TXT_TCTX *txt_tctx = 0; global TXT_Shared *txt_shared = 0; //////////////////////////////// @@ -292,23 +262,11 @@ internal TXT_TokenArray txt_token_array_from_string__disasm_x64_intel(Arena *are internal void txt_init(void); -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void txt_tctx_ensure_inited(void); - -//////////////////////////////// -//~ rjf: Scoped Access - -internal TXT_Scope *txt_scope_open(void); -internal void txt_scope_close(TXT_Scope *scope); -internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node); - //////////////////////////////// //~ rjf: Cache Lookups -internal TXT_TextInfo txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang); -internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, C_Key key, TXT_LangKind lang, U128 *hash_out); +internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); +internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); //////////////////////////////// //~ rjf: Text Info Extractor Helpers From c5bcdbf232ae9d3867dda5a3f64397e002ade315 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 15:40:13 -0700 Subject: [PATCH 209/302] eliminate geo_scope, fold into base layer's 'access' construct --- src/geo_cache/geo_cache.c | 91 +++------------------------------------ src/geo_cache/geo_cache.h | 45 +------------------ src/raddbg/raddbg_views.c | 8 ++-- 3 files changed, 12 insertions(+), 132 deletions(-) diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 589f1ccf..0f4003ba 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -31,92 +31,11 @@ geo_init(void) geo_shared->evictor_thread = thread_launch(geo_evictor_thread__entry_point, 0); } -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void -geo_tctx_ensure_inited(void) -{ - if(geo_tctx == 0) - { - Arena *arena = arena_alloc(); - geo_tctx = push_array(arena, GEO_TCTX, 1); - geo_tctx->arena = arena; - } -} - -//////////////////////////////// -//~ rjf: Scoped Access - -internal GEO_Scope * -geo_scope_open(void) -{ - geo_tctx_ensure_inited(); - GEO_Scope *scope = geo_tctx->free_scope; - if(scope) - { - SLLStackPop(geo_tctx->free_scope); - } - else - { - scope = push_array_no_zero(geo_tctx->arena, GEO_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -geo_scope_close(GEO_Scope *scope) -{ - for(GEO_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - U128 hash = touch->hash; - next = touch->next; - U64 slot_idx = hash.u64[1]%geo_shared->slots_count; - U64 stripe_idx = slot_idx%geo_shared->stripes_count; - GEO_Slot *slot = &geo_shared->slots[slot_idx]; - GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - SLLStackPush(geo_tctx->free_touch, touch); - } - SLLStackPush(geo_tctx->free_scope, scope); -} - -internal void -geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node) -{ - GEO_Touch *touch = geo_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); - if(touch != 0) - { - SLLStackPop(geo_tctx->free_touch); - } - else - { - touch = push_array_no_zero(geo_tctx->arena, GEO_Touch, 1); - } - MemoryZeroStruct(touch); - touch->hash = node->hash; - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Cache Lookups internal R_Handle -geo_buffer_from_hash(GEO_Scope *scope, U128 hash) +geo_buffer_from_hash(Access *access, U128 hash) { R_Handle handle = {0}; if(!u128_match(hash, u128_zero())) @@ -134,7 +53,9 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) { handle = n->buffer; found = !r_handle_match(r_handle_zero(), handle); - geo_scope_touch_node__stripe_r_guarded(scope, n); + ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); + access_touch(access, &n->scope_ref_count, stripe->cv); break; } } @@ -181,13 +102,13 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) } internal R_Handle -geo_buffer_from_key(GEO_Scope *scope, C_Key key) +geo_buffer_from_key(Access *access, C_Key key) { R_Handle handle = {0}; for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { U128 hash = c_hash_from_key(key, rewind_idx); - handle = geo_buffer_from_hash(scope, hash); + handle = geo_buffer_from_hash(access, hash); if(!r_handle_match(handle, r_handle_zero())) { break; diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index fd85e300..af88db79 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -36,34 +36,6 @@ struct GEO_Stripe CondVar cv; }; -//////////////////////////////// -//~ rjf: Scoped Access - -typedef struct GEO_Touch GEO_Touch; -struct GEO_Touch -{ - GEO_Touch *next; - U128 hash; -}; - -typedef struct GEO_Scope GEO_Scope; -struct GEO_Scope -{ - GEO_Scope *next; - GEO_Touch *top_touch; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct GEO_TCTX GEO_TCTX; -struct GEO_TCTX -{ - Arena *arena; - GEO_Scope *free_scope; - GEO_Touch *free_touch; -}; - //////////////////////////////// //~ rjf: Shared State @@ -94,7 +66,6 @@ struct GEO_Shared //////////////////////////////// //~ rjf: Globals -thread_static GEO_TCTX *geo_tctx = 0; global GEO_Shared *geo_shared = 0; //////////////////////////////// @@ -102,23 +73,11 @@ global GEO_Shared *geo_shared = 0; internal void geo_init(void); -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void geo_tctx_ensure_inited(void); - -//////////////////////////////// -//~ rjf: Scoped Access - -internal GEO_Scope *geo_scope_open(void); -internal void geo_scope_close(GEO_Scope *scope); -internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node); - //////////////////////////////// //~ rjf: Cache Lookups -internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash); -internal R_Handle geo_buffer_from_key(GEO_Scope *scope, C_Key key); +internal R_Handle geo_buffer_from_hash(Access *access, U128 hash); +internal R_Handle geo_buffer_from_key(Access *access, C_Key key); //////////////////////////////// //~ rjf: Transfer Threads diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index cd17f550..0120789f 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -4338,7 +4338,7 @@ EV_EXPAND_RULE_INFO_FUNCTION_DEF(geo3d) RD_VIEW_UI_FUNCTION_DEF(geo3d) { Temp scratch = scratch_begin(0, 0); - GEO_Scope *geo_scope = geo_scope_open(); + Access *access = access_open(); RD_Geo3DViewState *state = rd_view_state(RD_Geo3DViewState); ////////////////////////////// @@ -4360,8 +4360,8 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d) Rng1U64 vtxs_range = r1u64(vtx_base_off, vtx_base_off+vtx_size); C_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); C_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); - R_Handle idxs_buffer = geo_buffer_from_key(geo_scope, idxs_key); - R_Handle vtxs_buffer = geo_buffer_from_key(geo_scope, vtxs_key); + R_Handle idxs_buffer = geo_buffer_from_key(access, idxs_key); + R_Handle vtxs_buffer = geo_buffer_from_key(access, vtxs_key); ////////////////////////////// //- rjf: equip loading info @@ -4445,6 +4445,6 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d) rd_store_view_param_f32(str8_lit("pitch"), pitch_target); rd_store_view_param_f32(str8_lit("zoom"), zoom_target); - geo_scope_close(geo_scope); + access_close(access); scratch_end(scratch); } From 4e99312b75854e72be6463b6f99d104d5a4517b1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 15:53:00 -0700 Subject: [PATCH 210/302] eliminate tex_scope; fold into access --- src/raddbg/raddbg_views.c | 4 +- src/texture_cache/texture_cache.c | 92 ++----------------------------- src/texture_cache/texture_cache.h | 46 +--------------- 3 files changed, 9 insertions(+), 133 deletions(-) diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 0120789f..7e9efbcf 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -3821,7 +3821,6 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) { Temp scratch = scratch_begin(0, 0); Access *access = access_open(); - TEX_Scope *tex_scope = tex_scope_open(); ////////////////////////////// //- rjf: evaluate expression @@ -3871,7 +3870,7 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) C_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); TEX_Topology topology = tex_topology_make(dim, fmt); U128 data_hash = {0}; - R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology, &data_hash); + R_Handle texture = tex_texture_from_key_topology(access, texture_key, topology, &data_hash); String8 data = c_data_from_hash(access, data_hash); ////////////////////////////// @@ -4025,7 +4024,6 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) rd_store_view_param_f32(str8_lit("x"), view_center_pos.x); rd_store_view_param_f32(str8_lit("y"), view_center_pos.y); - tex_scope_close(tex_scope); access_close(access); scratch_end(scratch); } diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 54d3e55c..d5e63181 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -44,93 +44,11 @@ tex_init(void) tex_shared->evictor_thread = thread_launch(tex_evictor_thread__entry_point, 0); } -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void -tex_tctx_ensure_inited(void) -{ - if(tex_tctx == 0) - { - Arena *arena = arena_alloc(); - tex_tctx = push_array(arena, TEX_TCTX, 1); - tex_tctx->arena = arena; - } -} - -//////////////////////////////// -//~ rjf: Scoped Access - -internal TEX_Scope * -tex_scope_open(void) -{ - tex_tctx_ensure_inited(); - TEX_Scope *scope = tex_tctx->free_scope; - if(scope) - { - SLLStackPop(tex_tctx->free_scope); - } - else - { - scope = push_array_no_zero(tex_tctx->arena, TEX_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -tex_scope_close(TEX_Scope *scope) -{ - for(TEX_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - U128 hash = touch->hash; - next = touch->next; - U64 slot_idx = hash.u64[1]%tex_shared->slots_count; - U64 stripe_idx = slot_idx%tex_shared->stripes_count; - TEX_Slot *slot = &tex_shared->slots[slot_idx]; - TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && MemoryMatchStruct(&touch->topology, &n->topology)) - { - ins_atomic_u64_dec_eval(&n->scope_ref_count); - break; - } - } - } - SLLStackPush(tex_tctx->free_touch, touch); - } - SLLStackPush(tex_tctx->free_scope, scope); -} - -internal void -tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node) -{ - TEX_Touch *touch = tex_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); - if(touch != 0) - { - SLLStackPop(tex_tctx->free_touch); - } - else - { - touch = push_array_no_zero(tex_tctx->arena, TEX_Touch, 1); - } - MemoryZeroStruct(touch); - touch->hash = node->hash; - touch->topology = node->topology; - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Cache Lookups internal R_Handle -tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology) +tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology) { R_Handle handle = {0}; { @@ -148,7 +66,9 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog { handle = n->texture; found = !r_handle_match(r_handle_zero(), handle); - tex_scope_touch_node__stripe_r_guarded(scope, n); + ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); + access_touch(access, &n->scope_ref_count, stripe->cv); break; } } @@ -196,13 +116,13 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog } internal R_Handle -tex_texture_from_key_topology(TEX_Scope *scope, C_Key key, TEX_Topology topology, U128 *hash_out) +tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out) { R_Handle handle = {0}; for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) { U128 hash = c_hash_from_key(key, rewind_idx); - handle = tex_texture_from_hash_topology(scope, hash, topology); + handle = tex_texture_from_hash_topology(access, hash, topology); if(!r_handle_match(handle, r_handle_zero())) { if(hash_out) diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index b91007b3..a9140e91 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -47,35 +47,6 @@ struct TEX_Stripe CondVar cv; }; -//////////////////////////////// -//~ rjf: Scoped Access - -typedef struct TEX_Touch TEX_Touch; -struct TEX_Touch -{ - TEX_Touch *next; - U128 hash; - TEX_Topology topology; -}; - -typedef struct TEX_Scope TEX_Scope; -struct TEX_Scope -{ - TEX_Scope *next; - TEX_Touch *top_touch; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct TEX_TCTX TEX_TCTX; -struct TEX_TCTX -{ - Arena *arena; - TEX_Scope *free_scope; - TEX_Touch *free_touch; -}; - //////////////////////////////// //~ rjf: Shared State @@ -106,7 +77,6 @@ struct TEX_Shared //////////////////////////////// //~ rjf: Globals -thread_static TEX_TCTX *tex_tctx = 0; global TEX_Shared *tex_shared = 0; //////////////////////////////// @@ -119,23 +89,11 @@ internal TEX_Topology tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt); internal void tex_init(void); -//////////////////////////////// -//~ rjf: Thread Context Initialization - -internal void tex_tctx_ensure_inited(void); - -//////////////////////////////// -//~ rjf: Scoped Access - -internal TEX_Scope *tex_scope_open(void); -internal void tex_scope_close(TEX_Scope *scope); -internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node); - //////////////////////////////// //~ rjf: Cache Lookups -internal R_Handle tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology); -internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, C_Key key, TEX_Topology topology, U128 *hash_out); +internal R_Handle tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology); +internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out); //////////////////////////////// //~ rjf: Transfer Threads From 30ae9620f914cdf36d97d998ad781f6ba52f1992 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 15:59:21 -0700 Subject: [PATCH 211/302] eliminate ptr graph scope; simplify dasm cache eviction loop --- src/dasm_cache/dasm_cache.c | 81 ++++++++++++++------------- src/ptr_graph_cache/ptr_graph_cache.c | 75 +------------------------ src/ptr_graph_cache/ptr_graph_cache.h | 47 +--------------- 3 files changed, 43 insertions(+), 160 deletions(-) diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 601f0497..392ec884 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -405,63 +405,64 @@ dasm_tick(void) U64 stripe_idx = slot_idx%dasm_shared->stripes_count; DASM_Slot *slot = &dasm_shared->slots[slot_idx]; DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - for(DASM_Node *n = slot->first; n != 0; n = n->next) + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) for(DASM_Node *n = slot->first; n != 0; n = n->next) { + // rjf: node needs eviction if(n->scope_ref_count == 0 && n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && ins_atomic_u64_eval(&n->working_count) == 0) { slot_has_work = 1; - break; + if(!write_mode) + { + break; + } + else + { + DLLRemove(slot->first, slot->last, n); + if(n->info_arena != 0) + { + arena_release(n->info_arena); + } + SLLStackPush(stripe->free_node, n); + } } + + // rjf: node needs recomputation if(n->change_gen != 0 && n->change_gen != change_gen && n->last_time_requested_us+retry_threshold_us <= check_time_us && n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) { slot_has_work = 1; - break; + if(!write_mode) + { + break; + } + else + { + MutexScope(dasm_shared->req_mutex) + { + DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); + SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); + dasm_shared->req_count += 1; + req_n->v.root = n->root; + req_n->v.hash = n->hash; + req_n->v.params = n->params; + req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); + } + n->last_time_requested_us = os_now_microseconds(); + n->last_user_clock_idx_requested = check_time_user_clocks; + ins_atomic_u64_inc_eval(&n->working_count); + } } } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next) + if(!slot_has_work) { - next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - ins_atomic_u64_eval(&n->working_count) == 0) - { - DLLRemove(slot->first, slot->last, n); - if(n->info_arena != 0) - { - arena_release(n->info_arena); - } - SLLStackPush(stripe->free_node, n); - } - if(n->change_gen != 0 && n->change_gen != change_gen && - n->last_time_requested_us+retry_threshold_us <= check_time_us && - n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) - { - MutexScope(dasm_shared->req_mutex) - { - DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); - SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); - dasm_shared->req_count += 1; - req_n->v.root = n->root; - req_n->v.hash = n->hash; - req_n->v.params = n->params; - req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); - } - n->last_time_requested_us = os_now_microseconds(); - n->last_user_clock_idx_requested = check_time_user_clocks; - ins_atomic_u64_inc_eval(&n->working_count); - } + break; } } } diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 7db6944c..7b624fba 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -33,83 +33,11 @@ ptg_init(void) ptg_shared->evictor_thread = thread_launch(ptg_evictor_thread__entry_point, 0); } -//////////////////////////////// -//~ rjf: User Clock - -internal void -ptg_user_clock_tick(void) -{ - ins_atomic_u64_inc_eval(&ptg_shared->user_clock_idx); -} - -internal U64 -ptg_user_clock_idx(void) -{ - return ins_atomic_u64_eval(&ptg_shared->user_clock_idx); -} - -//////////////////////////////// -//~ rjf: Scoped Access - -internal PTG_Scope * -ptg_scope_open(void) -{ - if(ptg_tctx == 0) - { - Arena *arena = arena_alloc(); - ptg_tctx = push_array(arena, PTG_TCTX, 1); - ptg_tctx->arena = arena; - } - PTG_Scope *scope = ptg_tctx->free_scope; - if(scope) - { - SLLStackPop(ptg_tctx->free_scope); - } - else - { - scope = push_array_no_zero(ptg_tctx->arena, PTG_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -ptg_scope_close(PTG_Scope *scope) -{ - for(PTG_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) - { - next = touch->next; - ins_atomic_u64_dec_eval(&touch->node->scope_ref_count); - SLLStackPush(ptg_tctx->free_touch, touch); - } - SLLStackPush(ptg_tctx->free_scope, scope); -} - -internal void -ptg_scope_touch_node__stripe_r_guarded(PTG_Scope *scope, PTG_GraphNode *node) -{ - PTG_Touch *touch = ptg_tctx->free_touch; - ins_atomic_u64_inc_eval(&node->scope_ref_count); - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, ptg_user_clock_idx()); - if(touch != 0) - { - SLLStackPop(ptg_tctx->free_touch); - } - else - { - touch = push_array_no_zero(ptg_tctx->arena, PTG_Touch, 1); - } - MemoryZeroStruct(touch); - touch->node = node; - SLLStackPush(scope->top_touch, touch); -} - //////////////////////////////// //~ rjf: Cache Lookups internal PTG_Graph * -ptg_graph_from_key(PTG_Scope *scope, PTG_Key *key) +ptg_graph_from_key(Access *access, PTG_Key *key) { PTG_Graph *g = 0; return g; @@ -198,7 +126,6 @@ ptg_builder_thread__entry_point(void *p) } - //- rjf: commit results to cache if(got_task) MutexScopeW(stripe->rw_mutex) { diff --git a/src/ptr_graph_cache/ptr_graph_cache.h b/src/ptr_graph_cache/ptr_graph_cache.h index 43befd6b..cc30be76 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.h +++ b/src/ptr_graph_cache/ptr_graph_cache.h @@ -126,34 +126,6 @@ struct PTG_GraphStripe PTG_GraphNode *free_node; }; -//////////////////////////////// -//~ rjf: Scoped Access Types - -typedef struct PTG_Touch PTG_Touch; -struct PTG_Touch -{ - PTG_Touch *next; - PTG_GraphNode *node; -}; - -typedef struct PTG_Scope PTG_Scope; -struct PTG_Scope -{ - PTG_Scope *next; - PTG_Touch *top_touch; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct PTG_TCTX PTG_TCTX; -struct PTG_TCTX -{ - Arena *arena; - PTG_Scope *free_scope; - PTG_Touch *free_touch; -}; - //////////////////////////////// //~ rjf: Shared State @@ -162,9 +134,6 @@ struct PTG_Shared { Arena *arena; - // rjf: user clock - U64 user_clock_idx; - // rjf: cache U64 slots_count; U64 stripes_count; @@ -190,7 +159,6 @@ struct PTG_Shared //////////////////////////////// //~ rjf: Globals -thread_static PTG_TCTX *ptg_tctx = 0; global PTG_Shared *ptg_shared = 0; //////////////////////////////// @@ -198,23 +166,10 @@ global PTG_Shared *ptg_shared = 0; internal void ptg_init(void); -//////////////////////////////// -//~ rjf: User Clock - -internal void ptg_user_clock_tick(void); -internal U64 ptg_user_clock_idx(void); - -//////////////////////////////// -//~ rjf: Scoped Access - -internal PTG_Scope *ptg_scope_open(void); -internal void ptg_scope_close(PTG_Scope *scope); -internal void ptg_scope_touch_node__stripe_r_guarded(PTG_Scope *scope, PTG_GraphNode *node); - //////////////////////////////// //~ rjf: Cache Lookups -internal PTG_Graph *ptg_graph_from_key(PTG_Scope *scope, PTG_Key *key); +internal PTG_Graph *ptg_graph_from_key(Access *access, PTG_Key *key); //////////////////////////////// //~ rjf: Transfer Threads From 8e2ceeee9ec00767237a0eff1b76b2ec703f8475 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Sep 2025 16:20:17 -0700 Subject: [PATCH 212/302] provide mechanism to not wait at top of async loop --- src/base/base_entry_point.c | 11 +++++++++-- src/dasm_cache/dasm_cache.c | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 7b7bec00..8368a725 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -6,7 +6,7 @@ global CondVar async_tick_start_cond_var = {0}; global CondVar async_tick_stop_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; -global U64 async_wait_timeout = 0; +global B32 async_loop_again = 0; global B32 global_async_exit = 0; internal void @@ -190,7 +190,14 @@ async_thread_entry_point(void *params) ThreadNameF("async_thread_%I64u", lane_idx()); for(;!ins_atomic_u32_eval(&global_async_exit);) { - MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); + if(!ins_atomic_u32_eval(&async_loop_again)) + { + MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); + if(lane_idx() == 0) + { + async_loop_again = 0; + } + } #if defined(CONTENT_H) c_tick(); #endif diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 392ec884..9755cc44 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -728,6 +728,7 @@ dasm_tick(void) req_n->v.hash = hash; req_n->v.params = params; req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); + ins_atomic_u32_eval_assign(&async_loop_again, 1); } di_scope_close(di_scope); From 8fa01d3e300133fbf8018325d478d4784c8f66c7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 19 Sep 2025 15:31:30 -0700 Subject: [PATCH 213/302] expand access scope touches to automatically record update clock idx touch time, + timestamp; move texture cache to new async wavefront --- src/base/base_entry_point.c | 3 + src/base/base_thread_context.c | 24 ++- src/base/base_thread_context.h | 15 +- src/content/content.c | 167 ++++++++-------- src/content/content.h | 26 ++- src/dasm_cache/dasm_cache.c | 9 +- src/dasm_cache/dasm_cache.h | 6 +- src/geo_cache/geo_cache.c | 12 +- src/geo_cache/geo_cache.h | 4 +- src/text_cache/text_cache.c | 16 +- src/text_cache/text_cache.h | 4 +- src/texture_cache/texture_cache.c | 310 +++++++++++++----------------- src/texture_cache/texture_cache.h | 48 ++--- 13 files changed, 314 insertions(+), 330 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 8368a725..b9cc7abe 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -206,6 +206,9 @@ async_thread_entry_point(void *params) #endif #if defined(DASM_CACHE_H) dasm_tick(); +#endif +#if defined(TEXTURE_CACHE_H) + tex_tick(); #endif cond_var_broadcast(async_tick_stop_cond_var); } diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 465fcb37..c9e04f7f 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -160,7 +160,7 @@ access_close(Access *access) for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next) { next = touch->next; - ins_atomic_u64_dec_eval(touch->touch_count); + ins_atomic_u64_dec_eval(&touch->pt->access_refcount); if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); } SLLStackPush(tctx_thread_local->free_touch, touch); } @@ -168,9 +168,11 @@ access_close(Access *access) } internal void -access_touch(Access *access, U64 *touch_count, CondVar cv) +access_touch(Access *access, AccessPt *pt, CondVar cv) { - ins_atomic_u64_inc_eval(touch_count); + ins_atomic_u64_inc_eval(&pt->access_refcount); + ins_atomic_u64_eval_assign(&pt->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx()); Touch *touch = tctx_thread_local->free_touch; if(touch != 0) { @@ -183,5 +185,19 @@ access_touch(Access *access, U64 *touch_count, CondVar cv) MemoryZeroStruct(touch); SLLStackPush(access->top_touch, touch); touch->cv = cv; - touch->touch_count = touch_count; + touch->pt = pt; +} + +//- rjf: access points + +internal B32 +access_pt_is_expired(AccessPt *pt) +{ + U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount); + U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us); + U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched); + B32 result = (access_refcount == 0 && + last_time_touched_us + 2000000 < os_now_microseconds() && + last_update_idx_touched + 10 < update_tick_idx()); + return result; } diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index cfd9e18b..340bccf1 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -18,11 +18,19 @@ struct LaneCtx //////////////////////////////// //~ rjf: Access Scopes +typedef struct AccessPt AccessPt; +struct AccessPt +{ + U64 access_refcount; + U64 last_time_touched_us; + U64 last_update_idx_touched; +}; + typedef struct Touch Touch; struct Touch { Touch *next; - U64 *touch_count; + AccessPt *pt; CondVar cv; }; @@ -95,6 +103,9 @@ internal void tctx_read_srcloc(char **file_name, U64 *line_number); //- rjf: access scopes internal Access *access_open(void); internal void access_close(Access *access); -internal void access_touch(Access *access, U64 *touch_count, CondVar cv); +internal void access_touch(Access *access, AccessPt *pt, CondVar cv); + +//- rjf: access points +internal B32 access_pt_is_expired(AccessPt *pt); #endif // BASE_THREAD_CONTEXT_H diff --git a/src/content/content.c b/src/content/content.c index 4995f600..f16383b5 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -169,45 +169,7 @@ c_root_release(C_Root root) { C_ID id = id_chunk_n->v[chunk_idx]; C_Key key = c_key_make(root, id); - U64 key_hash = c_little_hash_from_data(str8_struct(&key)); - U64 key_slot_idx = key_hash%c_shared->key_slots_count; - U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; - C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; - C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; - MutexScopeW(key_stripe->rw_mutex) - { - for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(c_key_match(n->key, key)) - { - // rjf: release reference to all hashes - for(U64 history_idx = 0; history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) - { - U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; - U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count; - U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count; - C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx]; - C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx]; - MutexScopeR(hash_stripe->rw_mutex) - { - for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - ins_atomic_u64_dec_eval(&n->key_ref_count); - break; - } - } - } - } - - // rjf: release key node - DLLRemove(key_slot->first, key_slot->last, n); - SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n); - break; - } - } - } + c_close_key(key); } } } @@ -218,11 +180,14 @@ c_root_release(C_Root root) internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data) { + //- rjf: unpack key U64 key_hash = c_little_hash_from_data(str8_struct(&key)); U64 key_slot_idx = key_hash%c_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; + + //- rjf: hash data, unpack hash U128 hash = c_hash_from_data(data); U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count; U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; @@ -250,15 +215,15 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) } else { - node = push_array(stripe->arena, C_BlobNode, 1); + node = push_array_no_zero(stripe->arena, C_BlobNode, 1); } + MemoryZeroStruct(node); node->hash = hash; if(data_arena != 0) { node->arena = *data_arena; } node->data = data; - node->scope_ref_count = 0; node->key_ref_count = 1; DLLPushBack(slot->first, slot->last, node); } @@ -377,6 +342,52 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) return hash; } +//////////////////////////////// +//~ rjf: Key Closing + +internal void +c_close_key(C_Key key) +{ + U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%c_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; + C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; + C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; + RWMutexScope(key_stripe->rw_mutex, 1) + { + for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(c_key_match(n->key, key)) + { + for(U64 history_idx = 0; + history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; + history_idx += 1) + { + U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; + U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count; + U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx]; + C_Stripe *hash_stripe = &c_shared->blob_stripes[hash_stripe_idx]; + MutexScopeR(hash_stripe->rw_mutex) + { + for(C_BlobNode *n = hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + DLLRemove(key_slot->first, key_slot->last, n); + SLLStackPush(c_shared->key_stripes_free_nodes[key_stripe_idx], n); + break; + } + } + } +} + //////////////////////////////// //~ rjf: Downstream Accesses @@ -432,7 +443,7 @@ c_hash_from_key(C_Key key, U64 rewind_count) U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx]; - MutexScopeR(key_stripe->rw_mutex) + RWMutexScope(key_stripe->rw_mutex, 0) { for(C_KeyNode *n = key_slot->first; n != 0; n = n->next) { @@ -462,7 +473,7 @@ c_data_from_hash(Access *access, U128 hash) if(u128_match(n->hash, hash)) { result = n->data; - access_touch(access, &n->scope_ref_count, stripe->cv); + access_touch(access, &n->access_pt, stripe->cv); break; } } @@ -478,46 +489,52 @@ internal void c_tick(void) { ProfBeginFunction(); - Rng1U64 range = lane_range(c_shared->blob_slots_count); - for EachInRange(slot_idx, range) + + //- rjf: garbage collect blobs { - U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; - C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; - C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) + Rng1U64 range = lane_range(c_shared->blob_slots_count); + for EachInRange(slot_idx, range) { - for(C_BlobNode *n = slot->first; n != 0; n = n->next) + U64 stripe_idx = slot_idx%c_shared->blob_stripes_count; + C_BlobSlot *slot = &c_shared->blob_slots[slot_idx]; + C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx]; + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); + U64 scope_ref_count = ins_atomic_u64_eval(&n->access_pt.access_refcount); + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + { + slot_has_work = 1; + if(!write_mode) + { + break; + } + else + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n); + if(n->arena != 0) + { + arena_release(n->arena); + } + } + } + } + } + if(!slot_has_work) { - slot_has_work = 1; break; } } } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(C_BlobNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) - { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(c_shared->blob_stripes_free_nodes[stripe_idx], n); - if(n->arena != 0) - { - arena_release(n->arena); - } - } - } - } } + ProfEnd(); } diff --git a/src/content/content.h b/src/content/content.h index b91ad606..659c5c03 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -63,6 +63,17 @@ struct C_Key C_ID id; }; +//////////////////////////////// +//~ rjf: Cache Stripe Type + +typedef struct C_Stripe C_Stripe; +struct C_Stripe +{ + Arena *arena; + RWMutex rw_mutex; + CondVar cv; +}; + //////////////////////////////// //~ rjf: Root Cache Types @@ -135,7 +146,7 @@ struct C_BlobNode U128 hash; Arena *arena; String8 data; - U64 scope_ref_count; + AccessPt access_pt; U64 key_ref_count; U64 downstream_ref_count; }; @@ -147,14 +158,6 @@ struct C_BlobSlot C_BlobNode *last; }; -typedef struct C_Stripe C_Stripe; -struct C_Stripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; -}; - //////////////////////////////// //~ rjf: Shared State @@ -217,6 +220,11 @@ internal void c_root_release(C_Root root); internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data); +//////////////////////////////// +//~ rjf: Key Closing + +internal void c_close_key(C_Key key); + //////////////////////////////// //~ rjf: Downstream Accesses diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 9755cc44..a4d49003 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -346,9 +346,7 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) // rjf: nonzero node, request if needed - touch & return results if(node != 0) { - ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx()); - access_touch(access, &node->scope_ref_count, stripe->cv); + access_touch(access, &node->access_pt, stripe->cv); MemoryCopyStruct(&info, &node->info); } } @@ -411,10 +409,7 @@ dasm_tick(void) RWMutexScope(stripe->rw_mutex, write_mode) for(DASM_Node *n = slot->first; n != 0; n = n->next) { // rjf: node needs eviction - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - ins_atomic_u64_eval(&n->working_count) == 0) + if(access_pt_is_expired(&n->access_pt) && ins_atomic_u64_eval(&n->working_count) == 0) { slot_has_work = 1; if(!write_mode) diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 890a4bd0..e95cb148 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -196,10 +196,8 @@ struct DASM_Node DASM_Info info; // rjf: metadata + AccessPt access_pt; U64 working_count; - U64 scope_ref_count; - U64 last_time_touched_us; - U64 last_user_clock_idx_touched; U64 last_time_requested_us; U64 last_user_clock_idx_requested; }; @@ -249,8 +247,6 @@ struct DASM_Shared DASM_RequestNode *first_req; DASM_RequestNode *last_req; U64 req_count; - - // rjf: request take counter U64 lane_req_take_counter; }; diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 0f4003ba..938fe565 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -53,9 +53,7 @@ geo_buffer_from_hash(Access *access, U128 hash) { handle = n->buffer; found = !r_handle_match(r_handle_zero(), handle); - ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); - access_touch(access, &n->scope_ref_count, stripe->cv); + access_touch(access, &n->access_pt, stripe->cv); break; } } @@ -249,9 +247,7 @@ geo_evictor_thread__entry_point(void *p) { for(GEO_Node *n = slot->first; n != 0; n = n->next) { - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + if(access_pt_is_expired(&n->access_pt) && n->load_count != 0 && n->is_working == 0) { @@ -265,9 +261,7 @@ geo_evictor_thread__entry_point(void *p) for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next) { next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + if(access_pt_is_expired(&n->access_pt) && n->load_count != 0 && n->is_working == 0) { diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index af88db79..fe55b7b0 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -15,10 +15,8 @@ struct GEO_Node U128 hash; R_Handle buffer; B32 is_working; - U64 scope_ref_count; - U64 last_time_touched_us; - U64 last_user_clock_idx_touched; U64 load_count; + AccessPt access_pt; }; typedef struct GEO_Slot GEO_Slot; diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 554c8dd1..edca8496 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1641,9 +1641,7 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) info.bytes_processed = ins_atomic_u64_eval(&n->info.bytes_processed); info.bytes_to_process = ins_atomic_u64_eval(&n->info.bytes_to_process); found = 1; - ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); - access_touch(access, &n->scope_ref_count, stripe->cv); + access_touch(access, &n->access_pt, stripe->cv); break; } } @@ -2434,10 +2432,6 @@ txt_evictor_thread__entry_point(void *p) ThreadNameF("txt_evictor_thread"); for(;;) { - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 2*1000000; - U64 evict_threshold_user_clocks = 10; for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1) { U64 stripe_idx = slot_idx%txt_shared->stripes_count; @@ -2448,9 +2442,7 @@ txt_evictor_thread__entry_point(void *p) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + if(access_pt_is_expired(&n->access_pt) && n->load_count != 0 && n->is_working == 0) { @@ -2464,9 +2456,7 @@ txt_evictor_thread__entry_point(void *p) for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) { next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && + if(access_pt_is_expired(&n->access_pt) && n->load_count != 0 && n->is_working == 0) { diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index abf41f24..3e5d5cb2 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -174,10 +174,8 @@ struct TXT_Node TXT_TextInfo info; // rjf: metadata + AccessPt access_pt; B32 is_working; - U64 scope_ref_count; - U64 last_time_touched_us; - U64 last_user_clock_idx_touched; U64 load_count; }; diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index d5e63181..95d137a0 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -37,11 +37,8 @@ tex_init(void) tex_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); tex_shared->stripes[idx].cv = cond_var_alloc(); } - tex_shared->u2x_ring_size = KB(64); - tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); - tex_shared->u2x_ring_cv = cond_var_alloc(); - tex_shared->u2x_ring_mutex = mutex_alloc(); - tex_shared->evictor_thread = thread_launch(tex_evictor_thread__entry_point, 0); + tex_shared->req_mutex = mutex_alloc(); + tex_shared->req_arena = arena_alloc(); } //////////////////////////////// @@ -52,42 +49,32 @@ tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology) { R_Handle handle = {0}; { + //- rjf: unpack hash U64 slot_idx = hash.u64[1]%tex_shared->slots_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count; TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - B32 found = 0; - B32 stale = 0; - MutexScopeR(stripe->rw_mutex) + + //- rjf: get results, request if needed + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) - { - handle = n->texture; - found = !r_handle_match(r_handle_zero(), handle); - ins_atomic_u64_eval_assign(&n->last_time_touched_us, os_now_microseconds()); - ins_atomic_u64_eval_assign(&n->last_user_clock_idx_touched, update_tick_idx()); - access_touch(access, &n->scope_ref_count, stripe->cv); - break; - } - } - } - B32 node_is_new = 0; - if(!found) - { - MutexScopeW(stripe->rw_mutex) + B32 got_node = 0; + RWMutexScope(stripe->rw_mutex, write_mode) { + // rjf: get node TEX_Node *node = 0; for(TEX_Node *n = slot->first; n != 0; n = n->next) { if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) { node = n; + got_node = 1; break; } } - if(node == 0) + + // rjf: no node? -> create & request + if(write_mode && !node) { node = tex_shared->stripes_free_nodes[stripe_idx]; if(node) @@ -102,14 +89,27 @@ tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology) DLLPushBack(slot->first, slot->last, node); node->hash = hash; MemoryCopyStruct(&node->topology, &topology); - node_is_new = 1; + MutexScope(tex_shared->req_mutex) + { + TEX_RequestNode *n = push_array(tex_shared->req_arena, TEX_RequestNode, 1); + SLLQueuePush(tex_shared->first_req, tex_shared->last_req, n); + n->v.hash = hash; + n->v.top = topology; + tex_shared->req_count += 1; + } + } + + // rjf: node? -> grab & access + if(!write_mode && node) + { + handle = node->texture; + access_touch(access, &node->access_pt, stripe->cv); } } - } - if(node_is_new) - { - tex_u2x_enqueue_req(hash, topology, max_U64); - async_push_work(tex_xfer_work); + if(got_node) + { + break; + } } } return handle; @@ -136,173 +136,129 @@ tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, } //////////////////////////////// -//~ rjf: Transfer Threads - -internal B32 -tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) -{ - B32 good = 0; - MutexScope(tex_shared->u2x_ring_mutex) for(;;) - { - U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; - U64 available_size = tex_shared->u2x_ring_size-unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(top)) - { - good = 1; - tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &hash); - tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &top); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(tex_shared->u2x_ring_cv); - } - return good; -} +//~ rjf: Tick internal void -tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) -{ - MutexScope(tex_shared->u2x_ring_mutex) for(;;) - { - U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out)+sizeof(*top_out)) - { - tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, hash_out); - tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out); - break; - } - cond_var_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64); - } - cond_var_broadcast(tex_shared->u2x_ring_cv); -} - -ASYNC_WORK_DEF(tex_xfer_work) +tex_tick(void) { + if(ins_atomic_u64_eval(&tex_shared) == 0) { return; } ProfBeginFunction(); - Access *access = access_open(); + Temp scratch = scratch_begin(0, 0); - //- rjf: decode - U128 hash = {0}; - TEX_Topology top = {0}; - tex_u2x_dequeue_req(&hash, &top); - - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%tex_shared->slots_count; - U64 stripe_idx = slot_idx%tex_shared->stripes_count; - TEX_Slot *slot = &tex_shared->slots[slot_idx]; - TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - - //- rjf: take task - B32 got_task = 0; - MutexScopeR(stripe->rw_mutex) - { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) - { - got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); - break; - } - } - } - - //- rjf: hash -> data - String8 data = {0}; - if(got_task) - { - data = c_data_from_hash(access, hash); - } - - //- rjf: data * topology -> texture - R_Handle texture = {0}; - if(got_task && top.dim.x > 0 && top.dim.y > 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt]) - { - texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); - } - - //- rjf: commit results to cache - if(got_task) MutexScopeW(stripe->rw_mutex) - { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) - { - n->texture = texture; - ins_atomic_u32_eval_assign(&n->is_working, 0); - ins_atomic_u64_inc_eval(&n->load_count); - break; - } - } - } - - access_close(access); - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void -tex_evictor_thread__entry_point(void *p) -{ - ThreadNameF("tex_evictor_thread"); - for(;;) + //- rjf: do eviction pass { U64 check_time_us = os_now_microseconds(); U64 check_time_user_clocks = update_tick_idx(); U64 evict_threshold_us = 10*1000000; U64 evict_threshold_user_clocks = 10; - for(U64 slot_idx = 0; slot_idx < tex_shared->slots_count; slot_idx += 1) + Rng1U64 range = lane_range(tex_shared->slots_count); + for EachInRange(slot_idx, range) { U64 stripe_idx = slot_idx%tex_shared->stripes_count; TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - for(TEX_Node *n = slot->first; n != 0; n = n->next) + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) { - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) + for(TEX_Node *n = slot->first; n != 0; n = n->next) { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(TEX_Node *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) - { - DLLRemove(slot->first, slot->last, n); - if(!r_handle_match(n->texture, r_handle_zero())) + if(access_pt_is_expired(&n->access_pt) && + n->load_count != 0 && + n->working_count == 0) { - r_tex2d_release(n->texture); + slot_has_work = 1; + if(!write_mode) + { + break; + } + else + { + DLLRemove(slot->first, slot->last, n); + if(!r_handle_match(n->texture, r_handle_zero())) + { + r_tex2d_release(n->texture); + } + SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n); + } } - SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n); } } + if(!slot_has_work) + { + break; + } } - os_sleep_milliseconds(5); } - os_sleep_milliseconds(1000); } + + //- rjf: gather all requests + local_persist TEX_Request *reqs = 0; + local_persist U64 reqs_count = 0; + if(lane_idx() == 0) MutexScope(tex_shared->req_mutex) + { + reqs_count = tex_shared->req_count; + reqs = push_array(scratch.arena, TEX_Request, reqs_count); + U64 idx = 0; + for EachNode(r, TEX_RequestNode, tex_shared->first_req) + { + MemoryCopyStruct(&reqs[idx], &r->v); + idx += 1; + } + arena_clear(tex_shared->req_arena); + tex_shared->first_req = tex_shared->last_req = 0; + tex_shared->req_count = 0; + tex_shared->lane_req_take_counter = 0; + } + lane_sync(); + + //- rjf: do requests + for(;;) + { + //- rjf: get next request + U64 req_num = ins_atomic_u64_inc_eval(&tex_shared->lane_req_take_counter); + if(req_num < 1 || reqs_count < req_num) + { + break; + } + U64 req_idx = req_num-1; + U128 hash = reqs[req_idx].hash; + TEX_Topology top = reqs[req_idx].top; + Access *access = access_open(); + + //- rjf: unpack request + U64 slot_idx = hash.u64[1]%tex_shared->slots_count; + U64 stripe_idx = slot_idx%tex_shared->stripes_count; + TEX_Slot *slot = &tex_shared->slots[slot_idx]; + TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; + String8 data = c_data_from_hash(access, hash); + + //- rjf: create texture + R_Handle texture = {0}; + if(top.dim.x > 0 && top.dim.y > 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt]) + { + texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); + } + + //- rjf: commit results to cache + RWMutexScope(stripe->rw_mutex, 1) + { + for(TEX_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) + { + n->texture = texture; + ins_atomic_u64_dec_eval(&n->working_count); + ins_atomic_u64_inc_eval(&n->load_count); + break; + } + } + } + + access_close(access); + } + + scratch_end(scratch); + ProfEnd(); } diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index a9140e91..86ac7e96 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -25,10 +25,8 @@ struct TEX_Node U128 hash; TEX_Topology topology; R_Handle texture; - B32 is_working; - U64 scope_ref_count; - U64 last_time_touched_us; - U64 last_user_clock_idx_touched; + AccessPt access_pt; + U64 working_count; U64 load_count; }; @@ -50,6 +48,20 @@ struct TEX_Stripe //////////////////////////////// //~ rjf: Shared State +typedef struct TEX_Request TEX_Request; +struct TEX_Request +{ + U128 hash; + TEX_Topology top; +}; + +typedef struct TEX_RequestNode TEX_RequestNode; +struct TEX_RequestNode +{ + TEX_RequestNode *next; + TEX_Request v; +}; + typedef struct TEX_Shared TEX_Shared; struct TEX_Shared { @@ -62,16 +74,13 @@ struct TEX_Shared TEX_Stripe *stripes; TEX_Node **stripes_free_nodes; - // rjf: user -> xfer thread - U64 u2x_ring_size; - U8 *u2x_ring_base; - U64 u2x_ring_write_pos; - U64 u2x_ring_read_pos; - CondVar u2x_ring_cv; - Mutex u2x_ring_mutex; - - // rjf: evictor thread - Thread evictor_thread; + // rjf: requests + Mutex req_mutex; + Arena *req_arena; + TEX_RequestNode *first_req; + TEX_RequestNode *last_req; + U64 req_count; + U64 lane_req_take_counter; }; //////////////////////////////// @@ -96,15 +105,8 @@ internal R_Handle tex_texture_from_hash_topology(Access *access, U128 hash, TEX_ internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out); //////////////////////////////// -//~ rjf: Transfer Threads +//~ rjf: Tick -internal B32 tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us); -internal void tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out); -ASYNC_WORK_DEF(tex_xfer_work); - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void tex_evictor_thread__entry_point(void *p); +internal void tex_tick(void); #endif //TEXTURE_CACHE_H From 53054e5addca54cecc1c4edca6e51c63f497051f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 19 Sep 2025 16:41:49 -0700 Subject: [PATCH 214/302] fix incorrect loop-again logic on async threads --- src/base/base_entry_point.c | 8 ++++---- src/texture_cache/texture_cache.c | 1 + src/texture_cache/texture_cache.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index b9cc7abe..4a7726ed 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -193,10 +193,10 @@ async_thread_entry_point(void *params) if(!ins_atomic_u32_eval(&async_loop_again)) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); - if(lane_idx() == 0) - { - async_loop_again = 0; - } + } + else if(lane_idx() == 0) + { + async_loop_again = 0; } #if defined(CONTENT_H) c_tick(); diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 95d137a0..a5b598a2 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -97,6 +97,7 @@ tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology) n->v.top = topology; tex_shared->req_count += 1; } + cond_var_broadcast(async_tick_start_cond_var); } // rjf: node? -> grab & access diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 86ac7e96..6eece14c 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -109,4 +109,4 @@ internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_T internal void tex_tick(void); -#endif //TEXTURE_CACHE_H +#endif // TEXTURE_CACHE_H From 1745ad47584d9c59867a798b3e2895e3c4eec08e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 19 Sep 2025 16:55:07 -0700 Subject: [PATCH 215/302] eliminate old profiling markup --- src/draw/draw.c | 8 -------- src/font_cache/font_cache.c | 21 --------------------- src/ui/ui_core.c | 18 ------------------ 3 files changed, 47 deletions(-) diff --git a/src/draw/draw.c b/src/draw/draw.c index 82145c4a..250317cb 100644 --- a/src/draw/draw.c +++ b/src/draw/draw.c @@ -165,7 +165,6 @@ dr_fuzzy_match_find_from_fstrs(Arena *arena, DR_FStrList *fstrs, String8 needle) internal DR_FRunList dr_fruns_from_fstrs(Arena *arena, F32 tab_size_px, DR_FStrList *strs) { - ProfBeginFunction(); DR_FRunList run_list = {0}; F32 base_align_px = 0; for(DR_FStrNode *n = strs->first; n != 0; n = n->next) @@ -182,7 +181,6 @@ dr_fruns_from_fstrs(Arena *arena, F32 tab_size_px, DR_FStrList *strs) run_list.dim.y = Max(run_list.dim.y, dst_n->v.run.dim.y); base_align_px += dst_n->v.run.dim.x; } - ProfEnd(); return run_list; } @@ -536,8 +534,6 @@ dr_sub_bucket(DR_Bucket *bucket) internal void dr_truncated_fancy_run_list(Vec2F32 p, DR_FRunList *list, F32 max_x, FNT_Run trailer_run) { - ProfBeginFunction(); - //- rjf: total advance > max? -> enable trailer B32 trailer_enabled = (list->dim.x > max_x && trailer_run.dim.x < max_x); @@ -632,8 +628,6 @@ dr_truncated_fancy_run_list(Vec2F32 p, DR_FRunList *list, F32 max_x, FNT_Run tra advance += piece->advance; } } - - ProfEnd(); } internal void @@ -691,7 +685,6 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FRunList *list, F32 max_x, Fu internal void dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run) { - ProfBeginFunction(); F32 advance = 0; FNT_Piece *piece_first = run.pieces.v; FNT_Piece *piece_opl = piece_first + run.pieces.count; @@ -712,7 +705,6 @@ dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run) } advance += piece->advance; } - ProfEnd(); } internal void diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index 330e03bc..6779aa72 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -246,8 +246,6 @@ fnt_path_from_tag(FNT_Tag tag) internal Rng2S16 fnt_atlas_region_alloc(Arena *arena, FNT_Atlas *atlas, Vec2S16 needed_size) { - ProfBeginFunction(); - //- rjf: find node with best-fit size Vec2S16 region_p0 = {0}; Vec2S16 region_sz = {0}; @@ -356,15 +354,12 @@ fnt_atlas_region_alloc(Arena *arena, FNT_Atlas *atlas, Vec2S16 needed_size) Rng2S16 result = {0}; result.p0 = region_p0; result.p1 = add_2s16(region_p0, region_sz); - ProfEnd(); return result; } internal void fnt_atlas_region_release(FNT_Atlas *atlas, Rng2S16 region) { - ProfBeginFunction(); - //- rjf: extract region size Vec2S16 region_size = v2s16(region.x1 - region.x0, region.y1 - region.y0); @@ -463,7 +458,6 @@ fnt_atlas_region_release(FNT_Atlas *atlas, Rng2S16 region) } } } - ProfEnd(); } //////////////////////////////// @@ -542,7 +536,6 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) //- rjf: style hash -> style node FNT_Hash2StyleRasterCacheNode *hash2style_node = 0; { - ProfBegin("style hash -> style node"); U64 slot_idx = style_hash%fnt_state->hash2style_slots_count; FNT_Hash2StyleRasterCacheSlot *slot = &fnt_state->hash2style_slots[slot_idx]; for(FNT_Hash2StyleRasterCacheNode *n = slot->first; @@ -567,7 +560,6 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) hash2style_node->hash2info_slots_count = 1024; hash2style_node->hash2info_slots = push_array(fnt_state->raster_arena, FNT_Hash2InfoRasterCacheSlot, hash2style_node->hash2info_slots_count); } - ProfEnd(); } return hash2style_node; @@ -576,8 +568,6 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) internal FNT_Run fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, String8 string) { - ProfBeginFunction(); - //- rjf: map tag/size to style node FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags); @@ -615,8 +605,6 @@ fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F run = run_node->run; } else - ProfScope("no run node? -> cache miss") - ProfScope("compute & build & fill node for '%.*s'", str8_varg(string)) { //- rjf: decode string & produce run pieces FNT_PieceChunkList piece_chunks = {0}; @@ -700,7 +688,6 @@ fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F //- rjf: no info found -> miss... fill this hash in the cache if(info == 0) { - ProfBegin("no info found -> miss... fill this hash in the cache"); Temp scratch = scratch_begin(0, 0); // rjf: grab font handle for this tag if we don't have one already @@ -822,7 +809,6 @@ fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F } scratch_end(scratch); - ProfEnd(); } //- rjf: push piece for this raster portion @@ -898,7 +884,6 @@ fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F run_node->run = run; } - ProfEnd(); return run; } @@ -1018,20 +1003,17 @@ fnt_wrapped_string_lines_from_font_size_string_max(Arena *arena, FNT_Tag font, F internal Vec2F32 fnt_dim_from_tag_size_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string) { - ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); Vec2F32 result = {0}; FNT_Run run = fnt_run_from_string(tag, size, base_align_px, tab_size_px, 0, string); result = run.dim; scratch_end(scratch); - ProfEnd(); return result; } internal Vec2F32 fnt_dim_from_tag_size_string_list(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8List list) { - ProfBeginFunction(); Vec2F32 sum = {0}; for(String8Node *n = list.first; n != 0; n = n->next) { @@ -1039,7 +1021,6 @@ fnt_dim_from_tag_size_string_list(FNT_Tag tag, F32 size, F32 base_align_px, F32 sum.x += str_dim.x; sum.y = Max(sum.y, str_dim.y); } - ProfEnd(); return sum; } @@ -1084,7 +1065,6 @@ fnt_char_pos_from_tag_size_string_p(FNT_Tag tag, F32 size, F32 base_align_px, F3 internal FNT_Metrics fnt_metrics_from_tag_size(FNT_Tag tag, F32 size) { - ProfBeginFunction(); FP_Metrics metrics = fnt_fp_metrics_from_tag(tag); FNT_Metrics result = {0}; { @@ -1093,7 +1073,6 @@ fnt_metrics_from_tag_size(FNT_Tag tag, F32 size) result.line_gap = floor_f32(size) * metrics.line_gap / metrics.design_units_per_em; result.capital_height = floor_f32(size) * metrics.capital_height / metrics.design_units_per_em; } - ProfEnd(); return result; } diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 8bd50c8f..333d1b47 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -9,12 +9,6 @@ thread_static UI_State *ui_state = 0; //////////////////////////////// //~ rjf: Basic Type Functions -#if !defined(XXH_IMPLEMENTATION) -# define XXH_IMPLEMENTATION -# define XXH_STATIC_LINKING_ONLY -# include "third_party/xxHash/xxhash.h" -#endif - internal String8 ui_hash_part_from_key_string(String8 string) { @@ -56,14 +50,12 @@ ui_key_make(U64 v) internal UI_Key ui_key_from_string(UI_Key seed_key, String8 string) { - ProfBeginFunction(); UI_Key result = {0}; if(string.size != 0) { String8 hash_part = ui_hash_part_from_key_string(string); result.u64[0] = u64_hash_from_seed_str8(seed_key.u64[0], hash_part); } - ProfEnd(); return result; } @@ -2416,7 +2408,6 @@ ui_color_from_tags_key_name(UI_Key key, String8 name) internal UI_Box * ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) { - ProfBeginFunction(); ui_state->build_box_count += 1; //- rjf: grab active parent @@ -2622,7 +2613,6 @@ ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) } //- rjf: return - ProfEnd(); return box; } @@ -2646,8 +2636,6 @@ ui_active_seed_key(void) internal UI_Box * ui_build_box_from_string(UI_BoxFlags flags, String8 string) { - ProfBeginFunction(); - //- rjf: grab active parent UI_Box *parent = ui_top_parent(); @@ -2662,7 +2650,6 @@ ui_build_box_from_string(UI_BoxFlags flags, String8 string) } //- rjf: return - ProfEnd(); return box; } @@ -2684,7 +2671,6 @@ ui_build_box_from_stringf(UI_BoxFlags flags, char *fmt, ...) internal void ui_box_equip_display_string(UI_Box *box, String8 string) { - ProfBeginFunction(); box->string = push_str8_copy(ui_build_arena(), string); box->flags |= UI_BoxFlag_HasDisplayString; Vec4F32 text_color = box->text_color; @@ -2721,7 +2707,6 @@ ui_box_equip_display_string(UI_Box *box, String8 string) } scratch_end(scratch); } - ProfEnd(); } internal void @@ -2822,7 +2807,6 @@ ui_box_char_pos_from_xy(UI_Box *box, Vec2F32 xy) internal UI_Signal ui_signal_from_box(UI_Box *box) { - ProfBeginFunction(); B32 is_focus_hot = box->flags & UI_BoxFlag_FocusHot && !(box->flags & UI_BoxFlag_FocusHotDisabled); UI_Signal sig = {box}; sig.event_flags |= os_get_modifiers(); @@ -2843,7 +2827,6 @@ ui_signal_from_box(UI_Box *box) //- rjf: determine if we're under the context menu or not // B32 ctx_menu_is_ancestor = 0; - ProfScope("check context menu ancestor") { for(UI_Box *parent = box; !ui_box_is_nil(parent); parent = parent->parent) { @@ -3230,7 +3213,6 @@ ui_signal_from_box(UI_Box *box) } } - ProfEnd(); return sig; } From aa0eec576381fb621709b844752defc534e28165 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 19 Sep 2025 16:58:41 -0700 Subject: [PATCH 216/302] prevent focusing null window, which was causing weird input event stealing on run... --- src/os/gfx/win32/os_gfx_win32.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index 7874d97e..5b8ab880 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -1382,8 +1382,11 @@ internal void os_focus_external_window(OS_Handle handle) { HWND hwnd = (HWND)handle.u64[0]; - SetForegroundWindow(hwnd); - SetFocus(hwnd); + if(hwnd != 0) + { + SetForegroundWindow(hwnd); + SetFocus(hwnd); + } } //////////////////////////////// From e864674fbda61cb573fe6bf30685688f8d4ed23f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 15:19:56 -0700 Subject: [PATCH 217/302] add pgo support to build.cmd --- build.bat | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/build.bat b/build.bat index 34a69c08..872312bf 100644 --- a/build.bat +++ b/build.bat @@ -43,6 +43,26 @@ if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELE if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled] if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] +if "%pgo%"=="1" ( + if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1 + where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 + + if "%clang%"=="1" ( + if "%pgo_run%" == "1" ( + call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1 + set auto_compile_flags=%auto_compile_flags% -fprofile-use=%~dp0build\build.profdata + set pgo_run=0 + ) else ( + echo [pgo enabled] + set auto_compile_flags=%auto_compile_flags% -fprofile-generate -mllvm -vp-counters-per-site=5 + set LLVM_PROFILE_FILE=%~dp0build\build.profraw + set pgo_run=1 + ) + ) else ( + echo ERROR: PGO build is not supported with current compiler + exit /b 1 + ) +) :: --- Compile/Link Line Definitions ------------------------------------------ set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 @@ -139,3 +159,15 @@ if "%didbuild%"=="" ( echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`. exit /b 1 ) + +:: --- PGO Run --------------------------------------------------------------- + +if "%pgo_run%"=="1" ( + if "%radlink%"=="1" ( + pushd build + call radlink lnk.obj /debug:full + popd + ) + call %0 %* +) + From 17058e71bf409f2feb9a1ccfdfb61476307d89c5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 15:56:13 -0700 Subject: [PATCH 218/302] remove empty nodes --- src/linker/lnk_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index cd4f5e82..28ab3673 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -55,7 +55,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L // parse symbol names { Temp scratch = scratch_begin(&arena, 1); - String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties); + String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0); Assert(symbol_name_list.node_count >= symbol_count); symbol_names = str8_array_from_list(arena, &symbol_name_list); scratch_end(scratch); From a060f581d9ea827794c123a1e4d9405323c8a260 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 16:01:07 -0700 Subject: [PATCH 219/302] stub /d2 --- src/linker/lnk_config.c | 5 +++++ src/linker/lnk_config.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 688b3915..eb9b1f7d 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -32,6 +32,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = { LNK_CmdSwitch_Dll, 0, "DLL", "", "" }, { LNK_CmdSwitch_NotImplemented, 0, "DRIVER", "", "" }, { LNK_CmdSwitch_DisallowLib, 1, "DISALLOWLIB", ":LIBRARY", "", }, + { LNK_CmdSwitch_D2, 0, "D2", "" }, { LNK_CmdSwitch_EditAndContinue, 1, "EDITANDCONTINUE", "[:NO]", "" }, { LNK_CmdSwitch_DynamicBase, 0, "DYNAMICBASE", "[:NO]", "" }, { LNK_CmdSwitch_NotImplemented, 0, "EMITVOLATILEMETADATA", "", "" }, @@ -1286,6 +1287,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unsupported switch; binary dump is done by passing /DUMP to link.exe"); } break; + case LNK_CmdSwitch_D2: { + // not supported -- ignore + } break; + case LNK_CmdSwitch_Entry: { String8 new_entry_point_name = {0}; lnk_cmd_switch_parse_string_copy(config->arena, obj, cmd_switch, value_strings, &new_entry_point_name); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 86cc075e..32fc0fa0 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -45,6 +45,7 @@ typedef enum LNK_CmdSwitch_Dll, LNK_CmdSwitch_DynamicBase, LNK_CmdSwitch_Dump, + LNK_CmdSwitch_D2, LNK_CmdSwitch_Entry, LNK_CmdSwitch_ErrorReport, LNK_CmdSwitch_Export, From ce044e7e83924c16a70a36cf42ed81d793806e56 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 16:22:33 -0700 Subject: [PATCH 220/302] detect removed fixup symbol and propagate correct section number --- src/linker/lnk.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 9c91ba89..c8926852 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2897,12 +2897,13 @@ lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patch LNK_ObjSymbolRef fixup_symbol = {0}; B32 is_resolved = lnk_resolve_symbol(symtab, symbol_to_resolve, &fixup_symbol); if (is_resolved) { - COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx); - COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class); + COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx); + COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class); + B32 was_fixup_removed = fixup_src.section_number == lnk_obj_get_removed_section_number(fixup_symbol.obj); U32 section_number; U32 value; - if (fixup_type == COFF_SymbolValueInterp_Undefined || fixup_type == COFF_SymbolValueInterp_Weak) { + if (was_fixup_removed || fixup_type == COFF_SymbolValueInterp_Undefined || fixup_type == COFF_SymbolValueInterp_Weak) { section_number = lnk_obj_get_removed_section_number(obj); value = 0; } else { From ee75ada087572d2483c4226329e56b7ea21710ea Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 16:43:39 -0700 Subject: [PATCH 221/302] mark function override meta-data sections with link info flag so they do not get a section definition --- src/linker/lnk_obj.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index aa3362d7..7a8e1a88 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -261,15 +261,24 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // - // mark debug info sections + // mark sections // { for EachIndex(sect_idx, header.section_count_no_null) { COFF_SectionHeader *sect_header = &coff_section_table[sect_idx]; - String8 sect_name = str8_cstring_capped(sect_header->name, sect_header->name + sizeof(sect_header->name)); + String8 sect_name = coff_name_from_section_header(raw_coff_string_table, sect_header); + + // debug info if (str8_starts_with(sect_name, str8_lit(".debug$"))) { sect_header->flags |= LNK_SECTION_FLAG_DEBUG; } + + // function overrides + if (str8_ends_with(sect_name, str8_lit("$fo$"), 0) || + str8_ends_with(sect_name, str8_lit("$fo_rvas$"), 0) || + str8_ends_with(sect_name, str8_lit("$fo_bdd$"), 0)) { + sect_header->flags |= COFF_SectionFlag_LnkInfo; + } } } From 371e52ad421c3bf55d4aca2e67bac11a7e6d4acd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 17 Sep 2025 18:49:48 -0700 Subject: [PATCH 222/302] add /rad_alt_pch_dir for remapping objs in the local folder for pgo builds --- src/linker/lnk.c | 2 +- src/linker/lnk_config.c | 10 ++++++++++ src/linker/lnk_config.h | 2 ++ src/linker/lnk_debug_info.c | 20 ++++++++++++++++---- src/linker/lnk_debug_info.h | 4 ++-- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index c8926852..cb463e94 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -5032,7 +5032,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) // // CodeView // - LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, debug_info_objs_count, debug_info_objs); + LNK_CodeViewInput input = lnk_make_code_view_input(tp, arena, config->io_flags, config->lib_dir_list, config->alt_pch_dirs, debug_info_objs_count, debug_info_objs); CV_DebugT *types = lnk_import_types(tp, arena, &input); // diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index eb9b1f7d..a06de23b 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -124,6 +124,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] = //- internal switches { LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." }, + { LNK_CmdSwitch_Rad_AltPchDir, 0, "RAD_ALT_PCH_DIR", ":PATH", "Alternative directory to search for PCH object files." }, { LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." }, { LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" }, { LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." }, @@ -1779,6 +1780,15 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List lnk_cmd_switch_parse_u32(obj, cmd_switch, value_strings, &config->age, 0); } break; + case LNK_CmdSwitch_Rad_AltPchDir: { + if (value_strings.node_count == 0) { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "missing parameters"); + break; + } + String8List dirs = str8_list_copy(config->arena, &value_strings); + str8_list_concat_in_place(&config->alt_pch_dirs, &dirs); + } break; + case LNK_CmdSwitch_Rad_BuildInfo: { lnk_print_build_info(); os_abort(0); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 32fc0fa0..3638ea29 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -151,6 +151,7 @@ typedef enum LNK_CmdSwitch_Wx, LNK_CmdSwitch_Rad_Age, + LNK_CmdSwitch_Rad_AltPchDir, LNK_CmdSwitch_Rad_BuildInfo, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, LNK_CmdSwitch_Rad_Debug, @@ -417,6 +418,7 @@ typedef struct LNK_Config U64 unresolved_symbol_limit; U64 unresolved_symbol_ref_limit; LNK_SwitchState map_lines_for_unresolved_symbols; + String8List alt_pch_dirs; } LNK_Config; // --- MSVC Error Codes -------------------------------------------------------- diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index f0fdf62d..3a86eb4f 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -140,7 +140,7 @@ THREAD_POOL_TASK_FUNC(lnk_parse_cv_symbols_task) } internal LNK_PchInfo * -lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols) +lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols, String8List alt_pch_dirs) { Temp scratch = scratch_begin(&arena, 1); @@ -180,9 +180,20 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t String8 obj_path = path_absolute_dst_from_relative_dst_src(scratch.arena, precomp.obj_name, work_dir); + // map obj name in LF_PRECOMP to obj index - U64 debug_p_obj_idx; + U64 debug_p_obj_idx = max_U64; if (!hash_table_search_path_u64(debug_p_ht, obj_path, &debug_p_obj_idx)) { + String8 obj_name = str8_skip_last_slash(obj_path); + for EachNode(alt_dir_n, String8Node, alt_pch_dirs.first) { + String8 alt_obj_path = str8f(scratch.arena, "%S/%S", alt_dir_n->string, obj_name); + if (hash_table_search_path_u64(debug_p_ht, alt_obj_path, &debug_p_obj_idx)) { + break; + } + } + } + + if (debug_p_obj_idx == max_U64) { lnk_error_obj(LNK_Error_PrecompObjNotFound, obj_arr[obj_idx], "LF_PRECOMP references non-existent obj %S", obj_path); lnk_exit(LNK_Error_PrecompObjNotFound); } @@ -358,7 +369,7 @@ lnk_merge_debug_t_and_debug_p(Arena *arena, U64 obj_count, CV_DebugT *debug_t_ar } internal LNK_CodeViewInput -lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, U64 obj_count, LNK_Obj **obj_arr) +lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, String8List alt_pch_dirs, U64 obj_count, LNK_Obj **obj_arr) { ProfBegin("Extract CodeView"); Temp scratch = scratch_begin(0,0); @@ -522,7 +533,8 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla internal_obj_arr, internal_debug_t_arr, internal_debug_p_arr, - internal_parsed_symbols); + internal_parsed_symbols, + alt_pch_dirs); CV_DebugT *merged_debug_t_p_arr = lnk_merge_debug_t_and_debug_p(tp_arena->v[0], internal_count, internal_debug_t_arr, internal_debug_p_arr); diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index 8f086ba3..ba8990b3 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -496,9 +496,9 @@ typedef struct internal CV_DebugS * lnk_parse_debug_s_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *sect_list_arr); internal CV_DebugT * lnk_parse_debug_t_sections(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8List *debug_t_list_arr); internal CV_SymbolList * lnk_cv_symbol_list_arr_from_debug_s_arr(TP_Context *tp, TP_Arena *arena, U64 obj_count, CV_DebugS *debug_s_arr); -internal LNK_PchInfo * lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols); +internal LNK_PchInfo * lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t_arr, CV_DebugT *debug_p_arr, CV_SymbolListArray *parsed_symbols, String8List alt_pch_dirs); -internal LNK_CodeViewInput lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, U64 objs_count, LNK_Obj **objs); +internal LNK_CodeViewInput lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_flags, String8List lib_dir_list, String8List alt_pch_dirs, U64 objs_count, LNK_Obj **objs); internal LNK_LeafRef lnk_leaf_ref(U32 idx, U32 leaf_idx); internal LNK_LeafRef lnk_obj_leaf_ref(U32 obj_idx, U32 leaf_idx); From ac985bb5da1ed3e7e936a21d40598b6e0426b1ea Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:28:25 -0700 Subject: [PATCH 223/302] add a real pgo PGO target --- build.bat | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/build.bat b/build.bat index 872312bf..02ee7439 100644 --- a/build.bat +++ b/build.bat @@ -45,8 +45,7 @@ if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=add if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] if "%pgo%"=="1" ( if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1 - where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 - + where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 if "%clang%"=="1" ( if "%pgo_run%" == "1" ( call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1 @@ -160,12 +159,11 @@ if "%didbuild%"=="" ( exit /b 1 ) -:: --- PGO Run --------------------------------------------------------------- - +:: --- PGO Run ---------------------------------------------------------------- if "%pgo_run%"=="1" ( if "%radlink%"=="1" ( - pushd build - call radlink lnk.obj /debug:full + pushd local\lyra_pgo + call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1 popd ) call %0 %* From 553154eb39d713de3caef1da768031c1b4658b6b Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:29:02 -0700 Subject: [PATCH 224/302] layer color fix --- src/base/base_inc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/base_inc.c b/src/base/base_inc.c index ec199ac0..7e9462f5 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -5,7 +5,7 @@ //~ rjf: Base Includes #undef LAYER_COLOR -#define LAYER_COLOR 0.20f, 0.60f, 0.80f +#define LAYER_COLOR 0x3399ccff #include "base_core.c" #include "base_profile.c" From 42999bea631f098828469e55cab53aea13bb0362 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:30:23 -0700 Subject: [PATCH 225/302] profile markup obj relocation patching --- src/linker/lnk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index cb463e94..f4f0f0bc 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2974,6 +2974,8 @@ lnk_compute_win32_image_header_size(LNK_Config *config, U64 sect_count) internal THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) { + ProfBeginFunction(); + LNK_ObjRelocPatcher *task = raw_task; LNK_Obj *obj = task->objs[task_id]; @@ -3074,6 +3076,8 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) MemoryCopy(section_data.str + reloc->apply_off, &reloc_result, reloc_value.size); } } + + ProfEnd(); } internal int From 3d7afb58fad7f63feb7845b56ce3a642f6ee6b85 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:31:02 -0700 Subject: [PATCH 226/302] speed up symbol patching --- src/linker/lnk_debug_info.c | 58 ++++++++++++++++++++----------------- src/linker/lnk_debug_info.h | 1 + 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 3a86eb4f..0aeb62c5 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -179,8 +179,7 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t CV_PrecompInfo precomp = cv_precomp_info_from_leaf(precomp_leaf); String8 obj_path = path_absolute_dst_from_relative_dst_src(scratch.arena, precomp.obj_name, work_dir); - - + // map obj name in LF_PRECOMP to obj index U64 debug_p_obj_idx = max_U64; if (!hash_table_search_path_u64(debug_p_ht, obj_path, &debug_p_obj_idx)) { @@ -1981,39 +1980,43 @@ lnk_assign_type_indices(TP_Context *tp, LNK_LeafBucketArray bucket_arr, CV_TypeI internal THREAD_POOL_TASK_FUNC(lnk_patch_symbols_task) { + ProfBeginFunction(); LNK_PatchSymbolTypesTask *task = raw_task; - Arena *fixed_arena = task->arena_arr[worker_id]; - LNK_CodeViewSymbolsInput symbol_input = task->input->symbol_inputs[task_id]; + Arena *fixed_arena = task->arena_arr[task_id]; - LNK_LeafLocType loc_type = lnk_loc_type_from_obj_idx(task->input, symbol_input.obj_idx); - U64 loc_idx = lnk_loc_idx_from_obj_idx(task->input, symbol_input.obj_idx); + for EachInRange(symbol_input_idx, task->ranges[task_id]) { + LNK_CodeViewSymbolsInput symbol_input = task->input->symbol_inputs[symbol_input_idx]; + LNK_LeafLocType loc_type = lnk_loc_type_from_obj_idx(task->input, symbol_input.obj_idx); + U64 loc_idx = lnk_loc_idx_from_obj_idx(task->input, symbol_input.obj_idx); - CV_TypeIndex ti_lo_arr[CV_TypeIndexSource_COUNT]; - ti_lo_arr[CV_TypeIndexSource_NULL] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_NULL); - ti_lo_arr[CV_TypeIndexSource_TPI ] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_TPI); - ti_lo_arr[CV_TypeIndexSource_IPI ] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_IPI); + CV_TypeIndex ti_lo_arr[CV_TypeIndexSource_COUNT]; + ti_lo_arr[CV_TypeIndexSource_NULL] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_NULL); + ti_lo_arr[CV_TypeIndexSource_TPI ] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_TPI); + ti_lo_arr[CV_TypeIndexSource_IPI ] = lnk_ti_lo_from_loc(task->input, loc_type, loc_idx, CV_TypeIndexSource_IPI); - for (CV_SymbolNode *symnode = symbol_input.symbol_list->first; symnode != 0; symnode = symnode->next) { - Temp temp = temp_begin(fixed_arena); + for (CV_SymbolNode *symnode = symbol_input.symbol_list->first; symnode != 0; symnode = symnode->next) { + Temp temp = temp_begin(fixed_arena); - // find type index offsets in symbol - CV_TypeIndexInfoList ti_list = cv_get_symbol_type_index_offsets(temp.arena, symnode->data.kind, symnode->data.data); - - // overwrite type indices in symbol - for (CV_TypeIndexInfo *ti_info = ti_list.first; ti_info != 0; ti_info = ti_info->next) { - CV_TypeIndex *ti_ptr = (CV_TypeIndex *) (symnode->data.data.str + ti_info->offset); - if (*ti_ptr >= ti_lo_arr[ti_info->source]) { - LNK_LeafHashTable *leaf_ht = &task->leaf_ht_arr[ti_info->source]; - LNK_LeafRef leaf_ref = lnk_leaf_ref_from_loc_idx_and_ti(task->input, loc_type, ti_info->source, loc_idx, *ti_ptr); - LNK_LeafBucket *leaf_bucket = lnk_leaf_hash_table_search(leaf_ht, task->input, task->hashes, leaf_ref); + // find type index offsets in symbol + CV_TypeIndexInfoList ti_list = cv_get_symbol_type_index_offsets(temp.arena, symnode->data.kind, symnode->data.data); - // we overwrite section memory directly - *ti_ptr = leaf_bucket->type_index; + // overwrite type indices in symbol + for (CV_TypeIndexInfo *ti_info = ti_list.first; ti_info != 0; ti_info = ti_info->next) { + CV_TypeIndex *ti_ptr = (CV_TypeIndex *) (symnode->data.data.str + ti_info->offset); + if (*ti_ptr >= ti_lo_arr[ti_info->source]) { + LNK_LeafHashTable *leaf_ht = &task->leaf_ht_arr[ti_info->source]; + LNK_LeafRef leaf_ref = lnk_leaf_ref_from_loc_idx_and_ti(task->input, loc_type, ti_info->source, loc_idx, *ti_ptr); + LNK_LeafBucket *leaf_bucket = lnk_leaf_hash_table_search(leaf_ht, task->input, task->hashes, leaf_ref); + + // we overwrite section memory directly + *ti_ptr = leaf_bucket->type_index; + } } + + temp_end(temp); } - - temp_end(temp); } + ProfEnd(); } internal void @@ -2028,11 +2031,12 @@ lnk_patch_symbols(TP_Context *tp, U64 max_ti_list_size = sizeof(CV_TypeIndexInfo) * (max_U16 / sizeof(CV_TypeIndex)); LNK_PatchSymbolTypesTask task = {0}; + task.ranges = tp_divide_work(scratch.arena, input->total_symbol_input_count, tp->worker_count); task.input = input; task.hashes = hashes; task.leaf_ht_arr = leaf_ht_arr; task.arena_arr = alloc_fixed_size_arena_array(scratch.arena, tp->worker_count, max_ti_list_size, max_ti_list_size); - tp_for_parallel(tp, 0, input->total_symbol_input_count, lnk_patch_symbols_task, &task); + tp_for_parallel(tp, 0, tp->worker_count, lnk_patch_symbols_task, &task); scratch_end(scratch); ProfEnd(); diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index ba8990b3..5d93dd36 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -236,6 +236,7 @@ typedef struct typedef struct { + Rng1U64 *ranges; LNK_CodeViewInput *input; LNK_LeafHashes *hashes; LNK_LeafHashTable *leaf_ht_arr; From 872c387bad94784e1c1322bc8086124bdc0653b5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:32:18 -0700 Subject: [PATCH 227/302] let errors from MT to bubble up to linker's stdout and stderr --- src/linker/lnk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f4f0f0bc..bb7491c5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -394,7 +394,7 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest OS_ProcessLaunchParams launch_opts = {0}; launch_opts.cmd_line = cmd_line; launch_opts.inherit_env = 1; - launch_opts.consoleless = 1; + launch_opts.consoleless = 0; OS_Handle mt_handle = os_process_launch(&launch_opts); if (os_handle_match(mt_handle, os_handle_zero())) { lnk_error(LNK_Error_Mt, "unable to start process: %S", mt_path); From 362557e503f586b1ce32ae198ad9b7f56e0a2e19 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:37:44 -0700 Subject: [PATCH 228/302] renormalize line endings --- src/os/core/os_core.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 656ab4a4..a35852a6 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -286,11 +286,11 @@ internal void os_semaphore_release(Semaphore semaphore); internal Semaphore os_semaphore_open(String8 name); internal void os_semaphore_close(Semaphore semaphore); internal B32 os_semaphore_take(Semaphore semaphore, U64 endt_us); -internal void os_semaphore_drop(Semaphore semaphore); - -//- rjf: barriers -internal Barrier os_barrier_alloc(U64 count); -internal void os_barrier_release(Barrier barrier); +internal void os_semaphore_drop(Semaphore semaphore); + +//- rjf: barriers +internal Barrier os_barrier_alloc(U64 count); +internal void os_barrier_release(Barrier barrier); internal void os_barrier_wait(Barrier barrier); //////////////////////////////// From 471770154092610f71241c4a34bb6b9303d29389 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 18 Sep 2025 00:42:56 -0700 Subject: [PATCH 229/302] update threading API --- src/linker/lnk.c | 9 ++++++--- src/linker/thread_pool/thread_pool.c | 14 +++++++------- src/linker/thread_pool/thread_pool.h | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index bb7491c5..1ba486ba 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -132,7 +132,10 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv) { Temp scratch = scratch_begin(&arena, 1); - String8List raw_cmd_line = os_string_list_from_argcv(arena, argc, argv); + String8List raw_cmd_line = {0}; + for EachIndex(i, argc) { + str8_list_push(arena, &raw_cmd_line, str8_cstring(argv[i])); + } // remove exe name first argument str8_list_pop_front(&raw_cmd_line); @@ -4995,7 +4998,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) image_write_ctx->path = config->image_name; image_write_ctx->temp_path = config->temp_image_name; image_write_ctx->data = image_ctx.image_data; - OS_Handle image_write_thread = os_thread_launch(lnk_write_thread, image_write_ctx, 0); + Thread image_write_thread = thread_launch(lnk_write_thread, image_write_ctx); // // RAD Map @@ -5098,7 +5101,7 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) } // wait for the thread to finish writing image to disk - os_thread_join(image_write_thread, -1); + thread_join(image_write_thread, -1); // // Timers diff --git a/src/linker/thread_pool/thread_pool.c b/src/linker/thread_pool/thread_pool.c index d4cbec81..da2f7814 100644 --- a/src/linker/thread_pool/thread_pool.c +++ b/src/linker/thread_pool/thread_pool.c @@ -99,7 +99,7 @@ tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name) // launch worker threads for (U64 i = 1; i < worker_count; i += 1) { TP_Worker *worker = &pool->worker_arr[i]; - worker->handle = os_thread_launch(worker_entry, worker, 0); + worker->handle = thread_launch(worker_entry, worker); } ProfEnd(); @@ -114,20 +114,20 @@ tp_release(TP_Context *pool) B32 is_shared = pool->exec_semaphore.u64[0] != 0; if (is_shared) { for (U64 i = 0; i < pool->worker_count; ++i) { - os_semaphore_drop(pool->exec_semaphore); + semaphore_drop(pool->exec_semaphore); } } for (U64 i = 0; i < pool->worker_count; ++i) { - os_semaphore_drop(pool->task_semaphore); + semaphore_drop(pool->task_semaphore); } for (U64 i = 1; i < pool->worker_count; i += 1) { - os_thread_detach(pool->worker_arr[i].handle); + thread_detach(pool->worker_arr[i].handle); } if (is_shared) { - os_semaphore_release(pool->exec_semaphore); + semaphore_release(pool->exec_semaphore); } - os_semaphore_release(pool->task_semaphore); - os_semaphore_release(pool->main_semaphore); + semaphore_release(pool->task_semaphore); + semaphore_release(pool->main_semaphore); MemoryZeroStruct(pool); } diff --git a/src/linker/thread_pool/thread_pool.h b/src/linker/thread_pool/thread_pool.h index c7e534df..abae8606 100644 --- a/src/linker/thread_pool/thread_pool.h +++ b/src/linker/thread_pool/thread_pool.h @@ -22,7 +22,7 @@ typedef struct TP_Worker { U64 id; struct TP_Context *pool; - OS_Handle handle; + Thread handle; } TP_Worker; typedef struct TP_Context From 861c2cf893a31f27232b02ebf2bce8bc3b8e632d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 19 Sep 2025 13:43:11 -0700 Subject: [PATCH 230/302] macro for aligning types --- src/base/base_core.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/base/base_core.h b/src/base/base_core.h index c705f532..6cb32aa2 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -125,6 +125,14 @@ # error AlignOf not defined for this compiler. #endif +#if COMPILER_MSVC +# define AlignType(x) __declspec(align(x)) +#elif COMPILER_CLANG || COMPILER_GCC +# define AlignType(x) __attribute__((aligned(x))) +#else +# error AlignType not defined for this compiler. +#endif + //////////////////////////////// //~ rjf: Member Offsets From d1dd8e654cde5ac0a7e8a07e03e257138fdd6491 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 19 Sep 2025 13:44:17 -0700 Subject: [PATCH 231/302] add 128-bit compare exchange --- build.bat | 2 +- src/base/base_core.h | 64 +++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/build.bat b/build.bat index 02ee7439..3513251e 100644 --- a/build.bat +++ b/build.bat @@ -70,7 +70,7 @@ set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo set cl_out= /out: set cl_linker= -set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 +set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" diff --git a/src/base/base_core.h b/src/base/base_core.h index 6cb32aa2..e1123db9 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -209,48 +209,46 @@ #if COMPILER_MSVC # include # if ARCH_X64 -# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((volatile CHAR *)(x), (c)) -# define ins_atomic_u64_eval(x) *((volatile U64 *)(x)) -# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x)) -# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x)) -# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c)) -# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c) -# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c)) -# define ins_atomic_u32_eval(x) *((volatile U32 *)(x)) -# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)(x)) -# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((volatile LONG *)(x)) -# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c)) -# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c)) -# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), (c)) +# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)c) +# define ins_atomic_u64_eval(x) *((volatile U64 *)(x)) +# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((__int64 *)(x)) +# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((__int64 *)(x)) +# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((__int64 *)(x),(c)) +# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((__int64 *)(x), c) +# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((__int64 *)(x),(k),(c)) +# define ins_atomic_u32_eval(x) *((volatile U32 *)(x)) +# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((LONG *)(x)) +# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((LONG *)(x)) +# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((LONG *)(x),(c)) +# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((LONG *)(x),(k),(c)) +# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((LONG *)(x), (c)) +# define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((CHAR *)(x), (c)) # else # error Atomic intrinsics not defined for this compiler / architecture combination. # endif #elif COMPILER_CLANG || COMPILER_GCC -# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) -# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) -# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1) -# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1) -# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST) -# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c)) -# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) -# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) -# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1) -# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1) -# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c)) -# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) -# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) +# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)__atomic_compare_exchange_n((__int128 *)(x),(__int128 *)(c),*(__int128 *)(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST) +# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) +# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1) +# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1) +# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST) +# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((U64 *)(x), c, __ATOMIC_SEQ_CST) + (c)) +# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) +# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) +# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1) +# define ins_atomic_u32_dec_eval(x) (__atomic_fetch_sub((U32 *)(x), 1, __ATOMIC_SEQ_CST) - 1) +# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((U32 *)(x), c, __ATOMIC_SEQ_CST) + (c)) +# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) +# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) +# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) #else # error Atomic intrinsics not defined for this compiler / architecture. #endif #if ARCH_64BIT -# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c)) -# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c)) -# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x) -#elif ARCH_32BIT -# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c)) -# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c)) -# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x) +# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void *)ins_atomic_u64_eval_cond_assign((U64 *)(x), (U64)(k), (U64)(c)) +# define ins_atomic_ptr_eval_assign(x,c) (void *)ins_atomic_u64_eval_assign((U64 *)(x), (U64)(c)) +# define ins_atomic_ptr_eval(x) (void *)ins_atomic_u64_eval((U64 *)x) #else # error Atomic intrinsics for pointers not defined for this architecture. #endif From e72512f63859129864c0b0738cac593704c070aa Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 19 Sep 2025 13:51:26 -0700 Subject: [PATCH 232/302] switch over to 64-bit pointer tagging --- src/linker/lnk.c | 91 ++++++++++++++++++++---------------------------- src/linker/lnk.h | 31 ++++++++--------- 2 files changed, 51 insertions(+), 71 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1ba486ba..e1ab498c 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2167,26 +2167,21 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer } internal void -lnk_reloc_refs_list_push_node(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_node) +lnk_reloc_refs_list_push_node(LNK_RelocRefsList *list, LNK_RelocRefsNode *node) { - U64 node_tag = UnpackPointerTag(tagged_node); - LNK_RelocRefsNode *node = UnpackPointer(tagged_node); - - node->next = list->head; - list->head = PackPointer(node, node_tag); + LNK_RelocRefsPointer old_head = list->head; + node->next = old_head.node; + list->head = (LNK_RelocRefsPointer){ .node = node, .tag = old_head.tag + 1 }; } internal LNK_RelocRefsNode * lnk_reloc_refs_list_pop_node(LNK_RelocRefsList *list) { - LNK_RelocRefsNode *result = list->head; - - if (list->head) { - LNK_RelocRefsNode *head = UnpackPointer(list->head); - list->head = head->next; + LNK_RelocRefsPointer old_head = list->head; + if (old_head.node) { + list->head = (LNK_RelocRefsPointer){ .node = old_head.node->next, .tag = old_head.tag + 1}; } - - return result; + return old_head.node; } internal LNK_RelocRefsNode * @@ -2201,43 +2196,34 @@ lnk_reloc_refs_list_push(Arena *arena, LNK_RelocRefsList *list, LNK_RelocRefs *v internal LNK_RelocRefsNode * lnk_reloc_refs_list_pop_node_atomic(LNK_RelocRefsList *list) { - LNK_RelocRefsNode *tagged_node; + LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) }; for (;;) { - tagged_node = list->head; - if (tagged_node == 0) { break; } - - LNK_RelocRefsNode *head = UnpackPointer(tagged_node); - LNK_RelocRefsNode *tagged_next = head->next; - - void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_next, tagged_node); - if (swap == tagged_node) { break; } + if (old_head.node == 0) { break; } + LNK_RelocRefsPointer new_head = { .node = old_head.node->next, .tag = old_head.tag + 1 }; + if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; } } - return tagged_node; + return old_head.node; } internal void -lnk_reloc_refs_list_push_node_atomic(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_node) +lnk_reloc_refs_list_push_node_atomic(LNK_RelocRefsList *list, LNK_RelocRefsNode *node) { - tagged_node = BumpPointerTag(tagged_node); + LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) }; for (;;) { - LNK_RelocRefsNode *old_head = list->head; - LNK_RelocRefsNode *node = UnpackPointer(tagged_node); - node->next = old_head; - void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_node, old_head); - if (swap == old_head) { break; } + node->next = old_head.node; + LNK_RelocRefsPointer new_head = { .node = node, .tag = old_head.tag + 1 }; + if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; } } } internal void -lnk_reloc_refs_list_concat_in_place(LNK_RelocRefsList *list, LNK_RelocRefsNode *tagged_first, LNK_RelocRefsNode *tagged_last) +lnk_reloc_refs_list_concat_in_place(LNK_RelocRefsList *list, LNK_RelocRefsNode *first, LNK_RelocRefsNode *last) { - tagged_first = BumpPointerTag(tagged_first); + LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) }; for (;;) { - LNK_RelocRefsNode *old_head = list->head; - LNK_RelocRefsNode *last = UnpackPointer(tagged_last); - last->next = old_head; - void *swap = ins_atomic_ptr_eval_cond_assign(&list->head, tagged_first, old_head); - if (swap == old_head) { break;} + last->next = old_head.node; + LNK_RelocRefsPointer new_head = { .node = first, .tag = old_head.tag + 1 }; + if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; } } } @@ -2257,11 +2243,10 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task) for (;;) { // pop head node - LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(&task->reloc_refs); + LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(task->reloc_refs); if (!node) { break; } - LNK_RelocRefsNode *reloc_refs_node = UnpackPointer(node); - LNK_RelocRefs *reloc_refs = reloc_refs_node->v; + LNK_RelocRefs *reloc_refs = node->v; LNK_RelocRefsNode *first_node = 0, *last_node = 0; for EachIndex(reloc_idx, reloc_refs->relocs.count) { @@ -2330,25 +2315,23 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task) // mark section live section_header->flags |= LNK_SECTION_FLAG_LIVE; - LNK_RelocRefsNode *tagged_node; - if (free_list.head) { - tagged_node = lnk_reloc_refs_list_pop_node(&free_list); - tagged_node = BumpPointerTag(tagged_node); + LNK_RelocRefsNode *node; + if (free_list.head.node) { + node = lnk_reloc_refs_list_pop_node(&free_list); } else { - tagged_node = push_array(scratch.arena, LNK_RelocRefsNode, 1); - tagged_node->v = push_array(scratch.arena, LNK_RelocRefs, 1); + node = push_array(scratch.arena, LNK_RelocRefsNode, 1); + node->v = push_array(scratch.arena, LNK_RelocRefs, 1); } - LNK_RelocRefsNode *node = UnpackPointer(tagged_node); node->v->obj = ref_obj; node->v->relocs = lnk_coff_reloc_info_from_section_number(ref_obj, section_number_n->data); if (first_node == 0) { - first_node = tagged_node; - last_node = tagged_node; + first_node = node; + last_node = node; } else { node->next = first_node; - first_node = tagged_node; + first_node = node; } } } @@ -2357,18 +2340,18 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task) lnk_reloc_refs_list_push_node(&free_list, node); if (first_node && last_node) { - lnk_reloc_refs_list_concat_in_place(&task->reloc_refs, first_node, last_node); + lnk_reloc_refs_list_concat_in_place(task->reloc_refs, first_node, last_node); } } // are all threads done walking? U32 active_thread_count = ins_atomic_u32_dec_eval(&task->active_thread_count); - if (active_thread_count == 0 && task->reloc_refs.head == 0) { + if (active_thread_count == 0 && ins_atomic_ptr_eval(&task->reloc_refs->head.node) == 0) { break; } // comprehensive solution to the waiting problem - for (; ins_atomic_ptr_eval(&task->reloc_refs.head) == 0; ) { + for (; ins_atomic_ptr_eval(&task->reloc_refs->head.node) == 0; ) { // was signaled to exit? if (ins_atomic_u64_eval(&task->active_thread_count) == 0) { goto exit; } } @@ -2455,7 +2438,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj // LNK_OptRefTask task = {0}; task.symtab = symtab; - task.reloc_refs = reloc_refs; + task.reloc_refs = &reloc_refs; tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_walk_relocs_and_mark_ref_sections_task, &task, "Mark Live Sections"); ProfBegin("Remove Unreachable Sections"); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index cf7bfe0a..b50669e0 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -120,18 +120,6 @@ typedef struct LNK_CommonBlockContrib // --- Ref --------------------------------------------------------------------- -#define PointerBitSize 64u -#define PointerFreeBitsSize 16u - -#define PointerTagBitSize PointerFreeBitsSize -#define PointerTagMask ((1ull << (PointerTagBitSize)) - 1u) -#define PointerTagShift (PointerBitSize - PointerTagBitSize) - -#define PackPointer(ptr, tag) (void *)(IntFromPtr(ptr) | (((tag) & PointerTagMask) << PointerTagShift)) -#define UnpackPointerTag(ptr) ((IntFromPtr(ptr) >> PointerTagShift) & PointerTagMask) -#define UnpackPointer(ptr) (void *)(IntFromPtr(ptr) & ~(PointerTagMask << PointerTagShift)) -#define BumpPointerTag(ptr) PackPointer(UnpackPointer(ptr), UnpackPointerTag(ptr) + 1) - #define LNK_RELOCS_PER_TASK 0x1000 typedef struct LNK_RelocRefs @@ -146,9 +134,18 @@ typedef struct LNK_RelocRefsNode struct LNK_RelocRefsNode *next; } LNK_RelocRefsNode; -typedef struct LNK_RelocRefsList +typedef union LNK_RelocRefsPointer { - LNK_RelocRefsNode *head; + struct { + LNK_RelocRefsNode *node; + U64 tag; + }; + U64 v[2]; +} LNK_RelocRefsPointer; + +typedef struct AlignType(16) LNK_RelocRefsList +{ + LNK_RelocRefsPointer head; } LNK_RelocRefsList; // --- Base Reloc -------------------------------------------------------------- @@ -191,9 +188,9 @@ typedef struct typedef struct { - LNK_SymbolTable *symtab; - U32 active_thread_count; - LNK_RelocRefsList reloc_refs; + LNK_SymbolTable *symtab; + U32 active_thread_count; + LNK_RelocRefsList *reloc_refs; } LNK_OptRefTask; typedef struct From a75a33e6d3cc5f3f29465ee10e60c29ef95269bf Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 19 Sep 2025 14:25:14 -0700 Subject: [PATCH 233/302] minor fix for UBA detour --- src/linker/lnk_debug_info.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 0aeb62c5..b209ee00 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -550,6 +550,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla // push null CV_TypeServerInfoNode *null_ts_info = push_array(scratch.arena, CV_TypeServerInfoNode, 1); + null_ts_info->data.name = str8_lit("\0"); SLLQueuePush(ts_info_list.first, ts_info_list.last, null_ts_info); ++ts_info_list.count; From 6b278e1ccc40abf7970176a155042ed26b56ac6e Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 19 Sep 2025 17:52:58 -0700 Subject: [PATCH 234/302] parallelize image fill --- src/linker/lnk.c | 103 ++++++++++++++++++++------------- src/linker/lnk.h | 13 +++++ src/linker/lnk_section_table.c | 17 ++++++ src/linker/lnk_section_table.h | 2 + 4 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index e1ab498c..ccf646fc 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -2828,7 +2828,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_regular_symbols_task) U64 obj_idx = task_id; LNK_Obj *obj = task->objs[obj_idx]; - ProfBegin("Patch Regular Symbols [%S]", obj->path); + ProfBeginV("Patch Regular Symbols [%S]", obj->path); COFF_ParsedSymbol symbol; for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); @@ -2944,6 +2944,27 @@ THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_task) lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Weak); } +internal +THREAD_POOL_TASK_FUNC(lnk_image_fill_task) +{ + ProfBeginFunction(); + LNK_BuildImageTask *task = raw_task; + String8 image_data = task->u.image_fill.image_data; + for EachNode(n, LNK_ImageFillNode, task->u.image_fill.fill_nodes[task_id]) { + for EachIndex(i, n->sc_count) { + LNK_SectionContrib *sc = n->sc[i]; + U64 cursor = 0; + for EachNode(data_n, String8Node, &sc->first_data_node) { + U64 image_off = sc->u.off + n->base_foff + cursor; + Assert(image_off + data_n->string.size <= image_data.size); + MemoryCopyStr8(image_data.str + image_off, data_n->string); + cursor += data_n->string.size; + } + } + } + ProfEnd(); +} + internal U64 lnk_compute_win32_image_header_size(LNK_Config *config, U64 sect_count) { @@ -4406,55 +4427,59 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT { ProfBegin("Image Fill"); - LNK_SectionArray sects = lnk_section_array_from_list(scratch.arena, sectab->list); + ProfBeginV("Alloc Image Buffer [%M]", lnk_section_table_total_fsize(sectab)); + image_data.size = lnk_section_table_total_fsize(sectab); + image_data.str = push_array_no_zero(arena->v[0], U8, image_data.size); + ProfEnd(); - U64 image_size = 0; - for EachIndex(sect_idx, sects.count) { image_size += sects.v[sect_idx]->fsize; } + ProfBegin("Fill Align Bytes"); + for EachNode(sect_n, LNK_SectionNode, sectab->list.first) { + LNK_Section *sect = §_n->data; + ProfBeginV("Section: %S Size: %M", sect->name, sect->fsize); + U8 fill_byte = sect->flags & COFF_SectionFlag_CntCode ? coff_code_align_byte_from_machine(config->machine) : 0; + MemorySet(image_data.str + sect->foff, fill_byte, sect->fsize); + ProfEnd(); + } + ProfEnd(); - image_data.size = image_size; - image_data.str = push_array_no_zero(arena->v[0], U8, image_size); + Temp temp = temp_begin(scratch.arena); - for EachIndex(sect_idx, sects.count) { - LNK_Section *sect = sects.v[sect_idx]; + ProfBegin("Prepare Worker Nodes"); + LNK_ImageFillNode **fill_nodes = push_array(scratch.arena, LNK_ImageFillNode *, tp->worker_count); + U64 worker_cap = 4096, worker_load = 0, worker_idx = 0; + for EachNode(sect_n, LNK_SectionNode, sectab->list.first) { + LNK_Section *sect = §_n->data; - if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { - // pick fill pick - U8 fill_byte = 0; - if (sect->flags & COFF_SectionFlag_CntCode) { - fill_byte = coff_code_align_byte_from_machine(config->machine); - } + // skip bss sections + if (sect->flags & COFF_SectionFlag_CntUninitializedData) { continue; } - // copy section contribution - U64 prev_sc_opl = 0; - for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) { - for EachIndex(sc_idx, sc_chunk->count) { - LNK_SectionContrib *sc = sc_chunk->v[sc_idx]; + for EachNode(sc_chunk, LNK_SectionContribChunk, sect->contribs.first) { + for (U64 sc_left = sc_chunk->count; sc_left > 0; ) { + U64 count = Min(worker_cap - worker_load, sc_left); + U64 sc_pos = sc_chunk->count - sc_left; + sc_left -= count; - // fill align bytes - Assert(sc->u.off >= prev_sc_opl); - U64 fill_size = sc->u.off - prev_sc_opl; - MemorySet(image_data.str + sect->foff + prev_sc_opl, fill_byte, fill_size); - prev_sc_opl = sc->u.off + lnk_size_from_section_contrib(sc); + LNK_ImageFillNode *n = push_array(scratch.arena, LNK_ImageFillNode, 1); + n->base_foff = sect->foff; + n->sc_count = count; + n->sc = sc_chunk->v + sc_pos; + SLLStackPush(fill_nodes[worker_idx], n); - // copy contrib contents - { - U64 cursor = 0; - for (String8Node *data_n = &sc->first_data_node; data_n != 0; data_n = data_n->next) { - Assert(sc->u.off + data_n->string.size <= sect->vsize); - MemoryCopy(image_data.str + sect->foff + sc->u.off + cursor, data_n->string.str, data_n->string.size); - cursor += data_n->string.size; - } - } + worker_load += count; + if (worker_load >= worker_cap) { + worker_load = 0; + worker_idx = (worker_idx + 1) % tp->worker_count; } } - - // fill section align bytes - { - U64 fill_size = sect->fsize - prev_sc_opl; - MemorySet(image_data.str + sect->foff + prev_sc_opl, fill_byte, fill_size); - } } } + ProfEnd(); + + task.u.image_fill.image_data = image_data; + task.u.image_fill.fill_nodes = fill_nodes; + tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_image_fill_task, &task, "Fill"); + + temp_end(temp); ProfEnd(); } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index b50669e0..bed105b2 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -193,6 +193,15 @@ typedef struct LNK_RelocRefsList *reloc_refs; } LNK_OptRefTask; +typedef struct LNK_ImageFillNode +{ + U64 base_foff; + U64 sc_count; + LNK_SectionContrib **sc; + + struct LNK_ImageFillNode *next; +} LNK_ImageFillNode; + typedef struct { LNK_SymbolTable *symtab; @@ -224,6 +233,10 @@ typedef struct LNK_CommonBlockContrib *common_block_contribs; COFF_SymbolValueInterpType fixup_type; } patch_symtabs; + struct { + String8 image_data; + LNK_ImageFillNode **fill_nodes; + } image_fill; } u; } LNK_BuildImageTask; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index c37d906f..7c3a464e 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -310,6 +310,22 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l ProfEnd(); } +internal U64 +lnk_section_table_total_fsize(LNK_SectionTable *sectab) +{ + U64 total_fsize = 0; + for EachNode(n, LNK_SectionNode, sectab->list.first) { total_fsize += n->data.fsize; } + return total_fsize; +} + +internal U64 +lnk_section_table_total_vsize(LNK_SectionTable *sectab) +{ + U64 total_vsize = 0; + for EachNode(n, LNK_SectionNode, sectab->list.first) { total_vsize += n->data.vsize; } + return total_vsize; +} + internal int lnk_section_contrib_chunk_is_before(void *raw_a, void *raw_b) { @@ -468,3 +484,4 @@ lnk_get_first_section_contrib_voff(COFF_SectionHeader **image_section_table, LNK LNK_SectionContrib *sc = lnk_get_first_section_contrib(sect); return lnk_voff_from_section_contrib(image_section_table, sc); } + diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index cd61810f..071f7c9c 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -110,6 +110,8 @@ internal void lnk_section_table_purge(LNK_SectionTable *sectab, S internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); internal LNK_SectionArray lnk_section_table_search_many(Arena *arena, LNK_SectionTable *sectab, String8 full_or_partial_name); internal void lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list); +internal U64 lnk_section_table_total_fsize(LNK_SectionTable *sectab); +internal U64 lnk_section_table_total_vsize(LNK_SectionTable *sectab); // --- Section Finalization ---------------------------------------------------- From 945932768713a0817bc39a1bfbc46069723b9bad Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 14:07:21 -0700 Subject: [PATCH 235/302] pull out table stripe arrays as base layer primitive; unified 'artifact cache' experiment --- src/artifact_cache/artifact_cache.c | 207 ++++++++++++++++++++++++++++ src/artifact_cache/artifact_cache.h | 104 ++++++++++++++ src/base/base_entry_point.c | 6 + src/base/base_threads.c | 36 +++++ src/base/base_threads.h | 26 ++++ src/raddbg/raddbg_main.c | 2 + src/text_cache/text_cache.c | 74 ++++++++-- src/text_cache/text_cache.h | 37 +++-- 8 files changed, 467 insertions(+), 25 deletions(-) create mode 100644 src/artifact_cache/artifact_cache.c create mode 100644 src/artifact_cache/artifact_cache.h diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c new file mode 100644 index 00000000..19bd5d8a --- /dev/null +++ b/src/artifact_cache/artifact_cache.c @@ -0,0 +1,207 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Layer Initialization + +internal void +ac_init(void) +{ + Arena *arena = arena_alloc(); + ac_shared = push_array(arena, AC_Shared, 1); + ac_shared->arena = arena; + ac_shared->cache_slots_count = 256; + ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count); + ac_shared->cache_stripes = stripe_array_alloc(arena); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal void * +ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count) +{ + //- rjf: create function -> cache + AC_Cache *cache = 0; + { + U64 cache_hash = u64_hash_from_str8(str8_struct(&create)); + U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + RWMutexScope(cache_stripe->rw_mutex, write_mode) + { + for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) + { + if(c->create == create) + { + cache = c; + break; + } + } + if(write_mode && cache == 0) + { + cache = push_array(cache_stripe->arena, AC_Cache, 1); + SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache); + cache->create = create; + cache->destroy = destroy; + cache->slots_count = slots_count; + cache->slots = push_array(cache_stripe->arena, AC_Slot, slots_count); + cache->stripes = stripe_array_alloc(cache_stripe->arena); + } + } + if(cache != 0) + { + break; + } + } + } + + //- rjf: cache * key -> artifact + void *artifact = 0; + { + U64 hash = u64_hash_from_str8(key); + U64 slot_idx = hash%cache->slots_count; + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 found = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(AC_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, key, 0)) + { + found = 1; + artifact = n->val; + access_touch(access, &n->access_pt, stripe->cv); + break; + } + } + if(write_mode && !found) + { + AC_Node *node = stripe->free; + if(node) + { + stripe->free = node->next; + } + else + { + node = push_array(stripe->arena, AC_Node, 1); + DLLPushBack(slot->first, slot->last, node); + // TODO(rjf): string allocator for keys + node->key = str8_copy(stripe->arena, key); + node->working_count = 1; + } + } + } + if(found) + { + break; + } + else if(write_mode) + { + MutexScope(ac_shared->req_mutex) + { + AC_RequestNode *n = push_array(ac_shared->req_arena, AC_RequestNode, 1); + SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); + ac_shared->req_count += 1; + n->v.key = str8_copy(ac_shared->req_arena, key); + n->v.create = create; + } + } + } + } + + return artifact; +} + +//////////////////////////////// +//~ rjf: Tick + +internal void +ac_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: do eviction pass across all caches + for EachIndex(cache_slot_idx, ac_shared->cache_slots_count) + { + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + RWMutexScope(cache_stripe->rw_mutex, 0) + { + for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx]) + { + Rng1U64 slot_range = lane_range(cache->slots_count); + for EachInRange(slot_idx, slot_range) + { + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(AC_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(access_pt_is_expired(&n->access_pt) && ins_atomic_u64_eval(&n->working_count) == 0) + { + slot_has_work = 1; + if(!write_mode) + { + break; + } + else + { + DLLRemove(slot->first, slot->last, n); + n->next = (AC_Node *)stripe->free; + stripe->free = n; + if(cache->destroy) + { + cache->destroy(n->val); + } + } + } + } + } + if(!slot_has_work) + { + break; + } + } + } + } + } + } + + //- rjf: gather all requests + local_persist AC_Request *reqs = 0; + local_persist U64 reqs_count = 0; + if(lane_idx() == 0) MutexScope(ac_shared->req_mutex) + { + reqs_count = ac_shared->req_count; + reqs = push_array(scratch.arena, AC_Request, reqs_count); + U64 idx = 0; + for EachNode(r, AC_RequestNode, ac_shared->first_req) + { + MemoryCopyStruct(&reqs[idx], &r->v); + reqs[idx].key = str8_copy(scratch.arena, reqs[idx].key); + idx += 1; + } + arena_clear(ac_shared->req_arena); + ac_shared->first_req = ac_shared->last_req = 0; + ac_shared->req_count = 0; + } + lane_sync(); + + //- rjf: do all requests on all lanes + for EachIndex(idx, reqs_count) + { + reqs[idx].create(reqs[idx].key); + } + lane_sync(); + + scratch_end(scratch); +} diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h new file mode 100644 index 00000000..9d851859 --- /dev/null +++ b/src/artifact_cache/artifact_cache.h @@ -0,0 +1,104 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ARTIFACT_CACHE_H +#define ARTIFACT_CACHE_H + +//////////////////////////////// +//~ rjf: Artifact Computation Function Types + +typedef void *AC_CreateFunctionType(String8 key); +typedef void AC_DestroyFunctionType(void *artifact); + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct AC_Request AC_Request; +struct AC_Request +{ + String8 key; + AC_CreateFunctionType *create; +}; + +typedef struct AC_RequestNode AC_RequestNode; +struct AC_RequestNode +{ + AC_RequestNode *next; + AC_Request v; +}; + +typedef struct AC_Node AC_Node; +struct AC_Node +{ + AC_Node *next; + AC_Node *prev; + + // rjf: key/value + String8 key; + void *val; + + // rjf: metadata + AccessPt access_pt; + U64 working_count; +}; + +typedef struct AC_Slot AC_Slot; +struct AC_Slot +{ + AC_Node *first; + AC_Node *last; +}; + +typedef struct AC_Cache AC_Cache; +struct AC_Cache +{ + // rjf: link / key for cache-cache + AC_Cache *next; + AC_CreateFunctionType *create; + AC_DestroyFunctionType *destroy; + + // rjf: artifact cache + U64 slots_count; + AC_Slot *slots; + StripeArray stripes; +}; + +typedef struct AC_Shared AC_Shared; +struct AC_Shared +{ + Arena *arena; + + // rjf: cache cache + U64 cache_slots_count; + AC_Cache **cache_slots; + StripeArray cache_stripes; + + // rjf: requests + Mutex req_mutex; + Arena *req_arena; + AC_RequestNode *first_req; + AC_RequestNode *last_req; + U64 req_count; +}; + +//////////////////////////////// +//~ rjf: Globals + +global AC_Shared *ac_shared = 0; + +//////////////////////////////// +//~ rjf: Layer Initialization + +internal void ac_init(void); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal void *ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); + +//////////////////////////////// +//~ rjf: Tick + +internal void ac_tick(void); + +#endif // ARTIFACT_CACHE_H diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 4a7726ed..24415763 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -53,6 +53,9 @@ main_thread_base_entry_point(int arguments_count, char **arguments) } //- rjf: initialize all included layers +#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL) + ac_init(); +#endif #if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL) async_init(&cmdline); #endif @@ -198,6 +201,9 @@ async_thread_entry_point(void *params) { async_loop_again = 0; } +#if defined(ARTIFACT_CACHE_H) + ac_tick(); +#endif #if defined(CONTENT_H) c_tick(); #endif diff --git a/src/base/base_threads.c b/src/base/base_threads.c index a992ed6f..50c6e370 100644 --- a/src/base/base_threads.c +++ b/src/base/base_threads.c @@ -64,3 +64,39 @@ internal void semaphore_drop(Semaphore semaphore) internal Barrier barrier_alloc(U64 count) {return os_barrier_alloc(count);} internal void barrier_release(Barrier barrier) {os_barrier_release(barrier);} internal void barrier_wait(Barrier barrier) {os_barrier_wait(barrier);} + +//////////////////////////////// +//~ rjf: Table Stripe Functions + +internal StripeArray +stripe_array_alloc(Arena *arena) +{ + StripeArray array = {0}; + array.count = os_get_system_info()->logical_processor_count; + array.v = push_array(arena, Stripe, array.count); + for EachIndex(idx, array.count) + { + array.v[idx].arena = arena_alloc(); + array.v[idx].rw_mutex = rw_mutex_alloc(); + array.v[idx].cv = cond_var_alloc(); + } + return array; +} + +internal void +stripe_array_release(StripeArray *stripes) +{ + for EachIndex(idx, stripes->count) + { + arena_release(stripes->v[idx].arena); + rw_mutex_release(stripes->v[idx].rw_mutex); + cond_var_release(stripes->v[idx].cv); + } +} + +internal Stripe * +stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx) +{ + Stripe *stripe = &stripes->v[slot_idx%stripes->count]; + return stripe; +} diff --git a/src/base/base_threads.h b/src/base/base_threads.h index d33712b5..330efb00 100644 --- a/src/base/base_threads.h +++ b/src/base/base_threads.h @@ -47,6 +47,25 @@ struct Barrier U64 u64[1]; }; +//////////////////////////////// +//~ rjf: Table Stripes + +typedef struct Stripe Stripe; +struct Stripe +{ + Arena *arena; + RWMutex rw_mutex; + CondVar cv; + void *free; +}; + +typedef struct StripeArray StripeArray; +struct StripeArray +{ + Stripe *v; + U64 count; +}; + //////////////////////////////// //~ rjf: Thread Functions @@ -104,4 +123,11 @@ internal void barrier_wait(Barrier barrier); #define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex)) #define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex))) +//////////////////////////////// +//~ rjf: Table Stripe Functions + +internal StripeArray stripe_array_alloc(Arena *arena); +internal void stripe_array_release(StripeArray *stripes); +internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx); + #endif // BASE_THREADS_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 27ad88a6..9f502c45 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -222,6 +222,7 @@ #include "linker/hash_table.h" #include "os/os_inc.h" #include "async/async.h" +#include "artifact_cache/artifact_cache.h" #include "rdi/rdi_local.h" #include "rdi_make/rdi_make_local.h" #include "mdesk/mdesk.h" @@ -271,6 +272,7 @@ #include "linker/hash_table.c" #include "os/os_inc.c" #include "async/async.c" +#include "artifact_cache/artifact_cache.c" #include "rdi/rdi_local.c" #include "rdi_make/rdi_make_local.c" #include "mdesk/mdesk.c" diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index edca8496..28fc010b 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1601,15 +1601,8 @@ txt_init(void) txt_shared->arena = arena; txt_shared->slots_count = 1024; txt_shared->slots = push_array(arena, TXT_Slot, txt_shared->slots_count); - txt_shared->stripes_count = Min(txt_shared->slots_count, os_get_system_info()->logical_processor_count); - txt_shared->stripes = push_array(arena, TXT_Stripe, txt_shared->stripes_count); - txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes_count); - for(U64 idx = 0; idx < txt_shared->stripes_count; idx += 1) - { - txt_shared->stripes[idx].arena = arena_alloc(); - txt_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - txt_shared->stripes[idx].cv = cond_var_alloc(); - } + txt_shared->stripes = stripe_array_alloc(arena); + txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes.count); txt_shared->u2p_ring_size = KB(64); txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); txt_shared->u2p_ring_cv = cond_var_alloc(); @@ -1627,9 +1620,9 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) if(!u128_match(hash, u128_zero())) { U64 slot_idx = hash.u64[1]%txt_shared->slots_count; - U64 stripe_idx = slot_idx%txt_shared->stripes_count; TXT_Slot *slot = &txt_shared->slots[slot_idx]; - TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); + U64 stripe_idx = (stripe - txt_shared->stripes.v); B32 found = 0; MutexScopeR(stripe->rw_mutex) { @@ -2128,9 +2121,8 @@ ASYNC_WORK_DEF(txt_parse_work) //- rjf: unpack hash U64 slot_idx = hash.u64[1]%txt_shared->slots_count; - U64 stripe_idx = slot_idx%txt_shared->stripes_count; TXT_Slot *slot = &txt_shared->slots[slot_idx]; - TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); //- rjf: take task B32 got_task = 0; @@ -2434,9 +2426,9 @@ txt_evictor_thread__entry_point(void *p) { for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1) { - U64 stripe_idx = slot_idx%txt_shared->stripes_count; TXT_Slot *slot = &txt_shared->slots[slot_idx]; - TXT_Stripe *stripe = &txt_shared->stripes[stripe_idx]; + Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); + U64 stripe_idx = (stripe - txt_shared->stripes.v); B32 slot_has_work = 0; MutexScopeR(stripe->rw_mutex) { @@ -2474,3 +2466,55 @@ txt_evictor_thread__entry_point(void *p) os_sleep_milliseconds(500); } } + +//////////////////////////////// +//~ rjf: Tick + +internal void +txt_tick(void) +{ + //- rjf: do eviction pass + { + Rng1U64 range = lane_range(txt_shared->slots_count); + for EachInRange(slot_idx, range) + { + TXT_Slot *slot = &txt_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 slot_has_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(access_pt_is_expired(&n->access_pt) && + n->load_count != 0 && + n->is_working == 0) + { + slot_has_work = 1; + if(!write_mode) + { + break; + } + else + { + DLLRemove(slot->first, slot->last, n); + c_hash_downstream_dec(n->hash); + if(n->arena != 0) + { + arena_release(n->arena); + } + SLLStackPush(txt_shared->stripes_free_nodes[(stripe - txt_shared->stripes.v)], n); + } + } + } + } + if(!slot_has_work) + { + break; + } + } + } + } +} diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 3e5d5cb2..9370bc85 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -158,6 +158,20 @@ typedef TXT_TokenArray TXT_LangLexFunctionType(Arena *arena, U64 *bytes_processe //////////////////////////////// //~ rjf: Cache Types +typedef struct TXT_Request TXT_Request; +struct TXT_Request +{ + U128 hash; + TXT_LangKind lang; +}; + +typedef struct TXT_RequestNode TXT_RequestNode; +struct TXT_RequestNode +{ + TXT_RequestNode *next; + TXT_Request v; +}; + typedef struct TXT_Node TXT_Node; struct TXT_Node { @@ -186,14 +200,6 @@ struct TXT_Slot TXT_Node *last; }; -typedef struct TXT_Stripe TXT_Stripe; -struct TXT_Stripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; -}; - //////////////////////////////// //~ rjf: Shared State @@ -207,11 +213,17 @@ struct TXT_Shared // rjf: cache U64 slots_count; - U64 stripes_count; TXT_Slot *slots; - TXT_Stripe *stripes; + StripeArray stripes; TXT_Node **stripes_free_nodes; + // rjf: requests + Mutex req_mutex; + Arena *req_arena; + TXT_RequestNode *first_req; + TXT_RequestNode *last_req; + U64 req_count; + // rjf: user -> parse thread U64 u2p_ring_size; U8 *u2p_ring_base; @@ -293,4 +305,9 @@ ASYNC_WORK_DEF(txt_parse_work); internal void txt_evictor_thread__entry_point(void *p); +//////////////////////////////// +//~ rjf: Tick + +internal void txt_tick(void); + #endif // TEXT_CACHE_H From 811e58c2496a95264ebe8716f606d7ab73b844de Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 15:13:31 -0700 Subject: [PATCH 236/302] progress on single async-filled computation artifact cache; hook up to text cache layer, eliminate bespoke cache for text only --- src/artifact_cache/artifact_cache.c | 58 ++- src/base/base_entry_point.c | 3 - src/base/base_thread_context.h | 11 + src/text_cache/text_cache.c | 714 ++++++++++------------------ src/text_cache/text_cache.h | 34 +- 5 files changed, 306 insertions(+), 514 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 19bd5d8a..0167dd49 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -13,6 +13,8 @@ ac_init(void) ac_shared->cache_slots_count = 256; ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count); ac_shared->cache_stripes = stripe_array_alloc(arena); + ac_shared->req_mutex = mutex_alloc(); + ac_shared->req_arena = arena_alloc(); } //////////////////////////////// @@ -88,12 +90,13 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, } else { - node = push_array(stripe->arena, AC_Node, 1); - DLLPushBack(slot->first, slot->last, node); - // TODO(rjf): string allocator for keys - node->key = str8_copy(stripe->arena, key); - node->working_count = 1; + node = push_array_no_zero(stripe->arena, AC_Node, 1); } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + // TODO(rjf): string allocator for keys + node->key = str8_copy(stripe->arena, key); + node->working_count = 1; } } if(found) @@ -110,6 +113,7 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, n->v.key = str8_copy(ac_shared->req_arena, key); n->v.create = create; } + cond_var_broadcast(async_tick_start_cond_var); } } } @@ -199,7 +203,49 @@ ac_tick(void) //- rjf: do all requests on all lanes for EachIndex(idx, reqs_count) { - reqs[idx].create(reqs[idx].key); + lane_sync(); + + // rjf: compute val + void *val = reqs[idx].create(reqs[idx].key); + + // rjf: create function -> cache + AC_Cache *cache = 0; + { + U64 cache_hash = u64_hash_from_str8(str8_struct(&reqs[idx].create)); + U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + RWMutexScope(cache_stripe->rw_mutex, 0) + { + for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) + { + if(c->create == reqs[idx].create) + { + cache = c; + break; + } + } + } + } + + // rjf: write value into cache + if(lane_idx() == 0) + { + U64 hash = u64_hash_from_str8(reqs[idx].key); + U64 slot_idx = hash%cache->slots_count; + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + for(AC_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, reqs[idx].key, 0)) + { + n->val = val; + ins_atomic_u64_dec_eval(&n->working_count); + } + } + } + } } lane_sync(); diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 24415763..6c79091c 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -65,9 +65,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) fs_init(); #endif -#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL) - txt_init(); -#endif #if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL) mtx_init(); #endif diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 340bccf1..ef605e14 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -65,6 +65,10 @@ struct TCTX Arena *access_arena; Access *free_access; Touch *free_touch; + + // rjf: progress + U64 *progress_counter_ptr; + U64 *progress_target_ptr; }; //////////////////////////////// @@ -108,4 +112,11 @@ internal void access_touch(Access *access, AccessPt *pt, CondVar cv); //- rjf: access points internal B32 access_pt_is_expired(AccessPt *pt); +//- rjf: progress counters +#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr)) +#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr)) +#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0) +#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0) +#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0) + #endif // BASE_THREAD_CONTEXT_H diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 28fc010b..ae39b4d3 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1590,117 +1590,6 @@ txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed return result; } -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -txt_init(void) -{ - Arena *arena = arena_alloc(); - txt_shared = push_array(arena, TXT_Shared, 1); - txt_shared->arena = arena; - txt_shared->slots_count = 1024; - txt_shared->slots = push_array(arena, TXT_Slot, txt_shared->slots_count); - txt_shared->stripes = stripe_array_alloc(arena); - txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes.count); - txt_shared->u2p_ring_size = KB(64); - txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); - txt_shared->u2p_ring_cv = cond_var_alloc(); - txt_shared->u2p_ring_mutex = mutex_alloc(); - txt_shared->evictor_thread = thread_launch(txt_evictor_thread__entry_point, 0); -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal TXT_TextInfo -txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) -{ - TXT_TextInfo info = {0}; - if(!u128_match(hash, u128_zero())) - { - U64 slot_idx = hash.u64[1]%txt_shared->slots_count; - TXT_Slot *slot = &txt_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); - U64 stripe_idx = (stripe - txt_shared->stripes.v); - B32 found = 0; - MutexScopeR(stripe->rw_mutex) - { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && n->lang == lang) - { - MemoryCopyStruct(&info, &n->info); - info.bytes_processed = ins_atomic_u64_eval(&n->info.bytes_processed); - info.bytes_to_process = ins_atomic_u64_eval(&n->info.bytes_to_process); - found = 1; - access_touch(access, &n->access_pt, stripe->cv); - break; - } - } - } - B32 node_is_new = 0; - if(!found) - { - MutexScopeW(stripe->rw_mutex) - { - TXT_Node *node = 0; - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && n->lang == lang) - { - node = n; - break; - } - } - if(node == 0) - { - node = txt_shared->stripes_free_nodes[stripe_idx]; - if(node) - { - SLLStackPop(txt_shared->stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array_no_zero(stripe->arena, TXT_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->hash = hash; - node->lang = lang; - node_is_new = 1; - } - } - } - if(node_is_new) - { - txt_u2p_enqueue_req(hash, lang, max_U64); - async_push_work(txt_parse_work); - } - } - return info; -} - -internal TXT_TextInfo -txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out) -{ - TXT_TextInfo result = {0}; - for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) - { - U128 hash = c_hash_from_key(key, rewind_idx); - result = txt_text_info_from_hash_lang(access, hash, lang); - if(result.lines_count != 0) - { - if(hash_out) - { - *hash_out = hash; - } - break; - } - } - return result; -} - //////////////////////////////// //~ rjf: Text Info Extractor Helpers @@ -2062,120 +1951,61 @@ txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt) } //////////////////////////////// -//~ rjf: Transfer Threads +//~ rjf: Artifact Cache Hooks / Lookups -internal B32 -txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us) +typedef struct TXT_Artifact TXT_Artifact; +struct TXT_Artifact { - B32 good = 0; - MutexScope(txt_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; - U64 available_size = txt_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(lang)) - { - good = 1; - txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &hash); - txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &lang); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(txt_shared->u2p_ring_cv); - } - return good; -} + Arena *arena; + TXT_TextInfo info; +}; -internal void -txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out) +typedef struct TXT_ArtifactCreateShared TXT_ArtifactCreateShared; +struct TXT_ArtifactCreateShared { - MutexScope(txt_shared->u2p_ring_mutex) for(;;) - { - U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out) + sizeof(*lang_out)) - { - txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, hash_out); - txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, lang_out); - break; - } - cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, max_U64); - } - cond_var_broadcast(txt_shared->u2p_ring_cv); -} + Arena *arena; + TXT_TextInfo info; + TXT_Artifact *artifact; +}; -ASYNC_WORK_DEF(txt_parse_work) +internal void * +txt_artifact_create(String8 key) { ProfBeginFunction(); - - //- rjf: get next key - U128 hash = {0}; - TXT_LangKind lang = TXT_LangKind_Null; - txt_u2p_dequeue_req(&hash, &lang); + Temp scratch = scratch_begin(0, 0); Access *access = access_open(); - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%txt_shared->slots_count; - TXT_Slot *slot = &txt_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); - - //- rjf: take task - B32 got_task = 0; - MutexScopeR(stripe->rw_mutex) + //- rjf: get shared state + local_persist TXT_ArtifactCreateShared *shared = 0; + if(lane_idx() == 0) { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && n->lang == lang) - { - got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); - break; - } - } + shared = push_array(scratch.arena, TXT_ArtifactCreateShared, 1); } + lane_sync(); - //- rjf: hash -> data - String8 data = {0}; - if(got_task) - { - data = c_data_from_hash(access, hash); - } + //- rjf: unpack key + U128 hash = {0}; + TXT_LangKind lang = TXT_LangKind_Null; + str8_deserial_read_struct(key, 0, &hash); + str8_deserial_read_struct(key, sizeof(hash), &lang); + String8 data = c_data_from_hash(access, hash); + TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang); //- rjf: data -> text info - Arena *info_arena = 0; - TXT_TextInfo info = {0}; - if(got_task && !u128_match(hash, u128_zero())) + if(!u128_match(hash, u128_zero())) { - info_arena = arena_alloc(); - - //- rjf: grab pointers to working counters - U64 *bytes_processed_ptr = 0; - U64 *bytes_to_process_ptr = 0; - MutexScopeR(stripe->rw_mutex) + if(lane_idx() == 0) { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && n->lang == lang) - { - bytes_processed_ptr = &n->info.bytes_processed; - bytes_to_process_ptr = &n->info.bytes_to_process; - } - } + shared->arena = arena_alloc(); } //- rjf: set # of bytes to process - if(bytes_to_process_ptr) - { - // (line ending calc) (line counting) (line measuring) (lexing) - ins_atomic_u64_eval_assign(bytes_to_process_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lang != TXT_LangKind_Null)); - } + // (line ending calc) (line counting) (line measuring) (lexing) + set_progress_target(Min(data.size, 1024) + data.size + data.size + data.size*(lang != TXT_LangKind_Null)); //- rjf: detect line end kind TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null; + if(lane_idx() == 0) { U64 lf_count = 0; U64 cr_count = 0; @@ -2198,323 +2028,255 @@ ASYNC_WORK_DEF(txt_parse_work) { line_end_kind = TXT_LineEndKind_LF; } - info.line_end_kind = line_end_kind; - } - - //- rjf: bump progress - if(bytes_processed_ptr) - { - ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024)); + shared->info.line_end_kind = line_end_kind; } + lane_sync(); + set_progress(Min(data.size, 1024)); //- rjf: count # of lines - U64 line_count = 1; - U64 byte_process_start_idx = 0; - for(U64 idx = 0; idx < data.size; idx += 1) + U64 lane_line_count = 0; + if(lane_idx() == 0) { - if(data.str[idx] == '\n' || data.str[idx] == '\r') + lane_line_count = 1; + } + { + Rng1U64 range = lane_range(data.size); + for EachInRange(idx, range) { - line_count += 1; - if(data.str[idx] == '\r') + if(data.str[idx] == '\n' || data.str[idx] == '\r') { - idx += 1; + lane_line_count += 1; + if(data.str[idx] == '\r') + { + idx += 1; + } + } + if(idx && idx%1000 == 0) + { + add_progress(1000); } } - if(idx && idx%1000 == 0) - { - ins_atomic_u64_add_eval(bytes_processed_ptr, 1000); - } - } - - //- rjf: bump progress - if(bytes_processed_ptr) - { - ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size); } + ins_atomic_u64_add_eval(&shared->info.lines_count, lane_line_count); + lane_sync(); + set_progress(Min(data.size, 1024) + data.size); //- rjf: allocate & store line ranges - info.lines_count = line_count; - info.lines_ranges = push_array_no_zero(info_arena, Rng1U64, info.lines_count); - U64 line_idx = 0; - U64 line_start_idx = 0; - for(U64 idx = 0; idx <= data.size; idx += 1) + if(lane_idx() == 0) { - if(idx == data.size || data.str[idx] == '\n' || data.str[idx] == '\r') + shared->info.lines_ranges = push_array_no_zero(shared->arena, Rng1U64, shared->info.lines_count); + U64 line_idx = 0; + U64 line_start_idx = 0; + for(U64 idx = 0; idx <= data.size; idx += 1) { - Rng1U64 line_range = r1u64(line_start_idx, idx); - U64 line_size = dim_1u64(line_range); - info.lines_ranges[line_idx] = line_range; - info.lines_max_size = Max(info.lines_max_size, line_size); - line_idx += 1; - line_start_idx = idx+1; - if(idx < data.size && data.str[idx] == '\r') + if(idx == data.size || data.str[idx] == '\n' || data.str[idx] == '\r') { - line_start_idx += 1; - idx += 1; + Rng1U64 line_range = r1u64(line_start_idx, idx); + U64 line_size = dim_1u64(line_range); + shared->info.lines_ranges[line_idx] = line_range; + shared->info.lines_max_size = Max(shared->info.lines_max_size, line_size); + line_idx += 1; + line_start_idx = idx+1; + if(idx < data.size && data.str[idx] == '\r') + { + line_start_idx += 1; + idx += 1; + } + } + if(idx && idx%1000 == 0) + { + add_progress(1000); } } - if(idx && idx%1000 == 0) - { - ins_atomic_u64_add_eval(bytes_processed_ptr, 1000); - } - } - - //- rjf: bump progress - if(bytes_processed_ptr) - { - ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size); } + lane_sync(); + set_progress(Min(data.size, 1024) + data.size + data.size); //- rjf: lex function * data -> tokens - TXT_TokenArray tokens = {0}; - TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang); - if(lex_function != 0) + if(lane_idx() == 0 && lex_function != 0) { - tokens = lex_function(info_arena, bytes_processed_ptr, data); - } - info.tokens = tokens; - - //- rjf: bump progress - if(bytes_processed_ptr) - { - ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lex_function != 0)); + shared->info.tokens = lex_function(shared->arena, 0, data); } + lane_sync(); + set_progress(Min(data.size, 1024) + data.size + data.size + data.size*(lex_function != 0)); + TXT_TokenArray tokens = shared->info.tokens; //- rjf: count scope points - U64 scope_pt_opener_count = 0; - U64 scope_pt_count = 0; - for EachIndex(idx, tokens.count) { - if(tokens.v[idx].kind == TXT_TokenKind_Symbol) + U64 lane_scope_pt_opener_count = 0; + U64 lane_scope_pt_count = 0; + Rng1U64 range = lane_range(tokens.count); + for EachInRange(idx, range) { - String8 token_string = str8_substr(data, tokens.v[idx].range); - B32 is_opener = (token_string.str[0] == '{' || - token_string.str[0] == '(' || - token_string.str[0] == '['); - B32 is_closer = (token_string.str[0] == '}' || - token_string.str[0] == ')' || - token_string.str[0] == ']'); - if(token_string.size == 1 && (is_opener || is_closer)) + if(tokens.v[idx].kind == TXT_TokenKind_Symbol) { - scope_pt_count += 1; - scope_pt_opener_count += !!is_opener; - } - } - } - - //- rjf: allocate & fill scope data - info.scope_pts.count = scope_pt_count; - info.scope_pts.v = push_array_no_zero(info_arena, TXT_ScopePt, info.scope_pts.count); - info.scope_nodes.count = scope_pt_opener_count; - info.scope_nodes.v = push_array_no_zero(info_arena, TXT_ScopeNode, info.scope_nodes.count); - { - typedef struct ScopeTask ScopeTask; - struct ScopeTask - { - ScopeTask *next; - U64 scope_idx; - }; - Temp scratch = scratch_begin(0, 0); - ScopeTask *top_scope_task = 0; - ScopeTask *free_scope_task = 0; - U64 pt_idx = 0; - U64 scope_idx = 0; - for EachIndex(token_idx, tokens.count) - { - if(tokens.v[token_idx].kind == TXT_TokenKind_Symbol) - { - String8 token_string = str8_substr(data, tokens.v[token_idx].range); + String8 token_string = str8_substr(data, tokens.v[idx].range); B32 is_opener = (token_string.str[0] == '{' || token_string.str[0] == '(' || token_string.str[0] == '['); B32 is_closer = (token_string.str[0] == '}' || token_string.str[0] == ')' || token_string.str[0] == ']'); - - // rjf: opener symbols -> push scope - if(is_opener) + if(token_string.size == 1 && (is_opener || is_closer)) { - // rjf: insert into scope tree - TXT_ScopeNode *new_scope = &info.scope_nodes.v[scope_idx]; - new_scope->token_idx_range.min = token_idx; - if(top_scope_task) - { - U64 new_scope_num = scope_idx+1; - TXT_ScopeNode *parent = &info.scope_nodes.v[top_scope_task->scope_idx]; - if(parent->first_num == 0) - { - parent->first_num = new_scope_num; - } - if(parent->last_num != 0) - { - TXT_ScopeNode *prev_scope = &info.scope_nodes.v[parent->last_num-1]; - prev_scope->next_num = new_scope_num; - } - parent->last_num = new_scope_num; - new_scope->parent_num = top_scope_task->scope_idx+1; - } + lane_scope_pt_count += 1; + lane_scope_pt_opener_count += !!is_opener; + } + } + } + ins_atomic_u64_add_eval(&shared->info.scope_pts.count, lane_scope_pt_count); + ins_atomic_u64_add_eval(&shared->info.scope_nodes.count, lane_scope_pt_opener_count); + } + lane_sync(); + + //- rjf: allocate & fill scope data + if(lane_idx() == 0) + { + shared->info.scope_pts.v = push_array_no_zero(shared->arena, TXT_ScopePt, shared->info.scope_pts.count); + shared->info.scope_nodes.v = push_array_no_zero(shared->arena, TXT_ScopeNode, shared->info.scope_nodes.count); + { + typedef struct ScopeTask ScopeTask; + struct ScopeTask + { + ScopeTask *next; + U64 scope_idx; + }; + Temp scratch = scratch_begin(0, 0); + ScopeTask *top_scope_task = 0; + ScopeTask *free_scope_task = 0; + U64 pt_idx = 0; + U64 scope_idx = 0; + for EachIndex(token_idx, tokens.count) + { + if(tokens.v[token_idx].kind == TXT_TokenKind_Symbol) + { + String8 token_string = str8_substr(data, tokens.v[token_idx].range); + B32 is_opener = (token_string.str[0] == '{' || + token_string.str[0] == '(' || + token_string.str[0] == '['); + B32 is_closer = (token_string.str[0] == '}' || + token_string.str[0] == ')' || + token_string.str[0] == ']'); - // rjf: push onto scope stack - ScopeTask *scope_task = free_scope_task; - if(scope_task) + // rjf: opener symbols -> push scope + if(is_opener) { - SLLStackPop(free_scope_task); - } - else - { - scope_task = push_array(scratch.arena, ScopeTask, 1); - } - scope_task->scope_idx = scope_idx; - scope_idx += 1; - SLLStackPush(top_scope_task, scope_task); - } - - // rjf: opener or closer -> fill endpoint - if(top_scope_task && (is_opener || is_closer)) - { - info.scope_pts.v[pt_idx].token_idx = token_idx; - info.scope_pts.v[pt_idx].scope_idx = top_scope_task->scope_idx; - pt_idx += 1; - } - - // rjf: closer symbols -> pop - if(is_closer && top_scope_task != 0) - { - ScopeTask *popped = top_scope_task; - info.scope_nodes.v[popped->scope_idx].token_idx_range.max = token_idx; - SLLStackPop(top_scope_task); - SLLStackPush(free_scope_task, popped); - } - } - } - scratch_end(scratch); - } - } - - //- rjf: commit results to cache - if(got_task) MutexScopeW(stripe->rw_mutex) - { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && n->lang == lang) - { - c_hash_downstream_inc(n->hash); - n->arena = info_arena; - info.bytes_processed = n->info.bytes_processed; - info.bytes_to_process = n->info.bytes_to_process; - MemoryCopyStruct(&n->info, &info); - ins_atomic_u32_eval_assign(&n->is_working, 0); - ins_atomic_u64_inc_eval(&n->load_count); - break; - } - } - } - - access_close(access); - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void -txt_evictor_thread__entry_point(void *p) -{ - ThreadNameF("txt_evictor_thread"); - for(;;) - { - for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1) - { - TXT_Slot *slot = &txt_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); - U64 stripe_idx = (stripe - txt_shared->stripes.v); - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(TXT_Node *n = slot->first; n != 0; n = n->next) - { - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->is_working == 0) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->is_working == 0) - { - DLLRemove(slot->first, slot->last, n); - c_hash_downstream_dec(n->hash); - if(n->arena != 0) - { - arena_release(n->arena); - } - SLLStackPush(txt_shared->stripes_free_nodes[stripe_idx], n); - } - } - } - } - os_sleep_milliseconds(500); - } -} - -//////////////////////////////// -//~ rjf: Tick - -internal void -txt_tick(void) -{ - //- rjf: do eviction pass - { - Rng1U64 range = lane_range(txt_shared->slots_count); - for EachInRange(slot_idx, range) - { - TXT_Slot *slot = &txt_shared->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx); - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 slot_has_work = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->is_working == 0) - { - slot_has_work = 1; - if(!write_mode) + // rjf: insert into scope tree + TXT_ScopeNode *new_scope = &shared->info.scope_nodes.v[scope_idx]; + new_scope->token_idx_range.min = token_idx; + if(top_scope_task) { - break; + U64 new_scope_num = scope_idx+1; + TXT_ScopeNode *parent = &shared->info.scope_nodes.v[top_scope_task->scope_idx]; + if(parent->first_num == 0) + { + parent->first_num = new_scope_num; + } + if(parent->last_num != 0) + { + TXT_ScopeNode *prev_scope = &shared->info.scope_nodes.v[parent->last_num-1]; + prev_scope->next_num = new_scope_num; + } + parent->last_num = new_scope_num; + new_scope->parent_num = top_scope_task->scope_idx+1; + } + + // rjf: push onto scope stack + ScopeTask *scope_task = free_scope_task; + if(scope_task) + { + SLLStackPop(free_scope_task); } else { - DLLRemove(slot->first, slot->last, n); - c_hash_downstream_dec(n->hash); - if(n->arena != 0) - { - arena_release(n->arena); - } - SLLStackPush(txt_shared->stripes_free_nodes[(stripe - txt_shared->stripes.v)], n); + scope_task = push_array(scratch.arena, ScopeTask, 1); } + scope_task->scope_idx = scope_idx; + scope_idx += 1; + SLLStackPush(top_scope_task, scope_task); + } + + // rjf: opener or closer -> fill endpoint + if(top_scope_task && (is_opener || is_closer)) + { + shared->info.scope_pts.v[pt_idx].token_idx = token_idx; + shared->info.scope_pts.v[pt_idx].scope_idx = top_scope_task->scope_idx; + pt_idx += 1; + } + + // rjf: closer symbols -> pop + if(is_closer && top_scope_task != 0) + { + ScopeTask *popped = top_scope_task; + shared->info.scope_nodes.v[popped->scope_idx].token_idx_range.max = token_idx; + SLLStackPop(top_scope_task); + SLLStackPush(free_scope_task, popped); } } } - if(!slot_has_work) - { - break; - } + scratch_end(scratch); } } + lane_sync(); } + + //- rjf: package as artifact + if(lane_idx() == 0 && shared->arena != 0) + { + shared->artifact = push_array(shared->arena, TXT_Artifact, 1); + shared->artifact->arena = shared->arena; + shared->artifact->info = shared->info; + } + lane_sync(); + + access_close(access); + scratch_end(scratch); + ProfEnd(); + return shared->artifact; +} + +internal void +txt_artifact_destroy(void *ptr) +{ + if(ptr == 0) { return; } + TXT_Artifact *artifact = (TXT_Artifact *)ptr; + arena_release(artifact->arena); +} + +internal TXT_TextInfo +txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) +{ + struct + { + U128 hash; + TXT_LangKind lang; + } key = {hash, lang}; + String8 key_string = str8_struct(&key); + TXT_Artifact *artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 1024); + TXT_TextInfo info = {0}; + if(artifact != 0) + { + info = artifact->info; + } + return info; +} + +internal TXT_TextInfo +txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out) +{ + TXT_TextInfo result = {0}; + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + { + U128 hash = c_hash_from_key(key, rewind_idx); + result = txt_text_info_from_hash_lang(access, hash, lang); + if(result.lines_count != 0) + { + if(hash_out) + { + *hash_out = hash; + } + break; + } + } + return result; } diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 9370bc85..0b28bdef 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -208,9 +208,6 @@ struct TXT_Shared { Arena *arena; - // rjf: user clock - U64 user_clock_idx; - // rjf: cache U64 slots_count; TXT_Slot *slots; @@ -240,7 +237,6 @@ struct TXT_Shared //~ rjf: Globals read_only global TXT_ScopeNode txt_scope_node_nil = {0}; -global TXT_Shared *txt_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers @@ -267,17 +263,6 @@ internal TXT_TokenArray txt_token_array_from_string__jai(Arena *arena, U64 *byte internal TXT_TokenArray txt_token_array_from_string__zig(Arena *arena, U64 *bytes_processed_counter, String8 string); internal TXT_TokenArray txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed_counter, String8 string); -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void txt_init(void); - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); -internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); - //////////////////////////////// //~ rjf: Text Info Extractor Helpers @@ -294,20 +279,11 @@ internal TXT_ScopeNode *txt_scope_node_from_info_off(TXT_TextInfo *info, U64 off internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt); //////////////////////////////// -//~ rjf: Parse Threads +//~ rjf: Artifact Cache Hooks / Lookups -internal B32 txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us); -internal void txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out); -ASYNC_WORK_DEF(txt_parse_work); - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void txt_evictor_thread__entry_point(void *p); - -//////////////////////////////// -//~ rjf: Tick - -internal void txt_tick(void); +internal void *txt_artifact_create(String8 key); +internal void txt_artifact_destroy(void *ptr); +internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); +internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); #endif // TEXT_CACHE_H From 8a1e6ab2e61356ace551888aa3095a4b32834d06 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 15:25:01 -0700 Subject: [PATCH 237/302] extend artifact cache with non-key-included generations, to allow gracefully decaying certain computations --- src/artifact_cache/artifact_cache.c | 28 ++++++++--- src/artifact_cache/artifact_cache.h | 6 ++- src/text_cache/text_cache.c | 2 +- src/text_cache/text_cache.h | 78 ----------------------------- 4 files changed, 27 insertions(+), 87 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 0167dd49..58509d16 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -21,7 +21,7 @@ ac_init(void) //~ rjf: Cache Lookups internal void * -ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count) +ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count) { //- rjf: create function -> cache AC_Cache *cache = 0; @@ -69,8 +69,10 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { B32 found = 0; + B32 need_request = 0; RWMutexScope(stripe->rw_mutex, write_mode) { + // rjf: look up node for(AC_Node *n = slot->first; n != 0; n = n->next) { if(str8_match(n->key, key, 0)) @@ -78,11 +80,19 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, found = 1; artifact = n->val; access_touch(access, &n->access_pt, stripe->cv); + if(n->gen != gen) + { + B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0); + need_request = got_task; + } break; } } + + // rjf: no node? -> create if(write_mode && !found) { + need_request = 1; AC_Node *node = stripe->free; if(node) { @@ -99,11 +109,9 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, node->working_count = 1; } } - if(found) - { - break; - } - else if(write_mode) + + // rjf: need request -> push + if(need_request) { MutexScope(ac_shared->req_mutex) { @@ -111,10 +119,17 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); ac_shared->req_count += 1; n->v.key = str8_copy(ac_shared->req_arena, key); + n->v.gen = gen; n->v.create = create; } cond_var_broadcast(async_tick_start_cond_var); } + + // rjf: found node -> break + if(found) + { + break; + } } } @@ -240,6 +255,7 @@ ac_tick(void) { if(str8_match(n->key, reqs[idx].key, 0)) { + n->gen = reqs[idx].gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); } diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 9d851859..30f19c1e 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -17,6 +17,7 @@ typedef struct AC_Request AC_Request; struct AC_Request { String8 key; + U64 gen; AC_CreateFunctionType *create; }; @@ -33,8 +34,9 @@ struct AC_Node AC_Node *next; AC_Node *prev; - // rjf: key/value + // rjf: key/gen/value String8 key; + U64 gen; void *val; // rjf: metadata @@ -94,7 +96,7 @@ internal void ac_init(void); //////////////////////////////// //~ rjf: Cache Lookups -internal void *ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); +internal void *ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); //////////////////////////////// //~ rjf: Tick diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index ae39b4d3..bb24811c 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -2252,7 +2252,7 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) TXT_LangKind lang; } key = {hash, lang}; String8 key_string = str8_struct(&key); - TXT_Artifact *artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 1024); + TXT_Artifact *artifact = ac_artifact_from_key(access, key_string, 0, txt_artifact_create, txt_artifact_destroy, 1024); TXT_TextInfo info = {0}; if(artifact != 0) { diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 0b28bdef..57d66de8 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -155,84 +155,6 @@ TXT_LangKind; typedef TXT_TokenArray TXT_LangLexFunctionType(Arena *arena, U64 *bytes_processed_counter, String8 string); -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct TXT_Request TXT_Request; -struct TXT_Request -{ - U128 hash; - TXT_LangKind lang; -}; - -typedef struct TXT_RequestNode TXT_RequestNode; -struct TXT_RequestNode -{ - TXT_RequestNode *next; - TXT_Request v; -}; - -typedef struct TXT_Node TXT_Node; -struct TXT_Node -{ - // rjf: links - TXT_Node *next; - TXT_Node *prev; - - // rjf: key - U128 hash; - TXT_LangKind lang; - - // rjf: artifacts - Arena *arena; - TXT_TextInfo info; - - // rjf: metadata - AccessPt access_pt; - B32 is_working; - U64 load_count; -}; - -typedef struct TXT_Slot TXT_Slot; -struct TXT_Slot -{ - TXT_Node *first; - TXT_Node *last; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct TXT_Shared TXT_Shared; -struct TXT_Shared -{ - Arena *arena; - - // rjf: cache - U64 slots_count; - TXT_Slot *slots; - StripeArray stripes; - TXT_Node **stripes_free_nodes; - - // rjf: requests - Mutex req_mutex; - Arena *req_arena; - TXT_RequestNode *first_req; - TXT_RequestNode *last_req; - U64 req_count; - - // rjf: user -> parse thread - U64 u2p_ring_size; - U8 *u2p_ring_base; - U64 u2p_ring_write_pos; - U64 u2p_ring_read_pos; - CondVar u2p_ring_cv; - Mutex u2p_ring_mutex; - - // rjf: evictor thread - Thread evictor_thread; -}; - //////////////////////////////// //~ rjf: Globals From 4b1939bd6d6daea8245423b9fb6960faa4771413 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 16:21:30 -0700 Subject: [PATCH 238/302] provide u64 broadcasting mechanism in base layer wavefront lane context, allows more flexible data sharing mechanism which does not depend on statics; reshape dasm building codepath for clicking into artifact cache --- src/artifact_cache/artifact_cache.c | 20 +- src/artifact_cache/artifact_cache.h | 2 +- src/base/base_entry_point.c | 2 + src/base/base_profile.h | 9 +- src/base/base_thread_context.c | 15 +- src/base/base_thread_context.h | 8 +- src/dasm_cache/dasm_cache.c | 466 ++++++++++++++---- src/dasm_cache/dasm_cache.h | 15 +- .../metagen_base/metagen_base_profile.h | 37 +- src/radbin/radbin.c | 8 +- src/text_cache/text_cache.c | 6 +- src/text_cache/text_cache.h | 2 +- 12 files changed, 444 insertions(+), 146 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 58509d16..ee2fb7ee 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -221,10 +221,26 @@ ac_tick(void) lane_sync(); // rjf: compute val - void *val = reqs[idx].create(reqs[idx].key); + B32 retry = 0; + void *val = reqs[idx].create(reqs[idx].key, &retry); + + // rjf: retry? -> resubmit request + if(retry && lane_idx() == 0) + { + MutexScope(ac_shared->req_mutex) + { + AC_RequestNode *n = push_array(ac_shared->req_arena, AC_RequestNode, 1); + SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); + ac_shared->req_count += 1; + MemoryCopyStruct(&n->v, &reqs[idx]); + n->v.key = str8_copy(ac_shared->req_arena, n->v.key); + } + ins_atomic_u32_eval_assign(&async_loop_again, 1); + } // rjf: create function -> cache AC_Cache *cache = 0; + if(!retry) { U64 cache_hash = u64_hash_from_str8(str8_struct(&reqs[idx].create)); U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; @@ -243,7 +259,7 @@ ac_tick(void) } // rjf: write value into cache - if(lane_idx() == 0) + if(!retry && lane_idx() == 0) { U64 hash = u64_hash_from_str8(reqs[idx].key); U64 slot_idx = hash%cache->slots_count; diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 30f19c1e..04de679d 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -7,7 +7,7 @@ //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef void *AC_CreateFunctionType(String8 key); +typedef void *AC_CreateFunctionType(String8 key, B32 *retry_out); typedef void AC_DestroyFunctionType(void *artifact); //////////////////////////////// diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 6c79091c..40b60d09 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -117,6 +117,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads); num_async_threads -= num_main_threads_clamped; num_async_threads = Max(1, num_async_threads); + U64 lane_broadcast_val = 0; Barrier barrier = barrier_alloc(num_async_threads); LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads); async_threads_count = num_async_threads; @@ -126,6 +127,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) lane_ctxs[idx].lane_idx = idx; lane_ctxs[idx].lane_count = num_async_threads; lane_ctxs[idx].barrier = barrier; + lane_ctxs[idx].broadcast_memory = &lane_broadcast_val; async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]); } } diff --git a/src/base/base_profile.h b/src/base/base_profile.h index b750427c..6ef4a046 100644 --- a/src/base/base_profile.h +++ b/src/base/base_profile.h @@ -20,6 +20,7 @@ #if PROFILE_TELEMETRY # include "rad_tm.h" # if OS_WINDOWS +# pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "rad_tm_win64.lib") # endif #elif PROFILE_SPALL @@ -44,8 +45,8 @@ # define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) # define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) # define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f) -# define ProfBeginV(...) \ -if (TM_API_PTR) { \ +# define ProfBeginV(...) \ +if (TM_API_PTR) { \ static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ Temp scratch = scratch_begin(0,0); \ String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ @@ -54,8 +55,8 @@ hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \ TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \ scratch_end(scratch); \ } -# define ProfNoteV(...) \ -if (TM_API_PTR) { \ +# define ProfNoteV(...) \ +if (TM_API_PTR) { \ static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ Temp scratch = scratch_begin(0,0); \ String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index c9e04f7f..e08d42b1 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -4,9 +4,9 @@ //////////////////////////////// //~ rjf: Globals -C_LINKAGE thread_static TCTX* tctx_thread_local; +C_LINKAGE thread_static TCTX *tctx_thread_local; #if !BUILD_SUPPLEMENTARY_UNIT -C_LINKAGE thread_static TCTX* tctx_thread_local = 0; +C_LINKAGE thread_static TCTX *tctx_thread_local = 0; #endif //////////////////////////////// @@ -85,12 +85,21 @@ tctx_set_lane_ctx(LaneCtx lane_ctx) } internal void -tctx_lane_barrier_wait(void) +tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx) { ProfBeginFunction(); ProfColor(0x00000ff); TCTX *tctx = tctx_selected(); + U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0])); + if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx) + { + MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped); + } os_barrier_wait(tctx->lane_ctx.barrier); + if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx) + { + MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped); + } ProfEnd(); } diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index ef605e14..b840e552 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -5,7 +5,7 @@ #define BASE_THREAD_CONTEXT_H //////////////////////////////// -//~ rjf: Lane Group Context +//~ rjf: Lane Context typedef struct LaneCtx LaneCtx; struct LaneCtx @@ -13,6 +13,7 @@ struct LaneCtx U64 lane_idx; U64 lane_count; Barrier barrier; + U64 *broadcast_memory; }; //////////////////////////////// @@ -87,12 +88,13 @@ internal Arena *tctx_get_scratch(Arena **conflicts, U64 count); //- rjf: lane metadata internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx); -internal void tctx_lane_barrier_wait(void); +internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx); #define lane_idx() (tctx_selected()->lane_ctx.lane_idx) #define lane_count() (tctx_selected()->lane_ctx.lane_count) #define lane_from_task_idx(idx) ((idx)%lane_count()) #define lane_ctx(ctx) tctx_set_lane_ctx((ctx)) -#define lane_sync() tctx_lane_barrier_wait() +#define lane_sync() tctx_lane_barrier_wait(0, 0, 0) +#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(U64), (src_lane_idx)) #define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count)) //- rjf: thread names diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index a4d49003..889e96b1 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -277,108 +277,6 @@ dasm_init(void) dasm_shared->req_arena = arena_alloc(); } -//////////////////////////////// -//~ rjf: Cache Lookups - -internal DASM_Info -dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) -{ - DASM_Info info = {0}; - if(!u128_match(hash, u128_zero())) - { - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - - //- rjf: try to get existing results; create node if needed - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 found = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - // rjf: find existing node - DASM_Node *node = 0; - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params)) - { - node = n; - found = 1; - break; - } - } - - // rjf: [write mode] allocate node if needed, and kick off request - if(write_mode && node == 0) - { - node = stripe->free_node; - if(node) - { - SLLStackPop(stripe->free_node); - } - else - { - node = push_array_no_zero(stripe->arena, DASM_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->hash = hash; - MemoryCopyStruct(&node->params, params); - node->root = c_root_alloc(); - // TODO(rjf): need to make this releasable - currently all exe_paths just leak - node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); - ins_atomic_u64_inc_eval(&node->working_count); - MutexScope(dasm_shared->req_mutex) - { - DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); - SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); - dasm_shared->req_count += 1; - req_n->v.root = node->root; - req_n->v.hash = hash; - MemoryCopyStruct(&req_n->v.params, params); - req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); - } - cond_var_broadcast(async_tick_start_cond_var); - } - - // rjf: nonzero node, request if needed - touch & return results - if(node != 0) - { - access_touch(access, &node->access_pt, stripe->cv); - MemoryCopyStruct(&info, &node->info); - } - } - if(found) - { - break; - } - } - } - return info; -} - -internal DASM_Info -dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out) -{ - DASM_Info result = {0}; - for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) - { - U128 hash = c_hash_from_key(key, rewind_idx); - result = dasm_info_from_hash_params(access, hash, params); - if(result.lines.count != 0) - { - if(hash_out) - { - *hash_out = hash; - } - break; - } - } - return result; -} - //////////////////////////////// //~ rjf: Ticks @@ -734,3 +632,367 @@ dasm_tick(void) scratch_end(scratch); ProfEnd(); } + +//////////////////////////////// +//~ rjf: Artifact Cache Hooks / Lookups + +typedef struct DASM_Artifact DASM_Artifact; +struct DASM_Artifact +{ + Arena *arena; + DASM_Info info; +}; + +internal void * +dasm_artifact_create(String8 key, B32 *retry_out) +{ + void *result = 0; + if(lane_idx() == 0) + { + Temp scratch = scratch_begin(0, 0); + Access *access = access_open(); + DI_Scope *di_scope = di_scope_open(); + + //- rjf: unpack key + U128 hash = {0}; + DASM_Params params = {0}; + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &hash); + key_read_off += str8_deserial_read_struct(key, key_read_off, ¶ms); + params.dbgi_key.path.str = key.str + key_read_off; + String8 data = c_data_from_hash(access, hash); + + //- rjf: get dbg info + B32 stale = 0; + RDI_Parsed *rdi = &rdi_parsed_nil; + if(params.dbgi_key.path.size != 0) + { + rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); + } + stale = (stale || (rdi == &rdi_parsed_nil)); + + //- rjf: data * arch * addr * dbg -> decode artifacts + DASM_LineChunkList line_list = {0}; + String8List inst_strings = {0}; + switch(params.arch) + { + default:{}break; + + //- rjf: x86/x64 decoding + case Arch_x64: + case Arch_x86: + { + // rjf: disassemble + RDI_SourceFile *last_file = &rdi_nil_element_union.source_file; + RDI_Line *last_line = 0; + for(U64 off = 0; off < data.size;) + { + // rjf: disassemble one instruction + DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax); + if(inst.size == 0) + { + break; + } + + // rjf: push strings derived from voff -> line info + if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines) && + rdi != &rdi_parsed_nil) + { + U64 voff = (params.vaddr+off) - params.base_vaddr; + U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff); + RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx); + RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx); + RDI_ParsedLineTable unit_line_info = {0}; + rdi_parsed_from_line_table(rdi, line_table, &unit_line_info); + U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff); + if(line_info_idx < unit_line_info.count) + { + RDI_Line *line = &unit_line_info.lines[line_info_idx]; + RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx); + String8 file_normalized_full_path = {0}; + file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); + if(file != last_file) + { + if(params.style_flags & DASM_StyleFlag_SourceFilesNames && + file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0) + { + String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0) + { + String8 inst_string = str8_lit(">"); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + last_file = file; + } + if(line && line != last_line && file->normal_full_path_string_idx != 0 && + params.style_flags & DASM_StyleFlag_SourceLines && + file_normalized_full_path.size != 0) + { + FileProperties props = os_properties_from_file_path(file_normalized_full_path); + if(props.modified != 0) + { + // TODO(rjf): need redirection path - this may map to a different path on the local machine, + // need frontend to communicate path remapping info to this layer + C_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); + U64 endt_us = max_U64; + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(access, key, lang_kind, &hash); + stale = (stale || u128_match(hash, u128_zero())); + if(0 < line->line_num && line->line_num < text_info.lines_count) + { + String8 data = c_data_from_hash(access, hash); + String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); + if(line_text.size != 0) + { + String8 inst_string = push_str8f(scratch.arena, "> %S", line_text); + DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + } + } + } + last_line = line; + } + } + } + + // rjf: push line + String8 addr_part = {0}; + if(params.style_flags & DASM_StyleFlag_Addresses) + { + addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &rdi_parsed_nil ? " " : "", params.vaddr+off); + } + String8 code_bytes_part = {0}; + if(params.style_flags & DASM_StyleFlag_CodeBytes) + { + String8List code_bytes_strings = {0}; + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{")); + for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1) + { + if(byte_idx < inst.size) + { + str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : ""); + } + else if(byte_idx < 8) + { + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + } + } + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); + } + String8 symbol_part = {0}; + if(inst.jump_dest_vaddr != 0 && rdi != &rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) + { + RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr); + if(scope_idx != 0) + { + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + RDI_U32 procedure_idx = scope->proc_idx; + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx); + String8 procedure_name = {0}; + procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); + if(procedure_name.size != 0) + { + symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name); + } + } + } + String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part); + DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line); + str8_list_push(scratch.arena, &inst_strings, inst_string); + + // rjf: increment + off += inst.size; + } + }break; + } + + //- rjf: artifacts -> value bundle + Arena *info_arena = 0; + DASM_Info info = {0}; + if(!stale) + { + //- rjf: produce joined text + Arena *text_arena = arena_alloc(); + StringJoin text_join = {0}; + text_join.sep = str8_lit("\n"); + String8 text = str8_list_join(text_arena, &inst_strings, &text_join); + + //- rjf: produce unique key for this disassembly's text + C_Key text_key = c_key_make(c_root_alloc(), c_id_make(0, 0)); + + //- rjf: submit text data to hash store + U128 text_hash = c_submit_data(text_key, &text_arena, text); + + //- rjf: produce value bundle + info_arena = arena_alloc(); + info.text_key = text_key; + info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list); + } + + //- rjf: if stale, retry + if(stale) + { + retry_out[0] = 1; + } + + //- rjf: fill result + if(info_arena != 0) + { + DASM_Artifact *artifact = push_array(info_arena, DASM_Artifact, 1); + artifact->arena = info_arena; + artifact->info = info; + result = artifact; + } + + di_scope_close(di_scope); + access_close(access); + scratch_end(scratch); + } + lane_sync_u64(&result, 0); + return result; +} + +internal void +dasm_artifact_destroy(void *ptr) +{ + if(ptr == 0) { return; } + DASM_Artifact *artifact = (DASM_Artifact *)ptr; + c_close_key(artifact->info.text_key); + arena_release(artifact->arena); +} + +internal DASM_Info +dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) +{ + DASM_Info info = {0}; + { + Temp scratch = scratch_begin(0, 0); + + // rjf: form key + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&hash)); + str8_list_push(scratch.arena, &key_parts, str8_struct(params)); + str8_list_push(scratch.arena, &key_parts, params->dbgi_key.path); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + + // rjf: get info + DASM_Artifact *artifact = ac_artifact_from_key(access, key, fs_change_gen(), dasm_artifact_create, dasm_artifact_destroy, 1024); + if(artifact) + { + info = artifact->info; + } + + scratch_end(scratch); + } + return info; +#if 0 + DASM_Info info = {0}; + if(!u128_match(hash, u128_zero())) + { + //- rjf: unpack hash + U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; + U64 stripe_idx = slot_idx%dasm_shared->stripes_count; + DASM_Slot *slot = &dasm_shared->slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; + + //- rjf: try to get existing results; create node if needed + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 found = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + // rjf: find existing node + DASM_Node *node = 0; + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params)) + { + node = n; + found = 1; + break; + } + } + + // rjf: [write mode] allocate node if needed, and kick off request + if(write_mode && node == 0) + { + node = stripe->free_node; + if(node) + { + SLLStackPop(stripe->free_node); + } + else + { + node = push_array_no_zero(stripe->arena, DASM_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->hash = hash; + MemoryCopyStruct(&node->params, params); + node->root = c_root_alloc(); + // TODO(rjf): need to make this releasable - currently all exe_paths just leak + node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); + ins_atomic_u64_inc_eval(&node->working_count); + MutexScope(dasm_shared->req_mutex) + { + DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); + SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); + dasm_shared->req_count += 1; + req_n->v.root = node->root; + req_n->v.hash = hash; + MemoryCopyStruct(&req_n->v.params, params); + req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); + } + cond_var_broadcast(async_tick_start_cond_var); + } + + // rjf: nonzero node, request if needed - touch & return results + if(node != 0) + { + access_touch(access, &node->access_pt, stripe->cv); + MemoryCopyStruct(&info, &node->info); + } + } + if(found) + { + break; + } + } + } + return info; +#endif +} + +internal DASM_Info +dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out) +{ + DASM_Info result = {0}; + for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + { + U128 hash = c_hash_from_key(key, rewind_idx); + result = dasm_info_from_hash_params(access, hash, params); + if(result.lines.count != 0) + { + if(hash_out) + { + *hash_out = hash; + } + break; + } + } + return result; +} diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index e95cb148..e00f4cf6 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -284,15 +284,18 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); internal void dasm_init(void); -//////////////////////////////// -//~ rjf: Cache Lookups - -internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); -internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); - //////////////////////////////// //~ rjf: Ticks internal void dasm_tick(void); +//////////////////////////////// +//~ rjf: Artifact Cache Hooks / Lookups + +internal void *dasm_artifact_create(String8 key, B32 *retry_out); +internal void dasm_artifact_destroy(void *ptr); + +internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); +internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); + #endif // DASM_CACHE_H diff --git a/src/metagen/metagen_base/metagen_base_profile.h b/src/metagen/metagen_base/metagen_base_profile.h index 098270f4..1e0d938b 100644 --- a/src/metagen/metagen_base/metagen_base_profile.h +++ b/src/metagen/metagen_base/metagen_base_profile.h @@ -21,6 +21,7 @@ #if PROFILE_TELEMETRY # include "rad_tm.h" # if OS_WINDOWS +# pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "rad_tm_win64.lib") # endif #endif @@ -44,25 +45,25 @@ # define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) # define ProfColor(color) tmZoneColorSticky(color) # define ProfBeginV(...) \ - if (TM_API_PTR) { \ - static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ - Temp scratch = scratch_begin(0,0); \ - String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ - tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \ - hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \ - TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \ - scratch_end(scratch); \ - } +if (TM_API_PTR) { \ +static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ +Temp scratch = scratch_begin(0,0); \ +String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ +tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \ +hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \ +TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \ +scratch_end(scratch); \ +} # define ProfNoteV(...) \ - if (TM_API_PTR) { \ - static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ - Temp scratch = scratch_begin(0,0); \ - String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ - tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \ - hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \ - TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \ - scratch_end(scratch); \ - } +if (TM_API_PTR) { \ +static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \ +Temp scratch = scratch_begin(0,0); \ +String8 string = push_str8f(scratch.arena, __VA_ARGS__); \ +tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \ +hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \ +TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \ +scratch_end(scratch); \ +} #endif //////////////////////////////// diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 64bde605..dfc84dc1 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -26,12 +26,14 @@ rb_entry_point(CmdLine *cmdline) Thread *threads = push_array(scratch.arena, Thread, threads_count); RB_ThreadParams *threads_params = push_array(scratch.arena, RB_ThreadParams, threads_count); Barrier barrier = barrier_alloc(threads_count); + U64 broadcast_val = 0; for EachIndex(idx, threads_count) { threads_params[idx].cmdline = cmdline; - threads_params[idx].lane_ctx.lane_idx = idx; - threads_params[idx].lane_ctx.lane_count = threads_count; - threads_params[idx].lane_ctx.barrier = barrier; + threads_params[idx].lane_ctx.lane_idx = idx; + threads_params[idx].lane_ctx.lane_count = threads_count; + threads_params[idx].lane_ctx.barrier = barrier; + threads_params[idx].lane_ctx.broadcast_memory = &broadcast_val; threads[idx] = thread_launch(rb_thread_entry_point, &threads_params[idx]); } for EachIndex(idx, threads_count) diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index bb24811c..015f54fb 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1969,19 +1969,19 @@ struct TXT_ArtifactCreateShared }; internal void * -txt_artifact_create(String8 key) +txt_artifact_create(String8 key, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); Access *access = access_open(); //- rjf: get shared state - local_persist TXT_ArtifactCreateShared *shared = 0; + TXT_ArtifactCreateShared *shared = 0; if(lane_idx() == 0) { shared = push_array(scratch.arena, TXT_ArtifactCreateShared, 1); } - lane_sync(); + lane_sync_u64(&shared, 0); //- rjf: unpack key U128 hash = {0}; diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 57d66de8..ba687a4e 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -203,7 +203,7 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal void *txt_artifact_create(String8 key); +internal void *txt_artifact_create(String8 key, B32 *retry_out); internal void txt_artifact_destroy(void *ptr); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From 6ac8c588f783e95f0560ba8bbb29f5c422da082c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 16:22:33 -0700 Subject: [PATCH 239/302] eliminate old disasm cache code --- src/dasm_cache/dasm_cache.c | 455 ------------------------------------ src/dasm_cache/dasm_cache.h | 96 -------- 2 files changed, 551 deletions(-) diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 889e96b1..fbaff78b 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -254,385 +254,6 @@ dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx) return off; } -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -dasm_init(void) -{ - Arena *arena = arena_alloc(); - dasm_shared = push_array(arena, DASM_Shared, 1); - dasm_shared->arena = arena; - dasm_shared->slots_count = 1024; - dasm_shared->stripes_count = Min(dasm_shared->slots_count, os_get_system_info()->logical_processor_count); - dasm_shared->slots = push_array(arena, DASM_Slot, dasm_shared->slots_count); - dasm_shared->stripes = push_array(arena, DASM_Stripe, dasm_shared->stripes_count); - for(U64 idx = 0; idx < dasm_shared->stripes_count; idx += 1) - { - dasm_shared->stripes[idx].arena = arena_alloc(); - dasm_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - dasm_shared->stripes[idx].cv = cond_var_alloc(); - } - dasm_shared->req_mutex = mutex_alloc(); - dasm_shared->req_arena = arena_alloc(); -} - -//////////////////////////////// -//~ rjf: Ticks - -internal void -dasm_tick(void) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //- rjf: do detection pass - { - U64 change_gen = fs_change_gen(); - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 10*1000000; - U64 retry_threshold_us = 1*1000000; - U64 evict_threshold_user_clocks = 10; - U64 retry_threshold_user_clocks = 10; - Rng1U64 range = lane_range(dasm_shared->slots_count); - for EachInRange(slot_idx, range) - { - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 slot_has_work = 0; - RWMutexScope(stripe->rw_mutex, write_mode) for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - // rjf: node needs eviction - if(access_pt_is_expired(&n->access_pt) && ins_atomic_u64_eval(&n->working_count) == 0) - { - slot_has_work = 1; - if(!write_mode) - { - break; - } - else - { - DLLRemove(slot->first, slot->last, n); - if(n->info_arena != 0) - { - arena_release(n->info_arena); - } - SLLStackPush(stripe->free_node, n); - } - } - - // rjf: node needs recomputation - if(n->change_gen != 0 && n->change_gen != change_gen && - n->last_time_requested_us+retry_threshold_us <= check_time_us && - n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) - { - slot_has_work = 1; - if(!write_mode) - { - break; - } - else - { - MutexScope(dasm_shared->req_mutex) - { - DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); - SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); - dasm_shared->req_count += 1; - req_n->v.root = n->root; - req_n->v.hash = n->hash; - req_n->v.params = n->params; - req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); - } - n->last_time_requested_us = os_now_microseconds(); - n->last_user_clock_idx_requested = check_time_user_clocks; - ins_atomic_u64_inc_eval(&n->working_count); - } - } - } - if(!slot_has_work) - { - break; - } - } - } - } - - //- rjf: gather all requests - local_persist DASM_Request *reqs = 0; - local_persist U64 reqs_count = 0; - if(lane_idx() == 0) MutexScope(dasm_shared->req_mutex) - { - reqs_count = dasm_shared->req_count; - reqs = push_array(scratch.arena, DASM_Request, reqs_count); - U64 idx = 0; - for EachNode(r, DASM_RequestNode, dasm_shared->first_req) - { - MemoryCopyStruct(&reqs[idx], &r->v); - reqs[idx].params.dbgi_key = di_key_copy(scratch.arena, &reqs[idx].params.dbgi_key); - idx += 1; - } - arena_clear(dasm_shared->req_arena); - dasm_shared->first_req = dasm_shared->last_req = 0; - dasm_shared->req_count = 0; - dasm_shared->lane_req_take_counter = 0; - } - lane_sync(); - - //- rjf: do requests - for(;;) - { - //- rjf: get next request - U64 req_num = ins_atomic_u64_inc_eval(&dasm_shared->lane_req_take_counter); - if(req_num < 1 || reqs_count < req_num) - { - break; - } - U64 req_idx = req_num-1; - Access *access = access_open(); - DI_Scope *di_scope = di_scope_open(); - - //- rjf: unpack - B32 stale = 0; - DASM_Request *r = &reqs[req_idx]; - C_Root root = r->root; - U128 hash = r->hash; - DASM_Params params = r->params; - String8 data = c_data_from_hash(access, hash); - U64 change_gen = fs_change_gen(); - U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - - //- rjf: get dbg info - RDI_Parsed *rdi = &rdi_parsed_nil; - if(params.dbgi_key.path.size != 0) - { - rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); - } - stale = (stale || (rdi == &rdi_parsed_nil)); - - //- rjf: data * arch * addr * dbg -> decode artifacts - DASM_LineChunkList line_list = {0}; - String8List inst_strings = {0}; - switch(params.arch) - { - default:{}break; - - //- rjf: x86/x64 decoding - case Arch_x64: - case Arch_x86: - { - // rjf: disassemble - RDI_SourceFile *last_file = &rdi_nil_element_union.source_file; - RDI_Line *last_line = 0; - for(U64 off = 0; off < data.size;) - { - // rjf: disassemble one instruction - DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax); - if(inst.size == 0) - { - break; - } - - // rjf: push strings derived from voff -> line info - if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines) && - rdi != &rdi_parsed_nil) - { - U64 voff = (params.vaddr+off) - params.base_vaddr; - U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff); - RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx); - RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx); - RDI_ParsedLineTable unit_line_info = {0}; - rdi_parsed_from_line_table(rdi, line_table, &unit_line_info); - U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff); - if(line_info_idx < unit_line_info.count) - { - RDI_Line *line = &unit_line_info.lines[line_info_idx]; - RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx); - String8 file_normalized_full_path = {0}; - file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); - if(file != last_file) - { - if(params.style_flags & DASM_StyleFlag_SourceFilesNames && - file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0) - { - String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0) - { - String8 inst_string = str8_lit(">"); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - last_file = file; - } - if(line && line != last_line && file->normal_full_path_string_idx != 0 && - params.style_flags & DASM_StyleFlag_SourceLines && - file_normalized_full_path.size != 0) - { - FileProperties props = os_properties_from_file_path(file_normalized_full_path); - if(props.modified != 0) - { - // TODO(rjf): need redirection path - this may map to a different path on the local machine, - // need frontend to communicate path remapping info to this layer - C_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); - TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); - U64 endt_us = max_U64; - U128 hash = {0}; - TXT_TextInfo text_info = txt_text_info_from_key_lang(access, key, lang_kind, &hash); - stale = (stale || u128_match(hash, u128_zero())); - if(0 < line->line_num && line->line_num < text_info.lines_count) - { - String8 data = c_data_from_hash(access, hash); - String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1])); - if(line_text.size != 0) - { - String8 inst_string = push_str8f(scratch.arena, "> %S", line_text); - DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst); - str8_list_push(scratch.arena, &inst_strings, inst_string); - } - } - } - last_line = line; - } - } - } - - // rjf: push line - String8 addr_part = {0}; - if(params.style_flags & DASM_StyleFlag_Addresses) - { - addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &rdi_parsed_nil ? " " : "", params.vaddr+off); - } - String8 code_bytes_part = {0}; - if(params.style_flags & DASM_StyleFlag_CodeBytes) - { - String8List code_bytes_strings = {0}; - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{")); - for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1) - { - if(byte_idx < inst.size) - { - str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : ""); - } - else if(byte_idx < 8) - { - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); - } - } - str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); - code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); - } - String8 symbol_part = {0}; - if(inst.jump_dest_vaddr != 0 && rdi != &rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) - { - RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr); - if(scope_idx != 0) - { - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - RDI_U32 procedure_idx = scope->proc_idx; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx); - String8 procedure_name = {0}; - procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size); - if(procedure_name.size != 0) - { - symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name); - } - } - } - String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part); - DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count, - inst_strings.total_size + inst_strings.node_count + inst_string.size)}; - dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line); - str8_list_push(scratch.arena, &inst_strings, inst_string); - - // rjf: increment - off += inst.size; - } - }break; - } - - //- rjf: artifacts -> value bundle - Arena *info_arena = 0; - DASM_Info info = {0}; - if(!stale) - { - //- rjf: produce joined text - Arena *text_arena = arena_alloc(); - StringJoin text_join = {0}; - text_join.sep = str8_lit("\n"); - String8 text = str8_list_join(text_arena, &inst_strings, &text_join); - - //- rjf: produce unique key for this disassembly's text - C_Key text_key = c_key_make(root, c_id_make(0, 0)); - - //- rjf: submit text data to hash store - U128 text_hash = c_submit_data(text_key, &text_arena, text); - - //- rjf: produce value bundle - info_arena = arena_alloc(); - info.text_key = text_key; - info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list); - } - - //- rjf: commit results to cache - if(!stale) RWMutexScope(stripe->rw_mutex, 1) - { - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms)) - { - n->info_arena = info_arena; - MemoryCopyStruct(&n->info, &info); - if(rdi != &rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) - { - n->change_gen = change_gen; - } - else - { - n->change_gen = 0; - } - ins_atomic_u64_dec_eval(&n->working_count); - break; - } - } - } - - //- rjf: re-request if stale - if(stale) MutexScope(dasm_shared->req_mutex) - { - DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); - SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); - dasm_shared->req_count += 1; - req_n->v.root = root; - req_n->v.hash = hash; - req_n->v.params = params; - req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); - ins_atomic_u32_eval_assign(&async_loop_again, 1); - } - - di_scope_close(di_scope); - access_close(access); - } - lane_sync(); - - scratch_end(scratch); - ProfEnd(); -} - //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups @@ -899,82 +520,6 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) scratch_end(scratch); } return info; -#if 0 - DASM_Info info = {0}; - if(!u128_match(hash, u128_zero())) - { - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; - U64 stripe_idx = slot_idx%dasm_shared->stripes_count; - DASM_Slot *slot = &dasm_shared->slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; - - //- rjf: try to get existing results; create node if needed - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 found = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - // rjf: find existing node - DASM_Node *node = 0; - for(DASM_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && dasm_params_match(params, &n->params)) - { - node = n; - found = 1; - break; - } - } - - // rjf: [write mode] allocate node if needed, and kick off request - if(write_mode && node == 0) - { - node = stripe->free_node; - if(node) - { - SLLStackPop(stripe->free_node); - } - else - { - node = push_array_no_zero(stripe->arena, DASM_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->hash = hash; - MemoryCopyStruct(&node->params, params); - node->root = c_root_alloc(); - // TODO(rjf): need to make this releasable - currently all exe_paths just leak - node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); - ins_atomic_u64_inc_eval(&node->working_count); - MutexScope(dasm_shared->req_mutex) - { - DASM_RequestNode *req_n = push_array(dasm_shared->req_arena, DASM_RequestNode, 1); - SLLQueuePush(dasm_shared->first_req, dasm_shared->last_req, req_n); - dasm_shared->req_count += 1; - req_n->v.root = node->root; - req_n->v.hash = hash; - MemoryCopyStruct(&req_n->v.params, params); - req_n->v.params.dbgi_key = di_key_copy(dasm_shared->req_arena, &req_n->v.params.dbgi_key); - } - cond_var_broadcast(async_tick_start_cond_var); - } - - // rjf: nonzero node, request if needed - touch & return results - if(node != 0) - { - access_touch(access, &node->access_pt, stripe->cv); - MemoryCopyStruct(&info, &node->info); - } - } - if(found) - { - break; - } - } - } - return info; -#endif } internal DASM_Info diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index e00f4cf6..15472faa 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -171,91 +171,6 @@ struct DASM_Info DASM_LineArray lines; }; -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct DASM_Node DASM_Node; -struct DASM_Node -{ - // rjf: links - DASM_Node *next; - DASM_Node *prev; - - // rjf: key - U128 hash; - DASM_Params params; - - // rjf: root - C_Root root; - - // rjf: generations - U64 change_gen; - - // rjf: value - Arena *info_arena; - DASM_Info info; - - // rjf: metadata - AccessPt access_pt; - U64 working_count; - U64 last_time_requested_us; - U64 last_user_clock_idx_requested; -}; - -typedef struct DASM_Slot DASM_Slot; -struct DASM_Slot -{ - DASM_Node *first; - DASM_Node *last; -}; - -typedef struct DASM_Stripe DASM_Stripe; -struct DASM_Stripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; - DASM_Node *free_node; -}; - -//////////////////////////////// -//~ rjf: Thread Context - -typedef struct DASM_TCTX DASM_TCTX; -struct DASM_TCTX -{ - Arena *arena; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct DASM_Shared DASM_Shared; -struct DASM_Shared -{ - Arena *arena; - - // rjf: cache - U64 slots_count; - U64 stripes_count; - DASM_Slot *slots; - DASM_Stripe *stripes; - - // rjf: requests - Mutex req_mutex; - Arena *req_arena; - DASM_RequestNode *first_req; - DASM_RequestNode *last_req; - U64 req_count; - U64 lane_req_take_counter; -}; - -//////////////////////////////// -//~ rjf: Globals - -thread_static DASM_TCTX *dasm_tctx = 0; -global DASM_Shared *dasm_shared = 0; - //////////////////////////////// //~ rjf: Instruction Decoding/Disassembling Type Functions @@ -279,22 +194,11 @@ internal DASM_LineArray dasm_line_array_from_chunk_list(Arena *arena, DASM_LineC internal U64 dasm_line_array_idx_from_code_off__linear_scan(DASM_LineArray *array, U64 off); internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void dasm_init(void); - -//////////////////////////////// -//~ rjf: Ticks - -internal void dasm_tick(void); - //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups internal void *dasm_artifact_create(String8 key, B32 *retry_out); internal void dasm_artifact_destroy(void *ptr); - internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); From 408c57639af80c7edb65a28824bafab761a88347 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 16:23:11 -0700 Subject: [PATCH 240/302] eliminate dasm cache hook calls --- src/base/base_entry_point.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 40b60d09..1b7b2f88 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -68,9 +68,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL) mtx_init(); #endif -#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) - dasm_init(); -#endif #if defined(DBGI_H) && !defined(DI_INIT_MANUAL) di_init(); #endif @@ -209,9 +206,6 @@ async_thread_entry_point(void *params) #if defined(FILE_STREAM_H) fs_tick(); #endif -#if defined(DASM_CACHE_H) - dasm_tick(); -#endif #if defined(TEXTURE_CACHE_H) tex_tick(); #endif From 8078b90f518c8245c2601e0ea587ee794540619b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 16:52:55 -0700 Subject: [PATCH 241/302] text_cache / dasm_cache -> text / disasm --- src/{dasm_cache/dasm_cache.c => disasm/disasm.c} | 0 src/{dasm_cache/dasm_cache.h => disasm/disasm.h} | 6 +++--- src/raddbg/raddbg_main.c | 8 ++++---- src/{text_cache/text_cache.c => text/text.c} | 0 src/{text_cache/text_cache.h => text/text.h} | 6 +++--- src/texture_cache/texture_cache.c | 15 +++++++++++++++ src/texture_cache/texture_cache.h | 6 ++++++ 7 files changed, 31 insertions(+), 10 deletions(-) rename src/{dasm_cache/dasm_cache.c => disasm/disasm.c} (100%) rename src/{dasm_cache/dasm_cache.h => disasm/disasm.h} (94%) rename src/{text_cache/text_cache.c => text/text.c} (100%) rename src/{text_cache/text_cache.h => text/text.h} (95%) diff --git a/src/dasm_cache/dasm_cache.c b/src/disasm/disasm.c similarity index 100% rename from src/dasm_cache/dasm_cache.c rename to src/disasm/disasm.c diff --git a/src/dasm_cache/dasm_cache.h b/src/disasm/disasm.h similarity index 94% rename from src/dasm_cache/dasm_cache.h rename to src/disasm/disasm.h index 15472faa..b1acf658 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/disasm/disasm.h @@ -1,8 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef DASM_CACHE_H -#define DASM_CACHE_H +#ifndef DISASM_H +#define DISASM_H //////////////////////////////// //~ rjf: Disassembly Syntax Types @@ -202,4 +202,4 @@ internal void dasm_artifact_destroy(void *ptr); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); -#endif // DASM_CACHE_H +#endif // DISASM_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 9f502c45..33939e69 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -228,7 +228,7 @@ #include "mdesk/mdesk.h" #include "content/content.h" #include "file_stream/file_stream.h" -#include "text_cache/text_cache.h" +#include "text/text.h" #include "mutable_text/mutable_text.h" #include "coff/coff.h" #include "coff/coff_parse.h" @@ -251,7 +251,7 @@ #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" #include "dbgi/dbgi.h" -#include "dasm_cache/dasm_cache.h" +#include "disasm/disasm.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" #include "eval_visualization/eval_visualization_inc.h" @@ -278,7 +278,7 @@ #include "mdesk/mdesk.c" #include "content/content.c" #include "file_stream/file_stream.c" -#include "text_cache/text_cache.c" +#include "text/text.c" #include "mutable_text/mutable_text.c" #include "coff/coff.c" #include "coff/coff_parse.c" @@ -301,7 +301,7 @@ #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" #include "dbgi/dbgi.c" -#include "dasm_cache/dasm_cache.c" +#include "disasm/disasm.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" #include "eval_visualization/eval_visualization_inc.c" diff --git a/src/text_cache/text_cache.c b/src/text/text.c similarity index 100% rename from src/text_cache/text_cache.c rename to src/text/text.c diff --git a/src/text_cache/text_cache.h b/src/text/text.h similarity index 95% rename from src/text_cache/text_cache.h rename to src/text/text.h index ba687a4e..bc41db58 100644 --- a/src/text_cache/text_cache.h +++ b/src/text/text.h @@ -1,8 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef TEXT_CACHE_H -#define TEXT_CACHE_H +#ifndef TEXT_H +#define TEXT_H //////////////////////////////// //~ rjf: Value Types @@ -208,4 +208,4 @@ internal void txt_artifact_destroy(void *ptr); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); -#endif // TEXT_CACHE_H +#endif // TEXT_H diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index a5b598a2..eb111261 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -263,3 +263,18 @@ tex_tick(void) scratch_end(scratch); ProfEnd(); } + +//////////////////////////////// +//~ rjf: Artifact Cache Hooks / Lookups + +internal void * +tex_artifact_create(String8 key, B32 *retry_out) +{ + +} + +internal void +tex_artifact_destroy(void *ptr) +{ + +} diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 6eece14c..18fa5011 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -109,4 +109,10 @@ internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_T internal void tex_tick(void); +//////////////////////////////// +//~ rjf: Artifact Cache Hooks / Lookups + +internal void *tex_artifact_create(String8 key, B32 *retry_out); +internal void tex_artifact_destroy(void *ptr); + #endif // TEXTURE_CACHE_H From 5c1cf77fdab5f46e8f46987424413ddb4e77a918 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 17:32:05 -0700 Subject: [PATCH 242/302] respect subset flags in pdb -> rdi converter --- src/rdi/rdi_local.c | 2 +- src/rdi_from_pdb/rdi_from_pdb.c | 3226 ++++++++++++++++--------------- 2 files changed, 1640 insertions(+), 1588 deletions(-) diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index f30651c1..8473578c 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -1061,7 +1061,7 @@ lane_sync(); if(flags & RDI_DumpSubsetFlag_##name) ProfScope(#name) // DumpSubset(Scopes) { - dumpf("\n"); + if(lane_idx() == 0) { dumpf("\n"); } RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); U64 scope_voffs_count = 0; U64 *scope_voffs = rdi_table_from_name(rdi, ScopeVOffData, &scope_voffs_count); diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index ad32b4a6..e67b8fca 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -1046,6 +1046,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) ////////////////////////////////////////////////////////////// //- rjf: build unified collection & map for source files // + if(params->subset_flags & (RDIM_SubsetFlag_NormalSourcePathNameMap| + RDIM_SubsetFlag_LineInfo| + RDIM_SubsetFlag_InlineLineInfo)) { //- rjf: set up table ProfScope("set up table") if(lane_idx() == 0) @@ -1104,9 +1107,12 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: set up outputs ProfScope("set up outputs") if(lane_idx() == 0) { - for EachIndex(idx, comp_units->count) + if(params->subset_flags & RDIM_SubsetFlag_Units) { - rdim_unit_chunk_list_push(arena, &p2r_shared->all_units, comp_units->count); + for EachIndex(idx, comp_units->count) + { + rdim_unit_chunk_list_push(arena, &p2r_shared->all_units, comp_units->count); + } } p2r_shared->units_line_tables = push_array(arena, RDIM_LineTableChunkList, comp_units->count); p2r_shared->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, comp_units->count); @@ -1119,335 +1125,345 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) Assert(units_count == comp_units->count); //- rjf: do per-lane work - ProfScope("wide fill") for(;;) + if(params->subset_flags & (RDIM_SubsetFlag_Units| + RDIM_SubsetFlag_NormalSourcePathNameMap| + RDIM_SubsetFlag_LineInfo| + RDIM_SubsetFlag_InlineLineInfo)) { - //- rjf: take next unit - U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); - if(unit_num > comp_units->count) + ProfScope("wide fill") for(;;) { - break; - } - Temp scratch = scratch_begin(&arena, 1); - U64 unit_idx = unit_num-1; - RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; - PDB_CompUnit *src_unit = comp_units->units[unit_idx]; - CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; - CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; - RDIM_Unit *dst_unit = &units[unit_idx]; - - // rjf: extract unit name - String8 unit_name = src_unit->obj_name; - if(unit_name.size != 0) - { - String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); - if(unit_name_past_last_slash.size != 0) + //- rjf: take next unit + U64 unit_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); + if(unit_num > comp_units->count) { - unit_name = unit_name_past_last_slash; + break; } - } - - // rjf: produce obj name/path - String8 obj_name = src_unit->obj_name; - if(str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) - { - MemoryZeroStruct(&obj_name); - } - String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); - - //- rjf: main unit line table conversion - ProfScope("main unit line table conversion") - { - RDIM_LineTable *line_table = 0; - for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; - node != 0; - node = node->next) + Temp scratch = scratch_begin(&arena, 1); + U64 unit_idx = unit_num-1; + RDIM_LineTableChunkList *dst_line_tables = &units_line_tables[unit_idx]; + PDB_CompUnit *src_unit = comp_units->units[unit_idx]; + CV_SymParsed *src_unit_sym = all_syms[unit_idx+1]; + CV_C13Parsed *src_unit_c13 = all_c13s[unit_idx+1]; + RDIM_Unit *dst_unit = 0; + if(params->subset_flags & RDIM_SubsetFlag_Units) { dst_unit = &units[unit_idx]; } + + // rjf: extract unit name + String8 unit_name = src_unit->obj_name; + if(unit_name.size != 0) { - if(node->kind == CV_C13SubSectionKind_Lines) + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) { - for(CV_C13LinesParsedNode *lines_n = node->lines_first; - lines_n != 0; - lines_n = lines_n->next) + unit_name = unit_name_past_last_slash; + } + } + + // rjf: produce obj name/path + String8 obj_name = src_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = backslashed_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: main unit line table conversion + if(params->subset_flags & RDIM_SubsetFlag_LineInfo) ProfScope("main unit line table conversion") + { + RDIM_LineTable *line_table = 0; + for(CV_C13SubSectionNode *node = src_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) { - CV_C13LinesParsed *lines = &lines_n->v; - - // rjf: file name -> sanitized file path - String8 file_path = lines->file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> sanitized file path + String8 file_path = lines->file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - if(lines->line_count != 0) - { - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) { - src_file_node = n; - break; + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + if(lines->line_count != 0) + { + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } } } - } - - // rjf: push sequence into both line table & source file's line map - if(src_file_node != 0) - { - if(line_table == 0) + + // rjf: push sequence into both line table & source file's line map + if(src_file_node != 0) { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } - RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); } } } + + // rjf: fill unit + if(dst_unit != 0) + { + dst_unit->unit_name = unit_name; + dst_unit->compiler_name = src_unit_sym->info.compiler_name; + dst_unit->object_file = obj_name; + dst_unit->archive_file = src_unit->group_name; + dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); + dst_unit->line_table = line_table; + dst_unit->voff_ranges = unit_ranges[unit_idx]; + } + } + + //- rjf: build per-inline-site line tables + if(params->subset_flags & RDIM_SubsetFlag_InlineLineInfo) ProfScope("build per-inline-site line tables") + { + CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; + void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + typedef struct LineChunk LineChunk; + struct LineChunk + { + LineChunk *next; + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + }; + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + // rjf: step & update + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && total_line_chunk_line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + + // rjf: file updated -> push line chunks gathered for this file + if(last_file_off != max_U32 && last_file_off != curr_file_off) + { + String8 seq_file_name = {0}; + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); + } + + // rjf: file name -> sanitized file path + String8 file_path = seq_file_name; + String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); + { + PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); + String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); + if(file_path_sanitized_style == PathStyle_Relative) + { + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); + file_path_sanitized_parts = obj_folder_path_parts; + file_path_sanitized_style = path_style_from_str8(obj_folder_path); + } + str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); + file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); + } + + // rjf: sanitized file path -> source file node + U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); + U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->path, file_path_sanitized, 0)) + { + src_file_node = n; + break; + } + } + + // rjf: gather all lines + RDI_U64 *voffs = 0; + RDI_U32 *line_nums = 0; + RDI_U64 line_count = 0; + if(src_file_node != 0) + { + voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + line_count = total_line_chunk_line_count; + U64 dst_idx = 0; + for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) + { + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); + MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); + dst_idx += chunk->count; + } + } + + // rjf: push + if(line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); + if(p2r_shared->units_first_inline_site_line_tables[unit_idx] == 0) + { + p2r_shared->units_first_inline_site_line_tables[unit_idx] = line_table; + } + } + rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + } + + // rjf: clear line chunks for subsequent sequences + first_line_chunk = last_line_chunk = 0; + total_line_chunk_line_count = 0; + } + + // rjf: new line -> emit to chunk + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 8; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + // rjf: no more flags -> done + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } } - // rjf: fill unit - dst_unit->unit_name = unit_name; - dst_unit->compiler_name = src_unit_sym->info.compiler_name; - dst_unit->object_file = obj_name; - dst_unit->archive_file = src_unit->group_name; - dst_unit->language = p2r_rdi_language_from_cv_language(src_unit_sym->info.language); - dst_unit->line_table = line_table; - dst_unit->voff_ranges = unit_ranges[unit_idx]; + scratch_end(scratch); } - - //- rjf: build per-inline-site line tables - ProfScope("build per-inline-site line tables") - { - CV_RecRange *rec_ranges_first = src_unit_sym->sym_ranges.ranges; - CV_RecRange *rec_ranges_opl = src_unit_sym->sym_ranges.ranges + src_unit_sym->sym_ranges.count; - U64 base_voff = 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > src_unit_sym->data.size || sym_off_first > src_unit_sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = src_unit_sym->data.str + sym_off_first; - void *sym_data_opl = src_unit_sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: process symbol - switch(kind) - { - default:{}break; - - //- rjf: LPROC32/GPROC32 (gather base address) - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - base_voff = section->voff + proc32->off; - } - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: map inlinee -> parsed cv c13 inlinee line info - CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; - { - U64 hash = cv_hash_from_item_id(sym->inlinee); - U64 slot_idx = hash%src_unit_c13->inlinee_lines_parsed_slots_count; - for(CV_C13InlineeLinesParsedNode *n = src_unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->v.inlinee == sym->inlinee) - { - inlinee_lines_parsed = &n->v; - break; - } - } - } - - // rjf: build line table, fill with parsed binary annotations - if(inlinee_lines_parsed != 0) - { - // rjf: grab checksums sub-section - CV_C13SubSectionNode *file_chksms = src_unit_c13->file_chksms_sub_section; - - // rjf: gathered lines - typedef struct LineChunk LineChunk; - struct LineChunk - { - LineChunk *next; - U64 cap; - U64 count; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - }; - LineChunk *first_line_chunk = 0; - LineChunk *last_line_chunk = 0; - U64 total_line_chunk_line_count = 0; - U32 last_file_off = max_U32; - U32 curr_file_off = max_U32; - RDIM_LineTable* line_table = 0; - - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); - for(;;) - { - // rjf: step & update - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) - { - last_file_off = curr_file_off; - curr_file_off = step.file_off; - } - if(step.flags == 0 && total_line_chunk_line_count > 0) - { - last_file_off = curr_file_off; - curr_file_off = max_U32; - } - - // rjf: file updated -> push line chunks gathered for this file - if(last_file_off != max_U32 && last_file_off != curr_file_off) - { - String8 seq_file_name = {0}; - if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) - { - CV_C13Checksum *checksum = (CV_C13Checksum*)(src_unit_c13->data.str + file_chksms->off + last_file_off); - U32 name_off = checksum->name_off; - seq_file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // rjf: file name -> sanitized file path - String8 file_path = seq_file_name; - String8 file_path_sanitized = str8_copy(scratch.arena, str8_skip_chop_whitespace(file_path)); - { - PathStyle file_path_sanitized_style = path_style_from_str8(file_path_sanitized); - String8List file_path_sanitized_parts = str8_split_path(scratch.arena, file_path_sanitized); - if(file_path_sanitized_style == PathStyle_Relative) - { - String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); - str8_list_concat_in_place(&obj_folder_path_parts, &file_path_sanitized_parts); - file_path_sanitized_parts = obj_folder_path_parts; - file_path_sanitized_style = path_style_from_str8(obj_folder_path); - } - str8_path_list_resolve_dots_in_place(&file_path_sanitized_parts, file_path_sanitized_style); - file_path_sanitized = str8_path_list_join_by_style(scratch.arena, &file_path_sanitized_parts, file_path_sanitized_style); - } - - // rjf: sanitized file path -> source file node - U64 file_path_sanitized_hash = rdi_hash(file_path_sanitized.str, file_path_sanitized.size); - U64 src_file_slot = file_path_sanitized_hash%src_file_map.slots_count; - P2R_SrcFileNode *src_file_node = 0; - for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) - { - if(str8_match(n->src_file->path, file_path_sanitized, 0)) - { - src_file_node = n; - break; - } - } - - // rjf: gather all lines - RDI_U64 *voffs = 0; - RDI_U32 *line_nums = 0; - RDI_U64 line_count = 0; - if(src_file_node != 0) - { - voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); - line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); - line_count = total_line_chunk_line_count; - U64 dst_idx = 0; - for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) - { - MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); - MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); - dst_idx += chunk->count; - } - } - - // rjf: push - if(line_count != 0) - { - if(line_table == 0) - { - line_table = rdim_line_table_chunk_list_push(arena, dst_line_tables, 256); - if(p2r_shared->units_first_inline_site_line_tables[unit_idx] == 0) - { - p2r_shared->units_first_inline_site_line_tables[unit_idx] = line_table; - } - } - rdim_line_table_push_sequence(arena, dst_line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); - } - - // rjf: clear line chunks for subsequent sequences - first_line_chunk = last_line_chunk = 0; - total_line_chunk_line_count = 0; - } - - // rjf: new line -> emit to chunk - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) - { - LineChunk *chunk = last_line_chunk; - if(chunk == 0 || chunk->count+1 >= chunk->cap) - { - chunk = push_array(scratch.arena, LineChunk, 1); - SLLQueuePush(first_line_chunk, last_line_chunk, chunk); - chunk->cap = 8; - chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); - chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); - } - chunk->voffs[chunk->count] = step.line_voff; - chunk->voffs[chunk->count+1] = step.line_voff_end; - chunk->line_nums[chunk->count] = step.ln; - chunk->count += 1; - total_line_chunk_line_count += 1; - } - - // rjf: no more flags -> done - if(step.flags == 0) - { - break; - } - } - } - }break; - } - } - } - - scratch_end(scratch); } } lane_sync(); @@ -1511,6 +1527,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) lane_sync(); //- rjf: do wide fill + if(params->subset_flags & RDIM_SubsetFlag_Types) { Rng1U64 range = lane_range(p2r_shared->itype_opl); for EachInRange(idx, range) @@ -1658,6 +1675,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) lane_sync(); //- rjf: do wide fill + if(params->subset_flags & RDIM_SubsetFlag_Types) { Rng1U64 range = lane_range(p2r_shared->itype_opl); for EachInRange(idx, range) @@ -1974,6 +1992,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: build basic types // + if(params->subset_flags & RDIM_SubsetFlag_Types) { for(RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; @@ -1990,6 +2009,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: build basic type aliases // + if(params->subset_flags & RDIM_SubsetFlag_Types) { RDIM_DataModel data_model = rdim_data_model_from_os_arch(OperatingSystem_Windows, arch); RDI_TypeKind short_type = rdim_short_type_kind_from_data_model(data_model); @@ -2065,432 +2085,435 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: build types from TPI // - for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) + if(params->subset_flags & RDIM_SubsetFlag_Types) { - for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; - itype_chain != 0; - itype_chain = itype_chain->next) + for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) { - CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; - B32 itype_is_basic = (itype < tpi->itype_first); - - ////////////////////////// - //- rjf: skip forward-reference itypes - all future resolutions will - // reference whatever this itype resolves to, and so there is no point - // in filling out this slot - // - if(itype_fwd_map[root_itype] != 0) + for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; + itype_chain != 0; + itype_chain = itype_chain->next) { - continue; - } - - ////////////////////////// - //- rjf: skip already produced dependencies - // - if(itype_type_ptrs[itype] != 0) - { - continue; - } - - ////////////////////////// - //- rjf: build basic type - // - if(itype_is_basic) - { - RDIM_Type *dst_type = 0; + CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; + B32 itype_is_basic = (itype < tpi->itype_first); - // rjf: unpack itype - CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); - CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); - - // rjf: get basic type slot, fill if unfilled - RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; - if(basic_type == 0) + ////////////////////////// + //- rjf: skip forward-reference itypes - all future resolutions will + // reference whatever this itype resolves to, and so there is no point + // in filling out this slot + // + if(itype_fwd_map[root_itype] != 0) { - RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); - U32 byte_size = rdi_size_from_basic_type_kind(type_kind); - basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(byte_size == 0xffffffff) + continue; + } + + ////////////////////////// + //- rjf: skip already produced dependencies + // + if(itype_type_ptrs[itype] != 0) + { + continue; + } + + ////////////////////////// + //- rjf: build basic type + // + if(itype_is_basic) + { + RDIM_Type *dst_type = 0; + + // rjf: unpack itype + CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); + CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); + + // rjf: get basic type slot, fill if unfilled + RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; + if(basic_type == 0) { - byte_size = arch_addr_size; + RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); + U32 byte_size = rdi_size_from_basic_type_kind(type_kind); + basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(byte_size == 0xffffffff) + { + byte_size = arch_addr_size; + } + basic_type->kind = type_kind; + basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); + basic_type->byte_size = byte_size; } - basic_type->kind = type_kind; - basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); - basic_type->byte_size = byte_size; - } - - // rjf: nonzero ptr kind -> form ptr type to basic tpye - if(cv_basic_ptr_kind != 0) - { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Ptr; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = basic_type; - } - - // rjf: fill this itype's slot with the finished type - itype_type_ptrs[itype] = dst_type; - } - - ////////////////////////// - //- rjf: build non-basic type - // - if(!itype_is_basic && itype >= itype_first) - { - RDIM_Type *dst_type = 0; - CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-itype_first]; - CV_LeafKind kind = range->hdr.kind; - U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); - if(range->off+range->hdr.size <= tpi_leaf->data.size && - range->off+2+header_struct_size <= tpi_leaf->data.size && - range->hdr.size >= 2) - { - U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; - U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; - switch(kind) + + // rjf: nonzero ptr kind -> form ptr type to basic tpye + if(cv_basic_ptr_kind != 0) { - //- rjf: MODIFIER - case CV_LeafKind_MODIFIER: + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Ptr; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = basic_type; + } + + // rjf: fill this itype's slot with the finished type + itype_type_ptrs[itype] = dst_type; + } + + ////////////////////////// + //- rjf: build non-basic type + // + if(!itype_is_basic && itype >= itype_first) + { + RDIM_Type *dst_type = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) { - // rjf: unpack leaf - CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; - - // rjf: cv -> rdi flags - RDI_TypeModifierFlags flags = 0; - if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} - if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} - - // rjf: fill type - if(flags == 0) + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: { - dst_type = p2r_type_ptr_from_itype(lf->itype); - } - else + // rjf: unpack leaf + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: cv -> rdi flags + RDI_TypeModifierFlags flags = 0; + if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} + if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} + + // rjf: fill type + if(flags == 0) + { + dst_type = p2r_type_ptr_from_itype(lf->itype); + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = flags; + dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); + dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: { + // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead + + // rjf: unpack leaf + CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); + + // rjf: cv -> rdi modifier flags + RDI_TypeModifierFlags modifier_flags = 0; + if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} + if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} + if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} + + // rjf: cv info -> rdi pointer type kind + RDI_TypeKind type_kind = RDI_TypeKind_Ptr; + { + if(lf->attribs & CV_PointerAttrib_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(lf->attribs & CV_PointerAttrib_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + if(ptr_mode == CV_PointerMode_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(ptr_mode == CV_PointerMode_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + } + + // rjf: fill type + if(modifier_flags != 0) + { + RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = modifier_flags; + dst_type->direct_type = pointer_type; + dst_type->byte_size = arch_addr_size; + pointer_type->kind = type_kind; + pointer_type->byte_size = arch_addr_size; + pointer_type->direct_type = direct_type; + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = type_kind; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = direct_type; + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + // TODO(rjf): handle call_kind & attribs + + // rjf: unpack leaf + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type's basics dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = flags; - dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); - dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; - } - }break; - - //- rjf: POINTER - case CV_LeafKind_POINTER: - { - // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead - - // rjf: unpack leaf - CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); - U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); - - // rjf: cv -> rdi modifier flags - RDI_TypeModifierFlags modifier_flags = 0; - if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} - if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} - if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} - - // rjf: cv info -> rdi pointer type kind - RDI_TypeKind type_kind = RDI_TypeKind_Ptr; - { - if(lf->attribs & CV_PointerAttrib_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(lf->attribs & CV_PointerAttrib_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - if(ptr_mode == CV_PointerMode_LRef) - { - type_kind = RDI_TypeKind_LRef; - } - else if(ptr_mode == CV_PointerMode_RRef) - { - type_kind = RDI_TypeKind_RRef; - } - } - - // rjf: fill type - if(modifier_flags != 0) - { - RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Modifier; - dst_type->flags = modifier_flags; - dst_type->direct_type = pointer_type; - dst_type->byte_size = arch_addr_size; - pointer_type->kind = type_kind; - pointer_type->byte_size = arch_addr_size; - pointer_type->direct_type = direct_type; - } - else - { - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = type_kind; + dst_type->kind = RDI_TypeKind_Function; dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count; + dst_type->param_types = params; + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + // TODO(rjf): handle call_kind & attribs + // TODO(rjf): preserve "this_adjust" + + // rjf: unpack leaf + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + U64 num_this_extras = 1; + if(lf->this_itype == 0) + { + num_this_extras = 0; + } + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + if(lf->this_itype != 0) + { + params[0] = p2r_type_ptr_from_itype(lf->this_itype); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count+num_this_extras; + dst_type->param_types = params; + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + // rjf: unpack leaf + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Bitfield; + dst_type->off = lf->pos; + dst_type->count = lf->len; + dst_type->byte_size = direct_type?direct_type->byte_size:0; dst_type->direct_type = direct_type; - } - }break; - - //- rjf: PROCEDURE - case CV_LeafKind_PROCEDURE: - { - // TODO(rjf): handle call_kind & attribs + }break; - // rjf: unpack leaf - CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type's basics - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + //- rjf: ARRAY + case CV_LeafKind_ARRAY: { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: build param type array - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count); - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - params[idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_count; - dst_type->param_types = params; - }break; - - //- rjf: MFUNCTION - case CV_LeafKind_MFUNCTION: - { - // TODO(rjf): handle call_kind & attribs - // TODO(rjf): preserve "this_adjust" - - // rjf: unpack leaf - CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; - RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; - dst_type->byte_size = arch_addr_size; - dst_type->direct_type = ret_type; - - // rjf: unpack arglist range - CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-itype_first]; - if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || - arglist_range->hdr.size<2 || - arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) - { - break; - } - U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; - U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; - if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) - { - break; - } - - // rjf: unpack arglist info - CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; - CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); - U32 arglist_itypes_count = arglist->count; - - // rjf: build param type array - U64 num_this_extras = 1; - if(lf->this_itype == 0) - { - num_this_extras = 0; - } - RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); - for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) - { - params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); - } - if(lf->this_itype != 0) - { - params[0] = p2r_type_ptr_from_itype(lf->this_itype); - } - - // rjf: fill dst type - dst_type->count = arglist_itypes_count+num_this_extras; - dst_type->param_types = params; - }break; - - //- rjf: BITFIELD - case CV_LeafKind_BITFIELD: - { - // rjf: unpack leaf - CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Bitfield; - dst_type->off = lf->pos; - dst_type->count = lf->len; - dst_type->byte_size = direct_type?direct_type->byte_size:0; - dst_type->direct_type = direct_type; - }break; - - //- rjf: ARRAY - case CV_LeafKind_ARRAY: - { - // rjf: unpack leaf - CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 full_size = cv_u64_from_numeric(&array_count); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - dst_type->kind = RDI_TypeKind_Array; - dst_type->direct_type = direct_type; - dst_type->byte_size = full_size; - dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; - }break; - - //- rjf: CLASS/STRUCTURE - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: CLASS2/STRUCT2 - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); - dst_type->name = name; - } - else - { - dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: UNION - case CV_LeafKind_UNION: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; - U8 *numeric_ptr = (U8*)(lf + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); - U64 size_u64 = cv_u64_from_numeric(&size); - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteUnion; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Union; - dst_type->byte_size = (U32)size_u64; - dst_type->name = name; - } - }break; - - //- rjf: ENUM - case CV_LeafKind_ENUM: - { - // TODO(rjf): handle props - - // rjf: unpack leaf - CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; - RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); - U8 *name_ptr = (U8 *)(lf + 1); - String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); - - // rjf: fill type - dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); - if(lf->props & CV_TypeProp_FwdRef) - { - dst_type->kind = RDI_TypeKind_IncompleteEnum; - dst_type->name = name; - } - else - { - dst_type->kind = RDI_TypeKind_Enum; + // rjf: unpack leaf + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 full_size = cv_u64_from_numeric(&array_count); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Array; dst_type->direct_type = direct_type; - dst_type->byte_size = direct_type ? direct_type->byte_size : 0; - dst_type->name = name; - } - }break; + dst_type->byte_size = full_size; + dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; + }break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteUnion; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Union; + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); + U8 *name_ptr = (U8 *)(lf + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteEnum; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Enum; + dst_type->direct_type = direct_type; + dst_type->byte_size = direct_type ? direct_type->byte_size : 0; + dst_type->name = name; + } + }break; + } } + + //- rjf: store finalized type to this itype's slot + itype_type_ptrs[itype] = dst_type; } - - //- rjf: store finalized type to this itype's slot - itype_type_ptrs[itype] = dst_type; } } } @@ -2520,6 +2543,8 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) lane_sync(); //- rjf: do wide fill + if(params->subset_flags & RDIM_SubsetFlag_Types && + params->subset_flags & RDIM_SubsetFlag_UDTs) { U64 udts_chunk_cap = 4096; RDIM_UDTChunkList *udts = &p2r_shared->lanes_udts[lane_idx()]; @@ -3187,172 +3212,837 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //////////////////////////// //- rjf: fill outputs for all unit sym blocks in this lane // - for(;;) + if(params->subset_flags & (RDIM_SubsetFlag_Procedures| + RDIM_SubsetFlag_GlobalVariables| + RDIM_SubsetFlag_ThreadVariables| + RDIM_SubsetFlag_Scopes| + RDIM_SubsetFlag_Locals| + RDIM_SubsetFlag_GlobalVariableNameMap| + RDIM_SubsetFlag_ThreadVariableNameMap| + RDIM_SubsetFlag_ProcedureNameMap| + RDIM_SubsetFlag_ConstantNameMap| + RDIM_SubsetFlag_LinkNameProcedureNameMap| + RDIM_SubsetFlag_Types)) { - //- rjf: take next sym - U64 sym_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); - if(sym_num > all_syms_count) + for(;;) { - break; - } - U64 sym_idx = sym_num-1; - - //- rjf: unpack sym - Temp scratch = scratch_begin(&arena, 1); - CV_SymParsed *sym = all_syms[sym_idx]; - Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); - U64 sym_locations_chunk_cap = 16384; - U64 sym_procedures_chunk_cap = 16384; - U64 sym_global_variables_chunk_cap = 16384; - U64 sym_thread_variables_chunk_cap = 16384; - U64 sym_constants_chunk_cap = 16384; - U64 sym_scopes_chunk_cap = 16384; - U64 sym_inline_sites_chunk_cap = 16384; - RDIM_LocationChunkList *sym_locations = &p2r_shared->syms_locations[sym_idx]; - RDIM_SymbolChunkList *sym_procedures = &p2r_shared->syms_procedures[sym_idx]; - RDIM_SymbolChunkList *sym_global_variables = &p2r_shared->syms_global_variables[sym_idx]; - RDIM_SymbolChunkList *sym_thread_variables = &p2r_shared->syms_thread_variables[sym_idx]; - RDIM_SymbolChunkList *sym_constants = &p2r_shared->syms_constants[sym_idx]; - RDIM_ScopeChunkList *sym_scopes = &p2r_shared->syms_scopes[sym_idx]; - RDIM_InlineSiteChunkList *sym_inline_sites = &p2r_shared->syms_inline_sites[sym_idx]; - RDIM_TypeChunkList *typedefs = &p2r_shared->syms_typedefs[sym_idx]; - - ////////////////////////// - //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) - // - U64 procedure_frameprocs_count = 0; - U64 procedure_frameprocs_cap = dim_1u64(sym_rec_range); - CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); - ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") - { - U64 procedure_num = 0; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) + //- rjf: take next sym + U64 sym_num = ins_atomic_u64_inc_eval(&p2r_shared->sym_lane_take_counter); + if(sym_num > all_syms_count) { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) - { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; - - //- rjf: FRAMEPROC - case CV_SymKind_FRAMEPROC: - { - if(procedure_num == 0) { break; } - if(procedure_num > procedure_frameprocs_cap) { break; } - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; - procedure_frameprocs[procedure_num-1] = frameproc; - procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - procedure_num += 1; - }break; - } + break; } - U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); - arena_pop(scratch.arena, scratch_overkill); - } - - ////////////////////////// - //- rjf: symbols pass 2: construct all symbols, given procedure frame info map - // - ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") - { - RDIM_Local *defrange_target = 0; - B32 defrange_target_is_param = 0; - U64 procedure_num = 0; - U64 procedure_base_voff = 0; - CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; - CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; - typedef struct P2R_ScopeNode P2R_ScopeNode; - struct P2R_ScopeNode + U64 sym_idx = sym_num-1; + + //- rjf: unpack sym + Temp scratch = scratch_begin(&arena, 1); + CV_SymParsed *sym = all_syms[sym_idx]; + Rng1U64 sym_rec_range = r1u64(0, sym->sym_ranges.count); + U64 sym_locations_chunk_cap = 16384; + U64 sym_procedures_chunk_cap = 16384; + U64 sym_global_variables_chunk_cap = 16384; + U64 sym_thread_variables_chunk_cap = 16384; + U64 sym_constants_chunk_cap = 16384; + U64 sym_scopes_chunk_cap = 16384; + U64 sym_inline_sites_chunk_cap = 16384; + RDIM_LocationChunkList *sym_locations = &p2r_shared->syms_locations[sym_idx]; + RDIM_SymbolChunkList *sym_procedures = &p2r_shared->syms_procedures[sym_idx]; + RDIM_SymbolChunkList *sym_global_variables = &p2r_shared->syms_global_variables[sym_idx]; + RDIM_SymbolChunkList *sym_thread_variables = &p2r_shared->syms_thread_variables[sym_idx]; + RDIM_SymbolChunkList *sym_constants = &p2r_shared->syms_constants[sym_idx]; + RDIM_ScopeChunkList *sym_scopes = &p2r_shared->syms_scopes[sym_idx]; + RDIM_InlineSiteChunkList *sym_inline_sites = &p2r_shared->syms_inline_sites[sym_idx]; + RDIM_TypeChunkList *typedefs = &p2r_shared->syms_typedefs[sym_idx]; + + ////////////////////////// + //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) + // + U64 procedure_frameprocs_count = 0; + U64 procedure_frameprocs_cap = dim_1u64(sym_rec_range); + CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); + ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") { - P2R_ScopeNode *next; - RDIM_Scope *scope; - }; - P2R_ScopeNode *top_scope_node = 0; - P2R_ScopeNode *free_scope_node = 0; - RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; - for(CV_RecRange *rec_range = rec_ranges_first; - rec_range < rec_ranges_opl; - rec_range += 1) - { - //- rjf: rec range -> symbol info range - U64 sym_off_first = rec_range->off + 2; - U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - - //- rjf: skip invalid ranges - if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + U64 procedure_num = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) { - continue; - } - - //- rjf: unpack symbol info - CV_SymKind kind = rec_range->hdr.kind; - U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); - void *sym_header_struct_base = sym->data.str + sym_off_first; - void *sym_data_opl = sym->data.str + sym_off_opl; - - //- rjf: skip bad sizes - if(sym_off_first + sym_header_struct_size > sym_off_opl) - { - continue; - } - - //- rjf: consume symbol based on kind - switch(kind) - { - default:{}break; + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; - //- rjf: END - case CV_SymKind_END: + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target_is_param = 0; - }break; + continue; + } - //- rjf: BLOCK32 - case CV_SymKind_BLOCK32: + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) { - // rjf: unpack sym - CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; - // rjf: build scope, insert into current parent scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + //- rjf: FRAMEPROC + case CV_SymKind_FRAMEPROC: { + if(procedure_num == 0) { break; } + if(procedure_num > procedure_frameprocs_cap) { break; } + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; + procedure_frameprocs[procedure_num-1] = frameproc; + procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + procedure_num += 1; + }break; + } + } + U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); + arena_pop(scratch.arena, scratch_overkill); + } + + ////////////////////////// + //- rjf: symbols pass 2: construct all symbols, given procedure frame info map + // + ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") + { + RDIM_Local *defrange_target = 0; + B32 defrange_target_is_param = 0; + U64 procedure_num = 0; + U64 procedure_base_voff = 0; + CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges + sym_rec_range.min; + CV_RecRange *rec_ranges_opl = sym->sym_ranges.ranges + sym_rec_range.max; + typedef struct P2R_ScopeNode P2R_ScopeNode; + struct P2R_ScopeNode + { + P2R_ScopeNode *next; + RDIM_Scope *scope; + }; + P2R_ScopeNode *top_scope_node = 0; + P2R_ScopeNode *free_scope_node = 0; + RDIM_LineTable *inline_site_line_table = sym_idx > 0 ? units_first_inline_site_line_tables[sym_idx-1] : 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > sym->data.size || sym_off_first > sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = sym->data.str + sym_off_first; + void *sym_data_opl = sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: END + case CV_SymKind_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: BLOCK32 + case CV_SymKind_BLOCK32: + { + // rjf: unpack sym + CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; + + // rjf: build scope, insert into current parent scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + { + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + block32->off; + U64 voff_last = voff_first + block32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); + } + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + }break; + + //- rjf: LDATA32/GDATA32 + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + // rjf: unpack sym + CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(data32+1, sym_data_opl); + COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; + U64 voff = (section ? section->voff : 0) + data32->off; + + // rjf: determine if this is an exact duplicate global + // + // PDB likes to have duplicates of these spread across different + // symbol streams so we deduplicate across the entire translation + // context. + // + B32 is_duplicate = 0; + { + // TODO(rjf): @important global symbol dedup + } + + // rjf: is not duplicate -> push new global + if(!is_duplicate) + { + // rjf: unpack global variable's type + RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); + + // rjf: unpack global's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack global's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); + symbol->is_extern = (kind == CV_SymKind_GDATA32); + symbol->name = name; + symbol->type = type; + symbol->offset = voff; + symbol->container_symbol = container_symbol; + symbol->container_type = container_type; + } + }break; + + //- rjf: UDT (typedefs) + case CV_SymKind_UDT: + if(sym == all_syms[0] && top_scope_node == 0) + { + if(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs|RDIM_SubsetFlag_TypeNameMap)) + { + CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; + String8 name = str8_cstring_capped(udt+1, sym_data_opl); + RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); + type->kind = RDI_TypeKind_Alias; + type->name = name; + type->direct_type = p2r_type_ptr_from_itype(udt->itype); + if(type->direct_type != 0) + { + type->byte_size = type->direct_type->byte_size; + } + } + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + // rjf: unpack sym + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(proc32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); + + // rjf: unpack proc's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2 && tpi_hash != 0 && tpi_leaf != 0) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack proc's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build procedure's root scope + // + // NOTE: even if there could be a containing scope at this point (which should be + // illegal in C/C++ but not necessarily in another language) we would not use + // it here because these scopes refer to the ranges of code that make up a + // procedure *not* the namespaces, so a procedure's root scope always has + // no parent. + RDIM_Scope *procedure_root_scope = 0; + if(params->subset_flags & RDIM_SubsetFlag_Scopes) + { + procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + proc32->off; + U64 voff_last = voff_first + proc32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); + procedure_base_voff = voff_first; + } + } + + // rjf: root scope voff minimum range -> link name + String8 link_name = {0}; + if(procedure_root_scope && procedure_root_scope->voff_ranges.min != 0) + { + U64 voff = procedure_root_scope->voff_ranges.min; + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%link_name_map.buckets_count; + P2R_LinkNameNode *node = 0; + for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) + { + if(n->voff == voff) + { + link_name = n->name; + break; + } + } + } + + // rjf: build procedure symbol + if(params->subset_flags & (RDIM_SubsetFlag_Procedures|RDIM_SubsetFlag_ProcedureNameMap)) + { + RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); + procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); + procedure_symbol->name = name; + procedure_symbol->link_name = link_name; + procedure_symbol->type = type; + procedure_symbol->container_symbol = container_symbol; + procedure_symbol->container_type = container_type; + procedure_symbol->root_scope = procedure_root_scope; + if(procedure_root_scope != 0) + { + procedure_root_scope->symbol = procedure_symbol; + } + } + + // rjf: push scope to scope stack + if(procedure_root_scope) + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = procedure_root_scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: increment procedure counter + procedure_num += 1; + }break; + + //- rjf: REGREL32 + case CV_SymKind_REGREL32: + if(params->subset_flags & RDIM_SubsetFlag_Locals) + { + // TODO(rjf): apparently some of the information here may end up being + // redundant with "better" information from CV_SymKind_LOCAL record. + // we don't currently handle this, but if those cases arise then it + // will obviously be better to prefer the better information from both + // records. + + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); + CV_Reg cv_reg = regrel32->reg; + U32 var_off = regrel32->reg_off; + + // rjf: determine if this is a parameter + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + { + B32 is_stack_reg = 0; + switch(arch) + { + default:{}break; + case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; + case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + } + if(is_stack_reg) + { + U32 frame_size = 0xFFFFFFFF; + if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) + { + CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; + frame_size = frameproc->frame_size; + } + if(var_off > frame_size) + { + local_kind = RDI_LocalKind_Parameter; + } + } + } + + // TODO(rjf): is this correct? + // rjf: redirect type, if 0, and if outside frame, to the return type of the + // containing procedure + if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && + top_scope_node->scope->symbol != 0 && + top_scope_node->scope->symbol->type != 0) + { + type = top_scope_node->scope->symbol->type->direct_type; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: add location info to local + if(type != 0) + { + // rjf: determine if we need an extra indirection to the value + B32 extra_indirection_to_value = 0; + switch(arch) + { + case RDI_Arch_X86: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); + }break; + case RDI_Arch_X64: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); + }break; + } + + // rjf: get raddbg register code + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + // TODO(rjf): real byte_size & byte_pos from cv_reg goes here + U32 byte_size = 8; + U32 byte_pos = 0; + + // rjf: build location + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Location *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_local_push_location_case(arena, sym_scopes, local, loc2, voff_range); + } + }break; + + //- rjf: LTHREAD32/GTHREAD32 + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + if(params->subset_flags & (RDIM_SubsetFlag_ThreadVariables|RDIM_SubsetFlag_ThreadVariableNameMap)) + { + // rjf: unpack sym + CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(thread32+1, sym_data_opl); + U32 tls_off = thread32->tls_off; + RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); + + // rjf: unpack thread variable's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack thread variable's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build symbol + RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); + tvar->name = name; + tvar->type = type; + tvar->is_extern = (kind == CV_SymKind_GTHREAD32); + tvar->offset = tls_off; + tvar->container_type = container_type; + tvar->container_symbol = container_symbol; + }break; + + //- rjf: LOCAL + case CV_SymKind_LOCAL: + if(params->subset_flags & (RDIM_SubsetFlag_Locals)) + { + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; + String8 name = str8_cstring_capped(slocal+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); + + // rjf: determine if this symbol encodes the beginning of a global modification + B32 is_global_modification = 0; + if((slocal->flags & CV_LocalFlag_Global) || + (slocal->flags & CV_LocalFlag_Static)) + { + is_global_modification = 1; + } + + // rjf: is global modification -> emit global modification symbol + if(is_global_modification) + { + // TODO(rjf): add global modification symbols + defrange_target = 0; + defrange_target_is_param = 0; + } + + // rjf: is not a global modification -> emit a local variable + if(!is_global_modification) + { + // rjf: determine local kind + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + if(slocal->flags & CV_LocalFlag_Param) + { + local_kind = RDI_LocalKind_Parameter; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: save defrange target, for subsequent defrange symbols + defrange_target = local; + defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); + } + }break; + + //- rjf: DEFRANGE_REGISTER + case CV_SymKind_DEFRANGE_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register->reg; + CV_LvarAddrRange *range = &defrange_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + + // rjf: emit locations over ranges + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; + CV_LvarAddrRange *range = &defrange_fprel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel->off; + RDIM_LocationInfo location_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); + + // rjf: emit locations over ranges + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_SUBFIELD_REGISTER + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_subfield_register->reg; + CV_LvarAddrRange *range = &defrange_subfield_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + + // rjf: skip "subfield" location info - currently not supported + if(defrange_subfield_register->field_offset != 0) + { + break; + } + + // rjf: build location + RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + + // rjf: emit locations over ranges + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel_full_scope->off; + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + + // rjf: emit location over ranges + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_local_push_location_case(arena, sym_scopes, defrange_target, loc, voff_range); + }break; + + //- rjf: DEFRANGE_REGISTER_REL + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register_rel->reg; + RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); + CV_LvarAddrRange *range = &defrange_register_rel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: build location + // TODO(rjf): offset & size from cv_reg code + U32 byte_size = rdi_addr_size_from_arch(arch); + U32 byte_pos = 0; + B32 extra_indirection_to_value = 0; + S64 var_off = defrange_register_rel->reg_off; + RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); + + // rjf: emit locations over ranges + p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); + }break; + + //- rjf: FILESTATIC + case CV_SymKind_FILESTATIC: + { + CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; + String8 name = str8_cstring_capped(file_static+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); + // TODO(rjf): emit a global modifier symbol + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + if(params->subset_flags & (RDIM_SubsetFlag_Scopes)) + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: extract external info about inline site + String8 name = str8_zero(); + RDIM_Type *type = 0; + RDIM_Type *owner = 0; + if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) + { + CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; + String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); + void *raw_leaf = rec_data.str + sizeof(U16); + + // rjf: extract method inline info + if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) + { + CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; + name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(mfunc_id->itype); + owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; + } + + // rjf: extract non-method function inline info + else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafFuncId)) + { + CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; + name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(func_id->itype); + owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; + } + } + + // rjf: build inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); + inline_site->name = name; + inline_site->type = type; + inline_site->owner = owner; + inline_site->line_table = inline_site_line_table; + + // rjf: increment to next inline site line table in this unit + if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) + { + RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; + U64 current_idx = (U64)(inline_site_line_table - chunk->v); + if(current_idx+1 < chunk->count) + { + inline_site_line_table += 1; + } + else + { + chunk = chunk->next; + inline_site_line_table = 0; + if(chunk != 0) + { + inline_site_line_table = chunk->v; + } + } + } + + // rjf: build scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); + scope->inline_site = inline_site; if(top_scope_node == 0) { // TODO(rjf): log @@ -3364,735 +4054,97 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) scope->parent_scope = top_scope; scope->symbol = top_scope->symbol; } - COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= coff_sections.count) ? &coff_sections.v[block32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + block32->off; - U64 voff_last = voff_first + block32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - }break; - - //- rjf: LDATA32/GDATA32 - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - // rjf: unpack sym - CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(data32+1, sym_data_opl); - COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= coff_sections.count) ? &coff_sections.v[data32->sec-1] : 0; - U64 voff = (section ? section->voff : 0) + data32->off; - - // rjf: determine if this is an exact duplicate global - // - // PDB likes to have duplicates of these spread across different - // symbol streams so we deduplicate across the entire translation - // context. - // - B32 is_duplicate = 0; - { - // TODO(rjf): @important global symbol dedup - } - - // rjf: is not duplicate -> push new global - if(!is_duplicate) - { - // rjf: unpack global variable's type - RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); - // rjf: unpack global's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) + // rjf: push this scope to scope stack { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); } - // rjf: unpack global's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) + // rjf: parse offset ranges of this inline site - attach to scope { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); - symbol->is_extern = (kind == CV_SymKind_GDATA32); - symbol->name = name; - symbol->type = type; - symbol->offset = voff; - symbol->container_symbol = container_symbol; - symbol->container_type = container_type; - } - }break; - - //- rjf: UDT (typedefs) - case CV_SymKind_UDT: - if(sym == all_syms[0] && top_scope_node == 0) - { - CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; - String8 name = str8_cstring_capped(udt+1, sym_data_opl); - RDIM_Type *type = rdim_type_chunk_list_push(arena, typedefs, 4096); - type->kind = RDI_TypeKind_Alias; - type->name = name; - type->direct_type = p2r_type_ptr_from_itype(udt->itype); - if(type->direct_type != 0) - { - type->byte_size = type->direct_type->byte_size; - } - }break; - - //- rjf: LPROC32/GPROC32 - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - // rjf: unpack sym - CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(proc32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); - - // rjf: unpack proc's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2 && tpi_hash != 0 && tpi_leaf != 0) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack proc's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build procedure's root scope - // - // NOTE: even if there could be a containing scope at this point (which should be - // illegal in C/C++ but not necessarily in another language) we would not use - // it here because these scopes refer to the ranges of code that make up a - // procedure *not* the namespaces, so a procedure's root scope always has - // no parent. - RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - { - COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= coff_sections.count) ? &coff_sections.v[proc32->sec-1] : 0; - if(section != 0) - { - U64 voff_first = section->voff + proc32->off; - U64 voff_last = voff_first + proc32->len; - RDIM_Rng1U64 voff_range = {voff_first, voff_last}; - rdim_scope_push_voff_range(arena, sym_scopes, procedure_root_scope, voff_range); - procedure_base_voff = voff_first; - } - } - - // rjf: root scope voff minimum range -> link name - String8 link_name = {0}; - if(procedure_root_scope->voff_ranges.min != 0) - { - U64 voff = procedure_root_scope->voff_ranges.min; - U64 hash = p2r_hash_from_voff(voff); - U64 bucket_idx = hash%link_name_map.buckets_count; - P2R_LinkNameNode *node = 0; - for(P2R_LinkNameNode *n = link_name_map.buckets[bucket_idx]; n != 0; n = n->next) - { - if(n->voff == voff) + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); + for(;;) { - link_name = n->name; - break; - } - } - } - - // rjf: build procedure symbol - RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); - procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); - procedure_symbol->name = name; - procedure_symbol->link_name = link_name; - procedure_symbol->type = type; - procedure_symbol->container_symbol = container_symbol; - procedure_symbol->container_type = container_type; - procedure_symbol->root_scope = procedure_root_scope; - - // rjf: fill root scope's symbol - procedure_root_scope->symbol = procedure_symbol; - - // rjf: push scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = procedure_root_scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: increment procedure counter - procedure_num += 1; - }break; - - //- rjf: REGREL32 - case CV_SymKind_REGREL32: - { - // TODO(rjf): apparently some of the information here may end up being - // redundant with "better" information from CV_SymKind_LOCAL record. - // we don't currently handle this, but if those cases arise then it - // will obviously be better to prefer the better information from both - // records. - - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); - CV_Reg cv_reg = regrel32->reg; - U32 var_off = regrel32->reg_off; - - // rjf: determine if this is a parameter - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - { - B32 is_stack_reg = 0; - switch(arch) - { - default:{}break; - case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; - case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; - } - if(is_stack_reg) - { - U32 frame_size = 0xFFFFFFFF; - if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) - { - CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; - frame_size = frameproc->frame_size; - } - if(var_off > frame_size) - { - local_kind = RDI_LocalKind_Parameter; - } - } - } - - // TODO(rjf): is this correct? - // rjf: redirect type, if 0, and if outside frame, to the return type of the - // containing procedure - if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && - top_scope_node->scope->symbol != 0 && - top_scope_node->scope->symbol->type != 0) - { - type = top_scope_node->scope->symbol->type->direct_type; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: add location info to local - if(type != 0) - { - // rjf: determine if we need an extra indirection to the value - B32 extra_indirection_to_value = 0; - switch(arch) - { - case RDI_Arch_X86: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); - }break; - case RDI_Arch_X64: - { - extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); - }break; - } - - // rjf: get raddbg register code - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - // TODO(rjf): real byte_size & byte_pos from cv_reg goes here - U32 byte_size = 8; - U32 byte_pos = 0; - - // rjf: build location - RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); - RDIM_Location *loc2 = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_local_push_location_case(arena, sym_scopes, local, loc2, voff_range); - } - }break; - - //- rjf: LTHREAD32/GTHREAD32 - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - // rjf: unpack sym - CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; - String8 name = str8_cstring_capped(thread32+1, sym_data_opl); - U32 tls_off = thread32->tls_off; - RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); - - // rjf: unpack thread variable's container type - RDIM_Type *container_type = 0; - U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); - if(container_name_opl > 2) - { - String8 container_name = str8(name.str, container_name_opl - 2); - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(tpi_hash, tpi_leaf, container_name, 0); - container_type = p2r_type_ptr_from_itype(cv_type_id); - } - - // rjf: unpack thread variable's container symbol - RDIM_Symbol *container_symbol = 0; - if(container_type == 0 && top_scope_node != 0) - { - container_symbol = top_scope_node->scope->symbol; - } - - // rjf: build symbol - RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, sym_thread_variables, sym_thread_variables_chunk_cap); - tvar->name = name; - tvar->type = type; - tvar->is_extern = (kind == CV_SymKind_GTHREAD32); - tvar->offset = tls_off; - tvar->container_type = container_type; - tvar->container_symbol = container_symbol; - }break; - - //- rjf: LOCAL - case CV_SymKind_LOCAL: - { - // rjf: no containing scope? -> malformed data; locals cannot be produced - // outside of a containing scope - if(top_scope_node == 0) - { - break; - } - - // rjf: unpack sym - CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; - String8 name = str8_cstring_capped(slocal+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); - - // rjf: determine if this symbol encodes the beginning of a global modification - B32 is_global_modification = 0; - if((slocal->flags & CV_LocalFlag_Global) || - (slocal->flags & CV_LocalFlag_Static)) - { - is_global_modification = 1; - } - - // rjf: is global modification -> emit global modification symbol - if(is_global_modification) - { - // TODO(rjf): add global modification symbols - defrange_target = 0; - defrange_target_is_param = 0; - } - - // rjf: is not a global modification -> emit a local variable - if(!is_global_modification) - { - // rjf: determine local kind - RDI_LocalKind local_kind = RDI_LocalKind_Variable; - if(slocal->flags & CV_LocalFlag_Param) - { - local_kind = RDI_LocalKind_Parameter; - } - - // rjf: build local - RDIM_Scope *scope = top_scope_node->scope; - RDIM_Local *local = rdim_scope_push_local(arena, sym_scopes, scope); - local->kind = local_kind; - local->name = name; - local->type = type; - - // rjf: save defrange target, for subsequent defrange symbols - defrange_target = local; - defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); - } - }break; - - //- rjf: DEFRANGE_REGISTER - case CV_SymKind_DEFRANGE_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register->reg; - CV_LvarAddrRange *range = &defrange_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: build location - RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - - // rjf: emit locations over ranges - p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; - CV_LvarAddrRange *range = &defrange_fprel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel->off; - RDIM_LocationInfo location_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location *location = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &location_info); - - // rjf: emit locations over ranges - p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_SUBFIELD_REGISTER - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; - CV_Reg cv_reg = defrange_subfield_register->reg; - CV_LvarAddrRange *range = &defrange_subfield_register->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - - // rjf: skip "subfield" location info - currently not supported - if(defrange_subfield_register->field_offset != 0) - { - break; - } - - // rjf: build location - RDIM_LocationInfo loc_info = {RDI_LocationKind_ValReg, reg_code}; - RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - - // rjf: emit locations over ranges - p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: find current procedure's frameproc - CV_SymFrameproc *frameproc = 0; - if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) - { - frameproc = procedure_frameprocs[procedure_num-1]; - } - - // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange - // without having an actually active procedure - break - if(frameproc == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; - CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); - RDI_RegCode fp_register_code = p2r_reg_code_from_arch_encoded_fp_reg(arch, encoded_fp_reg); - - // rjf: build location - B32 extra_indirection = 0; - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel_full_scope->off; - RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); - RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - - // rjf: emit location over ranges - RDIM_Rng1U64 voff_range = {0, max_U64}; - rdim_local_push_location_case(arena, sym_scopes, defrange_target, loc, voff_range); - }break; - - //- rjf: DEFRANGE_REGISTER_REL - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing - // a local - break immediately - if(defrange_target == 0) - { - break; - } - - // rjf: unpack sym - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; - CV_Reg cv_reg = defrange_register_rel->reg; - RDI_RegCode reg_code = p2r_rdi_reg_code_from_cv_reg_code(arch, cv_reg); - CV_LvarAddrRange *range = &defrange_register_rel->range; - COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= coff_sections.count) ? &coff_sections.v[range->sec-1] : 0; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); - U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); - - // rjf: build location - // TODO(rjf): offset & size from cv_reg code - U32 byte_size = rdi_addr_size_from_arch(arch); - U32 byte_pos = 0; - B32 extra_indirection_to_value = 0; - S64 var_off = defrange_register_rel->reg_off; - RDIM_LocationInfo loc_info = p2r_location_info_from_addr_reg_off(arena, arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); - RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, sym_locations, sym_locations_chunk_cap, &loc_info); - - // rjf: emit locations over ranges - p2r_local_push_location_cases_over_lvar_addr_range(arena, sym_scopes, defrange_target, loc, range, range_section, gaps, gap_count); - }break; - - //- rjf: FILESTATIC - case CV_SymKind_FILESTATIC: - { - CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; - String8 name = str8_cstring_capped(file_static+1, sym_data_opl); - RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); - // TODO(rjf): emit a global modifier symbol - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: INLINESITE - case CV_SymKind_INLINESITE: - { - // rjf: unpack sym - CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; - String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); - - // rjf: extract external info about inline site - String8 name = str8_zero(); - RDIM_Type *type = 0; - RDIM_Type *owner = 0; - if(ipi_leaf != 0 && ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < ipi_leaf->itype_opl) - { - CV_RecRange rec_range = ipi_leaf->leaf_ranges.ranges[sym->inlinee - ipi_leaf->itype_first]; - String8 rec_data = str8_substr(ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); - void *raw_leaf = rec_data.str + sizeof(U16); - - // rjf: extract method inline info - if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) - { - CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; - name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(mfunc_id->itype); - owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; - } - - // rjf: extract non-method function inline info - else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && - rec_range.hdr.size >= sizeof(CV_LeafFuncId)) - { - CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; - name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); - type = p2r_type_ptr_from_itype(func_id->itype); - owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; - } - } - - // rjf: build inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, sym_inline_sites, sym_inline_sites_chunk_cap); - inline_site->name = name; - inline_site->type = type; - inline_site->owner = owner; - inline_site->line_table = inline_site_line_table; - - // rjf: increment to next inline site line table in this unit - if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) - { - RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; - U64 current_idx = (U64)(inline_site_line_table - chunk->v); - if(current_idx+1 < chunk->count) - { - inline_site_line_table += 1; - } - else - { - chunk = chunk->next; - inline_site_line_table = 0; - if(chunk != 0) - { - inline_site_line_table = chunk->v; - } - } - } - - // rjf: build scope - RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap); - scope->inline_site = inline_site; - if(top_scope_node == 0) - { - // TODO(rjf): log - } - if(top_scope_node != 0) - { - RDIM_Scope *top_scope = top_scope_node->scope; - SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); - scope->parent_scope = top_scope; - scope->symbol = top_scope->symbol; - } - - // rjf: push this scope to scope stack - { - P2R_ScopeNode *node = free_scope_node; - if(node != 0) { SLLStackPop(free_scope_node); } - else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } - node->scope = scope; - SLLStackPush(top_scope_node, node); - } - - // rjf: parse offset ranges of this inline site - attach to scope - { - CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); - for(;;) - { - CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) - { - // rjf: build new range & add to scope - RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; - rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); - } - - if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) - { - if(scope->voff_ranges.last != 0) + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) { - scope->voff_ranges.last->v.max = step.range.max; + // rjf: build new range & add to scope + RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; + rdim_scope_push_voff_range(arena, sym_scopes, scope, voff_range); + } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) + { + if(scope->voff_ranges.last != 0) + { + scope->voff_ranges.last->v.max = step.range.max; + } + } + + if(step.flags == 0) + { + break; } } - - if(step.flags == 0) - { - break; - } } - } - }break; - - //- rjf: INLINESITE_END - case CV_SymKind_INLINESITE_END: - { - P2R_ScopeNode *n = top_scope_node; - if(n != 0) - { - SLLStackPop(top_scope_node); - SLLStackPush(free_scope_node, n); - } - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - //- rjf: CONSTANT - case CV_SymKind_CONSTANT: - { - // rjf: unpack - CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; - RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); - U8 *val_ptr = (U8 *)(sym+1); - CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); - U64 val64 = cv_u64_from_numeric(&val); - U8 *name_ptr = val_ptr + val.encoded_size; - String8 name = str8_cstring_capped(name_ptr, sym_data_opl); - String8 val_data = str8_struct(&val64); - U64 container_name_opl = 0; - if(type != 0) - { - container_name_opl = p2r_end_of_cplusplus_container_name(type->name); - } - String8 name_qualified = name; - if(container_name_opl != 0) - { - name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); - } + }break; - // rjf: build constant symbol - if(name_qualified.size != 0) + //- rjf: INLINESITE_END + case CV_SymKind_INLINESITE_END: { - RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); - cnst->name = name_qualified; - cnst->type = type; - rdim_symbol_push_value_data(arena, sym_constants, cnst, val_data); - } - }break; + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: CONSTANT + case CV_SymKind_CONSTANT: + { + // rjf: unpack + CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; + RDIM_Type *type = p2r_type_ptr_from_itype(sym->itype); + U8 *val_ptr = (U8 *)(sym+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, sym_data_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, sym_data_opl); + String8 val_data = str8_struct(&val64); + U64 container_name_opl = 0; + if(type != 0) + { + container_name_opl = p2r_end_of_cplusplus_container_name(type->name); + } + String8 name_qualified = name; + if(container_name_opl != 0) + { + name_qualified = push_str8f(arena, "%S%S", str8_prefix(type->name, container_name_opl), name); + } + + // rjf: build constant symbol + if(name_qualified.size != 0) + { + RDIM_Symbol *cnst = rdim_symbol_chunk_list_push(arena, sym_constants, sym_constants_chunk_cap); + cnst->name = name_qualified; + cnst->type = type; + rdim_symbol_push_value_data(arena, sym_constants, cnst, val_data); + } + }break; + } } } + + scratch_end(scratch); } - - scratch_end(scratch); } #undef p2r_type_ptr_from_itype } @@ -4190,7 +4242,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: build binary sections list RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") + if(params->subset_flags & RDIM_SubsetFlag_BinarySections) ProfScope("build binary section list") { COFF_SectionHeader *coff_ptr = coff_sections.v; COFF_SectionHeader *coff_opl = coff_ptr + coff_sections.count; From 2ce581fa19629d0cbe4c6d471ee8cb1dc10e07a5 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 22 Sep 2025 17:39:26 -0700 Subject: [PATCH 243/302] more subset flag respecting --- src/rdi_from_pdb/rdi_from_pdb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index e67b8fca..0a08c846 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -526,6 +526,10 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + if(!(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs))) + { + hash_data = aux_data = str8_zero(); + } p2r_shared->tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(2)) ProfScope("parse TPI leaf") @@ -537,6 +541,10 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + if(!(params->subset_flags & (RDIM_SubsetFlag_Types|RDIM_SubsetFlag_UDTs))) + { + hash_data = aux_data = str8_zero(); + } p2r_shared->ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); } if(lane_idx() == lane_from_task_idx(4)) ProfScope("parse IPI leaf") @@ -706,6 +714,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } // rjf: fill + if(params->subset_flags & RDIM_SubsetFlag_Procedures) { CV_SymParsed *sym = all_syms[0]; CV_RecRange *rec_ranges_first = sym->sym_ranges.ranges; From 9787c698e648fafd4d9de0e1d9785df2c9f50788 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 23 Sep 2025 10:58:17 -0700 Subject: [PATCH 244/302] sketch out new async path for ctrl memory streaming --- src/artifact_cache/artifact_cache.c | 4 +- src/artifact_cache/artifact_cache.h | 4 +- src/base/base_entry_point.c | 11 +- src/content/content.c | 19 +-- src/content/content.h | 5 +- src/ctrl/ctrl_core.c | 230 +++++++++++++++++++++++++--- src/ctrl/ctrl_core.h | 28 ++++ src/file_stream/file_stream.c | 4 +- src/file_stream/file_stream.h | 4 +- src/mutable_text/mutable_text.c | 2 +- src/texture_cache/texture_cache.c | 4 +- src/texture_cache/texture_cache.h | 4 +- 12 files changed, 263 insertions(+), 56 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index ee2fb7ee..100fc81c 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -137,10 +137,10 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType } //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick internal void -ac_tick(void) +ac_async_tick(void) { Temp scratch = scratch_begin(0, 0); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 04de679d..69035cde 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -99,8 +99,8 @@ internal void ac_init(void); internal void *ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick -internal void ac_tick(void); +internal void ac_async_tick(void); #endif // ARTIFACT_CACHE_H diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 1b7b2f88..fac1c3bf 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -198,16 +198,19 @@ async_thread_entry_point(void *params) async_loop_again = 0; } #if defined(ARTIFACT_CACHE_H) - ac_tick(); + ac_async_tick(); #endif #if defined(CONTENT_H) - c_tick(); + c_async_tick(); #endif #if defined(FILE_STREAM_H) - fs_tick(); + fs_async_tick(); +#endif +#if defined(CTRL_CORE_H) + ctrl_async_tick(); #endif #if defined(TEXTURE_CACHE_H) - tex_tick(); + tex_async_tick(); #endif cond_var_broadcast(async_tick_stop_cond_var); } diff --git a/src/content/content.c b/src/content/content.c index f16383b5..a7c2363b 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -13,13 +13,6 @@ # include "third_party/xxHash/xxhash.h" #endif -internal U64 -c_little_hash_from_data(String8 data) -{ - U64 result = XXH3_64bits(data.str, data.size); - return result; -} - internal U128 c_hash_from_data(String8 data) { @@ -181,7 +174,7 @@ internal U128 c_submit_data(C_Key key, Arena **data_arena, String8 data) { //- rjf: unpack key - U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); U64 key_slot_idx = key_hash%c_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; @@ -288,7 +281,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) // rjf: key is new -> add this key to the associated root if(key_is_new) { - U64 root_hash = c_little_hash_from_data(str8_struct(&key.root)); + U64 root_hash = u64_hash_from_str8(str8_struct(&key.root)); U64 root_slot_idx = root_hash%c_shared->root_slots_count; U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count; C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx]; @@ -348,7 +341,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data) internal void c_close_key(C_Key key) { - U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); U64 key_slot_idx = key_hash%c_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; @@ -438,7 +431,7 @@ internal U128 c_hash_from_key(C_Key key, U64 rewind_count) { U128 result = {0}; - U64 key_hash = c_little_hash_from_data(str8_struct(&key)); + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); U64 key_slot_idx = key_hash%c_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%c_shared->key_stripes_count; C_KeySlot *key_slot = &c_shared->key_slots[key_slot_idx]; @@ -483,10 +476,10 @@ c_data_from_hash(Access *access, U128 hash) } //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick internal void -c_tick(void) +c_async_tick(void) { ProfBeginFunction(); diff --git a/src/content/content.h b/src/content/content.h index 659c5c03..e314f0f6 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -197,7 +197,6 @@ global C_Shared *c_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers -internal U64 c_little_hash_from_data(String8 data); internal U128 c_hash_from_data(String8 data); internal C_ID c_id_make(U64 u64_0, U64 u64_1); internal B32 c_id_match(C_ID a, C_ID b); @@ -238,8 +237,8 @@ internal U128 c_hash_from_key(C_Key key, U64 rewind_count); internal String8 c_data_from_hash(Access *access, U128 hash); //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick -internal void c_tick(void); +internal void c_async_tick(void); #endif // CONTENT_H diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9456ddc6..b7ddb26b 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1594,6 +1594,8 @@ ctrl_init(void) ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); } } + ctrl_state->mem_req_mutex = mutex_alloc(); + ctrl_state->mem_req_arena = arena_alloc(); ctrl_state->u2ms_ring_size = KB(64); ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); ctrl_state->u2ms_ring_mutex = mutex_alloc(); @@ -1632,36 +1634,28 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; - //- rjf: get the hash store root for this process; construct process node if it + //- rjf: get the content root for this process; construct process node if it // doesn't exist C_Root root = {0}; { - B32 node_found = 0; - MutexScopeR(process_stripe->rw_mutex) + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + B32 node_found = 0; + RWMutexScope(process_stripe->rw_mutex, write_mode) { - if(ctrl_handle_match(n->handle, process)) + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - node_found = 1; - root = n->root; - break; + if(ctrl_handle_match(n->handle, process)) + { + node_found = 1; + root = n->root; + break; + } } } - } - if(!node_found) MutexScopeW(process_stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->handle, process)) - { - node_found = 1; - root = n->root; - break; - } - } - if(!node_found) + if(write_mode && !node_found) { + node_found = 1; Arena *node_arena = arena_alloc(); CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); DLLPushBack(process_slot->first, process_slot->last, node); @@ -1672,6 +1666,10 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); root = node->root; } + if(node_found) + { + break; + } } } @@ -1685,7 +1683,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 id.u128[0].u64[0] |= (1ull << 63); } } - U64 range_hash = c_little_hash_from_data(str8_struct(&id)); + U64 range_hash = u64_hash_from_str8(str8_struct(&id)); //- rjf: form full key C_Key key = c_key_make(root, id); @@ -6932,7 +6930,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; //- rjf: unpack address range hash cache key - U64 range_hash = c_little_hash_from_data(str8_struct(&key.id)); + U64 range_hash = u64_hash_from_str8(str8_struct(&key.id)); //- rjf: clamp vaddr range Rng1U64 vaddr_range_clamped = vaddr_range; @@ -7461,3 +7459,189 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) scratch_end(scratch); return 0; } + +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void +ctrl_async_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: get all memory requests + U64 mem_reqs_count = 0; + CTRL_MemRequest *mem_reqs = 0; + MutexScope(ctrl_state->mem_req_mutex) + { + mem_reqs_count = ctrl_state->mem_req_count; + mem_reqs = push_array(scratch.arena, CTRL_MemRequest, mem_reqs_count); + U64 idx = 0; + for EachNode(n, CTRL_MemRequestNode, ctrl_state->first_mem_req) + { + MemoryCopyStruct(&mem_reqs[idx], &n->v); + idx += 1; + } + } + + //- rjf: do all memory requests + { + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + U64 mem_req_take_counter = 0; + U64 *mem_req_take_counter_ptr = &mem_req_take_counter; + lane_sync_u64(&mem_req_take_counter_ptr, 0); + for(;;) + { + // rjf: take next task + U64 mem_req_num = ins_atomic_u64_inc_eval(mem_req_take_counter_ptr); + U64 mem_req_idx = (mem_req_num-1); + if(mem_reqs_count <= mem_req_idx) + { + break; + } + + // rjf: unpack request + CTRL_MemRequest *req = &mem_reqs[mem_req_idx]; + C_Key key = req->key; + CTRL_Handle process = req->process; + Rng1U64 vaddr_range = req->vaddr_range; + B32 zero_terminated = req->zero_terminated; + + // rjf: unpack process key + U64 process_hash = ctrl_hash_from_handle(process); + U64 process_slot_idx = process_hash%cache->slots_count; + U64 process_stripe_idx = process_slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; + CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; + + // rjf: unpack little hash of range key + U64 range_hash = u64_hash_from_str8(str8_struct(&key.id)); + + // rjf: clamp vaddr range + Rng1U64 vaddr_range_clamped = vaddr_range; + { + vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); + U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); + vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); + } + + // rjf: read + U64 range_size = 0; + Arena *range_arena = 0; + void *range_base = 0; + U64 zero_terminated_size = 0; + U64 pre_read_mem_gen = ctrl_mem_gen(); + B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + { + range_size = dim_1u64(vaddr_range_clamped); + U64 page_size = os_get_system_info()->page_size; + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); + range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); + if(range_arena == 0) + { + range_size = 0; + } + else + { + range_base = push_array_no_zero(range_arena, U8, range_size); + U64 bytes_read = 0; + U64 retry_count = 0; + U64 retry_limit = range_size > page_size ? 64 : 0; + for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; + retry_count <= retry_limit; + retry_count += 1) + { + bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); + if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) + { + U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + vaddr_range_clamped_retry.max -= diff; + vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); + if(diff == 0) + { + break; + } + } + else + { + break; + } + } + if(bytes_read == 0) + { + arena_release(range_arena); + range_base = 0; + range_size = 0; + range_arena = 0; + } + else if(bytes_read < range_size) + { + MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); + } + zero_terminated_size = range_size; + if(zero_terminated) + { + for(U64 idx = 0; idx < bytes_read; idx += 1) + { + if(((U8 *)range_base)[idx] == 0) + { + zero_terminated_size = idx; + break; + } + } + } + } + } + U64 post_read_mem_gen = ctrl_mem_gen(); + B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + + // rjf: read successful -> submit to hash store + U128 hash = {0}; + if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) + { + hash = c_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + } + else if(range_arena != 0) + { + arena_release(range_arena); + } + + // rjf: commit new info to cache + MutexScopeW(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->handle, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(c_id_match(range_n->id, key.id)) + { + if(pre_read_mem_gen == post_read_mem_gen) + { + range_n->mem_gen = post_read_mem_gen; + } + range_n->working_count -= 1; + goto commit__break_all; + } + } + } + } + commit__break_all:; + } + + // rjf: broadcast changes + cond_var_broadcast(process_stripe->cv); + if(!u128_match(u128_zero(), hash)) + { + if(ctrl_state->wakeup_hook != 0) + { + ctrl_state->wakeup_hook(); + } + } + } + } + + scratch_end(scratch); +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index d4464238..036a7288 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -828,6 +828,22 @@ typedef CTRL_WAKEUP_FUNCTION_DEF(CTRL_WakeupFunctionType); //////////////////////////////// //~ rjf: Main State Types +typedef struct CTRL_MemRequest CTRL_MemRequest; +struct CTRL_MemRequest +{ + C_Key key; + CTRL_Handle process; + Rng1U64 vaddr_range; + B32 zero_terminated; +}; + +typedef struct CTRL_MemRequestNode CTRL_MemRequestNode; +struct CTRL_MemRequestNode +{ + CTRL_MemRequestNode *next; + CTRL_MemRequest v; +}; + typedef struct CTRL_State CTRL_State; struct CTRL_State { @@ -891,6 +907,13 @@ struct CTRL_State String8List msg_user_bp_touched_files; String8List msg_user_bp_touched_symbols; + // rjf: memory requests + Mutex mem_req_mutex; + Arena *mem_req_arena; + CTRL_MemRequestNode *first_mem_req; + CTRL_MemRequestNode *last_mem_req; + U64 mem_req_count; + // rjf: user -> memstream ring buffer U64 u2ms_ring_size; U8 *u2ms_ring_base; @@ -1227,4 +1250,9 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work); ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void ctrl_async_tick(void); + #endif // CTRL_CORE_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 88869e33..23c0a480 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -241,10 +241,10 @@ fs_properties_from_path(String8 path) } //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick internal void -fs_tick(void) +fs_async_tick(void) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index dbee2562..05a8d930 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -125,8 +125,8 @@ internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal FileProperties fs_properties_from_path(String8 path); //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick -internal void fs_tick(void); +internal void fs_async_tick(void); #endif // FILE_STREAM_H diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index 7768a672..28a735ea 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -40,7 +40,7 @@ mtx_init(void) internal void mtx_push_op(C_Key buffer_key, MTX_Op op) { - U64 hash = c_little_hash_from_data(str8_struct(&buffer_key)); + U64 hash = u64_hash_from_str8(str8_struct(&buffer_key)); MTX_MutThread *thread = &mtx_shared->mut_threads[hash%mtx_shared->mut_threads_count]; mtx_enqueue_op(thread, buffer_key, op); } diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index eb111261..ef9c6d22 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -137,10 +137,10 @@ tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, } //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick internal void -tex_tick(void) +tex_async_tick(void) { if(ins_atomic_u64_eval(&tex_shared) == 0) { return; } ProfBeginFunction(); diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 18fa5011..4efeaee3 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -105,9 +105,9 @@ internal R_Handle tex_texture_from_hash_topology(Access *access, U128 hash, TEX_ internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out); //////////////////////////////// -//~ rjf: Tick +//~ rjf: Asynchronous Tick -internal void tex_tick(void); +internal void tex_async_tick(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups From 6cdce22284b69691a5718c20358db631ec95ffa4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 23 Sep 2025 11:27:56 -0700 Subject: [PATCH 245/302] expand artifacts a bit more, to be more useful with larger-than-ptr but not huge allocations --- src/artifact_cache/artifact_cache.c | 6 +++--- src/artifact_cache/artifact_cache.h | 17 +++++++++++++---- src/ctrl/ctrl_core.c | 19 +++++++++++++++++-- src/ctrl/ctrl_core.h | 6 ++++++ src/disasm/disasm.c | 28 +++++++++++++++------------- src/disasm/disasm.h | 4 ++-- src/text/text.c | 21 ++++++++++++--------- src/text/text.h | 4 ++-- 8 files changed, 70 insertions(+), 35 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 100fc81c..62443ede 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -20,7 +20,7 @@ ac_init(void) //////////////////////////////// //~ rjf: Cache Lookups -internal void * +internal AC_Artifact ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count) { //- rjf: create function -> cache @@ -60,7 +60,7 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType } //- rjf: cache * key -> artifact - void *artifact = 0; + AC_Artifact artifact = {0}; { U64 hash = u64_hash_from_str8(key); U64 slot_idx = hash%cache->slots_count; @@ -222,7 +222,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - void *val = reqs[idx].create(reqs[idx].key, &retry); + AC_Artifact val = reqs[idx].create(reqs[idx].key, &retry); // rjf: retry? -> resubmit request if(retry && lane_idx() == 0) diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 69035cde..a52ef971 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -4,11 +4,20 @@ #ifndef ARTIFACT_CACHE_H #define ARTIFACT_CACHE_H +//////////////////////////////// +//~ rjf: Artifact Handle Type + +typedef struct AC_Artifact AC_Artifact; +struct AC_Artifact +{ + U64 u64[4]; +}; + //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef void *AC_CreateFunctionType(String8 key, B32 *retry_out); -typedef void AC_DestroyFunctionType(void *artifact); +typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *retry_out); +typedef void AC_DestroyFunctionType(AC_Artifact artifact); //////////////////////////////// //~ rjf: Cache Types @@ -37,7 +46,7 @@ struct AC_Node // rjf: key/gen/value String8 key; U64 gen; - void *val; + AC_Artifact val; // rjf: metadata AccessPt access_pt; @@ -96,7 +105,7 @@ internal void ac_init(void); //////////////////////////////// //~ rjf: Cache Lookups -internal void *ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); +internal AC_Artifact ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index b7ddb26b..d77f8f91 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7460,6 +7460,21 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) return 0; } +//////////////////////////////// +//~ rjf: Process Memory Artifact Cache Hooks / Lookups + +internal void * +ctrl_memory_artifact_create(String8 key, B32 *retry_out) +{ + +} + +internal void +ctrl_memory_artifact_destroy(void *ptr) +{ + +} + //////////////////////////////// //~ rjf: Asynchronous Tick @@ -7467,7 +7482,7 @@ internal void ctrl_async_tick(void) { Temp scratch = scratch_begin(0, 0); - +#if 0 //- rjf: get all memory requests U64 mem_reqs_count = 0; CTRL_MemRequest *mem_reqs = 0; @@ -7642,6 +7657,6 @@ ctrl_async_tick(void) } } } - +#endif scratch_end(scratch); } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 036a7288..1add5ec4 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1250,6 +1250,12 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work); ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); +//////////////////////////////// +//~ rjf: Process Memory Artifact Cache Hooks / Lookups + +internal void *ctrl_memory_artifact_create(String8 key, B32 *retry_out); +internal void ctrl_memory_artifact_destroy(void *ptr); + //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index fbaff78b..11b461c1 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -264,10 +264,10 @@ struct DASM_Artifact DASM_Info info; }; -internal void * +internal AC_Artifact dasm_artifact_create(String8 key, B32 *retry_out) { - void *result = 0; + DASM_Artifact *artifact = 0; if(lane_idx() == 0) { Temp scratch = scratch_begin(0, 0); @@ -473,27 +473,28 @@ dasm_artifact_create(String8 key, B32 *retry_out) //- rjf: fill result if(info_arena != 0) { - DASM_Artifact *artifact = push_array(info_arena, DASM_Artifact, 1); + artifact = push_array(info_arena, DASM_Artifact, 1); artifact->arena = info_arena; artifact->info = info; - result = artifact; } di_scope_close(di_scope); access_close(access); scratch_end(scratch); } - lane_sync_u64(&result, 0); + lane_sync_u64(&artifact, 0); + AC_Artifact result = {0}; + result.u64[0] = (U64)artifact; return result; } internal void -dasm_artifact_destroy(void *ptr) +dasm_artifact_destroy(AC_Artifact artifact) { - if(ptr == 0) { return; } - DASM_Artifact *artifact = (DASM_Artifact *)ptr; - c_close_key(artifact->info.text_key); - arena_release(artifact->arena); + DASM_Artifact *dasm_artifact = (DASM_Artifact *)artifact.u64[0]; + if(dasm_artifact == 0) { return; } + c_close_key(dasm_artifact->info.text_key); + arena_release(dasm_artifact->arena); } internal DASM_Info @@ -511,10 +512,11 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) String8 key = str8_list_join(scratch.arena, &key_parts, 0); // rjf: get info - DASM_Artifact *artifact = ac_artifact_from_key(access, key, fs_change_gen(), dasm_artifact_create, dasm_artifact_destroy, 1024); - if(artifact) + AC_Artifact artifact = ac_artifact_from_key(access, key, fs_change_gen(), dasm_artifact_create, dasm_artifact_destroy, 1024); + DASM_Artifact *dasm_artifact = (DASM_Artifact *)artifact.u64[0]; + if(dasm_artifact) { - info = artifact->info; + info = dasm_artifact->info; } scratch_end(scratch); diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index b1acf658..cd346fd7 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -197,8 +197,8 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal void *dasm_artifact_create(String8 key, B32 *retry_out); -internal void dasm_artifact_destroy(void *ptr); +internal AC_Artifact dasm_artifact_create(String8 key, B32 *retry_out); +internal void dasm_artifact_destroy(AC_Artifact artifact); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); diff --git a/src/text/text.c b/src/text/text.c index 015f54fb..e5b1a305 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1968,7 +1968,7 @@ struct TXT_ArtifactCreateShared TXT_Artifact *artifact; }; -internal void * +internal AC_Artifact txt_artifact_create(String8 key, B32 *retry_out) { ProfBeginFunction(); @@ -2232,15 +2232,17 @@ txt_artifact_create(String8 key, B32 *retry_out) access_close(access); scratch_end(scratch); ProfEnd(); - return shared->artifact; + AC_Artifact result = {0}; + result.u64[0] = (U64)shared->artifact; + return result; } internal void -txt_artifact_destroy(void *ptr) +txt_artifact_destroy(AC_Artifact artifact) { - if(ptr == 0) { return; } - TXT_Artifact *artifact = (TXT_Artifact *)ptr; - arena_release(artifact->arena); + TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; + if(txt_artifact == 0) { return; } + arena_release(txt_artifact->arena); } internal TXT_TextInfo @@ -2252,11 +2254,12 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) TXT_LangKind lang; } key = {hash, lang}; String8 key_string = str8_struct(&key); - TXT_Artifact *artifact = ac_artifact_from_key(access, key_string, 0, txt_artifact_create, txt_artifact_destroy, 1024); + AC_Artifact artifact = ac_artifact_from_key(access, key_string, 0, txt_artifact_create, txt_artifact_destroy, 1024); + TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; TXT_TextInfo info = {0}; - if(artifact != 0) + if(txt_artifact != 0) { - info = artifact->info; + info = txt_artifact->info; } return info; } diff --git a/src/text/text.h b/src/text/text.h index bc41db58..45f9a2f3 100644 --- a/src/text/text.h +++ b/src/text/text.h @@ -203,8 +203,8 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal void *txt_artifact_create(String8 key, B32 *retry_out); -internal void txt_artifact_destroy(void *ptr); +internal AC_Artifact txt_artifact_create(String8 key, B32 *retry_out); +internal void txt_artifact_destroy(AC_Artifact artifact); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From 141b6c1396c1bd6863a9f58f8544628aa301161e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 23 Sep 2025 11:58:00 -0700 Subject: [PATCH 246/302] sketch out artifact cache hooks for file streaming layer --- src/base/base_entry_point.c | 3 - src/base/base_strings.c | 16 ++ src/base/base_strings.h | 2 + src/ctrl/ctrl_core.c | 279 +++++++++++++--------------------- src/ctrl/ctrl_core.h | 9 +- src/file_stream/file_stream.c | 109 +++++++++---- src/file_stream/file_stream.h | 4 +- src/raddbg/raddbg_views.c | 2 +- 8 files changed, 215 insertions(+), 209 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index fac1c3bf..ba60894d 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -206,9 +206,6 @@ async_thread_entry_point(void *params) #if defined(FILE_STREAM_H) fs_async_tick(); #endif -#if defined(CTRL_CORE_H) - ctrl_async_tick(); -#endif #if defined(TEXTURE_CACHE_H) tex_async_tick(); #endif diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 960fb163..84e3f448 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -2891,3 +2891,19 @@ u64_hash_from_str8(String8 string) U64 result = u64_hash_from_seed_str8(5381, string); return result; } + +internal U128 +u128_hash_from_seed_str8(U64 seed, String8 string) +{ + U128 result = {0}; + XXH128_hash_t hash = XXH3_128bits_withSeed(string.str, string.size, seed); + MemoryCopy(&result, &hash, sizeof(result)); + return result; +} + +internal U128 +u128_hash_from_str8(String8 string) +{ + U128 result = u128_hash_from_seed_str8(5381, string); + return result; +} diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 06459427..5a14e3dc 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -449,5 +449,7 @@ internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, Stri internal U64 u64_hash_from_seed_str8(U64 seed, String8 string); internal U64 u64_hash_from_str8(String8 string); +internal U128 u128_hash_from_seed_str8(U64 seed, String8 string); +internal U128 u128_hash_from_str8(String8 string); #endif // BASE_STRINGS_H diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d77f8f91..3583139b 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7463,200 +7463,137 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal void * +internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out) { - -} - -internal void -ctrl_memory_artifact_destroy(void *ptr) -{ - -} - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void -ctrl_async_tick(void) -{ - Temp scratch = scratch_begin(0, 0); -#if 0 - //- rjf: get all memory requests - U64 mem_reqs_count = 0; - CTRL_MemRequest *mem_reqs = 0; - MutexScope(ctrl_state->mem_req_mutex) + //- rjf: unpack key + CTRL_Handle process = {0}; + Rng1U64 vaddr_range = {0}; + B32 zero_terminated = 0; { - mem_reqs_count = ctrl_state->mem_req_count; - mem_reqs = push_array(scratch.arena, CTRL_MemRequest, mem_reqs_count); - U64 idx = 0; - for EachNode(n, CTRL_MemRequestNode, ctrl_state->first_mem_req) - { - MemoryCopyStruct(&mem_reqs[idx], &n->v); - idx += 1; - } + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &process); + key_read_off += str8_deserial_read_struct(key, key_read_off, &vaddr_range); + key_read_off += str8_deserial_read_struct(key, key_read_off, &zero_terminated); } - //- rjf: do all memory requests + //- rjf: clamp vaddr range + Rng1U64 vaddr_range_clamped = vaddr_range; { - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - U64 mem_req_take_counter = 0; - U64 *mem_req_take_counter_ptr = &mem_req_take_counter; - lane_sync_u64(&mem_req_take_counter_ptr, 0); - for(;;) + vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); + U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); + vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); + } + + //- rjf: do read + U64 range_size = 0; + Arena *range_arena = 0; + void *range_base = 0; + U64 zero_terminated_size = 0; + U64 pre_read_mem_gen = ctrl_mem_gen(); + B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + { + range_size = dim_1u64(vaddr_range_clamped); + U64 page_size = os_get_system_info()->page_size; + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); + range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); + if(range_arena == 0) { - // rjf: take next task - U64 mem_req_num = ins_atomic_u64_inc_eval(mem_req_take_counter_ptr); - U64 mem_req_idx = (mem_req_num-1); - if(mem_reqs_count <= mem_req_idx) + range_size = 0; + } + else + { + range_base = push_array_no_zero(range_arena, U8, range_size); + U64 bytes_read = 0; + U64 retry_count = 0; + U64 retry_limit = range_size > page_size ? 64 : 0; + for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; + retry_count <= retry_limit; + retry_count += 1) { - break; - } - - // rjf: unpack request - CTRL_MemRequest *req = &mem_reqs[mem_req_idx]; - C_Key key = req->key; - CTRL_Handle process = req->process; - Rng1U64 vaddr_range = req->vaddr_range; - B32 zero_terminated = req->zero_terminated; - - // rjf: unpack process key - U64 process_hash = ctrl_hash_from_handle(process); - U64 process_slot_idx = process_hash%cache->slots_count; - U64 process_stripe_idx = process_slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; - CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; - - // rjf: unpack little hash of range key - U64 range_hash = u64_hash_from_str8(str8_struct(&key.id)); - - // rjf: clamp vaddr range - Rng1U64 vaddr_range_clamped = vaddr_range; - { - vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); - U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); - vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); - } - - // rjf: read - U64 range_size = 0; - Arena *range_arena = 0; - void *range_base = 0; - U64 zero_terminated_size = 0; - U64 pre_read_mem_gen = ctrl_mem_gen(); - B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - { - range_size = dim_1u64(vaddr_range_clamped); - U64 page_size = os_get_system_info()->page_size; - U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); - range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); - if(range_arena == 0) + bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); + if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) { - range_size = 0; + U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + vaddr_range_clamped_retry.max -= diff; + vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); + if(diff == 0) + { + break; + } } else { - range_base = push_array_no_zero(range_arena, U8, range_size); - U64 bytes_read = 0; - U64 retry_count = 0; - U64 retry_limit = range_size > page_size ? 64 : 0; - for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; - retry_count <= retry_limit; - retry_count += 1) - { - bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); - if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) - { - U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; - vaddr_range_clamped_retry.max -= diff; - vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); - if(diff == 0) - { - break; - } - } - else - { - break; - } - } - if(bytes_read == 0) - { - arena_release(range_arena); - range_base = 0; - range_size = 0; - range_arena = 0; - } - else if(bytes_read < range_size) - { - MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); - } - zero_terminated_size = range_size; - if(zero_terminated) - { - for(U64 idx = 0; idx < bytes_read; idx += 1) - { - if(((U8 *)range_base)[idx] == 0) - { - zero_terminated_size = idx; - break; - } - } - } + break; } } - U64 post_read_mem_gen = ctrl_mem_gen(); - B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - - // rjf: read successful -> submit to hash store - U128 hash = {0}; - if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) - { - hash = c_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); - } - else if(range_arena != 0) + if(bytes_read == 0) { arena_release(range_arena); + range_base = 0; + range_size = 0; + range_arena = 0; } - - // rjf: commit new info to cache - MutexScopeW(process_stripe->rw_mutex) + else if(bytes_read < range_size) { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); + } + zero_terminated_size = range_size; + if(zero_terminated) + { + for(U64 idx = 0; idx < bytes_read; idx += 1) { - if(ctrl_handle_match(n->handle, process)) + if(((U8 *)range_base)[idx] == 0) { - U64 range_slot_idx = range_hash%n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) - { - if(c_id_match(range_n->id, key.id)) - { - if(pre_read_mem_gen == post_read_mem_gen) - { - range_n->mem_gen = post_read_mem_gen; - } - range_n->working_count -= 1; - goto commit__break_all; - } - } + zero_terminated_size = idx; + break; } } - commit__break_all:; - } - - // rjf: broadcast changes - cond_var_broadcast(process_stripe->cv); - if(!u128_match(u128_zero(), hash)) - { - if(ctrl_state->wakeup_hook != 0) - { - ctrl_state->wakeup_hook(); - } + U64 bytes_overkill = (bytes_read - zero_terminated_size); + arena_pop(range_arena, bytes_overkill); } } } -#endif - scratch_end(scratch); + U64 post_read_mem_gen = ctrl_mem_gen(); + B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + + //- rjf: form content key + C_Key content_key = {0}; + { + content_key.id.u128[0] = u128_hash_from_str8(key); + } + + //- rjf: read successful -> submit to hash store + U128 hash = {0}; + if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) + { + hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + } + else if(range_arena != 0) + { + arena_release(range_arena); + } + + //- rjf: wakeup on new reads + if(!u128_match(u128_zero(), hash)) + { + if(ctrl_state->wakeup_hook != 0) + { + ctrl_state->wakeup_hook(); + } + } + + //- rjf: return content key bundled as artifact + AC_Artifact artifact = {0}; + StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); + MemoryCopyStruct(&artifact, &content_key); + return artifact; +} + +internal void +ctrl_memory_artifact_destroy(AC_Artifact artifact) +{ + C_Key key = {0}; + MemoryCopyStruct(&key, &artifact); + c_close_key(key); } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 1add5ec4..1919e38b 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1253,12 +1253,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal void *ctrl_memory_artifact_create(String8 key, B32 *retry_out); -internal void ctrl_memory_artifact_destroy(void *ptr); - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void ctrl_async_tick(void); +internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out); +internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); #endif // CTRL_CORE_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 23c0a480..c0ed5590 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -68,6 +68,89 @@ fs_change_gen(void) //////////////////////////////// //~ rjf: Cache Interaction +internal AC_Artifact +fs_artifact_create(String8 key, B32 *retry_out) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack key + String8 path = {0}; + Rng1U64 range = {0}; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &path.size); + path.str = push_array(scratch.arena, U8, path.size); + key_read_off += str8_deserial_read(key, key_read_off, path.str, path.size, 1); + key_read_off += str8_deserial_read_struct(key, key_read_off, &range); + } + + //- rjf: do read + ProfBegin("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max); + FileProperties pre_props = os_properties_from_file_path(path); + U64 range_size = dim_1u64(range); + U64 read_size = Min(pre_props.size - range.min, range_size); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); + U64 data_arena_size = read_size+ARENA_HEADER_SIZE; + data_arena_size += KB(4)-1; + data_arena_size -= data_arena_size%KB(4); + ProfBegin("allocate"); + Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); + ProfEnd(); + ProfBegin("read"); + String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size)); + ProfEnd(); + os_file_close(file); + FileProperties post_props = os_properties_from_file_path(path); + + //- rjf: form content key + C_Key content_key = {0}; + { + content_key.id.u128[0] = u128_hash_from_str8(key); + } + + //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file + B32 read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + read_size == data.size && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + if(!read_good) + { + retry_out[0] = 1; + ProfScope("abort") + { + arena_release(data_arena); + MemoryZeroStruct(&data); + data_arena = 0; + } + } + + //- rjf: submit to content store + else + { + ProfScope("submit") + { + c_submit_data(content_key, &data_arena, data); + } + } + + //- rjf: bundle content key as artifact + AC_Artifact artifact = {0}; + StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); + MemoryCopyStruct(&artifact, &content_key); + + scratch_end(scratch); + return artifact; +} + +internal void +fs_artifact_destroy(AC_Artifact artifact) +{ + C_Key key = {0}; + MemoryCopyStruct(&key, &artifact); + c_close_key(key); +} + internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { @@ -214,32 +297,6 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) return hash; } -internal FileProperties -fs_properties_from_path(String8 path) -{ - Temp scratch = scratch_begin(0, 0); - FileProperties result = {0}; - path = path_normalized_from_string(scratch.arena, path); - U64 path_hash = fs_little_hash_from_string(path); - U64 slot_idx = path_hash%fs_shared->slots_count; - U64 stripe_idx = slot_idx%fs_shared->stripes_count; - FS_Slot *slot = &fs_shared->slots[slot_idx]; - FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) - { - for(FS_Node *n = slot->first; n != 0; n = n->next) - { - if(str8_match(path, n->path, 0)) - { - result = n->props; - break; - } - } - } - scratch_end(scratch); - return result; -} - //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 05a8d930..9e2ab093 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -120,9 +120,11 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Cache Interaction +internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out); +internal void fs_artifact_destroy(AC_Artifact artifact); + internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); -internal FileProperties fs_properties_from_path(String8 path); //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 7e9efbcf..16614e77 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -2177,7 +2177,7 @@ RD_VIEW_UI_FUNCTION_DEF(text) B32 file_is_out_of_date = 0; String8 out_of_date_dbgi_name = {0}; { - U64 file_timestamp = fs_properties_from_path(rd_regs()->file_path).modified; + U64 file_timestamp = os_properties_from_file_path(rd_regs()->file_path).modified; if(file_timestamp != 0) { for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) From 7e05a60ffe3b2f9b2718622a63ed1b40b2bada09 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 23 Sep 2025 17:05:45 -0700 Subject: [PATCH 247/302] checkpoint on more artifact cache port of ctrl process memory streaming --- src/artifact_cache/artifact_cache.c | 1 + src/ctrl/ctrl_core.c | 267 +++++++++++++++------------- src/ctrl/ctrl_core.h | 1 + 3 files changed, 149 insertions(+), 120 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 62443ede..932ce2eb 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -123,6 +123,7 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType n->v.create = create; } cond_var_broadcast(async_tick_start_cond_var); + ins_atomic_u32_eval_assign(&async_loop_again, 1); } // rjf: found node -> break diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 3583139b..46bc106e 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7466,127 +7466,134 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out) { - //- rjf: unpack key - CTRL_Handle process = {0}; - Rng1U64 vaddr_range = {0}; - B32 zero_terminated = 0; - { - U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &process); - key_read_off += str8_deserial_read_struct(key, key_read_off, &vaddr_range); - key_read_off += str8_deserial_read_struct(key, key_read_off, &zero_terminated); - } - - //- rjf: clamp vaddr range - Rng1U64 vaddr_range_clamped = vaddr_range; - { - vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); - U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); - vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); - } - - //- rjf: do read - U64 range_size = 0; - Arena *range_arena = 0; - void *range_base = 0; - U64 zero_terminated_size = 0; - U64 pre_read_mem_gen = ctrl_mem_gen(); - B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - { - range_size = dim_1u64(vaddr_range_clamped); - U64 page_size = os_get_system_info()->page_size; - U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); - range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); - if(range_arena == 0) - { - range_size = 0; - } - else - { - range_base = push_array_no_zero(range_arena, U8, range_size); - U64 bytes_read = 0; - U64 retry_count = 0; - U64 retry_limit = range_size > page_size ? 64 : 0; - for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; - retry_count <= retry_limit; - retry_count += 1) - { - bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); - if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) - { - U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; - vaddr_range_clamped_retry.max -= diff; - vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); - if(diff == 0) - { - break; - } - } - else - { - break; - } - } - if(bytes_read == 0) - { - arena_release(range_arena); - range_base = 0; - range_size = 0; - range_arena = 0; - } - else if(bytes_read < range_size) - { - MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); - } - zero_terminated_size = range_size; - if(zero_terminated) - { - for(U64 idx = 0; idx < bytes_read; idx += 1) - { - if(((U8 *)range_base)[idx] == 0) - { - zero_terminated_size = idx; - break; - } - } - U64 bytes_overkill = (bytes_read - zero_terminated_size); - arena_pop(range_arena, bytes_overkill); - } - } - } - U64 post_read_mem_gen = ctrl_mem_gen(); - B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - - //- rjf: form content key - C_Key content_key = {0}; - { - content_key.id.u128[0] = u128_hash_from_str8(key); - } - - //- rjf: read successful -> submit to hash store - U128 hash = {0}; - if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) - { - hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); - } - else if(range_arena != 0) - { - arena_release(range_arena); - } - - //- rjf: wakeup on new reads - if(!u128_match(u128_zero(), hash)) - { - if(ctrl_state->wakeup_hook != 0) - { - ctrl_state->wakeup_hook(); - } - } - - //- rjf: return content key bundled as artifact AC_Artifact artifact = {0}; - StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); - MemoryCopyStruct(&artifact, &content_key); + if(lane_idx() == 0) + { + //- rjf: unpack key + CTRL_Handle process = {0}; + Rng1U64 vaddr_range = {0}; + B32 zero_terminated = 0; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &process); + key_read_off += str8_deserial_read_struct(key, key_read_off, &vaddr_range); + key_read_off += str8_deserial_read_struct(key, key_read_off, &zero_terminated); + } + + //- rjf: clamp vaddr range + Rng1U64 vaddr_range_clamped = vaddr_range; + { + vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); + U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); + vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); + } + + //- rjf: do read + U64 range_size = 0; + Arena *range_arena = 0; + void *range_base = 0; + U64 zero_terminated_size = 0; + U64 pre_read_mem_gen = ctrl_mem_gen(); + B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + { + range_size = dim_1u64(vaddr_range_clamped); + U64 page_size = os_get_system_info()->page_size; + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); + range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); + if(range_arena == 0) + { + range_size = 0; + } + else + { + range_base = push_array_no_zero(range_arena, U8, range_size); + U64 bytes_read = 0; + U64 retry_count = 0; + U64 retry_limit = range_size > page_size ? 64 : 0; + for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; + retry_count <= retry_limit; + retry_count += 1) + { + bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); + if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) + { + U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + vaddr_range_clamped_retry.max -= diff; + vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); + if(diff == 0) + { + break; + } + } + else + { + break; + } + } + if(bytes_read == 0) + { + arena_release(range_arena); + range_base = 0; + range_size = 0; + range_arena = 0; + } + else if(bytes_read < range_size) + { + MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); + } + zero_terminated_size = range_size; + if(zero_terminated) + { + for(U64 idx = 0; idx < bytes_read; idx += 1) + { + if(((U8 *)range_base)[idx] == 0) + { + zero_terminated_size = idx; + break; + } + } + U64 bytes_overkill = (bytes_read - zero_terminated_size); + arena_pop(range_arena, bytes_overkill); + } + } + } + U64 post_read_mem_gen = ctrl_mem_gen(); + B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + + //- rjf: form content key + C_Key content_key = {0}; + { + content_key.id.u128[0] = u128_hash_from_str8(key); + } + + //- rjf: read successful -> submit to hash store + U128 hash = {0}; + if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) + { + hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size)); + } + else if(range_arena != 0) + { + arena_release(range_arena); + } + + //- rjf: wakeup on new reads + if(!u128_match(u128_zero(), hash)) + { + if(ctrl_state->wakeup_hook != 0) + { + ctrl_state->wakeup_hook(); + } + } + + //- rjf: bundle content key as artifact + StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); + MemoryCopyStruct(&artifact, &content_key); + } + lane_sync_u64(&artifact.u64[0], 0); + lane_sync_u64(&artifact.u64[1], 0); + lane_sync_u64(&artifact.u64[2], 0); + lane_sync_u64(&artifact.u64[3], 0); return artifact; } @@ -7597,3 +7604,23 @@ ctrl_memory_artifact_destroy(AC_Artifact artifact) MemoryCopyStruct(&key, &artifact); c_close_key(key); } + +internal C_Key +ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) +{ + ProfBeginFunction(); + struct + { + CTRL_Handle process; + Rng1U64 vaddr_range; + B32 zero_terminated; + } key_data = {process, vaddr_range, zero_terminated}; + String8 key = str8_struct(&key_data); + Access *access = access_open(); + AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_mem_gen(), ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, 2048); + C_Key content_key = {0}; + MemoryCopyStruct(&content_key, &artifact); + access_close(access); + ProfEnd(); + return content_key; +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 1919e38b..03e959c9 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1255,5 +1255,6 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); +internal C_Key ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); #endif // CTRL_CORE_H From e7368af35c1b48dff8582d9126e34377bfcd2db0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 11:25:18 -0700 Subject: [PATCH 248/302] artifact cache waitable cache access; debugging / fixes; start plugging in file stream to artifact cache --- src/artifact_cache/artifact_cache.c | 139 ++++++++++++++++----------- src/artifact_cache/artifact_cache.h | 14 ++- src/base/base_entry_point.c | 22 ++++- src/base/base_thread_context.c | 13 +++ src/base/base_thread_context.h | 2 +- src/ctrl/ctrl_core.c | 2 +- src/disasm/disasm.c | 2 +- src/file_stream/file_stream.c | 141 ++++++++++++++++++++-------- src/file_stream/file_stream.h | 3 + src/scratch/ryan_scratch.c | 99 ++++--------------- src/text/text.c | 2 +- 11 files changed, 260 insertions(+), 179 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 932ce2eb..7c074d9d 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -21,12 +21,12 @@ ac_init(void) //~ rjf: Cache Lookups internal AC_Artifact -ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count) +ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us) { //- rjf: create function -> cache AC_Cache *cache = 0; { - U64 cache_hash = u64_hash_from_str8(str8_struct(&create)); + U64 cache_hash = u64_hash_from_str8(str8_struct(¶ms->create)); U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) @@ -35,7 +35,7 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType { for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) { - if(c->create == create) + if(c->create == params->create) { cache = c; break; @@ -45,10 +45,10 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType { cache = push_array(cache_stripe->arena, AC_Cache, 1); SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache); - cache->create = create; - cache->destroy = destroy; - cache->slots_count = slots_count; - cache->slots = push_array(cache_stripe->arena, AC_Slot, slots_count); + cache->create = params->create; + cache->destroy = params->destroy; + cache->slots_count = Max(256, params->slots_count); + cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count); cache->stripes = stripe_array_alloc(cache_stripe->arena); } } @@ -59,78 +59,109 @@ ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType } } - //- rjf: cache * key -> artifact + //- rjf: unpack key + U64 hash = u64_hash_from_str8(key); + U64 slot_idx = hash%cache->slots_count; + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + + //- rjf: cache * key -> existing artifact + B32 got_artifact = 0; + B32 need_request = 0; AC_Artifact artifact = {0}; + RWMutexScope(stripe->rw_mutex, 0) { - U64 hash = u64_hash_from_str8(key); - U64 slot_idx = hash%cache->slots_count; - AC_Slot *slot = &cache->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + for(AC_Node *n = slot->first; n != 0; n = n->next) { - B32 found = 0; - B32 need_request = 0; - RWMutexScope(stripe->rw_mutex, write_mode) + if(str8_match(n->key, key, 0)) { - // rjf: look up node - for(AC_Node *n = slot->first; n != 0; n = n->next) + if(ins_atomic_u64_eval(&n->completion_count) != 0 && (n->gen == params->gen || !params->wait_for_fresh)) { - if(str8_match(n->key, key, 0)) - { - found = 1; - artifact = n->val; - access_touch(access, &n->access_pt, stripe->cv); - if(n->gen != gen) - { - B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0); - need_request = got_task; - } - break; - } + got_artifact = 1; + artifact = n->val; + access_touch(access, &n->access_pt, stripe->cv); } - - // rjf: no node? -> create - if(write_mode && !found) + if(n->gen != params->gen) { - need_request = 1; - AC_Node *node = stripe->free; - if(node) - { - stripe->free = node->next; - } - else - { - node = push_array_no_zero(stripe->arena, AC_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - // TODO(rjf): string allocator for keys - node->key = str8_copy(stripe->arena, key); - node->working_count = 1; + B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0); + need_request = got_task; + } + break; + } + } + } + + //- rjf: didn't get artifact we want? -> fall back to slow path + if(!got_artifact || need_request) + { + RWMutexScope(stripe->rw_mutex, 1) for(;;) + { + B32 out_of_time = (os_now_microseconds() >= endt_us); + + // rjf: find node in cache + AC_Node *node = 0; + for(AC_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, key, 0)) + { + node = n; + break; } } - // rjf: need request -> push + // rjf: no node? -> create + if(node == 0) + { + need_request = 1; + node = stripe->free; + if(node) + { + stripe->free = node->next; + } + else + { + node = push_array_no_zero(stripe->arena, AC_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + // TODO(rjf): string allocator for keys + node->key = str8_copy(stripe->arena, key); + node->working_count = 1; + } + + // rjf: request if(need_request) { + need_request = 0; MutexScope(ac_shared->req_mutex) { AC_RequestNode *n = push_array(ac_shared->req_arena, AC_RequestNode, 1); SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); ac_shared->req_count += 1; n->v.key = str8_copy(ac_shared->req_arena, key); - n->v.gen = gen; - n->v.create = create; + n->v.gen = params->gen; + n->v.create = params->create; } cond_var_broadcast(async_tick_start_cond_var); ins_atomic_u32_eval_assign(&async_loop_again, 1); } - // rjf: found node -> break - if(found) + // rjf: get value from node, if possible + if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->gen == params->gen) || !params->wait_for_fresh || out_of_time)) + { + got_artifact = 1; + artifact = node->val; + access_touch(access, &node->access_pt, stripe->cv); + } + + // rjf: abort if needed + if(out_of_time || got_artifact || is_async_thread) { break; } + + // rjf: wait for results + cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us); } } @@ -275,9 +306,11 @@ ac_async_tick(void) n->gen = reqs[idx].gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); + ins_atomic_u64_inc_eval(&n->completion_count); } } } + cond_var_broadcast(stripe->cv); } } lane_sync(); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index a52ef971..303c1d43 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -19,6 +19,16 @@ struct AC_Artifact typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *retry_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); +typedef struct AC_ArtifactParams AC_ArtifactParams; +struct AC_ArtifactParams +{ + AC_CreateFunctionType *create; + AC_DestroyFunctionType *destroy; + U64 slots_count; + U64 gen; + B32 wait_for_fresh; +}; + //////////////////////////////// //~ rjf: Cache Types @@ -51,6 +61,7 @@ struct AC_Node // rjf: metadata AccessPt access_pt; U64 working_count; + U64 completion_count; }; typedef struct AC_Slot AC_Slot; @@ -105,7 +116,8 @@ internal void ac_init(void); //////////////////////////////// //~ rjf: Cache Lookups -internal AC_Artifact ac_artifact_from_key(Access *access, String8 key, U64 gen, AC_CreateFunctionType *create, AC_DestroyFunctionType *destroy, U64 slots_count); +internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us); +#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), __VA_ARGS__}, (endt_us)) //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index ba60894d..be9be2e7 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -3,11 +3,11 @@ global U64 global_update_tick_idx = 0; global CondVar async_tick_start_cond_var = {0}; -global CondVar async_tick_stop_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; global B32 async_loop_again = 0; global B32 global_async_exit = 0; +thread_static B32 is_async_thread = 0; internal void main_thread_base_entry_point(int arguments_count, char **arguments) @@ -18,7 +18,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) //- rjf: set up async thread group info async_tick_start_cond_var = cond_var_alloc(); async_tick_start_mutex = mutex_alloc(); - async_tick_stop_cond_var = cond_var_alloc(); async_tick_stop_mutex = mutex_alloc(); //- rjf: set up telemetry @@ -186,9 +185,11 @@ async_thread_entry_point(void *params) { LaneCtx lctx = *(LaneCtx *)params; lane_ctx(lctx); + is_async_thread = 1; ThreadNameF("async_thread_%I64u", lane_idx()); - for(;!ins_atomic_u32_eval(&global_async_exit);) + for(;;) { + // rjf: wait for signal if we need, otherwise reset loop signal & continue if(!ins_atomic_u32_eval(&async_loop_again)) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); @@ -197,6 +198,7 @@ async_thread_entry_point(void *params) { async_loop_again = 0; } + #if defined(ARTIFACT_CACHE_H) ac_async_tick(); #endif @@ -209,6 +211,18 @@ async_thread_entry_point(void *params) #if defined(TEXTURE_CACHE_H) tex_async_tick(); #endif - cond_var_broadcast(async_tick_stop_cond_var); + + // rjf: take exit signal; break if set + lane_sync(); + B32 need_exit = 0; + if(lane_idx() == 0) + { + need_exit = ins_atomic_u32_eval(&global_async_exit); + } + lane_sync_u64(&need_exit, 0); + if(need_exit) + { + break; + } } } diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index e08d42b1..45ea750d 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -90,16 +90,29 @@ tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_sr ProfBeginFunction(); ProfColor(0x00000ff); TCTX *tctx = tctx_selected(); + + // rjf: doing broadcast -> copy to broadcast memory on source lane U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0])); if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx) { MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped); } + + // rjf: all cases: barrier os_barrier_wait(tctx->lane_ctx.barrier); + + // rjf: doing broadcast -> copy from broadcast memory on destination lanes if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx) { MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped); } + + // rjf: doing broadcast -> barrier on all lanes + if(broadcast_ptr != 0) + { + os_barrier_wait(tctx->lane_ctx.barrier); + } + ProfEnd(); } diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index b840e552..1a49a005 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -94,7 +94,7 @@ internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U6 #define lane_from_task_idx(idx) ((idx)%lane_count()) #define lane_ctx(ctx) tctx_set_lane_ctx((ctx)) #define lane_sync() tctx_lane_barrier_wait(0, 0, 0) -#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(U64), (src_lane_idx)) +#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx)) #define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count)) //- rjf: thread names diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 46bc106e..f063d1f6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7617,7 +7617,7 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, } key_data = {process, vaddr_range, zero_terminated}; String8 key = str8_struct(&key_data); Access *access = access_open(); - AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_mem_gen(), ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, 2048); + AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, .gen = ctrl_mem_gen(), .slots_count = 2048); C_Key content_key = {0}; MemoryCopyStruct(&content_key, &artifact); access_close(access); diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 11b461c1..3d470429 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -512,7 +512,7 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) String8 key = str8_list_join(scratch.arena, &key_parts, 0); // rjf: get info - AC_Artifact artifact = ac_artifact_from_key(access, key, fs_change_gen(), dasm_artifact_create, dasm_artifact_destroy, 1024); + AC_Artifact artifact = ac_artifact_from_key(access, key, dasm_artifact_create, dasm_artifact_destroy, 0, .gen = fs_change_gen()); DASM_Artifact *dasm_artifact = (DASM_Artifact *)artifact.u64[0]; if(dasm_artifact) { diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index c0ed5590..ce2e9277 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -84,24 +84,69 @@ fs_artifact_create(String8 key, B32 *retry_out) key_read_off += str8_deserial_read_struct(key, key_read_off, &range); } - //- rjf: do read - ProfBegin("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max); - FileProperties pre_props = os_properties_from_file_path(path); - U64 range_size = dim_1u64(range); - U64 read_size = Min(pre_props.size - range.min, range_size); - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + //- rjf: measure file properties *before* read + FileProperties pre_props = {0}; + if(lane_idx() == 0) + { + pre_props = os_properties_from_file_path(path); + } + + //- rjf: setup output data + Arena *data_arena = 0; + U64 data_buffer_size = 0; + U8 *data_buffer = 0; + if(lane_idx() == 0) + { + U64 range_size = dim_1u64(range); + U64 read_size = Min(pre_props.size - range.min, range_size); + U64 data_arena_size = read_size+ARENA_HEADER_SIZE; + data_arena_size += KB(4)-1; + data_arena_size -= data_arena_size%KB(4); + data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); + data_buffer_size = read_size; + data_buffer = push_array_no_zero(data_arena, U8, data_buffer_size); + } + lane_sync_u64(&data_buffer, 0); + lane_sync_u64(&data_buffer_size, 0); + + //- rjf: open file + OS_Handle file = {0}; + if(lane_idx() == 0) + { + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + } + lane_sync_u64(&file, 0); B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); - U64 data_arena_size = read_size+ARENA_HEADER_SIZE; - data_arena_size += KB(4)-1; - data_arena_size -= data_arena_size%KB(4); - ProfBegin("allocate"); - Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); - ProfEnd(); - ProfBegin("read"); - String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size)); - ProfEnd(); - os_file_close(file); - FileProperties post_props = os_properties_from_file_path(path); + + //- rjf: do read + U64 total_bytes_read = 0; + U64 *total_bytes_read_ptr = 0; + if(lane_idx() == 0) + { + total_bytes_read_ptr = &total_bytes_read; + } + lane_sync_u64(&total_bytes_read_ptr, 0); + ProfScope("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max) + { + Rng1U64 lane_read_range = lane_range(data_buffer_size); + U64 bytes_read = os_file_read(file, lane_read_range, data_buffer + (lane_read_range.min - range.min)); + ins_atomic_u64_add_eval(total_bytes_read_ptr, bytes_read); + } + lane_sync(); + lane_sync_u64(&total_bytes_read, 0); + + //- rjf: close file + if(lane_idx() == 0) + { + os_file_close(file); + } + + //- rjf: measure file properties *after* read + FileProperties post_props = {0}; + if(lane_idx() == 0) + { + post_props = os_properties_from_file_path(path); + } //- rjf: form content key C_Key content_key = {0}; @@ -109,30 +154,32 @@ fs_artifact_create(String8 key, B32 *retry_out) content_key.id.u128[0] = u128_hash_from_str8(key); } - //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file - B32 read_good = (pre_props.modified == post_props.modified && - pre_props.size == post_props.size && - read_size == data.size && - (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); - if(!read_good) + //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file; + // otherwise submit data + if(lane_idx() == 0) { - retry_out[0] = 1; - ProfScope("abort") + B32 read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + data_buffer_size == total_bytes_read && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + if(!read_good) { - arena_release(data_arena); - MemoryZeroStruct(&data); - data_arena = 0; - } - } - - //- rjf: submit to content store - else - { - ProfScope("submit") - { - c_submit_data(content_key, &data_arena, data); + retry_out[0] = 1; + ProfScope("abort") + { + arena_release(data_arena); + MemoryZeroStruct(&content_key); + } + } + else + { + ProfScope("submit") + { + c_submit_data(content_key, &data_arena, str8(data_buffer, data_buffer_size)); + } } } + lane_sync(); //- rjf: bundle content key as artifact AC_Artifact artifact = {0}; @@ -151,6 +198,26 @@ fs_artifact_destroy(AC_Artifact artifact) c_close_key(key); } +internal C_Key +fs_key_from_path_range_new(String8 path, Rng1U64 range, U64 endt_us) +{ + C_Key result = {0}; + Temp scratch = scratch_begin(0, 0); + Access *access = access_open(); + { + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&path.size)); + str8_list_push(scratch.arena, &key_parts, path); + str8_list_push(scratch.arena, &key_parts, str8_struct(&range)); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us); + MemoryCopyStruct(&result, &artifact); + } + access_close(access); + scratch_end(scratch); + return result; +} + internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 9e2ab093..99217712 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -123,6 +123,9 @@ internal U64 fs_change_gen(void); internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); +internal C_Key fs_key_from_path_range_new(String8 path, Rng1U64 range, U64 endt_us); +#define fs_key_from_path(path, endt_us) fs_key_from_path_range_new((path), r1u64(0, max_U64), (endt_us)) + internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 219a644e..adca33dd 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -5,7 +5,7 @@ //~ rjf: Build Options #define BUILD_TITLE "ryan_scratch" -#define OS_FEATURE_GRAPHICAL 1 +#define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes @@ -13,93 +13,32 @@ //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" -#include "render/render_inc.h" -#include "font_provider/font_provider_inc.h" -#include "font_cache/font_cache.h" -#include "draw/draw.h" +#include "content/content.h" +#include "artifact_cache/artifact_cache.h" +#include "file_stream/file_stream.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" -#include "render/render_inc.c" -#include "font_provider/font_provider_inc.c" -#include "font_cache/font_cache.c" -#include "draw/draw.c" +#include "content/content.c" +#include "artifact_cache/artifact_cache.c" +#include "file_stream/file_stream.c" //////////////////////////////// -//~ rjf: Globals - -global OS_Handle window_os = {0}; -global R_Handle window_r = {0}; - -//////////////////////////////// -//~ rjf: Entry Points - -internal B32 -frame(void) -{ - B32 quit = 0; - Temp scratch = scratch_begin(0, 0); - - //- rjf: events test - OS_EventList events = os_get_events(scratch.arena, 0); - for(OS_Event *ev = events.first; ev != 0; ev = ev->next) - { - if(ev->kind != OS_EventKind_MouseMove) - { - String8 string = push_str8f(scratch.arena, "%S (%S)\n", os_string_from_event_kind(ev->kind), os_g_key_display_string_table[ev->key]); - printf("%.*s", str8_varg(string)); - raddbg_log((char *)string.str); - fflush(stdout); - } - if(ev->kind == OS_EventKind_Press && ev->key == OS_Key_X) - { - *(volatile int *)0 = 0; - } - } - for(OS_Event *ev = events.first; ev != 0; ev = ev->next) - { - if(ev->kind == OS_EventKind_WindowClose) - { - quit = 1; - break; - } - } - - //- rjf: drawing test - r_begin_frame(); - r_window_begin_frame(window_os, window_r); - { - R_PassList passes = {0}; - R_Pass *pass = r_pass_from_kind(scratch.arena, &passes, R_PassKind_UI); - R_PassParams_UI *pass_ui = pass->params_ui; - R_BatchGroup2DNode group = {0}; - pass_ui->rects.first = pass_ui->rects.last = &group; - pass_ui->rects.count = 1; - group.batches = r_batch_list_make(sizeof(R_Rect2DInst)); - group.params.xform = mat_3x3f32(1.f); - group.params.clip = os_client_rect_from_window(window_os); - Vec2F32 mouse = os_mouse_from_window(window_os); - R_Rect2DInst *inst = r_batch_list_push_inst(scratch.arena, &group.batches, 256); - MemoryZeroStruct(inst); - inst->dst = r2f32p(mouse.x+30, mouse.y+30, mouse.x+100, mouse.y+100); - inst->src = r2f32p(0, 0, 1, 1); - inst->colors[Corner_00] = inst->colors[Corner_01] = inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(1, 0, 0, 1); - inst->corner_radii[Corner_00] = inst->corner_radii[Corner_01] = inst->corner_radii[Corner_10] = inst->corner_radii[Corner_11] = 8.f; - r_window_submit(window_os, window_r, &passes); - } - r_window_end_frame(window_os, window_r); - r_end_frame(); - - scratch_end(scratch); - return quit; -} +//~ rjf: Entry Point internal void entry_point(CmdLine *cmdline) { - window_os = os_window_open(r2f32p(0, 0, 1280, 720), OS_WindowFlag_UseDefaultPosition, str8_lit("Window")); - os_window_first_paint(window_os); - window_r = r_window_equip(window_os); - for(;!update();); + for(;;) + { + C_Key key = fs_key_from_path(str8_lit("C:/devel/raddebugger/build/x.dump"), os_now_microseconds() + 100000); + U128 hash = c_hash_from_key(key, 0); + printf("hash: 0x%I64x, 0x%I64x\n", hash.u64[0], hash.u64[1]); + fflush(stdout); + if(!u128_match(u128_zero(), hash)) + { + break; + } + } } diff --git a/src/text/text.c b/src/text/text.c index e5b1a305..caa42dad 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -2254,7 +2254,7 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) TXT_LangKind lang; } key = {hash, lang}; String8 key_string = str8_struct(&key); - AC_Artifact artifact = ac_artifact_from_key(access, key_string, 0, txt_artifact_create, txt_artifact_destroy, 1024); + AC_Artifact artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 0); TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; TXT_TextInfo info = {0}; if(txt_artifact != 0) From 5f883860e0c7b6f3983a2b671f337e01feecb0b6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 11:50:53 -0700 Subject: [PATCH 249/302] move part of file evaluations onto new async file reads --- src/base/base_entry_point.c | 25 +++++++++++++++---------- src/disasm/disasm.c | 2 +- src/file_stream/file_stream.c | 2 ++ src/raddbg/raddbg_core.c | 4 ++-- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index be9be2e7..751b8254 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -190,27 +190,32 @@ async_thread_entry_point(void *params) for(;;) { // rjf: wait for signal if we need, otherwise reset loop signal & continue - if(!ins_atomic_u32_eval(&async_loop_again)) + if(lane_idx() == 0) { - MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); - } - else if(lane_idx() == 0) - { - async_loop_again = 0; + if(!ins_atomic_u32_eval(&async_loop_again)) + { + MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); + } + ins_atomic_u32_eval_assign(&async_loop_again, 0); } + lane_sync(); + // rjf: do all ticks for all layers + ProfScope("async tick") + { #if defined(ARTIFACT_CACHE_H) - ac_async_tick(); + ac_async_tick(); #endif #if defined(CONTENT_H) - c_async_tick(); + c_async_tick(); #endif #if defined(FILE_STREAM_H) - fs_async_tick(); + fs_async_tick(); #endif #if defined(TEXTURE_CACHE_H) - tex_async_tick(); + tex_async_tick(); #endif + } // rjf: take exit signal; break if set lane_sync(); diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 3d470429..e2d8f743 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -289,8 +289,8 @@ dasm_artifact_create(String8 key, B32 *retry_out) if(params.dbgi_key.path.size != 0) { rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0); + stale = (stale || (rdi == &rdi_parsed_nil)); } - stale = (stale || (rdi == &rdi_parsed_nil)); //- rjf: data * arch * addr * dbg -> decode artifacts DASM_LineChunkList line_list = {0}; diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index ce2e9277..1ea280d6 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -71,6 +71,7 @@ fs_change_gen(void) internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out) { + ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); //- rjf: unpack key @@ -187,6 +188,7 @@ fs_artifact_create(String8 key, B32 *retry_out) MemoryCopyStruct(&artifact, &content_key); scratch_end(scratch); + ProfEnd(); return artifact; } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 1e1dce0d..4f2fb0a3 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1779,7 +1779,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) containing_range.max -= containing_range.max%chunk_size; // rjf: map to hash - C_Key key = fs_key_from_path_range(file_path, containing_range, 0); + C_Key key = fs_key_from_path_range(file_path, containing_range, 0); U128 hash = c_hash_from_key(key, 0); // rjf: look up from hash store @@ -2153,7 +2153,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) { U64 file_path_string_id = space.u64_0; String8 file_path = e_string_from_id(file_path_string_id); - result = fs_key_from_path_range(file_path, range, 0); + result = fs_key_from_path_range_new(file_path, range, 0); }break; case RD_EvalSpaceKind_CtrlEntity: { From 8e68187107cc0f537a70c5774e631ddd99685d49 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 11:53:52 -0700 Subject: [PATCH 250/302] fix incorrect file artifact reading offsets; switch file eval reads to new artifact cache --- src/file_stream/file_stream.c | 2 +- src/raddbg/raddbg_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 1ea280d6..b3d72097 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -130,7 +130,7 @@ fs_artifact_create(String8 key, B32 *retry_out) ProfScope("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max) { Rng1U64 lane_read_range = lane_range(data_buffer_size); - U64 bytes_read = os_file_read(file, lane_read_range, data_buffer + (lane_read_range.min - range.min)); + U64 bytes_read = os_file_read(file, shift_1u64(lane_read_range, range.min), data_buffer + lane_read_range.min); ins_atomic_u64_add_eval(total_bytes_read_ptr, bytes_read); } lane_sync(); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 4f2fb0a3..18dbecf8 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1779,7 +1779,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) containing_range.max -= containing_range.max%chunk_size; // rjf: map to hash - C_Key key = fs_key_from_path_range(file_path, containing_range, 0); + C_Key key = fs_key_from_path_range_new(file_path, containing_range, 0); U128 hash = c_hash_from_key(key, 0); // rjf: look up from hash store From 7f2a066e8f704afdd03aed184854ecade809e772 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 12:09:59 -0700 Subject: [PATCH 251/302] tear out old file stream tick; switch disasm to using new file stream for interleaved text lines --- src/disasm/disasm.c | 2 +- src/file_stream/file_stream.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index e2d8f743..783a91a3 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -362,7 +362,7 @@ dasm_artifact_create(String8 key, B32 *retry_out) { // TODO(rjf): need redirection path - this may map to a different path on the local machine, // need frontend to communicate path remapping info to this layer - C_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); + C_Key key = fs_key_from_path_range_new(file_normalized_full_path, r1u64(0, max_U64), 0); TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index b3d72097..4c4d44f0 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -372,6 +372,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) internal void fs_async_tick(void) { +#if 0 ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -530,4 +531,5 @@ fs_async_tick(void) scratch_end(scratch); ProfEnd(); +#endif } From fa0b2440ec53d48bc61fb92816dc6fa2a8f9658c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 12:42:04 -0700 Subject: [PATCH 252/302] subset flag for constants conversion; fix empty-tpi-hash case --- src/lib_rdi_make/rdi_make.h | 1 + src/pdb/pdb_parse.c | 344 ++++++++++++++++---------------- src/rdi_from_pdb/rdi_from_pdb.c | 1 + 3 files changed, 175 insertions(+), 171 deletions(-) diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 9094f017..5e872a64 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -318,6 +318,7 @@ X(Units, units)\ X(Procedures, procedures)\ X(GlobalVariables, global_variables)\ X(ThreadVariables, thread_variables)\ +X(Constants, constants)\ X(Scopes, scopes)\ X(Locals, locals)\ X(Types, types)\ diff --git a/src/pdb/pdb_parse.c b/src/pdb/pdb_parse.c index ad88308e..af3b52a5 100644 --- a/src/pdb/pdb_parse.c +++ b/src/pdb/pdb_parse.c @@ -823,207 +823,209 @@ pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi){ } internal CV_TypeIdArray -pdb_tpi_itypes_from_name(Arena *arena, PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *leaf, - String8 name, B32 compare_unique_name, U32 output_cap){ - U32 hash = pdb_hash_v1(name); - U32 bucket_idx = ((tpi_hash->bucket_mask != 0) ? - hash&tpi_hash->bucket_mask : - hash%tpi_hash->bucket_count); - - CV_TypeId itype_first = leaf->itype_first; - CV_TypeId itype_opl = leaf->itype_opl; - String8 data = leaf->data; - - Temp scratch = scratch_begin(&arena, 1); - struct Chain{ - struct Chain *next; - CV_TypeId itype; - }; - struct Chain *first = 0; - struct Chain *last = 0; - U32 count = 0; - - for (PDB_TpiHashBlock *block = tpi_hash->buckets[bucket_idx]; - block != 0; - block = block->next){ - U32 local_count = block->local_count; - CV_TypeId *itype_ptr = block->itypes; - for (U32 i = 0; i < local_count; i += 1, itype_ptr += 1){ - - String8 extracted_name = {0}; - - CV_TypeId itype = *itype_ptr; - if (itype_first <= itype && itype < itype_opl){ - CV_RecRange *range = &leaf->leaf_ranges.ranges[itype - leaf->itype_first]; - if (range->off + range->hdr.size <= data.size){ - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - - switch (range->hdr.kind){ - default:break; +pdb_tpi_itypes_from_name(Arena *arena, PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *leaf, String8 name, B32 compare_unique_name, U32 output_cap) +{ + CV_TypeIdArray result = {0}; + if(tpi_hash->bucket_count != 0) + { + U32 hash = pdb_hash_v1(name); + U32 bucket_idx = ((tpi_hash->bucket_mask != 0) ? + hash&tpi_hash->bucket_mask : + hash%tpi_hash->bucket_count); + + CV_TypeId itype_first = leaf->itype_first; + CV_TypeId itype_opl = leaf->itype_opl; + String8 data = leaf->data; + + Temp scratch = scratch_begin(&arena, 1); + struct Chain + { + struct Chain *next; + CV_TypeId itype; + }; + struct Chain *first = 0; + struct Chain *last = 0; + U32 count = 0; + + for (PDB_TpiHashBlock *block = tpi_hash->buckets[bucket_idx]; + block != 0; + block = block->next){ + U32 local_count = block->local_count; + CV_TypeId *itype_ptr = block->itypes; + for (U32 i = 0; i < local_count; i += 1, itype_ptr += 1){ + + String8 extracted_name = {0}; + + CV_TypeId itype = *itype_ptr; + if (itype_first <= itype && itype < itype_opl){ + CV_RecRange *range = &leaf->leaf_ranges.ranges[itype - leaf->itype_first]; + if (range->off + range->hdr.size <= data.size){ + U8 *first = data.str + range->off + 2; + U64 cap = range->hdr.size - 2; - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - if (sizeof(CV_LeafStruct) <= cap){ - CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; - - if (!(lf_struct->props & CV_TypeProp_FwdRef)){ - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + switch (range->hdr.kind){ + default:break; + + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + if (sizeof(CV_LeafStruct) <= cap){ + CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); - - // unique name - if (compare_unique_name){ - if (lf_struct->props & CV_TypeProp_HasUniqueName) { - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); - extracted_name = unique_name; + if (!(lf_struct->props & CV_TypeProp_FwdRef)){ + // size + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_struct->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; } } - else{ - extracted_name = name; - } } - } - }break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - if (sizeof(CV_LeafStruct2) <= cap){ - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2*)first; - - if (!(lf_struct->props & CV_TypeProp_FwdRef)){ - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + }break; + + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + if (sizeof(CV_LeafStruct2) <= cap){ + CV_LeafStruct2 *lf_struct = (CV_LeafStruct2*)first; - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); - - // unique name - if (compare_unique_name){ - if (lf_struct->props & CV_TypeProp_HasUniqueName) { - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); - extracted_name = unique_name; + if (!(lf_struct->props & CV_TypeProp_FwdRef)){ + // size + U8 *numeric_ptr = (U8*)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_struct->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; } } - else{ - extracted_name = name; - } } - } - }break; - - case CV_LeafKind_UNION: - { - if (sizeof(CV_LeafUnion) <= cap){ - CV_LeafUnion *lf_union = (CV_LeafUnion*)first; - - if (!(lf_union->props & CV_TypeProp_FwdRef)){ - // size - U8 *numeric_ptr = (U8*)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + }break; + + case CV_LeafKind_UNION: + { + if (sizeof(CV_LeafUnion) <= cap){ + CV_LeafUnion *lf_union = (CV_LeafUnion*)first; - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); - - // unique name - if (compare_unique_name){ - if (lf_union->props & CV_TypeProp_HasUniqueName) { - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); - extracted_name = unique_name; + if (!(lf_union->props & CV_TypeProp_FwdRef)){ + // size + U8 *numeric_ptr = (U8*)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); + + // name + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_union->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; } } - else{ - extracted_name = name; - } } - } - }break; - - case CV_LeafKind_ENUM: - { - if (sizeof(CV_LeafEnum) <= cap){ - CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; - - if (!(lf_enum->props & CV_TypeProp_FwdRef)){ - // name - U8 *name_ptr = (U8*)(lf_enum + 1); - String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + }break; + + case CV_LeafKind_ENUM: + { + if (sizeof(CV_LeafEnum) <= cap){ + CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; - // unique name - if (compare_unique_name){ - if (lf_enum->props & CV_TypeProp_HasUniqueName) { - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); - extracted_name = unique_name; + if (!(lf_enum->props & CV_TypeProp_FwdRef)){ + // name + U8 *name_ptr = (U8*)(lf_enum + 1); + String8 name = str8_cstring_capped((char*)name_ptr, (char *)(first + cap)); + + // unique name + if (compare_unique_name){ + if (lf_enum->props & CV_TypeProp_HasUniqueName) { + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, (char *)(first + cap)); + extracted_name = unique_name; + } + } + else{ + extracted_name = name; } } - else{ - extracted_name = name; - } } - } - }break; + }break; + } + } + } + + if (str8_match(extracted_name, name, 0)){ + struct Chain *chain = push_array(scratch.arena, struct Chain, 1); + SLLQueuePush(first, last, chain); + count += 1; + chain->itype = itype; + if (count == output_cap){ + goto dblbreak; } } } - - if (str8_match(extracted_name, name, 0)){ - struct Chain *chain = push_array(scratch.arena, struct Chain, 1); - SLLQueuePush(first, last, chain); - count += 1; - chain->itype = itype; - if (count == output_cap){ - goto dblbreak; - } + } + + dblbreak:; + + + // assemble result + CV_TypeId *itypes = push_array_aligned(arena, CV_TypeId, count, 8); + { + CV_TypeId *itype_ptr = itypes; + for (struct Chain *node = first; + node != 0; + node = node->next, itype_ptr += 1){ + *itype_ptr = node->itype; } } + result.itypes = itypes; + result.count = count; + + scratch_end(scratch); } - - dblbreak:; - - - // assemble result - CV_TypeId *itypes = push_array_aligned(arena, CV_TypeId, count, 8); - { - CV_TypeId *itype_ptr = itypes; - for (struct Chain *node = first; - node != 0; - node = node->next, itype_ptr += 1){ - *itype_ptr = node->itype; - } - } - CV_TypeIdArray result = {0}; - result.itypes = itypes; - result.count = count; - - scratch_end(scratch); - - return(result); + return result; } internal CV_TypeId -pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *tpi_leaf, - String8 name, B32 compare_unique_name){ +pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *tpi_leaf, String8 name, B32 compare_unique_name) +{ Temp scratch = scratch_begin(0, 0); - CV_TypeIdArray array = pdb_tpi_itypes_from_name(scratch.arena, tpi_hash, tpi_leaf, - name, compare_unique_name, 1); + CV_TypeIdArray array = pdb_tpi_itypes_from_name(scratch.arena, tpi_hash, tpi_leaf, name, compare_unique_name, 1); CV_TypeId result = 0; - if (array.count > 0){ + if(array.count > 0) + { result = array.itypes[0]; } - scratch_end(scratch); return(result); } diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 0a08c846..37b84abf 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -4118,6 +4118,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) //- rjf: CONSTANT case CV_SymKind_CONSTANT: + if(params->subset_flags & RDIM_SubsetFlag_Constants) { // rjf: unpack CV_SymConstant *sym = (CV_SymConstant *)sym_header_struct_base; From 0a930be613e60703a16636c7720f7c2c6aef1330 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 22 Sep 2025 10:41:46 -0700 Subject: [PATCH 253/302] use radsort for sorting base reloc pages --- src/linker/lnk.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index ccf646fc..f349bab8 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3675,19 +3675,10 @@ THREAD_POOL_TASK_FUNC(lnk_patch_section_symbols_task) ProfEnd(); } -internal int -lnk_base_reloc_page_compar(const void *raw_a, const void *raw_b) -{ - const LNK_BaseRelocPage *a = raw_a, *b = raw_b; - return u64_compar(&a->voff, &b->voff); -} - internal int lnk_base_reloc_page_is_before(void *raw_a, void *raw_b) { - LNK_BaseRelocPage* a = raw_a; - LNK_BaseRelocPage* b = raw_b; - return a->voff < b->voff; + return ((LNK_BaseRelocPage *)raw_a)->voff < ((LNK_BaseRelocPage *)raw_b)->voff; } internal String8List @@ -3760,8 +3751,7 @@ lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, U6 ProfEnd(); ProfBegin("Sort Pages on VOFF"); - //radsort(page_arr.v, page_arr.count, lnk_base_reloc_page_is_before); - qsort(page_arr.v, page_arr.count, sizeof(page_arr.v[0]), lnk_base_reloc_page_compar); + radsort(page_arr.v, page_arr.count, lnk_base_reloc_page_is_before); ProfEnd(); } From 3c0c531c5336fa5e668136c9d2b184aefcb4a269 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 23 Sep 2025 06:23:31 -0700 Subject: [PATCH 254/302] reloc helper --- src/coff/coff.c | 15 +++++++++++++++ src/coff/coff.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/coff/coff.c b/src/coff/coff.c index a37bc009..eef1c129 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -103,6 +103,21 @@ coff_read_symbol_name(String8 string_table, COFF_SymbolName *name) return name_str; } +internal U64 +coff_is_addr_reloc(COFF_MachineType machine, U32 type) +{ + U64 is_addr = 0; + switch (machine) { + case COFF_MachineType_Unknown: is_addr = 0; break; + case COFF_MachineType_X64: { + if (type == COFF_Reloc_X64_Addr32) is_addr = 4; + else if (type == COFF_Reloc_X64_Addr64) is_addr = 8; + } break; + default: NotImplemented; break; + } + return is_addr; +} + internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x) { diff --git a/src/coff/coff.h b/src/coff/coff.h index 69b72ff3..4adff448 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -601,6 +601,8 @@ internal String8 coff_read_symbol_name(String8 string_table, COFF_SymbolName *na //////////////////////////////// // Reloc +internal U64 coff_is_addr_reloc(COFF_MachineType machine, U32 type); + internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x); internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x); From 20c92e0bafe1333d856c4a54c6e53a92211456f0 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 23 Sep 2025 06:31:05 -0700 Subject: [PATCH 255/302] speed up base reloc gather step and serialize pages in parallel --- src/linker/lnk.c | 431 +++++++++++++++++++++++------------------------ src/linker/lnk.h | 32 ++-- 2 files changed, 234 insertions(+), 229 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f349bab8..be4779d6 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -3504,90 +3504,6 @@ lnk_build_guard_tables(TP_Context *tp, #endif } -internal -THREAD_POOL_TASK_FUNC(lnk_emit_base_relocs_from_objs_task) -{ - ProfBeginFunction(); - - LNK_ObjBaseRelocTask *task = raw_task; - Rng1U64 range = task->ranges[task_id]; - - HashTable *page_ht = task->page_ht_arr[task_id]; - LNK_BaseRelocPageList *page_list = &task->list_arr[task_id]; - - for (U64 obj_idx = range.min; obj_idx < range.max; ++obj_idx) { - LNK_Obj *obj = task->obj_arr[obj_idx]; - COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; - for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { - COFF_SectionHeader *sect_header = §ion_table[sect_idx]; - - if (sect_header->flags & COFF_SectionFlag_LnkRemove) { - continue; - } - - COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, sect_header); - COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off); - - for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; reloc_idx += 1) { - COFF_Reloc *r = &relocs[reloc_idx]; - - COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, r->isymbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - B32 is_symbol_address = symbol_interp != COFF_SymbolValueInterp_Abs; - - if (is_symbol_address) { - B32 is_addr32 = 0, is_addr64 = 0; - switch (obj->header.machine) { - case COFF_MachineType_Unknown: {} break; - case COFF_MachineType_X64: { - is_addr32 = r->type == COFF_Reloc_X64_Addr32; - is_addr64 = r->type == COFF_Reloc_X64_Addr64; - } break; - default: { NotImplemented; } break; - } - - if (is_addr32 || is_addr64) { - U64 reloc_voff = sect_header->voff + r->apply_off; - U64 page_voff = AlignDownPow2(reloc_voff, task->page_size); - - LNK_BaseRelocPageNode *page; - { - KeyValuePair *is_page_present = hash_table_search_u64(page_ht, page_voff); - if (is_page_present) { - page = is_page_present->value_raw; - } else { - // fill out page - page = push_array(arena, LNK_BaseRelocPageNode, 1); - page->v.voff = page_voff; - - // push page - SLLQueuePush(page_list->first, page_list->last, page); - page_list->count += 1; - - // register page voff - hash_table_push_u64_raw(arena, page_ht, page_voff, page); - } - } - - if (is_addr32) { - if (task->is_large_addr_aware) { - COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, r->isymbol); - lnk_error_obj(LNK_Error_LargeAddrAwareRequired, obj, "found out of range ADDR32 relocation for '%S', link with /LARGEADDRESSAWARE:NO", symbol.name); - } else { - u64_list_push(arena, &page->v.entries_addr32, reloc_voff); - } - } else { - u64_list_push(arena, &page->v.entries_addr64, reloc_voff); - } - } - } - } - } - } - - ProfEnd(); -} - internal THREAD_POOL_TASK_FUNC(lnk_patch_virtual_offsets_and_sizes_in_obj_section_headers_task) { @@ -3675,167 +3591,246 @@ THREAD_POOL_TASK_FUNC(lnk_patch_section_symbols_task) ProfEnd(); } +internal +THREAD_POOL_TASK_FUNC(lnk_gather_base_reloc_pages_task) +{ + LNK_BaseRelocsTask *task = raw_task; + HashTable *page_ht = task->gather.page_ht[worker_id]; + LNK_BaseRelocPageList *pages = &task->gather.pages[worker_id]; + LNK_Obj *obj = task->gather.objs[task_id]; + COFF_SectionHeader *sect_table = lnk_coff_section_table_from_obj(obj); + + ProfBeginV("%S", obj->path); + for EachIndex(sect_idx, obj->header.section_count_no_null) { + COFF_SectionHeader *sect_header = §_table[sect_idx]; + if (sect_header->flags & COFF_SectionFlag_LnkRemove) { continue; } + + COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, sect_header); + for EachIndex(reloc_idx, relocs.count) { + COFF_Reloc *r = &relocs.v[reloc_idx]; + + COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, r->isymbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol); + if (symbol_interp == COFF_SymbolValueInterp_Abs) { continue; } + + U64 is_addr = coff_is_addr_reloc(obj->header.machine, r->type); + if (is_addr == 0) { continue; } + + U64 reloc_voff = sect_header->voff + r->apply_off; + U64 page_voff = AlignDownPow2(reloc_voff, task->page_size); + LNK_BaseRelocPageNode *page = hash_table_search_u64_raw(page_ht, page_voff); + if (page == 0) { + // fill out page + page = push_array(arena, LNK_BaseRelocPageNode, 1); + page->v.voff = page_voff; + page->v.entries_addr32 = push_array(arena, U64List, 1); + page->v.entries_addr64 = push_array(arena, U64List, 1); + + // push page + SLLQueuePush(pages->first, pages->last, page); + pages->count += 1; + + // register page voff + hash_table_push_u64_raw(arena, page_ht, page_voff, page); + } + + switch (is_addr) { + case 4: { + if (task->is_large_addr_aware) { + lnk_error_obj(LNK_Error_LargeAddrAwareRequired, obj, "found out of range ADDR32 relocation for '%S', link with /LARGEADDRESSAWARE:NO", symbol.name); + } else { + u64_list_push(arena, page->v.entries_addr32, reloc_voff); + } + } break; + case 8: { + u64_list_push(arena, page->v.entries_addr64, reloc_voff); + } break; + default: { InvalidPath; } break; + } + } + + } + ProfEnd(); +} + +internal +THREAD_POOL_TASK_FUNC(lnk_serialize_base_reloc_pages_task) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + + LNK_BaseRelocsTask *task = raw_task; + HashTable *voff_ht = hash_table_init(scratch.arena, task->page_size); + + U64 voffs_max = task->page_size; + U32 *voffs32 = push_array(scratch.arena, U32, voffs_max); + U64 *voffs64 = push_array(scratch.arena, U64, voffs_max); + + for EachInRange(page_idx, task->serialize.ranges[task_id]) { + LNK_BaseRelocPage *page = &task->serialize.pages.v[page_idx]; + + // filter out duplicate 32-bit virtual offsets + U64 voff_count32 = 0; + for EachNode(voff_n, U64Node, page->entries_addr32->first) { + if (hash_table_search_u64(voff_ht, voff_n->data)) { continue; } + hash_table_push_u64_u64(scratch.arena, voff_ht, voff_n->data, 0); + voffs32[voff_count32] = voff_n->data; + voff_count32 += 1; + } + + // filter out duplicate 64-bit virtual offsets + U64 voff_count64 = 0; + for EachNode(voff_n, U64Node, page->entries_addr64->first) { + if (hash_table_search_u64(voff_ht, voff_n->data)) { continue; } + hash_table_push_u64_u64(scratch.arena, voff_ht, voff_n->data, 0); + voffs64[voff_count64] = voff_n->data; + voff_count64 += 1; + } + + // gather step is not deterministic + radsort(voffs32, voff_count32, u32_is_before); + radsort(voffs64, voff_count64, u64_is_before); + + // find block bytes in the buffer + void *block = task->serialize.buffer + page->buffer_offset; + + // setup pointers into the block + U32 *page_voff_ptr = block; + U32 *block_size_ptr = page_voff_ptr + 1; + U16 *reloc_arr_base = (U16 *)(block_size_ptr + 1); + U16 *reloc_arr_ptr = reloc_arr_base; + + // write 32-bit relocation entries + for EachIndex(i, voff_count32) { + U64 rel_off = voffs32[i] - page->voff; + *reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_HIGHLOW, rel_off); + reloc_arr_ptr += 1; + } + + // write 64-bit relocation entries + for EachIndex(i, voff_count64) { + U64 rel_off = voffs64[i] - page->voff; + *reloc_arr_ptr = PE_BaseRelocMake(PE_BaseRelocKind_DIR64, rel_off); + reloc_arr_ptr += 1; + } + + // compute block size + U64 reloc_arr_size = IntFromPtr(reloc_arr_ptr - reloc_arr_base) * sizeof(reloc_arr_ptr[0]); + U64 block_size = sizeof(*page_voff_ptr) + sizeof(*block_size_ptr) + reloc_arr_size; + U64 block_size_aligned = AlignPow2(block_size, sizeof(U32)); + + // zero-out alignment + U64 align_size = block_size_aligned - block_size; + MemoryZero(reloc_arr_ptr, align_size); + + // write page header + *page_voff_ptr = safe_cast_u32(page->voff); + *block_size_ptr = safe_cast_u32(block_size_aligned); + + // purge hash table for the next run + hash_table_purge(voff_ht); + } + + scratch_end(scratch); + ProfEnd(); +} + internal int lnk_base_reloc_page_is_before(void *raw_a, void *raw_b) { return ((LNK_BaseRelocPage *)raw_a)->voff < ((LNK_BaseRelocPage *)raw_b)->voff; } -internal String8List +internal String8 lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, U64 objs_count, LNK_Obj **objs) { ProfBeginFunction(); - Arena *arena = tp_arena->v[0]; Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); tp_arena->v[0] = scratch.arena; TP_Temp tp_temp = tp_temp_begin(tp_arena); + + LNK_BaseRelocsTask task = {0}; + task.page_size = config->machine_page_size; + task.is_large_addr_aware = !!(config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); - LNK_BaseRelocPageArray page_arr; + LNK_BaseRelocPageArray pages = {0}; { - LNK_BaseRelocPageList *page_list_arr = push_array(scratch.arena, LNK_BaseRelocPageList, tp->worker_count); - HashTable **page_ht_arr = push_array_no_zero(scratch.arena, HashTable *, tp->worker_count); - for (U64 i = 0; i < tp->worker_count; ++i) { - page_ht_arr[i] = hash_table_init(scratch.arena, 1024); - } + LNK_BaseRelocPageList *page_lists = push_array(scratch.arena, LNK_BaseRelocPageList, tp->worker_count); + HashTable **page_ht = push_array(scratch.arena, HashTable *, tp->worker_count); + for EachIndex(i, tp->worker_count) { page_ht[i] = hash_table_init(scratch.arena, task.page_size/2); } - { - ProfBegin("Emit Relocs From Objs"); - LNK_ObjBaseRelocTask task = {0}; - task.ranges = tp_divide_work(scratch.arena, objs_count, tp->worker_count); - task.page_size = config->machine_page_size; - task.page_ht_arr = page_ht_arr; - task.list_arr = page_list_arr; - task.obj_arr = objs; - task.is_large_addr_aware = !!(config->file_characteristics & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); - tp_for_parallel(tp, tp_arena, tp->worker_count, lnk_emit_base_relocs_from_objs_task, &task); - ProfEnd(); - } + task.gather.objs = objs; + task.gather.pages = page_lists; + task.gather.page_ht = page_ht; + tp_for_parallel_prof(tp, tp_arena, objs_count, lnk_gather_base_reloc_pages_task, &task, "Gather"); - LNK_BaseRelocPageList *main_page_list = &page_list_arr[0]; - { - ProfBegin("Merge Worker Page Lists"); - HashTable *main_ht = page_ht_arr[0]; - for (U64 list_idx = 1; list_idx < tp->worker_count; ++list_idx) { - LNK_BaseRelocPageList src = page_list_arr[list_idx]; + ProfBegin("Merge Page Lists"); + LNK_BaseRelocPageList *main_page_list = &page_lists[0]; + HashTable *main_ht = page_ht[0]; + for (U64 list_idx = 1; list_idx < tp->worker_count; list_idx += 1) { + for (LNK_BaseRelocPageNode *src_page = page_lists[list_idx].first, *src_next; src_page != 0; src_page = src_next) { + src_next = src_page->next; - for (LNK_BaseRelocPageNode *src_page = src.first, *src_next; src_page != 0; src_page = src_next) { - src_next = src_page->next; + LNK_BaseRelocPageNode *page = hash_table_search_u64_raw(main_ht, src_page->v.voff); + if (page) { + // page exists, concat voffs + Assert(page != src_page); + u64_list_concat_in_place(page->v.entries_addr32, src_page->v.entries_addr32); + u64_list_concat_in_place(page->v.entries_addr64, src_page->v.entries_addr64); + } else { + // push page to the main list + SLLQueuePush(main_page_list->first, main_page_list->last, src_page); + main_page_list->count += 1; - KeyValuePair *is_page_present = hash_table_search_u64(main_ht, src_page->v.voff); - if (is_page_present) { - // page exists concat voffs - LNK_BaseRelocPageNode *page = is_page_present->value_raw; - Assert(page != src_page); - u64_list_concat_in_place(&page->v.entries_addr32, &src_page->v.entries_addr32); - u64_list_concat_in_place(&page->v.entries_addr64, &src_page->v.entries_addr64); - } else { - // push page to main list - SLLQueuePush(main_page_list->first, main_page_list->last, src_page); - main_page_list->count += 1; - - // store lookup voff - hash_table_push_u64_raw(scratch.arena, main_ht, src_page->v.voff, src_page); - } + // store lookup voff + hash_table_push_u64_raw(scratch.arena, main_ht, src_page->v.voff, src_page); } } - ProfEnd(); } + ProfEnd(); ProfBegin("Page List -> Array"); - page_arr.count = 0; - page_arr.v = push_array_no_zero(scratch.arena, LNK_BaseRelocPage, main_page_list->count); - for (LNK_BaseRelocPageNode* n = main_page_list->first; n != 0; n = n->next) { - page_arr.v[page_arr.count++] = n->v; + pages.v = push_array_no_zero(scratch.arena, LNK_BaseRelocPage, main_page_list->count); + for EachNode(n, LNK_BaseRelocPageNode, main_page_list->first) { pages.v[pages.count++] = n->v; } + ProfEnd(); + } + + ProfBeginV("Sort Pages [Count %llu]", pages.count); + radsort(pages.v, pages.count, lnk_base_reloc_page_is_before); + ProfEnd(); + + String8 base_relocs = {0}; + { + ProfBegin("Compute Buffer Size"); + U64 buffer_size = 0; + for EachIndex(page_idx, pages.count) { + LNK_BaseRelocPage *page = &pages.v[page_idx]; + page->buffer_offset = buffer_size; + buffer_size += /* page base voff */ sizeof(U32) + /* size of block */ sizeof(U32); // header + buffer_size += sizeof(U16)*page->entries_addr32->count; // 32-bit voff entries + buffer_size += sizeof(U16)*page->entries_addr64->count; // 64-bit voff entries + buffer_size = AlignPow2(buffer_size, sizeof(U32)); } ProfEnd(); - ProfBegin("Sort Pages on VOFF"); - radsort(page_arr.v, page_arr.count, lnk_base_reloc_page_is_before); + ProfBeginV("Alloc Buffer [%M]", buffer_size); + U8 *buffer = push_array_no_zero(arena, U8, buffer_size); ProfEnd(); + + task.serialize.buffer_size = buffer_size; + task.serialize.buffer = buffer; + task.serialize.pages = pages; + task.serialize.ranges = tp_divide_work(scratch.arena, pages.count, tp->worker_count); + tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_serialize_base_reloc_pages_task, &task, "Serialize"); + + base_relocs = str8(task.serialize.buffer, task.serialize.buffer_size); } - - String8List result = {0}; - if (page_arr.count) { - ProfBegin("Serialize Pages"); - HashTable *voff_ht = hash_table_init(scratch.arena, config->machine_page_size); - for (U64 page_idx = 0; page_idx < page_arr.count; ++page_idx) { - LNK_BaseRelocPage *page = &page_arr.v[page_idx]; - U64 total_entry_count = 0; - total_entry_count += page->entries_addr32.count; - total_entry_count += page->entries_addr64.count; - - U32 *page_voff_ptr; - U32 *block_size_ptr; - U16 *reloc_arr_base; - - // push buffer - U64 buf_size = AlignPow2(sizeof(*page_voff_ptr) + sizeof(*block_size_ptr) + sizeof(*reloc_arr_base)*total_entry_count, sizeof(U32)); - void *buf = push_array_no_zero(arena, U8, buf_size); - - // setup pointers into buffer - page_voff_ptr = buf; - block_size_ptr = page_voff_ptr + 1; - reloc_arr_base = (U16*)(block_size_ptr + 1); - - // write 32-bit relocations - U16 *reloc_arr_ptr = reloc_arr_base; - for (U64Node *i = page->entries_addr32.first; i != 0; i = i->next) { - // was base reloc_entry made? - if (hash_table_search_u64(voff_ht, i->data)) { - continue; - } - hash_table_push_u64_u64(scratch.arena, voff_ht, i->data, 0); - - // write entry - U64 rel_off = i->data - page->voff; - Assert(rel_off <= config->machine_page_size); - *reloc_arr_ptr++ = PE_BaseRelocMake(PE_BaseRelocKind_HIGHLOW, rel_off); - } - - // write 64-bit relocations - for (U64Node *i = page->entries_addr64.first; i != 0; i = i->next) { - // was base reloc entry made? - if (hash_table_search_u64(voff_ht, i->data)) { - continue; - } - hash_table_push_u64_u64(scratch.arena, voff_ht, i->data, 0); - - // write entry - U64 rel_off = i->data - page->voff; - Assert(rel_off <= config->machine_page_size); - *reloc_arr_ptr++ = PE_BaseRelocMake(PE_BaseRelocKind_DIR64, rel_off); - } - - // write pad - U64 pad_reloc_count = AlignPadPow2(total_entry_count, sizeof(reloc_arr_ptr[0])); - MemoryZeroTyped(reloc_arr_ptr, pad_reloc_count); // fill pad with PE_BaseRelocKind_ABSOLUTE - reloc_arr_ptr += pad_reloc_count; - - // compute block size - U64 reloc_arr_size = (U64)((U8*)reloc_arr_ptr - (U8*)reloc_arr_base); - U64 block_size = sizeof(*page_voff_ptr) + sizeof(*block_size_ptr) + reloc_arr_size; - - // write header - *page_voff_ptr = safe_cast_u32(page->voff); - *block_size_ptr = safe_cast_u32(block_size); - Assert(*block_size_ptr <= buf_size); - - // push page - str8_list_push(arena, &result, str8(buf, buf_size)); - - // purge voffs for next page - hash_table_purge(voff_ht); - } - ProfEnd(); - } - tp_temp_end(tp_temp); // scratch is cleared here tp_arena->v[0] = arena; - ProfEnd(); - return result; + return base_relocs; } internal String8List @@ -4374,15 +4369,15 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // build base relocs if (~config->flags & LNK_ConfigFlag_Fixed) { - String8List base_relocs_data = lnk_build_base_relocs(tp, arena, config, objs_count, objs); - if (base_relocs_data.total_size) { + String8 base_relocs_data = lnk_build_base_relocs(tp, arena, config, objs_count, objs); + if (base_relocs_data.size) { LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), PE_RELOC_SECTION_FLAGS); LNK_SectionContribChunk *first_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1, str8_zero()); LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(first_sc_chunk, 1); - sc->first_data_node = *base_relocs_data.first; - sc->last_data_node = base_relocs_data.last; - sc->align = 1; - sc->u.obj_idx = max_U32; + sc->first_data_node.string = base_relocs_data; + sc->last_data_node = &sc->first_data_node; + sc->align = 1; + sc->u.obj_idx = max_U32; lnk_finalize_section_layout(reloc, config->file_align, config->function_pad_min); lnk_assign_section_virtual_space(reloc, config->sect_align, &voff_cursor); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index bed105b2..8fb16449 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -152,9 +152,10 @@ typedef struct AlignType(16) LNK_RelocRefsList typedef struct LNK_BaseRelocPage { - U64 voff; - U64List entries_addr32; - U64List entries_addr64; + U32 buffer_offset; + U32 voff; + U64List *entries_addr32; + U64List *entries_addr64; } LNK_BaseRelocPage; typedef struct LNK_BaseRelocPageNode @@ -251,13 +252,22 @@ typedef struct typedef struct { - Rng1U64 *ranges; - U64 page_size; - LNK_BaseRelocPageList *list_arr; - LNK_Obj **obj_arr; - HashTable **page_ht_arr; - B32 is_large_addr_aware; -} LNK_ObjBaseRelocTask; + U64 page_size; + B32 is_large_addr_aware; + union { + struct { + LNK_Obj **objs; + LNK_BaseRelocPageList *pages; + HashTable **page_ht; + } gather; + struct { + U64 buffer_size; + U8 *buffer; + LNK_BaseRelocPageArray pages; + Rng1U64 *ranges; + } serialize; + }; +} LNK_BaseRelocsTask; typedef struct { @@ -351,7 +361,7 @@ internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *c // --- Win32 Image ------------------------------------------------------------- internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag); -internal String8List lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs); +internal String8 lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs); internal String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size); internal LNK_ImageContext lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, U64 obj_count, LNK_Obj **objs); From 06e895be7c000bc6622d3b37a88a73dae3389c9f Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 23 Sep 2025 06:37:39 -0700 Subject: [PATCH 256/302] organize task structs --- src/linker/lnk.h | 63 +++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 8fb16449..fd96e826 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -194,6 +194,33 @@ typedef struct LNK_RelocRefsList *reloc_refs; } LNK_OptRefTask; +typedef struct +{ + String8 image_data; + LNK_Obj **objs; + U64 image_base; + COFF_SectionHeader **image_section_table; +} LNK_ObjRelocPatcher; + +typedef struct +{ + U64 page_size; + B32 is_large_addr_aware; + union { + struct { + LNK_Obj **objs; + LNK_BaseRelocPageList *pages; + HashTable **page_ht; + } gather; + struct { + U64 buffer_size; + U8 *buffer; + LNK_BaseRelocPageArray pages; + Rng1U64 *ranges; + } serialize; + }; +} LNK_BaseRelocsTask; + typedef struct LNK_ImageFillNode { U64 base_foff; @@ -241,42 +268,6 @@ typedef struct } u; } LNK_BuildImageTask; -typedef struct -{ - U64 page_size; - Rng1U64 *range_arr; - LNK_BaseRelocPageList *list_arr; - HashTable **page_ht_arr; - B32 is_large_addr_aware; -} LNK_BaseRelocTask; - -typedef struct -{ - U64 page_size; - B32 is_large_addr_aware; - union { - struct { - LNK_Obj **objs; - LNK_BaseRelocPageList *pages; - HashTable **page_ht; - } gather; - struct { - U64 buffer_size; - U8 *buffer; - LNK_BaseRelocPageArray pages; - Rng1U64 *ranges; - } serialize; - }; -} LNK_BaseRelocsTask; - -typedef struct -{ - String8 image_data; - LNK_Obj **objs; - U64 image_base; - COFF_SectionHeader **image_section_table; -} LNK_ObjRelocPatcher; - typedef struct { String8 path; From 647bc4206fd927da2c894a50d97b6fdd1905a6d2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 23 Sep 2025 19:34:19 -0700 Subject: [PATCH 257/302] minor typo --- src/linker/lnk_debug_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index b209ee00..faf449a1 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -747,7 +747,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla cv.type_server_count = ts_path_arr.count; cv.type_server_path_arr = ts_path_arr.v; cv.ts_to_obj_arr = ts_to_obj_arr; - cv.obj_arr = obj_arr; + cv.obj_arr = sorted_obj_arr; cv.pch_arr = pch_arr; cv.debug_s_arr = sorted_debug_s_arr; cv.debug_p_arr = sorted_debug_p_arr; From 18b5e270155c84d81a06655543c1cbe9fe67d86a Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 24 Sep 2025 06:46:37 -0700 Subject: [PATCH 258/302] change log --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c818c936 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log v9.22.0-alpha + +## Linker + +- Changed symbol resolution in libaries to match MSVC behavior. +- Optimized image building step to reduce memory usage. +- Linker memory maps all input files by default to lower memory usage. (`/RAD_MEMORY_MAP_FILES`) +- If debug info is available, linker uses it to show file and line number for unresolved relocations. +- Improved base relocation build performance for large images, cutting build time by 70%. +- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability with existing response files +- Implemented section garbage collection (`/OPT:REF`) +- Fixed bug where thread local variables pointed to incorrect types. +- Changed rules for weak and undefined symbols, now weak symbol is not allowed to replace an undefined symbol. +- Linker no longer creates thunks for imports that don't require them. + + From 0679b4b04c82bf1cc488f889eb559a725ee4fb97 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 13:43:51 -0700 Subject: [PATCH 259/302] #if 0 out old evictor thread for ptr graph --- src/ptr_graph_cache/ptr_graph_cache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c index 7b624fba..cbf81bf7 100644 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ b/src/ptr_graph_cache/ptr_graph_cache.c @@ -151,6 +151,7 @@ ptg_builder_thread__entry_point(void *p) internal void ptg_evictor_thread__entry_point(void *p) { +#if 0 for(;;) { U64 check_time_us = os_now_microseconds(); @@ -199,4 +200,5 @@ ptg_evictor_thread__entry_point(void *p) } os_sleep_milliseconds(1000); } +#endif } From 4b335103bc17b45859126adb0ac53cffd61c3d2e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 15:04:45 -0700 Subject: [PATCH 260/302] begin moving call stack computation / cache to artifact cache; fix incorrect broadcast val location --- src/artifact_cache/artifact_cache.c | 9 ++ src/artifact_cache/artifact_cache.h | 1 + src/base/base_entry_point.c | 2 +- src/ctrl/ctrl_core.c | 189 +++++++++++++++++++++++++++- src/ctrl/ctrl_core.h | 7 ++ src/raddbg/raddbg_core.c | 4 + src/raddbg/raddbg_core.h | 1 + src/raddbg/raddbg_eval.c | 2 +- 8 files changed, 212 insertions(+), 3 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 7c074d9d..1e0b647f 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -66,6 +66,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); //- rjf: cache * key -> existing artifact + B32 artifact_is_stale = 0; B32 got_artifact = 0; B32 need_request = 0; AC_Artifact artifact = {0}; @@ -78,6 +79,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 if(ins_atomic_u64_eval(&n->completion_count) != 0 && (n->gen == params->gen || !params->wait_for_fresh)) { got_artifact = 1; + artifact_is_stale = (n->gen == params->gen); artifact = n->val; access_touch(access, &n->access_pt, stripe->cv); } @@ -150,6 +152,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->gen == params->gen) || !params->wait_for_fresh || out_of_time)) { got_artifact = 1; + artifact_is_stale = (node->gen == params->gen); artifact = node->val; access_touch(access, &node->access_pt, stripe->cv); } @@ -165,6 +168,12 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } } + //- rjf: report staleness + if(params->stale_out) + { + params->stale_out[0] = artifact_is_stale; + } + return artifact; } diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 303c1d43..4f219dfd 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -27,6 +27,7 @@ struct AC_ArtifactParams U64 slots_count; U64 gen; B32 wait_for_fresh; + B32 *stale_out; }; //////////////////////////////// diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 751b8254..e0cadd76 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -104,6 +104,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) //- rjf: launch async threads Thread *async_threads = 0; U64 async_threads_count = 0; + U64 lane_broadcast_val = 0; { U64 num_main_threads = 1; #if defined(CTRL_CORE_H) @@ -113,7 +114,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads); num_async_threads -= num_main_threads_clamped; num_async_threads = Max(1, num_async_threads); - U64 lane_broadcast_val = 0; Barrier barrier = barrier_alloc(num_async_threads); LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads); async_threads_count = num_async_threads; diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index f063d1f6..5ed8b14d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7575,6 +7575,7 @@ ctrl_memory_artifact_create(String8 key, B32 *retry_out) else if(range_arena != 0) { arena_release(range_arena); + retry_out[0] = 1; } //- rjf: wakeup on new reads @@ -7617,10 +7618,196 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, } key_data = {process, vaddr_range, zero_terminated}; String8 key = str8_struct(&key_data); Access *access = access_open(); - AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, .gen = ctrl_mem_gen(), .slots_count = 2048); + AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, .gen = ctrl_mem_gen(), .slots_count = 2048, .stale_out = out_is_stale); C_Key content_key = {0}; MemoryCopyStruct(&content_key, &artifact); access_close(access); ProfEnd(); return content_key; } + +//////////////////////////////// +//~ rjf: Call Stack Artifact Cache Hooks / Lookups + +internal AC_Artifact +ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) +{ + AC_Artifact artifact = {0}; + if(lane_idx() == 0) + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack key + CTRL_Handle thread_handle = {0}; + str8_deserial_read_struct(key, 0, &thread_handle); + + //- rjf: produce mini entity context for just this call stack build + CTRL_EntityCtx *entity_ctx = push_array(scratch.arena, CTRL_EntityCtx, 1); + MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + { + CTRL_EntityCtx *src_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_EntityCtx *dst_ctx = entity_ctx; + { + dst_ctx->root = &ctrl_entity_nil; + dst_ctx->hash_slots_count = 1024; + dst_ctx->hash_slots = push_array(scratch.arena, CTRL_EntityHashSlot, dst_ctx->hash_slots_count); + MemoryCopyArray(dst_ctx->entity_kind_counts, src_ctx->entity_kind_counts); + MemoryCopyArray(dst_ctx->entity_kind_alloc_gens, src_ctx->entity_kind_alloc_gens); + } + CTRL_Entity *src_thread = ctrl_entity_from_handle(src_ctx, thread_handle); + CTRL_Entity *src_process = ctrl_process_from_entity(src_thread); + { + CTRL_EntityRec rec = {0}; + CTRL_Entity *dst_parent = &ctrl_entity_nil; + for(CTRL_Entity *src_e = src_process; src_e != &ctrl_entity_nil; src_e = rec.next) + { + rec = ctrl_entity_rec_depth_first_pre(src_e, src_process); + + // rjf: copy this entity + CTRL_Entity *dst_e = push_array(scratch.arena, CTRL_Entity, 1); + { + dst_e->first = dst_e->last = dst_e->next = dst_e->prev = &ctrl_entity_nil; + dst_e->parent = dst_parent; + dst_e->kind = src_e->kind; + dst_e->arch = src_e->arch; + dst_e->is_frozen = src_e->is_frozen; + dst_e->is_soloed = src_e->is_soloed; + dst_e->rgba = src_e->rgba; + dst_e->handle = src_e->handle; + dst_e->id = src_e->id; + dst_e->vaddr_range = src_e->vaddr_range; + dst_e->stack_base = src_e->stack_base; + dst_e->timestamp = src_e->timestamp; + dst_e->bp_flags = src_e->bp_flags; + dst_e->string = push_str8_copy(scratch.arena, src_e->string); + } + if(dst_parent == &ctrl_entity_nil) + { + dst_ctx->root = dst_e; + } + else + { + DLLPushBack_NPZ(&ctrl_entity_nil, dst_parent->first, dst_parent->last, dst_e, next, prev); + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_handle(dst_e->handle); + U64 slot_idx = hash%dst_ctx->hash_slots_count; + CTRL_EntityHashSlot *slot = &dst_ctx->hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->entity->handle, dst_e->handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(scratch.arena, CTRL_EntityHashNode, 1); + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = dst_e; + } + } + + // rjf: push/pop + if(rec.push_count) + { + dst_parent = dst_e; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_parent = dst_parent->parent; + } + } + } + } + + //- rjf: compute call stack + B32 good = 0; + Arena *arena = arena_alloc(); + CTRL_CallStack *call_stack = push_array(arena, CTRL_CallStack, 1); + { + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); + CTRL_Entity *process = ctrl_process_from_entity(thread); + U64 pre_reg_gen = 0; + U64 post_reg_gen = 0; + U64 pre_mem_gen = 0; + U64 post_mem_gen = 0; + CTRL_Unwind unwind = {0}; + { + pre_reg_gen = ctrl_reg_gen(); + pre_mem_gen = ctrl_mem_gen(); + unwind = ctrl_unwind_from_thread(arena, entity_ctx, thread_handle, os_now_microseconds()+5000); + if(unwind.flags == 0) + { + good = 1; + call_stack[0] = ctrl_call_stack_from_unwind(arena, process, &unwind); + } + post_reg_gen = ctrl_reg_gen(); + post_mem_gen = ctrl_mem_gen(); + } + if(pre_reg_gen != post_reg_gen || pre_mem_gen != post_mem_gen) + { + good = 0; + } + } + + //- rjf: broadcast update + if(good && ctrl_state->wakeup_hook != 0) + { + ctrl_state->wakeup_hook(); + } + + //- rjf: bundle call stack as artifact + if(good) + { + artifact.u64[0] = (U64)arena; + artifact.u64[1] = (U64)call_stack; + } + + //- rjf: release results on bad + if(!good) + { + arena_release(arena); + } + + //- rjf: retry on bad + if(!good) + { + retry_out[0] = 1; + } + + scratch_end(scratch); + } + lane_sync_u64(&artifact.u64[0], 0); + lane_sync_u64(&artifact.u64[1], 0); + return artifact; +} + +internal void +ctrl_call_stack_artifact_destroy(AC_Artifact artifact) +{ + Arena *arena = (Arena *)artifact.u64[0]; + if(arena != 0) + { + arena_release(arena); + } +} + +internal CTRL_CallStack +ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us) +{ + CTRL_CallStack result = {0}; + { + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&thread_handle), ctrl_call_stack_artifact_create, ctrl_call_stack_artifact_destroy, endt_us, .gen = ctrl_mem_gen() + ctrl_reg_gen()); + if(artifact.u64[1] != 0) + { + MemoryCopyStruct(&result, (CTRL_CallStack *)artifact.u64[1]); + } + } + return result; +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 03e959c9..44060551 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1257,4 +1257,11 @@ internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); internal C_Key ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); +//////////////////////////////// +//~ rjf: Call Stack Artifact Cache Hooks / Lookups + +internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *retry_out); +internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); +internal CTRL_CallStack ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); + #endif // CTRL_CORE_H diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 18dbecf8..2db08019 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11495,8 +11495,10 @@ rd_frame(void) ////////////////////////////// //- rjf: push frame scopes // + Access *frame_access_restore = rd_state->frame_access; DI_Scope *frame_di_scope_restore = rd_state->frame_di_scope; CTRL_Scope *frame_ctrl_scope_restore = rd_state->frame_ctrl_scope; + rd_state->frame_access = access_open(); rd_state->frame_di_scope = di_scope_open(); rd_state->frame_ctrl_scope = ctrl_scope_open(); rd_state->got_frame_call_stack_tree = 0; @@ -17323,8 +17325,10 @@ rd_frame(void) // will sleep for vsync, and we do not want to hold handles for long, // since eviction threads may be waiting to get rid of stuff. // + access_close(rd_state->frame_access); di_scope_close(rd_state->frame_di_scope); ctrl_scope_close(rd_state->frame_ctrl_scope); + rd_state->frame_access = frame_access_restore; rd_state->frame_di_scope = frame_di_scope_restore; rd_state->frame_ctrl_scope = frame_ctrl_scope_restore; diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 2d0d87af..388be833 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -599,6 +599,7 @@ struct RD_State // rjf: frame parameters F32 frame_dt; + Access *frame_access; DI_Scope *frame_di_scope; CTRL_Scope *frame_ctrl_scope; CTRL_CallStackTree frame_call_stack_tree; diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index c1795d34..d6b98a8b 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -968,7 +968,7 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack) B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); accel->arch = entity->arch; accel->process = ctrl_process_from_entity(entity)->handle; - accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + accel->call_stack = ctrl_call_stack_from_thread_new(rd_state->frame_access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); } scratch_end(scratch); } From 684f6344c58647f20077a3c11571f99c46e760e1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 15:08:07 -0700 Subject: [PATCH 261/302] switch to old call stack cache for now --- src/raddbg/raddbg_eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index d6b98a8b..c1795d34 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -968,7 +968,7 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack) B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); accel->arch = entity->arch; accel->process = ctrl_process_from_entity(entity)->handle; - accel->call_stack = ctrl_call_stack_from_thread_new(rd_state->frame_access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); } scratch_end(scratch); } From bdfd4c14ae2824f62e5f27471531572e8e33ca9e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 15:40:11 -0700 Subject: [PATCH 262/302] eliminate old file stream cache, just use simplified cache for linting filesystem changes; otherwise switch everything to artifact cache --- src/disasm/disasm.c | 2 +- src/file_stream/file_stream.c | 296 ++++++++++++++-------------------- src/file_stream/file_stream.h | 85 ++-------- src/raddbg/raddbg_core.c | 4 +- 4 files changed, 132 insertions(+), 255 deletions(-) diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 783a91a3..e2d8f743 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -362,7 +362,7 @@ dasm_artifact_create(String8 key, B32 *retry_out) { // TODO(rjf): need redirection path - this may map to a different path on the local machine, // need frontend to communicate path remapping info to this layer - C_Key key = fs_key_from_path_range_new(file_normalized_full_path, r1u64(0, max_U64), 0); + C_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 4c4d44f0..93711f11 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -4,34 +4,6 @@ #undef LAYER_COLOR #define LAYER_COLOR 0xfffa00ff -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -fs_little_hash_from_string(String8 string) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + string.str[i]; - } - return result; -} - -internal U128 -fs_big_hash_from_string_range(String8 string, Rng1U64 range) -{ - Temp scratch = scratch_begin(0, 0); - U64 buffer_size = string.size + sizeof(U64)*2; - U8 *buffer = push_array_no_zero(scratch.arena, U8, buffer_size); - MemoryCopy(buffer, string.str, string.size); - MemoryCopy(buffer + string.size, &range.min, sizeof(range.min)); - MemoryCopy(buffer + string.size + sizeof(range.min), &range.max, sizeof(range.max)); - U128 hash = c_hash_from_data(str8(buffer, buffer_size)); - scratch_end(scratch); - return hash; -} - //////////////////////////////// //~ rjf: Top-Level API @@ -43,17 +15,8 @@ fs_init(void) fs_shared->arena = arena; fs_shared->change_gen = 1; fs_shared->slots_count = 1024; - fs_shared->stripes_count = os_get_system_info()->logical_processor_count; fs_shared->slots = push_array(arena, FS_Slot, fs_shared->slots_count); - fs_shared->stripes = push_array(arena, FS_Stripe, fs_shared->stripes_count); - for(U64 idx = 0; idx < fs_shared->stripes_count; idx += 1) - { - fs_shared->stripes[idx].arena = arena_alloc(); - fs_shared->stripes[idx].cv = cond_var_alloc(); - fs_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - } - fs_shared->req_mutex = mutex_alloc(); - fs_shared->req_arena = arena_alloc(); + fs_shared->stripes = stripe_array_alloc(arena); } //////////////////////////////// @@ -68,6 +31,16 @@ fs_change_gen(void) //////////////////////////////// //~ rjf: Cache Interaction +internal C_Key +fs_content_key_from_artifact_key(String8 key) +{ + C_Key content_key = {0}; + { + content_key.id.u128[0] = u128_hash_from_str8(key); + } + return content_key; +} + internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out) { @@ -150,19 +123,17 @@ fs_artifact_create(String8 key, B32 *retry_out) } //- rjf: form content key - C_Key content_key = {0}; - { - content_key.id.u128[0] = u128_hash_from_str8(key); - } + C_Key content_key = fs_content_key_from_artifact_key(key); //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file; // otherwise submit data + B32 read_good = 0; if(lane_idx() == 0) { - B32 read_good = (pre_props.modified == post_props.modified && - pre_props.size == post_props.size && - data_buffer_size == total_bytes_read && - (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + data_buffer_size == total_bytes_read && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); if(!read_good) { retry_out[0] = 1; @@ -182,6 +153,45 @@ fs_artifact_create(String8 key, B32 *retry_out) } lane_sync(); + //- rjf: if the read was good, record this path's timestamp in this layer's path info cache + U64 path_hash = u64_hash_from_str8(path); + if(lane_idx() == 0 && read_good) + { + U64 slot_idx = path_hash%fs_shared->slots_count; + FS_Slot *slot = &fs_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&fs_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + FS_Node *node = 0; + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0)) + { + node = n; + break; + } + } + if(node == 0) + { + node = stripe->free; + if(node) + { + stripe->free = node->next; + } + else + { + node = push_array_no_zero(stripe->arena, FS_Node, 1); + } + MemoryZeroStruct(node); + node->path = str8_copy(stripe->arena, path); + DLLPushBack(slot->first, slot->last, node); + } + node->last_modified_timestamp = pre_props.modified; + node->size = pre_props.size; + } + } + lane_sync(); + //- rjf: bundle content key as artifact AC_Artifact artifact = {0}; StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); @@ -197,11 +207,12 @@ fs_artifact_destroy(AC_Artifact artifact) { C_Key key = {0}; MemoryCopyStruct(&key, &artifact); + key._padding_ = 0; c_close_key(key); } internal C_Key -fs_key_from_path_range_new(String8 path, Rng1U64 range, U64 endt_us) +fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { C_Key result = {0}; Temp scratch = scratch_begin(0, 0); @@ -212,142 +223,37 @@ fs_key_from_path_range_new(String8 path, Rng1U64 range, U64 endt_us) str8_list_push(scratch.arena, &key_parts, path); str8_list_push(scratch.arena, &key_parts, str8_struct(&range)); String8 key = str8_list_join(scratch.arena, &key_parts, 0); - AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us); + + //- rjf: find generation number for this key + U64 gen = 0; + { + U64 hash = u64_hash_from_str8(path); + U64 slot_idx = hash%fs_shared->slots_count; + FS_Slot *slot = &fs_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&fs_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) + { + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(path, n->path, 0)) + { + gen = n->gen; + break; + } + } + } + } + + //- rjf: map to artifact + AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us, .gen = gen); MemoryCopyStruct(&result, &artifact); + result._padding_ = 0; } access_close(access); scratch_end(scratch); return result; } -internal C_Key -fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) -{ - Temp scratch = scratch_begin(0, 0); - - //- rjf: unpack args - path = path_normalized_from_string(scratch.arena, path); - U64 path_little_hash = fs_little_hash_from_string(path); - U64 path_slot_idx = path_little_hash%fs_shared->slots_count; - U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count; - FS_Slot *path_slot = &fs_shared->slots[path_slot_idx]; - FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; - - //- rjf: get root for this path - on 1st try (read mode), try to read, on 2nd try (write mode), create node - C_Root root = {0}; - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 node_found = 0; - RWMutexScope(path_stripe->rw_mutex, write_mode) - { - for(FS_Node *n = path_slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, 0)) - { - node_found = 1; - root = n->root; - break; - } - } - if(write_mode && !node_found) - { - FS_Node *node = push_array(path_stripe->arena, FS_Node, 1); - SLLQueuePush(path_slot->first, path_slot->last, node); - node->path = push_str8_copy(path_stripe->arena, path); - node->root = c_root_alloc(); - node->slots_count = 64; - node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count); - root = node->root; - } - } - if(node_found) - { - break; - } - } - - //- rjf: build a key for this path/range combo - C_Key key = c_key_make(root, c_id_make(range.min, range.max)); - - //- rjf: if the most recent hash for this key is zero, then try to submit a new - // request to pull it in. - if(u128_match(c_hash_from_key(key, 0), u128_zero())) - { - // rjf: loop: request, check for results, return until we can't - RWMutexScope(path_stripe->rw_mutex, 1) for(;;) - { - // rjf: path -> node - FS_Node *node = 0; - for(FS_Node *n = path_slot->first; n != 0; n = n->next) - { - if(str8_match(path, n->path, 0)) - { - node = n; - break; - } - } - - // rjf: no node? -> weird case, node should've been made at this point. - if(node == 0) - { - break; - } - - // rjf: range -> node - U64 range_hash = fs_little_hash_from_string(str8_struct(&key.id)); - U64 range_slot_idx = range_hash%node->slots_count; - FS_RangeSlot *range_slot = &node->slots[range_slot_idx]; - FS_RangeNode *range_node = 0; - for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next) - { - if(c_id_match(n->id, key.id)) - { - range_node = n; - break; - } - } - - // rjf: range node does not exist? create & store - if(range_node == 0) - { - range_node = push_array(path_stripe->arena, FS_RangeNode, 1); - SLLQueuePush(range_slot->first, range_slot->last, range_node); - range_node->id = key.id; - } - - // rjf: push request - if(range_node->working_count == 0) - { - range_node->working_count += 1; - MutexScope(fs_shared->req_mutex) - { - FS_RequestNode *n = push_array(fs_shared->req_arena, FS_RequestNode, 1); - SLLQueuePush(fs_shared->first_req, fs_shared->last_req, n); - fs_shared->req_count += 1; - n->v.key = key; - n->v.path = str8_copy(fs_shared->req_arena, path); - n->v.range = range; - } - cond_var_broadcast(async_tick_start_cond_var); - } - - // rjf: have time to wait? -> wait on this stripe; otherwise exit - B32 have_results = !u128_match(c_hash_from_key(key, 0), u128_zero()); - if(!have_results && os_now_microseconds() < endt_us) - { - cond_var_wait_rw(path_stripe->cv, path_stripe->rw_mutex, 1, endt_us); - } - else - { - break; - } - } - } - - scratch_end(scratch); - return key; -} - internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { @@ -372,8 +278,42 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) internal void fs_async_tick(void) { -#if 0 ProfBeginFunction(); + + //- rjf: detect changed timestamps for active paths + { + Rng1U64 range = lane_range(fs_shared->slots_count); + for EachInRange(slot_idx, range) + { + FS_Slot *slot = &fs_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&fs_shared->stripes, slot_idx); + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + B32 found_work = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + FileProperties props = os_properties_from_file_path(n->path); + if(props.modified != n->last_modified_timestamp) + { + found_work = 1; + if(write_mode) + { + n->gen += 1; + } + } + } + } + if(!found_work) + { + break; + } + } + } + } + +#if 0 Temp scratch = scratch_begin(0, 0); //- rjf: do detection pass @@ -530,6 +470,6 @@ fs_async_tick(void) lane_sync(); scratch_end(scratch); - ProfEnd(); #endif + ProfEnd(); } diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 99217712..8b9306b2 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -5,38 +5,17 @@ #define FILE_STREAM_H //////////////////////////////// -//~ rjf: Per-Path Info Cache Types - -typedef struct FS_RangeNode FS_RangeNode; -struct FS_RangeNode -{ - FS_RangeNode *next; - C_ID id; - U64 working_count; -}; - -typedef struct FS_RangeSlot FS_RangeSlot; -struct FS_RangeSlot -{ - FS_RangeNode *first; - FS_RangeNode *last; -}; +//~ rjf: Path Cache typedef struct FS_Node FS_Node; struct FS_Node { FS_Node *next; - - // rjf: file metadata + FS_Node *prev; String8 path; - FileProperties props; - - // rjf: hash store root - C_Root root; - - // rjf: sub-table of per-requested-file-range info - U64 slots_count; - FS_RangeSlot *slots; + U64 gen; + U64 last_modified_timestamp; + U64 size; }; typedef struct FS_Slot FS_Slot; @@ -46,54 +25,17 @@ struct FS_Slot FS_Node *last; }; -typedef struct FS_Stripe FS_Stripe; -struct FS_Stripe -{ - Arena *arena; - CondVar cv; - RWMutex rw_mutex; -}; - //////////////////////////////// //~ rjf: Shared State Bundle -typedef struct FS_Request FS_Request; -struct FS_Request -{ - FS_Request *next; - C_Key key; - String8 path; - Rng1U64 range; -}; - -typedef struct FS_RequestNode FS_RequestNode; -struct FS_RequestNode -{ - FS_RequestNode *next; - FS_Request v; -}; - typedef struct FS_Shared FS_Shared; struct FS_Shared { Arena *arena; U64 change_gen; - - // rjf: path info cache U64 slots_count; - U64 stripes_count; FS_Slot *slots; - FS_Stripe *stripes; - - // rjf: requests - Mutex req_mutex; - Arena *req_arena; - FS_RequestNode *first_req; - FS_RequestNode *last_req; - U64 req_count; - - // rjf: request take counter - U64 lane_req_take_counter; + StripeArray stripes; }; //////////////////////////////// @@ -101,12 +43,6 @@ struct FS_Shared global FS_Shared *fs_shared = 0; -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 fs_little_hash_from_string(String8 string); -internal U128 fs_big_hash_from_string_range(String8 string, Rng1U64 range); - //////////////////////////////// //~ rjf: Top-Level API @@ -118,16 +54,17 @@ internal void fs_init(void); internal U64 fs_change_gen(void); //////////////////////////////// -//~ rjf: Cache Interaction +//~ rjf: Artifact Cache Hooks / Accessing API + +internal C_Key fs_content_key_from_artifact_key(String8 key); internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); -internal C_Key fs_key_from_path_range_new(String8 path, Rng1U64 range, U64 endt_us); -#define fs_key_from_path(path, endt_us) fs_key_from_path_range_new((path), r1u64(0, max_U64), (endt_us)) - internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); +#define fs_key_from_path(path, endt_us) fs_key_from_path_range((path), r1u64(0, max_U64), (endt_us)) +#define fs_hash_from_path(path, endt_us) fs_hash_from_path_range((path), r1u64(0, max_U64), (endt_us)) //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 2db08019..f95783b3 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1779,7 +1779,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) containing_range.max -= containing_range.max%chunk_size; // rjf: map to hash - C_Key key = fs_key_from_path_range_new(file_path, containing_range, 0); + C_Key key = fs_key_from_path_range(file_path, containing_range, 0); U128 hash = c_hash_from_key(key, 0); // rjf: look up from hash store @@ -2153,7 +2153,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) { U64 file_path_string_id = space.u64_0; String8 file_path = e_string_from_id(file_path_string_id); - result = fs_key_from_path_range_new(file_path, range, 0); + result = fs_key_from_path_range(file_path, range, 0); }break; case RD_EvalSpaceKind_CtrlEntity: { From 3dc3707b22e8c55e5f0049a3ef292adeb6ecca1f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 15:41:00 -0700 Subject: [PATCH 263/302] maintain fs change gen alsog --- src/file_stream/file_stream.c | 159 +--------------------------------- 1 file changed, 1 insertion(+), 158 deletions(-) diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 93711f11..c2b77e59 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -301,6 +301,7 @@ fs_async_tick(void) if(write_mode) { n->gen += 1; + ins_atomic_u64_inc_eval(&fs_shared->change_gen); } } } @@ -313,163 +314,5 @@ fs_async_tick(void) } } -#if 0 - Temp scratch = scratch_begin(0, 0); - - //- rjf: do detection pass - { - U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; - Rng1U64 range = lane_range(fs_shared->stripes_count); - for EachInRange(stripe_idx, range) - { - FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) - { - U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; - FS_Slot *slot = &fs_shared->slots[slot_idx]; - for(FS_Node *n = slot->first; n != 0; n = n->next) - { - FileProperties props = os_properties_from_file_path(n->path); - if(props.modified != n->props.modified) - { - for(U64 range_slot_idx = 0; range_slot_idx < n->slots_count; range_slot_idx += 1) - { - for(FS_RangeNode *range_n = n->slots[range_slot_idx].first; - range_n != 0; - range_n = range_n->next) - { - C_Key key = c_key_make(n->root, range_n->id); - if(ins_atomic_u64_eval(&range_n->working_count) == 0) - { - ins_atomic_u64_inc_eval(&range_n->working_count); - MutexScope(fs_shared->req_mutex) - { - FS_RequestNode *req_n = push_array(fs_shared->req_arena, FS_RequestNode, 1); - SLLQueuePush(fs_shared->first_req, fs_shared->last_req, req_n); - fs_shared->req_count += 1; - req_n->v.key = key; - req_n->v.path = str8_copy(fs_shared->req_arena, n->path); - req_n->v.range = range; - } - } - } - } - } - } - } - } - } - - //- rjf: gather all requests - local_persist FS_Request *reqs = 0; - local_persist U64 reqs_count = 0; - if(lane_idx() == 0) MutexScope(fs_shared->req_mutex) - { - reqs_count = fs_shared->req_count; - reqs = push_array(scratch.arena, FS_Request, reqs_count); - U64 idx = 0; - for EachNode(r, FS_RequestNode, fs_shared->first_req) - { - MemoryCopyStruct(&reqs[idx], &r->v); - reqs[idx].path = str8_copy(scratch.arena, reqs[idx].path); - idx += 1; - } - arena_clear(fs_shared->req_arena); - fs_shared->first_req = fs_shared->last_req = 0; - fs_shared->req_count = 0; - fs_shared->lane_req_take_counter = 0; - } - lane_sync(); - - //- rjf: do requests - for(;;) - { - //- rjf: unpack - U64 req_num = ins_atomic_u64_inc_eval(&fs_shared->lane_req_take_counter); - if(req_num < 1 || reqs_count < req_num) - { - break; - } - U64 req_idx = req_num-1; - FS_Request *r = &reqs[req_idx]; - C_Key key = r->key; - String8 path = r->path; - Rng1U64 range = r->range; - U64 path_hash = fs_little_hash_from_string(path); - U64 path_slot_idx = path_hash%fs_shared->slots_count; - U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count; - FS_Slot *path_slot = &fs_shared->slots[path_slot_idx]; - FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx]; - - //- rjf: load - ProfBegin("load \"%.*s\"", str8_varg(path)); - FileProperties pre_props = os_properties_from_file_path(path); - U64 range_size = dim_1u64(range); - U64 read_size = Min(pre_props.size - range.min, range_size); - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); - B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); - U64 data_arena_size = read_size+ARENA_HEADER_SIZE; - data_arena_size += KB(4)-1; - data_arena_size -= data_arena_size%KB(4); - ProfBegin("allocate"); - Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); - ProfEnd(); - ProfBegin("read"); - String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size)); - ProfEnd(); - os_file_close(file); - FileProperties post_props = os_properties_from_file_path(path); - - //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file - B32 read_good = (pre_props.modified == post_props.modified && - pre_props.size == post_props.size && - read_size == data.size && - (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); - if(!read_good) - { - ProfScope("abort") - { - arena_release(data_arena); - MemoryZeroStruct(&data); - data_arena = 0; - } - } - - //- rjf: submit - else - { - ProfScope("submit") - { - c_submit_data(key, &data_arena, data); - } - } - - //- rjf: commit info to cache - ProfScope("commit to cache") MutexScopeW(path_stripe->rw_mutex) - { - FS_Node *node = 0; - for(FS_Node *n = path_slot->first; n != 0; n = n->next) - { - if(str8_match(n->path, path, 0)) - { - node = n; - break; - } - } - if(node != 0 && read_good) - { - if(node->props.modified != 0) - { - ins_atomic_u64_inc_eval(&fs_shared->change_gen); - } - node->props = post_props; - } - } - cond_var_broadcast(path_stripe->cv); - } - lane_sync(); - - scratch_end(scratch); -#endif ProfEnd(); } From 10e8a10d9bdbfa4a21898c795f031c54617ceea4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 16:06:46 -0700 Subject: [PATCH 264/302] adjust new call stack artifact cache hooks to work gracefully with terminated threads/processes --- src/ctrl/ctrl_core.c | 22 ++++++++++++---------- src/file_stream/file_stream.c | 4 +--- src/file_stream/file_stream.h | 1 - src/raddbg/raddbg_core.c | 6 +++--- src/raddbg/raddbg_eval.c | 2 +- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5ed8b14d..c9d04747 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7727,11 +7727,15 @@ ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) } //- rjf: compute call stack - B32 good = 0; - Arena *arena = arena_alloc(); - CTRL_CallStack *call_stack = push_array(arena, CTRL_CallStack, 1); + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); + B32 good = 1; + Arena *arena = 0; + CTRL_CallStack *call_stack = 0; + if(thread != &ctrl_entity_nil) { - CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); + good = 0; + arena = arena_alloc(); + call_stack = push_array(arena, CTRL_CallStack, 1); CTRL_Entity *process = ctrl_process_from_entity(thread); U64 pre_reg_gen = 0; U64 post_reg_gen = 0; @@ -7754,6 +7758,10 @@ ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) { good = 0; } + if(!good) + { + arena_release(arena); + } } //- rjf: broadcast update @@ -7769,12 +7777,6 @@ ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) artifact.u64[1] = (U64)call_stack; } - //- rjf: release results on bad - if(!good) - { - arena_release(arena); - } - //- rjf: retry on bad if(!good) { diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index c2b77e59..eb2fc240 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -184,7 +184,7 @@ fs_artifact_create(String8 key, B32 *retry_out) } MemoryZeroStruct(node); node->path = str8_copy(stripe->arena, path); - DLLPushBack(slot->first, slot->last, node); + SLLQueuePush(slot->first, slot->last, node); } node->last_modified_timestamp = pre_props.modified; node->size = pre_props.size; @@ -207,7 +207,6 @@ fs_artifact_destroy(AC_Artifact artifact) { C_Key key = {0}; MemoryCopyStruct(&key, &artifact); - key._padding_ = 0; c_close_key(key); } @@ -247,7 +246,6 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) //- rjf: map to artifact AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us, .gen = gen); MemoryCopyStruct(&result, &artifact); - result._padding_ = 0; } access_close(access); scratch_end(scratch); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 8b9306b2..9bc219ca 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -11,7 +11,6 @@ typedef struct FS_Node FS_Node; struct FS_Node { FS_Node *next; - FS_Node *prev; String8 path; U64 gen; U64 last_modified_timestamp; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index f95783b3..a0caab90 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -12493,10 +12493,10 @@ rd_frame(void) }; for EachElement(idx, table) { - C_Scope *c_scope = c_scope_open(); + Access *access = access_open(); C_Key key = table[idx].key; U128 hash = c_hash_from_key(key, 0); - String8 data = c_data_from_hash(c_scope, hash); + String8 data = c_data_from_hash(access, hash); E_Space space = e_space_make(E_SpaceKind_HashStoreKey); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); space.u64_0 = key.root.u64[0]; @@ -12505,7 +12505,7 @@ rd_frame(void) expr->mode = E_Mode_Offset; expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); e_string2expr_map_insert(scratch.arena, macro_map, table[idx].name, expr); - c_scope_close(c_scope); + access_close(access); } } #endif diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index c1795d34..d6b98a8b 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -968,7 +968,7 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack) B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); accel->arch = entity->arch; accel->process = ctrl_process_from_entity(entity)->handle; - accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + accel->call_stack = ctrl_call_stack_from_thread_new(rd_state->frame_access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); } scratch_end(scratch); } From ca7bfab7eab2b121be8902e14dd9ce116a938cb6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 24 Sep 2025 17:08:08 -0700 Subject: [PATCH 265/302] bucket artifact cache requests by wideness/priority; do high/wide, high/thin, low/wide, low/thin --- src/artifact_cache/artifact_cache.c | 282 +++++++++++++++++++++------- src/artifact_cache/artifact_cache.h | 34 +++- src/base/base_thread_context.c | 6 +- src/base/base_thread_context.h | 10 +- src/ctrl/ctrl_core.c | 18 +- src/dbg_engine/dbg_engine_core.c | 12 +- src/disasm/disasm.c | 2 +- src/file_stream/file_stream.c | 2 +- src/raddbg/raddbg_core.c | 24 +-- src/raddbg/raddbg_views.c | 12 +- src/raddbg/raddbg_widgets.c | 6 +- src/text/text.c | 2 +- 12 files changed, 289 insertions(+), 121 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 1e0b647f..b06098b8 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -13,8 +13,11 @@ ac_init(void) ac_shared->cache_slots_count = 256; ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count); ac_shared->cache_stripes = stripe_array_alloc(arena); - ac_shared->req_mutex = mutex_alloc(); - ac_shared->req_arena = arena_alloc(); + for EachElement(idx, ac_shared->req_batches) + { + ac_shared->req_batches[idx].mutex = mutex_alloc(); + ac_shared->req_batches[idx].arena = arena_alloc(); + } } //////////////////////////////// @@ -23,6 +26,8 @@ ac_init(void) internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us) { + AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1]; + //- rjf: create function -> cache AC_Cache *cache = 0; { @@ -76,7 +81,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 { if(str8_match(n->key, key, 0)) { - if(ins_atomic_u64_eval(&n->completion_count) != 0 && (n->gen == params->gen || !params->wait_for_fresh)) + if(ins_atomic_u64_eval(&n->completion_count) != 0 && (n->gen == params->gen || !(params->flags & AC_Flag_WaitForFresh))) { got_artifact = 1; artifact_is_stale = (n->gen == params->gen); @@ -129,18 +134,27 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 // TODO(rjf): string allocator for keys node->key = str8_copy(stripe->arena, key); node->working_count = 1; + node->evict_threshold_us = params->evict_threshold_us; } // rjf: request if(need_request) { need_request = 0; - MutexScope(ac_shared->req_mutex) + MutexScope(req_batch->mutex) { - AC_RequestNode *n = push_array(ac_shared->req_arena, AC_RequestNode, 1); - SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); - ac_shared->req_count += 1; - n->v.key = str8_copy(ac_shared->req_arena, key); + AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1); + if(params->flags & AC_Flag_Wide) + { + SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n); + req_batch->wide_count += 1; + } + else + { + SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n); + req_batch->thin_count += 1; + } + n->v.key = str8_copy(req_batch->arena, key); n->v.gen = params->gen; n->v.create = params->create; } @@ -149,7 +163,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } // rjf: get value from node, if possible - if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->gen == params->gen) || !params->wait_for_fresh || out_of_time)) + if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time)) { got_artifact = 1; artifact_is_stale = (node->gen == params->gen); @@ -185,7 +199,9 @@ ac_async_tick(void) { Temp scratch = scratch_begin(0, 0); + ////////////////////////////// //- rjf: do eviction pass across all caches + // for EachIndex(cache_slot_idx, ac_shared->cache_slots_count) { Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); @@ -206,7 +222,7 @@ ac_async_tick(void) for(AC_Node *n = slot->first, *next = 0; n != 0; n = next) { next = n->next; - if(access_pt_is_expired(&n->access_pt) && ins_atomic_u64_eval(&n->working_count) == 0) + if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0) { slot_has_work = 1; if(!write_mode) @@ -236,90 +252,216 @@ ac_async_tick(void) } } - //- rjf: gather all requests - local_persist AC_Request *reqs = 0; - local_persist U64 reqs_count = 0; - if(lane_idx() == 0) MutexScope(ac_shared->req_mutex) + ////////////////////////////// + //- rjf: gather requests + // + typedef struct RequestBatchTask RequestBatchTask; + struct RequestBatchTask { - reqs_count = ac_shared->req_count; - reqs = push_array(scratch.arena, AC_Request, reqs_count); - U64 idx = 0; - for EachNode(r, AC_RequestNode, ac_shared->first_req) + AC_Request *wide; + U64 wide_count; + AC_Request *thin; + U64 thin_count; + }; + RequestBatchTask *tasks = 0; + U64 tasks_count = 0; + if(lane_idx() == 0) + { + tasks_count = 2; + tasks = push_array(scratch.arena, RequestBatchTask, tasks_count); + for EachElement(task_idx, ac_shared->req_batches) { - MemoryCopyStruct(&reqs[idx], &r->v); - reqs[idx].key = str8_copy(scratch.arena, reqs[idx].key); - idx += 1; + AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; + MutexScope(batch->mutex) + { + tasks[task_idx].wide_count = batch->wide_count; + tasks[task_idx].thin_count = batch->thin_count; + tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count); + tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count); + { + U64 idx = 0; + for EachNode(n, AC_RequestNode, batch->first_wide) + { + MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v); + tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key); + idx += 1; + } + } + { + U64 idx = 0; + for EachNode(n, AC_RequestNode, batch->first_thin) + { + MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v); + tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key); + idx += 1; + } + } + arena_clear(batch->arena); + batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0; + batch->wide_count = batch->thin_count = 0; + } } - arena_clear(ac_shared->req_arena); - ac_shared->first_req = ac_shared->last_req = 0; - ac_shared->req_count = 0; } - lane_sync(); + lane_sync_u64(&tasks, 0); + lane_sync_u64(&tasks_count, 0); - //- rjf: do all requests on all lanes - for EachIndex(idx, reqs_count) + ////////////////////////////// + //- rjf: do all requests + // + for EachIndex(task_idx, tasks_count) { lane_sync(); + RequestBatchTask *task = &tasks[task_idx]; - // rjf: compute val - B32 retry = 0; - AC_Artifact val = reqs[idx].create(reqs[idx].key, &retry); - - // rjf: retry? -> resubmit request - if(retry && lane_idx() == 0) + //- rjf: do all wide requests for this priority + ProfScope("wide requests (p%I64u)", task_idx) { - MutexScope(ac_shared->req_mutex) + for EachIndex(idx, task->wide_count) { - AC_RequestNode *n = push_array(ac_shared->req_arena, AC_RequestNode, 1); - SLLQueuePush(ac_shared->first_req, ac_shared->last_req, n); - ac_shared->req_count += 1; - MemoryCopyStruct(&n->v, &reqs[idx]); - n->v.key = str8_copy(ac_shared->req_arena, n->v.key); - } - ins_atomic_u32_eval_assign(&async_loop_again, 1); - } - - // rjf: create function -> cache - AC_Cache *cache = 0; - if(!retry) - { - U64 cache_hash = u64_hash_from_str8(str8_struct(&reqs[idx].create)); - U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; - Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); - RWMutexScope(cache_stripe->rw_mutex, 0) - { - for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) + AC_Request *r = &task->wide[idx]; + + // rjf: compute val + B32 retry = 0; + AC_Artifact val = r->create(r->key, &retry); + + // rjf: retry? -> resubmit request + if(retry && lane_idx() == 0) { - if(c->create == reqs[idx].create) + AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; + MutexScope(batch->mutex) { - cache = c; - break; + AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1); + SLLQueuePush(batch->first_wide, batch->last_wide, n); + batch->wide_count += 1; + MemoryCopyStruct(&n->v, r); + n->v.key = str8_copy(batch->arena, n->v.key); } + ins_atomic_u32_eval_assign(&async_loop_again, 1); + } + + // rjf: create function -> cache + AC_Cache *cache = 0; + if(!retry) + { + U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create)); + U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + RWMutexScope(cache_stripe->rw_mutex, 0) + { + for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) + { + if(c->create == r->create) + { + cache = c; + break; + } + } + } + } + + // rjf: write value into cache + if(!retry && lane_idx() == 0) + { + U64 hash = u64_hash_from_str8(r->key); + U64 slot_idx = hash%cache->slots_count; + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + for(AC_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, r->key, 0)) + { + n->gen = r->gen; + n->val = val; + ins_atomic_u64_dec_eval(&n->working_count); + ins_atomic_u64_inc_eval(&n->completion_count); + } + } + } + cond_var_broadcast(stripe->cv); } } } - // rjf: write value into cache - if(!retry && lane_idx() == 0) + //- rjf: do all thin requests for this priority + ProfScope("thin requests (p%I64u)", task_idx) { - U64 hash = u64_hash_from_str8(reqs[idx].key); - U64 slot_idx = hash%cache->slots_count; - AC_Slot *slot = &cache->slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); - RWMutexScope(stripe->rw_mutex, 1) + U64 req_take_counter = 0; + U64 *req_take_counter_ptr = 0; + if(lane_idx() == 0) { - for(AC_Node *n = slot->first; n != 0; n = n->next) + req_take_counter_ptr = &req_take_counter; + } + lane_sync_u64(&req_take_counter_ptr, 0); + for(;;) + { + U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1; + if(req_idx >= task->thin_count) { break; } + AC_Request *r = &task->thin[req_idx]; + + // rjf: compute val + B32 retry = 0; + AC_Artifact val = r->create(r->key, &retry); + + // rjf: retry? -> resubmit request + if(retry) { - if(str8_match(n->key, reqs[idx].key, 0)) + AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; + MutexScope(batch->mutex) { - n->gen = reqs[idx].gen; - n->val = val; - ins_atomic_u64_dec_eval(&n->working_count); - ins_atomic_u64_inc_eval(&n->completion_count); + AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1); + SLLQueuePush(batch->first_thin, batch->last_thin, n); + batch->thin_count += 1; + MemoryCopyStruct(&n->v, r); + n->v.key = str8_copy(batch->arena, n->v.key); + } + ins_atomic_u32_eval_assign(&async_loop_again, 1); + } + + // rjf: create function -> cache + AC_Cache *cache = 0; + if(!retry) + { + U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create)); + U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; + Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx); + RWMutexScope(cache_stripe->rw_mutex, 0) + { + for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next) + { + if(c->create == r->create) + { + cache = c; + break; + } + } } } + + // rjf: write value into cache + if(!retry) + { + U64 hash = u64_hash_from_str8(r->key); + U64 slot_idx = hash%cache->slots_count; + AC_Slot *slot = &cache->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + for(AC_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->key, r->key, 0)) + { + n->gen = r->gen; + n->val = val; + ins_atomic_u64_dec_eval(&n->working_count); + ins_atomic_u64_inc_eval(&n->completion_count); + } + } + } + cond_var_broadcast(stripe->cv); + } } - cond_var_broadcast(stripe->cv); } } lane_sync(); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 4f219dfd..2f874679 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -19,6 +19,15 @@ struct AC_Artifact typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *retry_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); +typedef U32 AC_Flags; +typedef enum AC_FlagsEnum +{ + AC_Flag_WaitForFresh = (1<<0), + AC_Flag_HighPriority = (1<<1), + AC_Flag_Wide = (1<<2), +} +AC_FlagsEnum; + typedef struct AC_ArtifactParams AC_ArtifactParams; struct AC_ArtifactParams { @@ -26,8 +35,9 @@ struct AC_ArtifactParams AC_DestroyFunctionType *destroy; U64 slots_count; U64 gen; - B32 wait_for_fresh; + U64 evict_threshold_us; B32 *stale_out; + AC_Flags flags; }; //////////////////////////////// @@ -63,6 +73,7 @@ struct AC_Node AccessPt access_pt; U64 working_count; U64 completion_count; + U64 evict_threshold_us; }; typedef struct AC_Slot AC_Slot; @@ -86,6 +97,19 @@ struct AC_Cache StripeArray stripes; }; +typedef struct AC_RequestBatch AC_RequestBatch; +struct AC_RequestBatch +{ + Mutex mutex; + Arena *arena; + AC_RequestNode *first_wide; + AC_RequestNode *last_wide; + AC_RequestNode *first_thin; + AC_RequestNode *last_thin; + U64 wide_count; + U64 thin_count; +}; + typedef struct AC_Shared AC_Shared; struct AC_Shared { @@ -97,11 +121,7 @@ struct AC_Shared StripeArray cache_stripes; // rjf: requests - Mutex req_mutex; - Arena *req_arena; - AC_RequestNode *first_req; - AC_RequestNode *last_req; - U64 req_count; + AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority }; //////////////////////////////// @@ -118,7 +138,7 @@ internal void ac_init(void); //~ rjf: Cache Lookups internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us); -#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), __VA_ARGS__}, (endt_us)) +#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us)) //////////////////////////////// //~ rjf: Asynchronous Tick diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 45ea750d..3e12a8b9 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -213,13 +213,13 @@ access_touch(Access *access, AccessPt *pt, CondVar cv) //- rjf: access points internal B32 -access_pt_is_expired(AccessPt *pt) +access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params) { U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount); U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us); U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched); B32 result = (access_refcount == 0 && - last_time_touched_us + 2000000 < os_now_microseconds() && - last_update_idx_touched + 10 < update_tick_idx()); + last_time_touched_us + params->time < os_now_microseconds() && + last_update_idx_touched + params->update_idxs < update_tick_idx()); return result; } diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index 1a49a005..5b1726be 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -27,6 +27,13 @@ struct AccessPt U64 last_update_idx_touched; }; +typedef struct AccessPtExpireParams AccessPtExpireParams; +struct AccessPtExpireParams +{ + U64 time; + U64 update_idxs; +}; + typedef struct Touch Touch; struct Touch { @@ -112,7 +119,8 @@ internal void access_close(Access *access); internal void access_touch(Access *access, AccessPt *pt, CondVar cv); //- rjf: access points -internal B32 access_pt_is_expired(AccessPt *pt); +internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params); +#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 10, __VA_ARGS__}) //- rjf: progress counters #define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr)) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index c9d04747..2dd0c65f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7467,7 +7467,6 @@ internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out) { AC_Artifact artifact = {0}; - if(lane_idx() == 0) { //- rjf: unpack key CTRL_Handle process = {0}; @@ -7591,10 +7590,6 @@ ctrl_memory_artifact_create(String8 key, B32 *retry_out) StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check); MemoryCopyStruct(&artifact, &content_key); } - lane_sync_u64(&artifact.u64[0], 0); - lane_sync_u64(&artifact.u64[1], 0); - lane_sync_u64(&artifact.u64[2], 0); - lane_sync_u64(&artifact.u64[3], 0); return artifact; } @@ -7618,7 +7613,10 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, } key_data = {process, vaddr_range, zero_terminated}; String8 key = str8_struct(&key_data); Access *access = access_open(); - AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, .gen = ctrl_mem_gen(), .slots_count = 2048, .stale_out = out_is_stale); + AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, + .gen = ctrl_mem_gen(), + .slots_count = 2048, + .stale_out = out_is_stale); C_Key content_key = {0}; MemoryCopyStruct(&content_key, &artifact); access_close(access); @@ -7633,7 +7631,6 @@ internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) { AC_Artifact artifact = {0}; - if(lane_idx() == 0) { Temp scratch = scratch_begin(0, 0); @@ -7785,8 +7782,6 @@ ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) scratch_end(scratch); } - lane_sync_u64(&artifact.u64[0], 0); - lane_sync_u64(&artifact.u64[1], 0); return artifact; } @@ -7805,7 +7800,10 @@ ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 h { CTRL_CallStack result = {0}; { - AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&thread_handle), ctrl_call_stack_artifact_create, ctrl_call_stack_artifact_destroy, endt_us, .gen = ctrl_mem_gen() + ctrl_reg_gen()); + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&thread_handle), ctrl_call_stack_artifact_create, ctrl_call_stack_artifact_destroy, endt_us, + .gen = ctrl_mem_gen() + ctrl_reg_gen(), + .evict_threshold_us = 10000000, + .flags = high_priority ? AC_Flag_HighPriority : 0); if(artifact.u64[1] != 0) { MemoryCopyStruct(&result, (CTRL_CallStack *)artifact.u64[1]); diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index c44c70e6..1203a9c6 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1208,13 +1208,13 @@ d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) } else { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); - CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, 0); + Access *access = access_open(); + CTRL_CallStack callstack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, 0); if(callstack.concrete_frames_count != 0) { result = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[unwind_count%callstack.concrete_frames_count]->regs); } - ctrl_scope_close(ctrl_scope); + access_close(access); } return result; } @@ -1886,10 +1886,10 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_StepOverLine: {traps = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; case D_CmdKind_StepOut: { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); // rjf: thread => call stack - CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack callstack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); // rjf: use first unwind frame to generate trap if(callstack.concrete_frames_count > 1) @@ -1904,7 +1904,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P good = 0; } - ctrl_scope_close(ctrl_scope); + access_close(access); }break; } if(good && traps.count != 0) diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index e2d8f743..56a9572f 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -512,7 +512,7 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params) String8 key = str8_list_join(scratch.arena, &key_parts, 0); // rjf: get info - AC_Artifact artifact = ac_artifact_from_key(access, key, dasm_artifact_create, dasm_artifact_destroy, 0, .gen = fs_change_gen()); + AC_Artifact artifact = ac_artifact_from_key(access, key, dasm_artifact_create, dasm_artifact_destroy, 0, .gen = fs_change_gen(), .flags = AC_Flag_Wide); DASM_Artifact *dasm_artifact = (DASM_Artifact *)artifact.u64[0]; if(dasm_artifact) { diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index eb2fc240..e170f367 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -244,7 +244,7 @@ fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) } //- rjf: map to artifact - AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us, .gen = gen); + AC_Artifact artifact = ac_artifact_from_key(access, key, fs_artifact_create, fs_artifact_destroy, endt_us, .gen = gen, .flags = AC_Flag_Wide); MemoryCopyStruct(&result, &artifact); } access_close(access); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index a0caab90..e8b579e2 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1816,8 +1816,8 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) }break; case CTRL_EntityKind_Thread: { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, 1, rd_state->frame_eval_memread_endt_us); + Access *access = access_open(); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, 1, rd_state->frame_eval_memread_endt_us); U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count; if(concrete_frame_idx < call_stack.concrete_frames_count) { @@ -1829,7 +1829,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, (U8 *)f->regs + read_range.min, read_size); result = (read_size == dim_1u64(range)); } - ctrl_scope_close(ctrl_scope); + access_close(access); }break; } }break; @@ -6464,12 +6464,12 @@ rd_window_frame(void) // rjf: unwind if(ctrl_entity->kind == CTRL_EntityKind_Thread) RD_Font(RD_FontSlot_Code) { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); Vec4F32 code_color = ui_color_from_name(str8_lit("code_default")); Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process); B32 call_stack_high_priority = ctrl_handle_match(ctrl_entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, ctrl_entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, ctrl_entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(call_stack.frames_count != 0) { ui_spacer(ui_em(1.5f, 1.f)); @@ -6486,7 +6486,7 @@ rd_window_frame(void) String8 rip_value_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, ui_top_font(), ui_top_font_size(), ui_top_font_size()*40.f, rip_eval); rd_code_label(1, 0, code_color, rip_value_string); } - ctrl_scope_close(ctrl_scope); + access_close(access); } }break; @@ -16258,9 +16258,9 @@ rd_frame(void) }break; case RD_CmdKind_SelectUnwind: { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); if(frame == 0) { @@ -16272,14 +16272,14 @@ rd_frame(void) rd_state->base_regs.v.inline_depth = rd_regs()->inline_depth; } rd_cmd(RD_CmdKind_FindThread, .thread = thread->handle, .unwind_count = rd_state->base_regs.v.unwind_count, .inline_depth = rd_state->base_regs.v.inline_depth); - ctrl_scope_close(ctrl_scope); + access_close(access); }break; case RD_CmdKind_UpOneFrame: case RD_CmdKind_DownOneFrame: { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *current_frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); CTRL_CallStackFrame *next_frame = current_frame; if(current_frame != 0) switch(kind) @@ -16303,7 +16303,7 @@ rd_frame(void) .unwind_count = next_frame->unwind_count, .inline_depth = next_frame->inline_depth); } - ctrl_scope_close(ctrl_scope); + access_close(access); }break; //- rjf: meta controls diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 16614e77..69267dec 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1026,11 +1026,11 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(block_eval.space); if(entity->kind == CTRL_EntityKind_Thread) { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); info.callstack_thread = entity; U64 frame_num = ev_block_num_from_id(block, key.child_id); B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(1 <= frame_num && frame_num <= call_stack.frames_count) { CTRL_CallStackFrame *f = &call_stack.frames[frame_num-1]; @@ -1038,7 +1038,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) info.callstack_inline_depth = f->inline_depth; info.callstack_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); } - ctrl_scope_close(ctrl_scope); + access_close(access); } } @@ -2930,10 +2930,10 @@ RD_VIEW_UI_FUNCTION_DEF(memory) }; AnnotationList *visible_memory_annotations = push_array(scratch.arena, AnnotationList, visible_memory_size); { - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *selected_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); - CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread(ctrl_scope, selected_thread->handle, 1, 0); + CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread_new(access, selected_thread->handle, 1, 0); CTRL_Entity *eval_process = &ctrl_entity_nil; if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity) { @@ -3203,7 +3203,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) } } - ctrl_scope_close(ctrl_scope); + access_close(access); } ////////////////////////////// diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 64ea699e..ccffbfef 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -547,12 +547,12 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e { Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); - CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Access *access = access_open(); DI_Scope *di_scope = di_scope_open(); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); Arch arch = entity->arch; B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); B32 did_first_known = 0; for(U64 idx = 0, limit = 10; idx < call_stack.frames_count && idx < limit; @@ -592,7 +592,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e } } di_scope_close(di_scope); - ctrl_scope_close(ctrl_scope); + access_close(access); } //- rjf: modules get debug info status extras diff --git a/src/text/text.c b/src/text/text.c index caa42dad..ef19c3a3 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -2254,7 +2254,7 @@ txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang) TXT_LangKind lang; } key = {hash, lang}; String8 key_string = str8_struct(&key); - AC_Artifact artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 0); + AC_Artifact artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 0, .flags = AC_Flag_Wide); TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; TXT_TextInfo info = {0}; if(txt_artifact != 0) From a338b3413e37a8dbabdcca63999fadba57ad280c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 10:35:47 -0700 Subject: [PATCH 266/302] artifact cache fixes, move ctrl process memory streaming to artifact cache --- src/artifact_cache/artifact_cache.c | 16 +++- src/base/base_entry_point.c | 4 +- src/ctrl/ctrl_core.c | 6 +- src/file_stream/file_stream.c | 125 +++++++++++++++------------- src/file_stream/file_stream.h | 2 - src/raddbg/raddbg_core.c | 2 +- 6 files changed, 87 insertions(+), 68 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index b06098b8..3c774b4a 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -81,14 +81,15 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 { if(str8_match(n->key, key, 0)) { - if(ins_atomic_u64_eval(&n->completion_count) != 0 && (n->gen == params->gen || !(params->flags & AC_Flag_WaitForFresh))) + B32 is_stale = (n->gen != params->gen); + if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh))) { got_artifact = 1; - artifact_is_stale = (n->gen == params->gen); + artifact_is_stale = is_stale; artifact = n->val; access_touch(access, &n->access_pt, stripe->cv); } - if(n->gen != params->gen) + if(is_stale) { B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0); need_request = got_task; @@ -135,6 +136,8 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 node->key = str8_copy(stripe->arena, key); node->working_count = 1; node->evict_threshold_us = params->evict_threshold_us; + node->access_pt.last_time_touched_us = os_now_microseconds(); + node->access_pt.last_update_idx_touched = update_tick_idx(); } // rjf: request @@ -304,6 +307,7 @@ ac_async_tick(void) } lane_sync_u64(&tasks, 0); lane_sync_u64(&tasks_count, 0); + lane_sync(); ////////////////////////////// //- rjf: do all requests @@ -318,6 +322,7 @@ ac_async_tick(void) { for EachIndex(idx, task->wide_count) { + lane_sync(); AC_Request *r = &task->wide[idx]; // rjf: compute val @@ -341,7 +346,7 @@ ac_async_tick(void) // rjf: create function -> cache AC_Cache *cache = 0; - if(!retry) + if(!retry && lane_idx() == 0) { U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create)); U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; @@ -383,6 +388,7 @@ ac_async_tick(void) } } } + lane_sync(); //- rjf: do all thin requests for this priority ProfScope("thin requests (p%I64u)", task_idx) @@ -462,7 +468,9 @@ ac_async_tick(void) cond_var_broadcast(stripe->cv); } } + lane_sync(); } + lane_sync(); } lane_sync(); diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index e0cadd76..851042bc 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -2,6 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) global U64 global_update_tick_idx = 0; +global U64 async_threads_count = 0; global CondVar async_tick_start_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; @@ -103,7 +104,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) //- rjf: launch async threads Thread *async_threads = 0; - U64 async_threads_count = 0; U64 lane_broadcast_val = 0; { U64 num_main_threads = 1; @@ -121,7 +121,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) for EachIndex(idx, num_async_threads) { lane_ctxs[idx].lane_idx = idx; - lane_ctxs[idx].lane_count = num_async_threads; + lane_ctxs[idx].lane_count = async_threads_count; lane_ctxs[idx].barrier = barrier; lane_ctxs[idx].broadcast_memory = &lane_broadcast_val; async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]); diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 2dd0c65f..960f7763 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1866,7 +1866,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn { U64 page_base_vaddr = page_range.min + page_idx*page_size; B32 page_is_stale = 0; - C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); + C_Key page_key = ctrl_key_from_process_vaddr_range_new(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); U128 page_hash = c_hash_from_key(page_key, 0); U128 page_last_hash = c_hash_from_key(page_key, 1); result.stale = (result.stale || page_is_stale); @@ -7610,13 +7610,15 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, CTRL_Handle process; Rng1U64 vaddr_range; B32 zero_terminated; + B32 _padding_; } key_data = {process, vaddr_range, zero_terminated}; String8 key = str8_struct(&key_data); Access *access = access_open(); AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, .gen = ctrl_mem_gen(), .slots_count = 2048, - .stale_out = out_is_stale); + .stale_out = out_is_stale, + .evict_threshold_us = 30000000); C_Key content_key = {0}; MemoryCopyStruct(&content_key, &artifact); access_close(access); diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index e170f367..d099f0c1 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -31,16 +31,6 @@ fs_change_gen(void) //////////////////////////////// //~ rjf: Cache Interaction -internal C_Key -fs_content_key_from_artifact_key(String8 key) -{ - C_Key content_key = {0}; - { - content_key.id.u128[0] = u128_hash_from_str8(key); - } - return content_key; -} - internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out) { @@ -59,60 +49,75 @@ fs_artifact_create(String8 key, B32 *retry_out) } //- rjf: measure file properties *before* read + B32 file_is_good = 0; FileProperties pre_props = {0}; if(lane_idx() == 0) { pre_props = os_properties_from_file_path(path); + file_is_good = (pre_props.modified != 0); } + lane_sync_u64(&file_is_good, 0); //- rjf: setup output data Arena *data_arena = 0; U64 data_buffer_size = 0; U8 *data_buffer = 0; - if(lane_idx() == 0) + if(file_is_good) { - U64 range_size = dim_1u64(range); - U64 read_size = Min(pre_props.size - range.min, range_size); - U64 data_arena_size = read_size+ARENA_HEADER_SIZE; - data_arena_size += KB(4)-1; - data_arena_size -= data_arena_size%KB(4); - data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); - data_buffer_size = read_size; - data_buffer = push_array_no_zero(data_arena, U8, data_buffer_size); + if(lane_idx() == 0) + { + U64 range_size = dim_1u64(range); + U64 read_size = Min(pre_props.size - range.min, range_size); + U64 data_arena_size = read_size+ARENA_HEADER_SIZE; + data_arena_size += KB(4)-1; + data_arena_size -= data_arena_size%KB(4); + data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size); + data_buffer_size = read_size; + data_buffer = push_array_no_zero(data_arena, U8, data_buffer_size); + } + lane_sync_u64(&data_buffer, 0); + lane_sync_u64(&data_buffer_size, 0); } - lane_sync_u64(&data_buffer, 0); - lane_sync_u64(&data_buffer_size, 0); //- rjf: open file OS_Handle file = {0}; - if(lane_idx() == 0) + if(file_is_good) { - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + if(lane_idx() == 0) + { + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + } + lane_sync_u64(&file, 0); } - lane_sync_u64(&file, 0); B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); //- rjf: do read U64 total_bytes_read = 0; - U64 *total_bytes_read_ptr = 0; - if(lane_idx() == 0) + if(file_handle_is_valid) { - total_bytes_read_ptr = &total_bytes_read; + U64 *total_bytes_read_ptr = 0; + if(lane_idx() == 0) + { + total_bytes_read_ptr = &total_bytes_read; + } + lane_sync_u64(&total_bytes_read_ptr, 0); + ProfScope("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max) + { + Rng1U64 lane_read_range = lane_range(data_buffer_size); + U64 bytes_read = os_file_read(file, shift_1u64(lane_read_range, range.min), data_buffer + lane_read_range.min); + ins_atomic_u64_add_eval(total_bytes_read_ptr, bytes_read); + } + lane_sync(); + lane_sync_u64(&total_bytes_read, 0); } - lane_sync_u64(&total_bytes_read_ptr, 0); - ProfScope("read \"%.*s\" [0x%I64x, 0x%I64x)", str8_varg(path), range.min, range.max) - { - Rng1U64 lane_read_range = lane_range(data_buffer_size); - U64 bytes_read = os_file_read(file, shift_1u64(lane_read_range, range.min), data_buffer + lane_read_range.min); - ins_atomic_u64_add_eval(total_bytes_read_ptr, bytes_read); - } - lane_sync(); - lane_sync_u64(&total_bytes_read, 0); //- rjf: close file - if(lane_idx() == 0) + if(file_handle_is_valid) { - os_file_close(file); + if(lane_idx() == 0) + { + os_file_close(file); + } } //- rjf: measure file properties *after* read @@ -123,35 +128,41 @@ fs_artifact_create(String8 key, B32 *retry_out) } //- rjf: form content key - C_Key content_key = fs_content_key_from_artifact_key(key); + C_Key content_key = {0}; + { + content_key.id.u128[0] = u128_hash_from_str8(key); + } //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file; // otherwise submit data B32 read_good = 0; - if(lane_idx() == 0) + if(file_is_good) { - read_good = (pre_props.modified == post_props.modified && - pre_props.size == post_props.size && - data_buffer_size == total_bytes_read && - (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); - if(!read_good) + if(lane_idx() == 0) { - retry_out[0] = 1; - ProfScope("abort") + read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + data_buffer_size == total_bytes_read && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + if(!read_good) { - arena_release(data_arena); - MemoryZeroStruct(&content_key); - } - } - else - { - ProfScope("submit") - { - c_submit_data(content_key, &data_arena, str8(data_buffer, data_buffer_size)); + retry_out[0] = 1; + ProfScope("abort") + { + arena_release(data_arena); + MemoryZeroStruct(&content_key); + } + } + else + { + ProfScope("submit") + { + c_submit_data(content_key, &data_arena, str8(data_buffer, data_buffer_size)); + } } } + lane_sync(); } - lane_sync(); //- rjf: if the read was good, record this path's timestamp in this layer's path info cache U64 path_hash = u64_hash_from_str8(path); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 9bc219ca..4ecc10ff 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -55,8 +55,6 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Accessing API -internal C_Key fs_content_key_from_artifact_key(String8 key); - internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index e8b579e2..6ddf6c8c 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -2160,7 +2160,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) { - result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0); + result = ctrl_key_from_process_vaddr_range_new(entity->handle, range, zero_terminated, 0, 0); } }break; } From b4d672efba0dbf4ba4eb58b1c855b56da3547d40 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:20:14 -0700 Subject: [PATCH 267/302] flag ctrl memory reads as high priority --- src/ctrl/ctrl_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 960f7763..9271ca3f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7615,6 +7615,7 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, String8 key = str8_struct(&key_data); Access *access = access_open(); AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us, + .flags = AC_Flag_HighPriority, .gen = ctrl_mem_gen(), .slots_count = 2048, .stale_out = out_is_stale, From d8fcbcd868edcf3b94d3292216799687aa3a8e99 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:40:35 -0700 Subject: [PATCH 268/302] eliminate texture_cache; replace with trivial usage of artifact cache, in raddbg layer defining the bitmap visualizer, which was the only usage --- src/base/base_entry_point.c | 6 - src/raddbg/raddbg_main.c | 3 - src/raddbg/raddbg_views.c | 71 +++++++- src/texture_cache/texture_cache.c | 280 ------------------------------ src/texture_cache/texture_cache.h | 118 ------------- 5 files changed, 69 insertions(+), 409 deletions(-) delete mode 100644 src/texture_cache/texture_cache.c delete mode 100644 src/texture_cache/texture_cache.h diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 851042bc..b8ba0f79 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -86,9 +86,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) r_init(&cmdline); #endif -#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL) - tex_init(); -#endif #if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) geo_init(); #endif @@ -211,9 +208,6 @@ async_thread_entry_point(void *params) #endif #if defined(FILE_STREAM_H) fs_async_tick(); -#endif -#if defined(TEXTURE_CACHE_H) - tex_async_tick(); #endif } diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 33939e69..f4533078 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -259,7 +259,6 @@ #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" #include "ptr_graph_cache/ptr_graph_cache.h" -#include "texture_cache/texture_cache.h" #include "geo_cache/geo_cache.h" #include "font_cache/font_cache.h" #include "draw/draw.h" @@ -309,7 +308,6 @@ #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" #include "ptr_graph_cache/ptr_graph_cache.c" -#include "texture_cache/texture_cache.c" #include "geo_cache/geo_cache.c" #include "font_cache/font_cache.c" #include "draw/draw.c" @@ -499,7 +497,6 @@ entry_point(CmdLine *cmd_line) os_gfx_init(); fp_init(); r_init(cmd_line); - tex_init(); geo_init(); fnt_init(); d_init(); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 69267dec..92e61641 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -3724,6 +3724,13 @@ EV_EXPAND_RULE_INFO_FUNCTION_DEF(graph) //////////////////////////////// //~ rjf: bitmap @view_hook_impl +typedef struct RD_BitmapTopology RD_BitmapTopology; +struct RD_BitmapTopology +{ + Vec2S16 dim; + R_Tex2DFormat fmt; +}; + typedef struct RD_BitmapBoxDrawData RD_BitmapBoxDrawData; struct RD_BitmapBoxDrawData { @@ -3742,6 +3749,46 @@ struct RD_BitmapCanvasBoxDrawData F32 zoom; }; +internal AC_Artifact +rd_bitmap_artifact_create(String8 key, B32 *retry_out) +{ + Access *access = access_open(); + + //- rjf: unpack key + U128 hash = {0}; + RD_BitmapTopology top = {0}; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, &hash); + key_read_off += str8_deserial_read_struct(key, key_read_off, &top); + } + String8 data = c_data_from_hash(access, hash); + + //- rjf: create texture + R_Handle texture = {0}; + if(top.dim.x > 0 && top.dim.y > 0 && + data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt]) + { + texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); + } + + //- rjf: bundle as artifact + AC_Artifact artifact = {0}; + StaticAssert(sizeof(artifact) >= sizeof(texture), tex_artifact_size_check); + MemoryCopy(&artifact, &texture, Min(sizeof(texture), sizeof(artifact))); + + access_close(access); + return artifact; +} + +internal void +rd_bitmap_artifact_destroy(AC_Artifact artifact) +{ + R_Handle texture = {0}; + MemoryCopy(&texture, &artifact, Min(sizeof(texture), sizeof(artifact))); + r_tex2d_release(texture); +} + internal Vec2F32 rd_bitmap_screen_from_canvas_pos(Vec2F32 view_center_pos, F32 zoom, Rng2F32 rect, Vec2F32 cvs) { @@ -3868,9 +3915,29 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap) //- rjf: map expression artifacts -> texture // C_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); - TEX_Topology topology = tex_topology_make(dim, fmt); + RD_BitmapTopology topology = {v2s16(dim.x, dim.y), fmt}; U128 data_hash = {0}; - R_Handle texture = tex_texture_from_key_topology(access, texture_key, topology, &data_hash); + R_Handle texture = {0}; + for EachIndex(rewind_idx, C_KEY_HASH_HISTORY_COUNT) + { + U128 hash = c_hash_from_key(texture_key, rewind_idx); + struct + { + U128 hash; + RD_BitmapTopology top; + } + key_data = {hash, topology}; + String8 key = str8_struct(&key_data); + AC_Artifact artifact = ac_artifact_from_key(access, key, rd_bitmap_artifact_create, rd_bitmap_artifact_destroy, 0); + R_Handle texture_candidate = {0}; + MemoryCopy(&texture_candidate, &artifact, Min(sizeof(texture_candidate), sizeof(artifact))); + if(!r_handle_match(texture_candidate, r_handle_zero())) + { + data_hash = hash; + texture = texture_candidate; + break; + } + } String8 data = c_data_from_hash(access, data_hash); ////////////////////////////// diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c deleted file mode 100644 index ef9c6d22..00000000 --- a/src/texture_cache/texture_cache.c +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#undef LAYER_COLOR -#define LAYER_COLOR 0xe34cd4ff - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal TEX_Topology -tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt) -{ - TEX_Topology top = {0}; - top.dim.x = (S16)Clamp(0, dim.x, max_S32); - top.dim.y = (S16)Clamp(0, dim.y, max_S32); - top.fmt = fmt; - return top; -} - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -tex_init(void) -{ - Arena *arena = arena_alloc(); - tex_shared = push_array(arena, TEX_Shared, 1); - tex_shared->arena = arena; - tex_shared->slots_count = 1024; - tex_shared->stripes_count = Min(tex_shared->slots_count, os_get_system_info()->logical_processor_count); - tex_shared->slots = push_array(arena, TEX_Slot, tex_shared->slots_count); - tex_shared->stripes = push_array(arena, TEX_Stripe, tex_shared->stripes_count); - tex_shared->stripes_free_nodes = push_array(arena, TEX_Node *, tex_shared->stripes_count); - for(U64 idx = 0; idx < tex_shared->stripes_count; idx += 1) - { - tex_shared->stripes[idx].arena = arena_alloc(); - tex_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - tex_shared->stripes[idx].cv = cond_var_alloc(); - } - tex_shared->req_mutex = mutex_alloc(); - tex_shared->req_arena = arena_alloc(); -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal R_Handle -tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology) -{ - R_Handle handle = {0}; - { - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%tex_shared->slots_count; - U64 stripe_idx = slot_idx%tex_shared->stripes_count; - TEX_Slot *slot = &tex_shared->slots[slot_idx]; - TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - - //- rjf: get results, request if needed - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 got_node = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - // rjf: get node - TEX_Node *node = 0; - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) - { - node = n; - got_node = 1; - break; - } - } - - // rjf: no node? -> create & request - if(write_mode && !node) - { - node = tex_shared->stripes_free_nodes[stripe_idx]; - if(node) - { - SLLStackPop(tex_shared->stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array_no_zero(stripe->arena, TEX_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->hash = hash; - MemoryCopyStruct(&node->topology, &topology); - MutexScope(tex_shared->req_mutex) - { - TEX_RequestNode *n = push_array(tex_shared->req_arena, TEX_RequestNode, 1); - SLLQueuePush(tex_shared->first_req, tex_shared->last_req, n); - n->v.hash = hash; - n->v.top = topology; - tex_shared->req_count += 1; - } - cond_var_broadcast(async_tick_start_cond_var); - } - - // rjf: node? -> grab & access - if(!write_mode && node) - { - handle = node->texture; - access_touch(access, &node->access_pt, stripe->cv); - } - } - if(got_node) - { - break; - } - } - } - return handle; -} - -internal R_Handle -tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out) -{ - R_Handle handle = {0}; - for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) - { - U128 hash = c_hash_from_key(key, rewind_idx); - handle = tex_texture_from_hash_topology(access, hash, topology); - if(!r_handle_match(handle, r_handle_zero())) - { - if(hash_out) - { - *hash_out = hash; - } - break; - } - } - return handle; -} - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void -tex_async_tick(void) -{ - if(ins_atomic_u64_eval(&tex_shared) == 0) { return; } - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //- rjf: do eviction pass - { - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 10*1000000; - U64 evict_threshold_user_clocks = 10; - Rng1U64 range = lane_range(tex_shared->slots_count); - for EachInRange(slot_idx, range) - { - U64 stripe_idx = slot_idx%tex_shared->stripes_count; - TEX_Slot *slot = &tex_shared->slots[slot_idx]; - TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 slot_has_work = 0; - RWMutexScope(stripe->rw_mutex, write_mode) - { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->working_count == 0) - { - slot_has_work = 1; - if(!write_mode) - { - break; - } - else - { - DLLRemove(slot->first, slot->last, n); - if(!r_handle_match(n->texture, r_handle_zero())) - { - r_tex2d_release(n->texture); - } - SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n); - } - } - } - } - if(!slot_has_work) - { - break; - } - } - } - } - - //- rjf: gather all requests - local_persist TEX_Request *reqs = 0; - local_persist U64 reqs_count = 0; - if(lane_idx() == 0) MutexScope(tex_shared->req_mutex) - { - reqs_count = tex_shared->req_count; - reqs = push_array(scratch.arena, TEX_Request, reqs_count); - U64 idx = 0; - for EachNode(r, TEX_RequestNode, tex_shared->first_req) - { - MemoryCopyStruct(&reqs[idx], &r->v); - idx += 1; - } - arena_clear(tex_shared->req_arena); - tex_shared->first_req = tex_shared->last_req = 0; - tex_shared->req_count = 0; - tex_shared->lane_req_take_counter = 0; - } - lane_sync(); - - //- rjf: do requests - for(;;) - { - //- rjf: get next request - U64 req_num = ins_atomic_u64_inc_eval(&tex_shared->lane_req_take_counter); - if(req_num < 1 || reqs_count < req_num) - { - break; - } - U64 req_idx = req_num-1; - U128 hash = reqs[req_idx].hash; - TEX_Topology top = reqs[req_idx].top; - Access *access = access_open(); - - //- rjf: unpack request - U64 slot_idx = hash.u64[1]%tex_shared->slots_count; - U64 stripe_idx = slot_idx%tex_shared->stripes_count; - TEX_Slot *slot = &tex_shared->slots[slot_idx]; - TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; - String8 data = c_data_from_hash(access, hash); - - //- rjf: create texture - R_Handle texture = {0}; - if(top.dim.x > 0 && top.dim.y > 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt]) - { - texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); - } - - //- rjf: commit results to cache - RWMutexScope(stripe->rw_mutex, 1) - { - for(TEX_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) - { - n->texture = texture; - ins_atomic_u64_dec_eval(&n->working_count); - ins_atomic_u64_inc_eval(&n->load_count); - break; - } - } - } - - access_close(access); - } - - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: Artifact Cache Hooks / Lookups - -internal void * -tex_artifact_create(String8 key, B32 *retry_out) -{ - -} - -internal void -tex_artifact_destroy(void *ptr) -{ - -} diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h deleted file mode 100644 index 4efeaee3..00000000 --- a/src/texture_cache/texture_cache.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef TEXTURE_CACHE_H -#define TEXTURE_CACHE_H - -//////////////////////////////// -//~ rjf: Texture Topology - -typedef struct TEX_Topology TEX_Topology; -struct TEX_Topology -{ - Vec2S16 dim; - R_Tex2DFormat fmt; -}; - -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct TEX_Node TEX_Node; -struct TEX_Node -{ - TEX_Node *next; - TEX_Node *prev; - U128 hash; - TEX_Topology topology; - R_Handle texture; - AccessPt access_pt; - U64 working_count; - U64 load_count; -}; - -typedef struct TEX_Slot TEX_Slot; -struct TEX_Slot -{ - TEX_Node *first; - TEX_Node *last; -}; - -typedef struct TEX_Stripe TEX_Stripe; -struct TEX_Stripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct TEX_Request TEX_Request; -struct TEX_Request -{ - U128 hash; - TEX_Topology top; -}; - -typedef struct TEX_RequestNode TEX_RequestNode; -struct TEX_RequestNode -{ - TEX_RequestNode *next; - TEX_Request v; -}; - -typedef struct TEX_Shared TEX_Shared; -struct TEX_Shared -{ - Arena *arena; - - // rjf: cache - U64 slots_count; - U64 stripes_count; - TEX_Slot *slots; - TEX_Stripe *stripes; - TEX_Node **stripes_free_nodes; - - // rjf: requests - Mutex req_mutex; - Arena *req_arena; - TEX_RequestNode *first_req; - TEX_RequestNode *last_req; - U64 req_count; - U64 lane_req_take_counter; -}; - -//////////////////////////////// -//~ rjf: Globals - -global TEX_Shared *tex_shared = 0; - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal TEX_Topology tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt); - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void tex_init(void); - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal R_Handle tex_texture_from_hash_topology(Access *access, U128 hash, TEX_Topology topology); -internal R_Handle tex_texture_from_key_topology(Access *access, C_Key key, TEX_Topology topology, U128 *hash_out); - -//////////////////////////////// -//~ rjf: Asynchronous Tick - -internal void tex_async_tick(void); - -//////////////////////////////// -//~ rjf: Artifact Cache Hooks / Lookups - -internal void *tex_artifact_create(String8 key, B32 *retry_out); -internal void tex_artifact_destroy(void *ptr); - -#endif // TEXTURE_CACHE_H From 7990b043a03c24464f9a97ef062cd7f95c2e5ce2 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:47:31 -0700 Subject: [PATCH 269/302] eliminate geo cache, replace with trivial use of artifact cache defined by geo visualizer --- src/base/base_entry_point.c | 3 - src/geo_cache/geo_cache.c | 281 ------------------------------------ src/geo_cache/geo_cache.h | 92 ------------ src/raddbg/raddbg_main.c | 2 - src/raddbg/raddbg_views.c | 49 ++++++- 5 files changed, 47 insertions(+), 380 deletions(-) delete mode 100644 src/geo_cache/geo_cache.c delete mode 100644 src/geo_cache/geo_cache.h diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index b8ba0f79..ce2de7d7 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -86,9 +86,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) r_init(&cmdline); #endif -#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) - geo_init(); -#endif #if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL) fnt_init(); #endif diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c deleted file mode 100644 index 938fe565..00000000 --- a/src/geo_cache/geo_cache.c +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#undef LAYER_COLOR -#define LAYER_COLOR 0xe34cd4ff - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -geo_init(void) -{ - Arena *arena = arena_alloc(); - geo_shared = push_array(arena, GEO_Shared, 1); - geo_shared->arena = arena; - geo_shared->slots_count = 1024; - geo_shared->stripes_count = Min(geo_shared->slots_count, os_get_system_info()->logical_processor_count); - geo_shared->slots = push_array(arena, GEO_Slot, geo_shared->slots_count); - geo_shared->stripes = push_array(arena, GEO_Stripe, geo_shared->stripes_count); - geo_shared->stripes_free_nodes = push_array(arena, GEO_Node *, geo_shared->stripes_count); - for(U64 idx = 0; idx < geo_shared->stripes_count; idx += 1) - { - geo_shared->stripes[idx].arena = arena_alloc(); - geo_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - geo_shared->stripes[idx].cv = cond_var_alloc(); - } - geo_shared->u2x_ring_size = KB(64); - geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); - geo_shared->u2x_ring_cv = cond_var_alloc(); - geo_shared->u2x_ring_mutex = mutex_alloc(); - geo_shared->evictor_thread = thread_launch(geo_evictor_thread__entry_point, 0); -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal R_Handle -geo_buffer_from_hash(Access *access, U128 hash) -{ - R_Handle handle = {0}; - if(!u128_match(hash, u128_zero())) - { - U64 slot_idx = hash.u64[1]%geo_shared->slots_count; - U64 stripe_idx = slot_idx%geo_shared->stripes_count; - GEO_Slot *slot = &geo_shared->slots[slot_idx]; - GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; - B32 found = 0; - MutexScopeR(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - handle = n->buffer; - found = !r_handle_match(r_handle_zero(), handle); - access_touch(access, &n->access_pt, stripe->cv); - break; - } - } - } - B32 node_is_new = 0; - if(!found) - { - MutexScopeW(stripe->rw_mutex) - { - GEO_Node *node = 0; - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(hash, n->hash)) - { - node = n; - break; - } - } - if(node == 0) - { - node = geo_shared->stripes_free_nodes[stripe_idx]; - if(node) - { - SLLStackPop(geo_shared->stripes_free_nodes[stripe_idx]); - } - else - { - node = push_array_no_zero(stripe->arena, GEO_Node, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->hash = hash; - node_is_new = 1; - } - } - } - if(node_is_new) - { - geo_u2x_enqueue_req(hash, max_U64); - async_push_work(geo_xfer_work); - } - } - return handle; -} - -internal R_Handle -geo_buffer_from_key(Access *access, C_Key key) -{ - R_Handle handle = {0}; - for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) - { - U128 hash = c_hash_from_key(key, rewind_idx); - handle = geo_buffer_from_hash(access, hash); - if(!r_handle_match(handle, r_handle_zero())) - { - break; - } - } - return handle; -} - -//////////////////////////////// -//~ rjf: Transfer Threads - -internal B32 -geo_u2x_enqueue_req(U128 hash, U64 endt_us) -{ - B32 good = 0; - MutexScope(geo_shared->u2x_ring_mutex) for(;;) - { - U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; - U64 available_size = geo_shared->u2x_ring_size-unconsumed_size; - if(available_size >= sizeof(hash)) - { - good = 1; - geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &hash); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(geo_shared->u2x_ring_cv); - } - return good; -} - -internal void -geo_u2x_dequeue_req(U128 *hash_out) -{ - MutexScope(geo_shared->u2x_ring_mutex) for(;;) - { - U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out)) - { - geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out); - break; - } - cond_var_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64); - } - cond_var_broadcast(geo_shared->u2x_ring_cv); -} - -ASYNC_WORK_DEF(geo_xfer_work) -{ - ProfBeginFunction(); - Access *access = access_open(); - - //- rjf: decode - U128 hash = {0}; - geo_u2x_dequeue_req(&hash); - - //- rjf: unpack hash - U64 slot_idx = hash.u64[1]%geo_shared->slots_count; - U64 stripe_idx = slot_idx%geo_shared->stripes_count; - GEO_Slot *slot = &geo_shared->slots[slot_idx]; - GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; - - //- rjf: take task - B32 got_task = 0; - MutexScopeR(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); - break; - } - } - } - - //- rjf: hash -> data - String8 data = {0}; - if(got_task) - { - data = c_data_from_hash(access, hash); - } - - //- rjf: data -> buffer - R_Handle buffer = {0}; - if(got_task && data.size != 0) - { - buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str); - } - - //- rjf: commit results to cache - if(got_task) MutexScopeW(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - n->buffer = buffer; - ins_atomic_u32_eval_assign(&n->is_working, 0); - ins_atomic_u64_inc_eval(&n->load_count); - break; - } - } - } - - access_close(access); - ProfEnd(); - return 0; -} - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void -geo_evictor_thread__entry_point(void *p) -{ - ThreadNameF("geo_evictor_thread"); - for(;;) - { - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 10*1000000; - U64 evict_threshold_user_clocks = 10; - for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%geo_shared->stripes_count; - GEO_Slot *slot = &geo_shared->slots[slot_idx]; - GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first; n != 0; n = n->next) - { - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->is_working == 0) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(access_pt_is_expired(&n->access_pt) && - n->load_count != 0 && - n->is_working == 0) - { - DLLRemove(slot->first, slot->last, n); - if(!r_handle_match(n->buffer, r_handle_zero())) - { - r_buffer_release(n->buffer); - } - SLLStackPush(geo_shared->stripes_free_nodes[stripe_idx], n); - } - } - } - os_sleep_milliseconds(5); - } - os_sleep_milliseconds(1000); - } -} diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h deleted file mode 100644 index fe55b7b0..00000000 --- a/src/geo_cache/geo_cache.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef GEO_CACHE_H -#define GEO_CACHE_H - -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct GEO_Node GEO_Node; -struct GEO_Node -{ - GEO_Node *next; - GEO_Node *prev; - U128 hash; - R_Handle buffer; - B32 is_working; - U64 load_count; - AccessPt access_pt; -}; - -typedef struct GEO_Slot GEO_Slot; -struct GEO_Slot -{ - GEO_Node *first; - GEO_Node *last; -}; - -typedef struct GEO_Stripe GEO_Stripe; -struct GEO_Stripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct GEO_Shared GEO_Shared; -struct GEO_Shared -{ - Arena *arena; - - // rjf: cache - U64 slots_count; - U64 stripes_count; - GEO_Slot *slots; - GEO_Stripe *stripes; - GEO_Node **stripes_free_nodes; - - // rjf: user -> xfer thread - U64 u2x_ring_size; - U8 *u2x_ring_base; - U64 u2x_ring_write_pos; - U64 u2x_ring_read_pos; - CondVar u2x_ring_cv; - Mutex u2x_ring_mutex; - - // rjf: evictor thread - Thread evictor_thread; -}; - -//////////////////////////////// -//~ rjf: Globals - -global GEO_Shared *geo_shared = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void geo_init(void); - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal R_Handle geo_buffer_from_hash(Access *access, U128 hash); -internal R_Handle geo_buffer_from_key(Access *access, C_Key key); - -//////////////////////////////// -//~ rjf: Transfer Threads - -internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us); -internal void geo_u2x_dequeue_req(U128 *hash_out); -ASYNC_WORK_DEF(geo_xfer_work); - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void geo_evictor_thread__entry_point(void *p); - -#endif //GEO_CACHE_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index f4533078..461f8c42 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -259,7 +259,6 @@ #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" #include "ptr_graph_cache/ptr_graph_cache.h" -#include "geo_cache/geo_cache.h" #include "font_cache/font_cache.h" #include "draw/draw.h" #include "ui/ui_inc.h" @@ -308,7 +307,6 @@ #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" #include "ptr_graph_cache/ptr_graph_cache.c" -#include "geo_cache/geo_cache.c" #include "font_cache/font_cache.c" #include "draw/draw.c" #include "ui/ui_inc.c" diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 92e61641..ab6efa48 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -4363,6 +4363,51 @@ struct RD_Geo3DBoxDrawData R_Handle index_buffer; }; +internal AC_Artifact +rd_geo3d_artifact_create(String8 key, B32 *retry_out) +{ + Access *access = access_open(); + U128 hash = {0}; + str8_deserial_read_struct(key, 0, &hash); + String8 data = c_data_from_hash(access, hash); + R_Handle buffer = {0}; + if(data.size != 0) + { + buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str); + } + AC_Artifact artifact = {0}; + MemoryCopy(&artifact, &buffer, Min(sizeof(artifact), sizeof(buffer))); + access_close(access); + return artifact; +} + +internal void +rd_geo3d_artifact_destroy(AC_Artifact artifact) +{ + R_Handle buffer = {0}; + MemoryCopy(&buffer, &artifact, Min(sizeof(buffer), sizeof(artifact))); + r_buffer_release(buffer); +} + +internal R_Handle +rd_geo3d_buffer_from_key(Access *access, C_Key key) +{ + R_Handle result = {0}; + for EachIndex(rewind_idx, C_KEY_HASH_HISTORY_COUNT) + { + U128 hash = c_hash_from_key(key, rewind_idx); + AC_Artifact artifact = ac_artifact_from_key(access, str8_struct(&hash), rd_geo3d_artifact_create, rd_geo3d_artifact_destroy, 0); + R_Handle buffer = {0}; + MemoryCopy(&buffer, &artifact, Min(sizeof(buffer), sizeof(artifact))); + if(!r_handle_match(buffer, r_handle_zero())) + { + result = buffer; + break; + } + } + return result; +} + internal UI_BOX_CUSTOM_DRAW(rd_geo3d_box_draw) { RD_Geo3DBoxDrawData *draw_data = (RD_Geo3DBoxDrawData *)user_data; @@ -4425,8 +4470,8 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d) Rng1U64 vtxs_range = r1u64(vtx_base_off, vtx_base_off+vtx_size); C_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); C_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); - R_Handle idxs_buffer = geo_buffer_from_key(access, idxs_key); - R_Handle vtxs_buffer = geo_buffer_from_key(access, vtxs_key); + R_Handle idxs_buffer = rd_geo3d_buffer_from_key(access, idxs_key); + R_Handle vtxs_buffer = rd_geo3d_buffer_from_key(access, vtxs_key); ////////////////////////////// //- rjf: equip loading info From f61cd2b6738433097f59e1923fa1e0a6a3c5a89f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:47:56 -0700 Subject: [PATCH 270/302] fix use of unused layers --- src/raddbg/raddbg_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 461f8c42..34a1b71f 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -208,8 +208,6 @@ #define OS_GFX_INIT_MANUAL 1 #define FP_INIT_MANUAL 1 #define R_INIT_MANUAL 1 -#define TEX_INIT_MANUAL 1 -#define GEO_INIT_MANUAL 1 #define FNT_INIT_MANUAL 1 #define D_INIT_MANUAL 1 #define RD_INIT_MANUAL 1 @@ -495,7 +493,6 @@ entry_point(CmdLine *cmd_line) os_gfx_init(); fp_init(); r_init(cmd_line); - geo_init(); fnt_init(); d_init(); rd_init(cmd_line); From 6d39a666724f0ba46c8606db7a8c465f00ae79a7 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:52:33 -0700 Subject: [PATCH 271/302] eliminate ptr graph cache experiment --- src/ptr_graph_cache/ptr_graph_cache.c | 204 -------------------------- src/ptr_graph_cache/ptr_graph_cache.h | 186 ----------------------- 2 files changed, 390 deletions(-) delete mode 100644 src/ptr_graph_cache/ptr_graph_cache.c delete mode 100644 src/ptr_graph_cache/ptr_graph_cache.h diff --git a/src/ptr_graph_cache/ptr_graph_cache.c b/src/ptr_graph_cache/ptr_graph_cache.c deleted file mode 100644 index cbf81bf7..00000000 --- a/src/ptr_graph_cache/ptr_graph_cache.c +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -ptg_init(void) -{ - Arena *arena = arena_alloc(); - ptg_shared = push_array(arena, PTG_Shared, 1); - ptg_shared->arena = arena; - ptg_shared->slots_count = 1024; - ptg_shared->stripes_count = Min(ptg_shared->slots_count, os_get_system_info()->logical_processor_count); - ptg_shared->slots = push_array(arena, PTG_GraphSlot, ptg_shared->slots_count); - ptg_shared->stripes = push_array(arena, PTG_GraphStripe, ptg_shared->stripes_count); - for(U64 idx = 0; idx < ptg_shared->stripes_count; idx += 1) - { - ptg_shared->stripes[idx].arena = arena_alloc(); - ptg_shared->stripes[idx].rw_mutex = rw_mutex_alloc(); - ptg_shared->stripes[idx].cv = cond_var_alloc(); - } - ptg_shared->u2b_ring_size = KB(64); - ptg_shared->u2b_ring_base = push_array_no_zero(arena, U8, ptg_shared->u2b_ring_size); - ptg_shared->u2b_ring_cv = cond_var_alloc(); - ptg_shared->u2b_ring_mutex = mutex_alloc(); - ptg_shared->builder_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4); - ptg_shared->builder_threads = push_array(arena, Thread, ptg_shared->builder_thread_count); - for(U64 idx = 0; idx < ptg_shared->builder_thread_count; idx += 1) - { - ptg_shared->builder_threads[idx] = thread_launch(ptg_builder_thread__entry_point, (void *)idx); - } - ptg_shared->evictor_thread = thread_launch(ptg_evictor_thread__entry_point, 0); -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal PTG_Graph * -ptg_graph_from_key(Access *access, PTG_Key *key) -{ - PTG_Graph *g = 0; - return g; -} - -//////////////////////////////// -//~ rjf: Transfer Threads - -internal B32 -ptg_u2b_enqueue_req(PTG_Key *key, U64 endt_us) -{ - B32 good = 0; - MutexScope(ptg_shared->u2b_ring_mutex) for(;;) - { - U64 unconsumed_size = ptg_shared->u2b_ring_write_pos-ptg_shared->u2b_ring_read_pos; - U64 available_size = ptg_shared->u2b_ring_size-unconsumed_size; - if(available_size >= sizeof(key)) - { - good = 1; - ptg_shared->u2b_ring_write_pos += ring_write_struct(ptg_shared->u2b_ring_base, ptg_shared->u2b_ring_size, ptg_shared->u2b_ring_write_pos, &key); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(ptg_shared->u2b_ring_cv); - } - return good; -} - -internal void -ptg_u2b_dequeue_req(PTG_Key *key_out) -{ - MutexScope(ptg_shared->u2b_ring_mutex) for(;;) - { - U64 unconsumed_size = ptg_shared->u2b_ring_write_pos-ptg_shared->u2b_ring_read_pos; - if(unconsumed_size >= sizeof(*key_out)) - { - ptg_shared->u2b_ring_read_pos += ring_read_struct(ptg_shared->u2b_ring_base, ptg_shared->u2b_ring_size, ptg_shared->u2b_ring_read_pos, key_out); - break; - } - cond_var_wait(ptg_shared->u2b_ring_cv, ptg_shared->u2b_ring_mutex, max_U64); - } - cond_var_broadcast(ptg_shared->u2b_ring_cv); -} - -internal void -ptg_builder_thread__entry_point(void *p) -{ - for(;;) - { - Access *access = access_open(); - - //- rjf: get next key - PTG_Key key = {0}; - ptg_u2b_dequeue_req(&key); - - //- rjf: unpack hash - U64 slot_idx = key.root_hash.u64[1]%ptg_shared->slots_count; - U64 stripe_idx = slot_idx%ptg_shared->stripes_count; - PTG_GraphSlot *slot = &ptg_shared->slots[slot_idx]; - PTG_GraphStripe *stripe = &ptg_shared->stripes[stripe_idx]; - - //- rjf: take task - B32 got_task = 0; - MutexScopeR(stripe->rw_mutex) - { - for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&n->key, &key)) - { - got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); - break; - } - } - } - - //- rjf: do task - if(got_task) - { - - } - - //- rjf: commit results to cache - if(got_task) MutexScopeW(stripe->rw_mutex) - { - for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&n->key, &key)) - { - - ins_atomic_u32_eval_assign(&n->is_working, 0); - ins_atomic_u64_inc_eval(&n->load_count); - break; - } - } - } - - access_close(access); - } -} - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void -ptg_evictor_thread__entry_point(void *p) -{ -#if 0 - for(;;) - { - U64 check_time_us = os_now_microseconds(); - U64 check_time_user_clocks = ptg_user_clock_idx(); - U64 evict_threshold_us = 10*1000000; - U64 evict_threshold_user_clocks = 10; - for(U64 slot_idx = 0; slot_idx < ptg_shared->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%ptg_shared->stripes_count; - PTG_GraphSlot *slot = &ptg_shared->slots[slot_idx]; - PTG_GraphStripe *stripe = &ptg_shared->stripes[stripe_idx]; - B32 slot_has_work = 0; - MutexScopeR(stripe->rw_mutex) - { - for(PTG_GraphNode *n = slot->first; n != 0; n = n->next) - { - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) - { - slot_has_work = 1; - break; - } - } - } - if(slot_has_work) MutexScopeW(stripe->rw_mutex) - { - for(PTG_GraphNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(n->scope_ref_count == 0 && - n->last_time_touched_us+evict_threshold_us <= check_time_us && - n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) - { - DLLRemove(slot->first, slot->last, n); - arena_clear(n->arena); - SLLStackPush(stripe->free_node, n); - } - } - } - os_sleep_milliseconds(5); - } - os_sleep_milliseconds(1000); - } -#endif -} diff --git a/src/ptr_graph_cache/ptr_graph_cache.h b/src/ptr_graph_cache/ptr_graph_cache.h deleted file mode 100644 index cc30be76..00000000 --- a/src/ptr_graph_cache/ptr_graph_cache.h +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef PTR_GRAPH_CACHE_H -#define PTR_GRAPH_CACHE_H - -//////////////////////////////// -//~ rjf: Graph Search Key - -typedef struct PTG_Key PTG_Key; -struct PTG_Key -{ - U128 root_hash; - U64 link_offsets[8]; - U64 link_offsets_count; -}; - -//////////////////////////////// -//~ rjf: Cache Types - -typedef struct PTG_Node PTG_Node; -struct PTG_Node -{ - U64 value; -}; - -typedef struct PTG_Link PTG_Link; -struct PTG_Link -{ - U32 from; - U32 to; -}; - -typedef struct PTG_NodeChunkNode PTG_NodeChunkNode; -struct PTG_NodeChunkNode -{ - PTG_NodeChunkNode *next; - PTG_Node *v; - U64 count; - U64 cap; -}; - -typedef struct PTG_NodeChunkList PTG_NodeChunkList; -struct PTG_NodeChunkList -{ - PTG_NodeChunkNode *first; - PTG_NodeChunkNode *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct PTG_NodeArray PTG_NodeArray; -struct PTG_NodeArray -{ - PTG_Node *v; - U64 count; -}; - -typedef struct PTG_LinkChunkNode PTG_LinkChunkNode; -struct PTG_LinkChunkNode -{ - PTG_LinkChunkNode *next; - PTG_Link *v; - U64 count; - U64 cap; -}; - -typedef struct PTG_LinkChunkList PTG_LinkChunkList; -struct PTG_LinkChunkList -{ - PTG_LinkChunkNode *first; - PTG_LinkChunkNode *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct PTG_LinkArray PTG_LinkArray; -struct PTG_LinkArray -{ - PTG_Link *v; - U64 count; -}; - -typedef struct PTG_Graph PTG_Graph; -struct PTG_Graph -{ - PTG_NodeArray nodes; - PTG_LinkArray links; -}; - -typedef struct PTG_GraphNode PTG_GraphNode; -struct PTG_GraphNode -{ - // rjf: links - PTG_GraphNode *next; - PTG_GraphNode *prev; - - // rjf: key - PTG_Key key; - - // rjf: metadata - U64 scope_ref_count; - U64 last_time_touched_us; - U64 last_user_clock_idx_touched; - U64 load_count; - B32 is_working; - - // rjf: content - Arena *arena; - PTG_Graph graph; -}; - -typedef struct PTG_GraphSlot PTG_GraphSlot; -struct PTG_GraphSlot -{ - PTG_GraphNode *first; - PTG_GraphNode *last; -}; - -typedef struct PTG_GraphStripe PTG_GraphStripe; -struct PTG_GraphStripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; - PTG_GraphNode *free_node; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct PTG_Shared PTG_Shared; -struct PTG_Shared -{ - Arena *arena; - - // rjf: cache - U64 slots_count; - U64 stripes_count; - PTG_GraphSlot *slots; - PTG_GraphStripe *stripes; - - // rjf: user -> xfer thread - U64 u2b_ring_size; - U8 *u2b_ring_base; - U64 u2b_ring_write_pos; - U64 u2b_ring_read_pos; - CondVar u2b_ring_cv; - Mutex u2b_ring_mutex; - - // rjf: builder threads - U64 builder_thread_count; - Thread *builder_threads; - - // rjf: evictor thread - Thread evictor_thread; -}; - -//////////////////////////////// -//~ rjf: Globals - -global PTG_Shared *ptg_shared = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void ptg_init(void); - -//////////////////////////////// -//~ rjf: Cache Lookups - -internal PTG_Graph *ptg_graph_from_key(Access *access, PTG_Key *key); - -//////////////////////////////// -//~ rjf: Transfer Threads - -internal B32 ptg_u2b_enqueue_req(PTG_Key *key, U64 endt_us); -internal void ptg_u2b_dequeue_req(PTG_Key *key_out); -internal void ptg_builder_thread__entry_point(void *p); - -//////////////////////////////// -//~ rjf: Evictor Threads - -internal void ptg_evictor_thread__entry_point(void *p); - -#endif // PTR_GRAPH_CACHE_H From 05fbd06f826a6972113147554dd52becace6064f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 11:57:23 -0700 Subject: [PATCH 272/302] delete dead code, dbgi -> dbg_info --- src/base/base_entry_point.c | 2 +- src/{dbgi/dbgi.c => dbg_info/dbg_info.c} | 0 src/{dbgi/dbgi.h => dbg_info/dbg_info.h} | 6 +- src/raddbg/raddbg_main.c | 6 +- src/scratch/convertperf.c | 77 ------------------------ 5 files changed, 6 insertions(+), 85 deletions(-) rename src/{dbgi/dbgi.c => dbg_info/dbg_info.c} (100%) rename src/{dbgi/dbgi.h => dbg_info/dbg_info.h} (95%) delete mode 100644 src/scratch/convertperf.c diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index ce2de7d7..d17dd15b 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -68,7 +68,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL) mtx_init(); #endif -#if defined(DBGI_H) && !defined(DI_INIT_MANUAL) +#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL) di_init(); #endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) diff --git a/src/dbgi/dbgi.c b/src/dbg_info/dbg_info.c similarity index 100% rename from src/dbgi/dbgi.c rename to src/dbg_info/dbg_info.c diff --git a/src/dbgi/dbgi.h b/src/dbg_info/dbg_info.h similarity index 95% rename from src/dbgi/dbgi.h rename to src/dbg_info/dbg_info.h index 10f59b27..22e4d8eb 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbg_info/dbg_info.h @@ -1,8 +1,8 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef DBGI_H -#define DBGI_H +#ifndef DBG_INFO_H +#define DBG_INFO_H //////////////////////////////// //~ rjf: Cache Key Type @@ -486,4 +486,4 @@ internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys); internal DI_Match di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us); ASYNC_WORK_DEF(di_match_work); -#endif // DBGI_H +#endif // DBG_INFO_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 34a1b71f..a835cc51 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -248,7 +248,7 @@ #include "radbin/radbin.h" #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" -#include "dbgi/dbgi.h" +#include "dbg_info/dbg_info.h" #include "disasm/disasm.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" @@ -256,7 +256,6 @@ #include "ctrl/ctrl_inc.h" #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" -#include "ptr_graph_cache/ptr_graph_cache.h" #include "font_cache/font_cache.h" #include "draw/draw.h" #include "ui/ui_inc.h" @@ -296,7 +295,7 @@ #include "radbin/radbin.c" #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" -#include "dbgi/dbgi.c" +#include "dbg_info/dbg_info.c" #include "disasm/disasm.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" @@ -304,7 +303,6 @@ #include "ctrl/ctrl_inc.c" #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" -#include "ptr_graph_cache/ptr_graph_cache.c" #include "font_cache/font_cache.c" #include "draw/draw.c" #include "ui/ui_inc.c" diff --git a/src/scratch/convertperf.c b/src/scratch/convertperf.c deleted file mode 100644 index 3043f1c2..00000000 --- a/src/scratch/convertperf.c +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Build Options - -#define BUILD_TITLE "convertperf" - -//////////////////////////////// -//~ rjf: Includes - -//- rjf: [lib] -#include "third_party/rad_lzb_simple/rad_lzb_simple.h" -#include "third_party/rad_lzb_simple/rad_lzb_simple.c" - -//- rjf: [h] -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "async/async.h" -#include "rdi_format/rdi_format_local.h" -#include "dbgi/dbgi.h" - -//- rjf: [c] -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "async/async.c" -#include "rdi_format/rdi_format_local.c" -#include "dbgi/dbgi.c" - -//////////////////////////////// -//~ rjf: Entry Points - -internal void -entry_point(CmdLine *cmdline) -{ - Arena *arena = arena_alloc(); - String8 list_path = str8_list_first(&cmdline->inputs); - String8 list_data = os_data_from_file_path(arena, list_path); - U8 splits[] = {'\n'}; - String8List lines = str8_split(arena, list_data, splits, ArrayCount(splits), 0); - OS_HandleList processes = {0}; - String8Node *processes_first_path_n = 0; - U64 limit = 64; - U64 idx = 0; - for(String8Node *n = lines.first; n != 0; n = n->next) - { - String8 dll_path = n->string; - ProfScope("kick off %.*s", str8_varg(dll_path)) - { - String8 dll_path_no_ext = str8_chop_last_dot(dll_path); - String8 dll_name = str8_skip_last_slash(dll_path_no_ext); - String8 pdb_path = push_str8f(arena, "%S.pdb", dll_path_no_ext); - String8 rdi_path = push_str8f(arena, "dump/%S.rdi", dll_name); - OS_Handle handle = os_cmd_line_launchf("raddbg --bin %S --out:%S", pdb_path, rdi_path); - os_handle_list_push(arena, &processes, handle); - if(processes_first_path_n == 0) - { - processes_first_path_n = n; - } - idx += 1; - } - if(idx >= limit) - { - String8Node *line_n = processes_first_path_n; - for(OS_HandleNode *n = processes.first; n != 0; n = n->next, line_n = line_n->next) - { - ProfScope("join %.*s", str8_varg(line_n->string)) - { - os_process_join(n->v, max_U64); - } - } - idx = 0; - MemoryZeroStruct(&processes); - processes_first_path_n = 0; - } - } -} From d3d91c64cc699ce497c8d724212c4f7d9e29e0d5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 24 Sep 2025 20:13:03 -0700 Subject: [PATCH 273/302] get DWARF converter up and running --- src/rdi_from_dwarf/rdi_from_dwarf.c | 1135 +++++++++++++-------------- src/rdi_from_dwarf/rdi_from_dwarf.h | 8 +- 2 files changed, 570 insertions(+), 573 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 71fe540a..b2554e34 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -200,7 +200,7 @@ d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input if (has_vargs) { RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); - n->v = type_table->varg_type; + n->v = type_table->builtin_types[RDI_TypeKind_Variadic]; SLLQueuePush(list.first, list.last, n); ++list.count; } @@ -1125,380 +1125,385 @@ d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D //////////////////////////////// //~ rjf: Main Conversion Entry Point + +static const U64 UNIT_CHUNK_CAP = 256; +static const U64 UDT_CHUNK_CAP = 256; +static const U64 TYPE_CHUNK_CAP = 256; +static const U64 GVAR_CHUNK_CAP = 256; +static const U64 TVAR_CHUNK_CAP = 256; +static const U64 PROC_CHUNK_CAP = 256; +static const U64 SCOPE_CHUNK_CAP = 256; +static const U64 INLINE_SITE_CHUNK_CAP = 256; +static const U64 SRC_FILE_CAP = 256; +static const U64 LINE_TABLE_CAP = 256; + +RDIM_TopLevelInfo top_level_info = {0}; +RDIM_BinarySectionList binary_sections = {0}; +RDIM_UnitChunkList units = {0}; +RDIM_UDTChunkList udts = {0}; +RDIM_TypeChunkList types = {0}; +RDIM_SymbolChunkList gvars = {0}; +RDIM_SymbolChunkList tvars = {0}; +RDIM_SymbolChunkList procs = {0}; +RDIM_ScopeChunkList scopes = {0}; +RDIM_InlineSiteChunkList inline_sites = {0}; +RDIM_SrcFileChunkList src_files = {0}; +RDIM_LineTableChunkList line_tables = {0}; internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params) { Temp scratch = scratch_begin(&arena, 1); - //////////////////////////////// - - ProfBegin("compute exe hash"); - U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); - ProfEnd(); - - //////////////////////////////// - - Arch arch = Arch_Null; - U64 image_base = 0; - RDIM_BinarySectionList binary_sections = {0}; - DW_Input input = {0}; - - switch(params->exe_kind) - { + if (lane_idx() == 0) { + //////////////////////////////// + + ProfBegin("compute exe hash"); + U64 exe_hash = rdi_hash(params->exe_data.str, params->exe_data.size); + ProfEnd(); + + //////////////////////////////// + + Arch arch = Arch_Null; + U64 image_base = 0; + DW_Input input = {0}; + + switch(params->exe_kind) { default:{}break; - case ExecutableImageKind_CoffPe: - { - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); - arch = pe.arch; - image_base = pe.image_base; - String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); - U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader); - COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_sections.str; - String8 string_table = str8_substr(params->exe_data, pe.string_table_range); - binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, section_count, section_table); - input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, section_count, section_table); - }break; + case ExecutableImageKind_CoffPe: { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, params->exe_data); + String8 raw_sections = str8_substr(params->exe_data, pe.section_table_range); + COFF_SectionHeader *section_table = str8_deserial_get_raw_ptr(raw_sections, 0, sizeof(COFF_SectionHeader) * pe.section_count); + String8 string_table = str8_substr(params->exe_data, pe.string_table_range); + arch = pe.arch; + image_base = pe.image_base; + binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, params->exe_data, string_table, pe.section_count, section_table); + input = dw_input_from_coff_section_table(scratch.arena, params->exe_data, string_table, pe.section_count, section_table); + } break; case ExecutableImageKind_Elf32: - case ExecutableImageKind_Elf64: - { + case ExecutableImageKind_Elf64: { ELF_Bin bin = elf_bin_from_data(scratch.arena, params->dbg_data); - arch = arch_from_elf_machine(bin.hdr.e_machine); - image_base = elf_base_addr_from_bin(&bin); + arch = arch_from_elf_machine(bin.hdr.e_machine); + image_base = elf_base_addr_from_bin(&bin); binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, bin.shdrs); - input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); - }break; - } - - //////////////////////////////// - - RDIM_TopLevelInfo top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); - - //////////////////////////////// - - U64 arch_addr_size = rdi_addr_size_from_arch(arch); - - //////////////////////////////// - - static const U64 UNIT_CHUNK_CAP = 256; - static const U64 UDT_CHUNK_CAP = 256; - static const U64 TYPE_CHUNK_CAP = 256; - static const U64 GVAR_CHUNK_CAP = 256; - static const U64 TVAR_CHUNK_CAP = 256; - static const U64 PROC_CHUNK_CAP = 256; - static const U64 SCOPE_CHUNK_CAP = 256; - static const U64 INLINE_SITE_CHUNK_CAP = 256; - static const U64 SRC_FILE_CAP = 256; - static const U64 LINE_TABLE_CAP = 256; - - RDIM_UnitChunkList units = {0}; - RDIM_UDTChunkList udts = {0}; - RDIM_TypeChunkList types = {0}; - RDIM_SymbolChunkList gvars = {0}; - RDIM_SymbolChunkList tvars = {0}; - RDIM_SymbolChunkList procs = {0}; - RDIM_ScopeChunkList scopes = {0}; - RDIM_InlineSiteChunkList inline_sites = {0}; - RDIM_SrcFileChunkList src_files = {0}; - RDIM_LineTableChunkList line_tables = {0}; - - //////////////////////////////// - - RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); - - //////////////////////////////// - - ProfBegin("Make Unit Contrib Map"); - D2R_CompUnitContribMap cu_contrib_map = {0}; - if (input.sec[DW_Section_ARanges].data.size > 0) { - cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); - } else { - // TODO: synthesize cu ranges from scopes - NotImplemented; - } - ProfEnd(); - - ProfBegin("Parse Comop Unit Ranges"); - DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); - Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); - Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); - ProfEnd(); - - //////////////////////////////// - - ProfBegin("Parse Compile Unit Headers"); - // TODO(rjf): parse should always be relaxed. any verification checks we do - // should just be logged via log_info(...), and then the caller of this - // converter can collect those & display as necessary. - B32 is_parse_relaxed = 1; - DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { - cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); - } - ProfEnd(); - - //////////////////////////////// - - ProfBegin("Parse Line Tables"); - DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { - DW_CompUnit *cu = &cu_arr[cu_idx]; - String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_StmtList); - String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); - cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); - } - ProfEnd(); - - //////////////////////////////// - - ProfBegin("Convert Line Tables"); - - HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); - RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); - - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { - cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); - - DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; - DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; - DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; - RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); - for (U64 file_idx = 0; file_idx < file_table->count; ++file_idx) { - DW_LineFile *file = &file_table->v[file_idx]; - String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); - String8List file_path_split = str8_split_path(scratch.arena, file_path); - str8_path_list_resolve_dots_in_place(&file_path_split, PathStyle_WindowsAbsolute); - String8 file_path_resolved = str8_path_list_join_by_style(scratch.arena, &file_path_split, PathStyle_WindowsAbsolute); - RDIM_SrcFile *src_file = hash_table_search_path_raw(source_file_ht, file_path_resolved); - if (src_file == 0) { - src_file = rdim_src_file_chunk_list_push(arena, &src_files, SRC_FILE_CAP); - src_file->path = push_str8_copy(arena, file_path_resolved); - hash_table_push_path_raw(scratch.arena, source_file_ht, src_file->path, src_file); - } - src_file_map[file_idx] = src_file; + input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin); + } break; } - - for (DW_LineSeqNode *line_seq = line_table->first_seq; line_seq != 0; line_seq = line_seq->next) { - if (line_seq->count == 0) { - continue; + + //////////////////////////////// + + top_level_info = rdim_make_top_level_info(params->exe_name, arch, exe_hash, binary_sections); + + //////////////////////////////// + + U64 arch_addr_size = rdi_addr_size_from_arch(top_level_info.arch); + + //////////////////////////////// + + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); + + //////////////////////////////// + + ProfBegin("Make Unit Contrib Map"); + D2R_CompUnitContribMap cu_contrib_map = {0}; + if (input.sec[DW_Section_ARanges].data.size > 0) { + cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); + } else { + // TODO: synthesize cu ranges from scopes + NotImplemented; + } + ProfEnd(); + + ProfBegin("Parse Comop Unit Ranges"); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); + Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); + Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Compile Unit Headers"); + // TODO(rjf): parse should always be relaxed. any verification checks we do + // should just be logged via log_info(...), and then the caller of this + // converter can collect those & display as necessary. + B32 is_parse_relaxed = 1; + DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Line Tables"); + DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + DW_CompUnit *cu = &cu_arr[cu_idx]; + String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_StmtList); + String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); + cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Convert Line Tables"); + HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); + RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); + + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; + DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; + DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; + RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); + for (U64 file_idx = 0; file_idx < file_table->count; ++file_idx) { + DW_LineFile *file = &file_table->v[file_idx]; + String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); + String8List file_path_split = str8_split_path(scratch.arena, file_path); + str8_path_list_resolve_dots_in_place(&file_path_split, PathStyle_WindowsAbsolute); + String8 file_path_resolved = str8_path_list_join_by_style(scratch.arena, &file_path_split, PathStyle_WindowsAbsolute); + RDIM_SrcFile *src_file = hash_table_search_path_raw(source_file_ht, file_path_resolved); + if (src_file == 0) { + src_file = rdim_src_file_chunk_list_push(arena, &src_files, SRC_FILE_CAP); + src_file->path = push_str8_copy(arena, file_path_resolved); + hash_table_push_path_raw(scratch.arena, source_file_ht, src_file->path, src_file); + } + src_file_map[file_idx] = src_file; } - - U64 *voffs = push_array(arena, U64, line_seq->count); - U32 *line_nums = push_array(arena, U32, line_seq->count); - U16 *col_nums = 0; - U64 line_idx = 0; - - DW_LineNode *file_line_n = line_seq->first; - U64 file_line_count = 0; - - for (DW_LineNode *line_n = file_line_n; line_n != 0; line_n = line_n->next) { - if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { + + for (DW_LineSeqNode *line_seq = line_table->first_seq; line_seq != 0; line_seq = line_seq->next) { + if (line_seq->count == 0) { + continue; + } + + U64 *voffs = push_array(arena, U64, line_seq->count); + U32 *line_nums = push_array(arena, U32, line_seq->count); + U16 *col_nums = 0; + U64 line_idx = 0; + + DW_LineNode *file_line_n = line_seq->first; + U64 file_line_count = 0; + + for (DW_LineNode *line_n = file_line_n; line_n != 0; line_n = line_n->next) { + if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { + U64 file_index = file_line_n->v.file_index; + U64 *file_voffs = &voffs[line_idx]; + U32 *file_line_nums = &line_nums[line_idx]; + U16 *file_col_nums = 0; + + U64 lines_written = 0; + U64 prev_ln = max_U64; + DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; + for (; file_line_n != sentinel; file_line_n = file_line_n->next) { + if (file_line_n->v.line != prev_ln) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; + + ++lines_written; + ++line_idx; + + prev_ln = file_line_n->v.line; + } + } + + RDIM_SrcFile *src_file = src_file_map[file_index]; + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); + rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + + file_line_count = 1; + } else { + ++file_line_count; + } + } + + // handle last line + if (file_line_n) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - - U64 lines_written = 0; - U64 prev_ln = max_U64; - DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; - for (; file_line_n != sentinel; file_line_n = file_line_n->next) { - if (file_line_n->v.line != prev_ln) { - // TODO: error handling - AssertAlways(file_line_n->v.address >= image_base); - - voffs[line_idx] = file_line_n->v.address - image_base; - line_nums[line_idx] = file_line_n->v.line; - - ++lines_written; - ++line_idx; - - prev_ln = file_line_n->v.line; - } + + for (; file_line_n != 0; file_line_n = file_line_n->next, ++line_idx) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; } - + RDIM_SrcFile *src_file = src_file_map[file_index]; - RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); - - file_line_count = 1; - } else { - ++file_line_count; } + + //Assert(line_idx == line_seq->count); } - - // handle last line - if (file_line_n) { - U64 file_index = file_line_n->v.file_index; - U64 *file_voffs = &voffs[line_idx]; - U32 *file_line_nums = &line_nums[line_idx]; - U16 *file_col_nums = 0; - - for (; file_line_n != 0; file_line_n = file_line_n->next, ++line_idx) { - // TODO: error handling - AssertAlways(file_line_n->v.address >= image_base); - voffs[line_idx] = file_line_n->v.address - image_base; - line_nums[line_idx] = file_line_n->v.line; - } - - RDIM_SrcFile *src_file = src_file_map[file_index]; - RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); - rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + } + ProfEnd(); + + //////////////////////////////// + + RDIM_Type *builtin_types[RDI_TypeKind_Count] = {0}; + for (RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) { + RDIM_Type *type = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); + type->kind = type_kind; + type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); + type->byte_size = rdi_size_from_basic_type_kind(type_kind); + builtin_types[type_kind] = type; + } + builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; + builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); + + //////////////////////////////// + + ProfBegin("Convert Units"); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + DW_CompUnit *cu = &cu_arr[cu_idx]; + + // parse and build tag tree + DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); + + // build tag hash table for abstract origin resolution + cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); + + String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); + String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); + if (dwo_name.size || gnu_dwo_name.size || cu->dwo_id) { + // TODO: report that we dont support DWO + continue; } - - //Assert(line_idx == line_seq->count); - } - } - - ProfEnd(); - - //////////////////////////////// - - ProfBegin("Convert Units"); - - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { - Temp comp_temp = temp_begin(scratch.arena); - - DW_CompUnit *cu = &cu_arr[cu_idx]; - - // parse and build tag tree - DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); - - // build tag hash table for abstract origin resolution - cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); - - String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); - String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); - if (dwo_name.size || gnu_dwo_name.size || cu->dwo_id) { - // TODO: report that we dont support DWO - continue; - } - - // get unit's contribution ranges - RDIM_Rng1U64ChunkList cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); - - String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); - String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); - DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - - RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); - unit->unit_name = cu_name; - unit->compiler_name = cu_prod; - unit->source_file = str8_zero(); - unit->object_file = str8_zero(); - unit->archive_file = str8_zero(); - unit->build_path = cu_dir; - unit->language = d2r_rdi_language_from_dw_language(cu_lang); - unit->line_table = cu_line_tables_rdi[cu_idx]; - unit->voff_ranges = cu_voff_ranges; - - D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); - type_table->ht = hash_table_init(comp_temp.arena, 0x4000); - type_table->types = &types; - type_table->type_chunk_cap = TYPE_CHUNK_CAP; - type_table->varg_type = d2r_create_type(arena, type_table); - type_table->varg_type->kind = RDI_TypeKind_Variadic; - - D2R_TagNode *free_tags = push_array(comp_temp.arena, D2R_TagNode, 1); - D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); - tag_stack->cur_node = tag_tree.root; - - while (tag_stack) { - while (tag_stack->cur_node) { - DW_TagNode *cur_node = tag_stack->cur_node; - DW_Tag tag = cur_node->tag; - B32 visit_children = 1; - - switch (tag.kind) { + + // get unit's contribution ranges + RDIM_Rng1U64ChunkList cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); + + String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); + String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); + DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); + + RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); + unit->unit_name = cu_name; + unit->compiler_name = cu_prod; + unit->source_file = str8_zero(); + unit->object_file = str8_zero(); + unit->archive_file = str8_zero(); + unit->build_path = cu_dir; + unit->language = d2r_rdi_language_from_dw_language(cu_lang); + unit->line_table = cu_line_tables_rdi[cu_idx]; + unit->voff_ranges = cu_voff_ranges; + + D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); + type_table->ht = hash_table_init(comp_temp.arena, 0x4000); + type_table->types = &types; + type_table->type_chunk_cap = TYPE_CHUNK_CAP; + type_table->builtin_types = builtin_types; + + D2R_TagNode *free_tags = push_array(comp_temp.arena, D2R_TagNode, 1); + D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); + tag_stack->cur_node = tag_tree.root; + + while (tag_stack) { + while (tag_stack->cur_node) { + DW_TagNode *cur_node = tag_stack->cur_node; + DW_Tag tag = cur_node->tag; + B32 visit_children = 1; + + switch (tag.kind) { case DW_TagKind_Null: { InvalidPath; } break; case DW_TagKind_ClassType: { RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); if (is_decl) { type->kind = RDI_TypeKind_IncompleteClass; - + Assert(!cur_node->first_child); visit_children = 0; } else { RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); udt->self_type = type; - + type->kind = RDI_TypeKind_Class; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - + tag_stack->type = type; } } break; case DW_TagKind_StructureType: { RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); if (is_decl) { type->kind = RDI_TypeKind_IncompleteStruct; - + // TODO: error handling Assert(!cur_node->first_child); visit_children = 0; } else { RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); udt->self_type = type; - + type->kind = RDI_TypeKind_Struct; type->udt = udt; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - + tag_stack->type = type; } } break; case DW_TagKind_UnionType: { RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); if (is_decl) { type->kind = RDI_TypeKind_IncompleteUnion; - + // TODO: error handling Assert(!cur_node->first_child); visit_children = 0; } else { RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); udt->self_type = type; - + type->kind = RDI_TypeKind_Union; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; - + tag_stack->type = type; } } break; case DW_TagKind_EnumerationType: { RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); if (is_decl) { type->kind = RDI_TypeKind_IncompleteEnum; - + // TODO: error handling Assert(!cur_node->first_child); visit_children = 0; } else { RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); udt->self_type = type; - + type->kind = RDI_TypeKind_Enum; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; - + tag_stack->type = type; } } break; @@ -1510,13 +1515,13 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_AttribKind_Type); rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->varg_type); + rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); } else { // TODO: error handling AssertAlways(!"unexpected tag"); } } - + // init proceudre type RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); @@ -1525,7 +1530,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) type->direct_type = ret_type; type->count = param_list.count; type->param_types = rdim_array_from_type_list(arena, param_list); - + visit_children = 0; } break; case DW_TagKind_Typedef: { @@ -1537,133 +1542,125 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) case DW_TagKind_BaseType: { DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Encoding); U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); - + // convert base type encoding to RDI version RDI_TypeKind kind = RDI_TypeKind_NULL; switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling } - - // TODO(rjf): this is not good. we can't grab existing type nodes & mutate them here. - // to parallelize this properly, we need to *produce* new data only, otherwise threads - // will stomp over each other everywhere. - // - RDIM_Type *base_type = 0; // rdim_builtin_type_from_kind(types, kind); - base_type->kind = kind; - base_type->byte_size = byte_size; - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Alias; type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - type->direct_type = base_type; + type->direct_type = type_table->builtin_types[kind]; } break; case DW_TagKind_PointerType: { RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - + // TODO: Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Allocated)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Associated)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_AddressClass)); - + U64 byte_size = arch_addr_size; if (cu->version == DW_Version_5 || cu->relaxed) { dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); } - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Ptr; type->byte_size = byte_size; @@ -1673,7 +1670,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; type->byte_size = arch_addr_size; @@ -1683,7 +1680,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) case DW_TagKind_VolatileType: { // TODO: Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; type->byte_size = arch_addr_size; @@ -1694,7 +1691,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Modifier; type->byte_size = arch_addr_size; @@ -1724,11 +1721,11 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from // B to A. - + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); type->kind = RDI_TypeKind_Array; type->direct_type = 0; - + U64 subrange_count = 0; RDIM_Type *t = type; for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { @@ -1737,18 +1734,18 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) AssertAlways(!"unexpected tag"); continue; } - + if (subrange_count > 0) { // init array type node RDIM_Type *s = d2r_create_type(arena, type_table); s->kind = RDI_TypeKind_Array; s->direct_type = 0; - + // append new array type node t->direct_type = s; t = s; } - + // resolve array lower bound U64 lower_bound = 0; if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound)) { @@ -1756,7 +1753,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } else { lower_bound = dw_pick_default_lower_bound(cu_lang); } - + // resolve array upper bound U64 upper_bound = 0; if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_Count)) { @@ -1769,14 +1766,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } else { // zero size array } - + t->count = upper_bound - lower_bound; ++subrange_count; } - + Assert(t->direct_type == 0); t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - + visit_children = 0; } break; case DW_TagKind_SubrangeType: { @@ -1790,7 +1787,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: error handling AssertAlways(!"unexpected parent tag"); } - + RDIM_Type *parent = tag_stack->next->type; RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); member->kind = RDI_MemberKind_Base; @@ -1803,7 +1800,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: error handling AssertAlways(!"unexpected parent tag"); } - + RDIM_Type *type = tag_stack->next->type; RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); @@ -1818,13 +1815,13 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // TODO: error handling AssertAlways(!"unexpected parent tag"); } - + DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_AttribKind_DataMemberLocation); DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); if (data_member_location_class == DW_AttribClass_LocList) { AssertAlways(!"UDT member with multiple locations are not supported"); } - + RDIM_Type *type = tag_stack->next->type; RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); member->kind = RDI_MemberKind_DataField; @@ -1835,86 +1832,86 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) case DW_TagKind_SubProgram: { DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_AttribKind_Inline); switch (inl) { - case DW_Inl_NotInlined: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *container_type = 0; - if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { + container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_TagKind_ClassType || parent_tag_kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_ClassType || parent_tag_kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = tag_stack->next->type; - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag_kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - tag_stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - visit_children = 0; - } break; - default: InvalidPath; break; + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag_kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + tag_stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + visit_children = 0; + } break; + default: InvalidPath; break; } } break; case DW_TagKind_InlinedSubroutine: { U64 param_count = 0; RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); - + // get return type RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - + // fill out proc type RDIM_Type *proc_type = d2r_create_type(arena, type_table); proc_type->kind = RDI_TypeKind_Function; @@ -1922,20 +1919,20 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) proc_type->direct_type = ret_type; proc_type->count = param_count; proc_type->param_types = params; - + // get container type RDIM_Type *owner = 0; if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); } - + // fill out inline site RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); inline_site->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); inline_site->type = proc_type; inline_site->owner = owner; inline_site->line_table = 0; - + // make scope Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); @@ -1944,7 +1941,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) case DW_TagKind_Variable: { String8 name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine || @@ -1956,13 +1953,13 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) local->type = type; local->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); } else { - + // NOTE: due to a bug in clang in stb_sprint.h local variables // are declared in global scope without a name if (name.size == 0) { break; } - + RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); gvar->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); gvar->name = name; @@ -2004,112 +2001,112 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) case DW_TagKind_Label: case DW_TagKind_CompileUnit: case DW_TagKind_UnspecifiedParameters: - break; + break; case DW_TagKind_Namespace: break; case DW_TagKind_ImportedDeclaration: break; case DW_TagKind_PtrToMemberType: break; case DW_TagKind_TemplateTypeParameter: break; case DW_TagKind_ReferenceType: break; default: NotImplemented; break; - } - - if (tag_stack->cur_node->first_child && visit_children) { - D2R_TagNode *frame = free_tags; - if (frame) { - SLLStackPop(free_tags); - MemoryZeroStruct(frame); - } else { - frame = push_array(scratch.arena, D2R_TagNode, 1); } - frame->cur_node = tag_stack->cur_node->first_child; - SLLStackPush(tag_stack, frame); - } else { + + if (tag_stack->cur_node->first_child && visit_children) { + D2R_TagNode *frame = free_tags; + if (frame) { + SLLStackPop(free_tags); + MemoryZeroStruct(frame); + } else { + frame = push_array(scratch.arena, D2R_TagNode, 1); + } + frame->cur_node = tag_stack->cur_node->first_child; + SLLStackPush(tag_stack, frame); + } else { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } + + // recycle free frame + D2R_TagNode *frame = tag_stack; + SLLStackPop(tag_stack); + SLLStackPush(free_tags, frame); + + if (tag_stack) { tag_stack->cur_node = tag_stack->cur_node->sibling; } } - - // recycle free frame - D2R_TagNode *frame = tag_stack; - SLLStackPop(tag_stack); - SLLStackPush(free_tags, frame); - - if (tag_stack) { - tag_stack->cur_node = tag_stack->cur_node->sibling; - } + + temp_end(comp_temp); } - - temp_end(comp_temp); - } - - ProfEnd(); - - { - for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { - for (U64 i = 0; i < chunk_n->count; ++i) { - RDIM_Type *type = &chunk_n->v[i]; - if (type->kind == RDI_TypeKind_Alias) { - for (RDIM_Type *t = type->direct_type; t != 0; t = t->direct_type) { - if (t->byte_size != 0) { - type->byte_size = t->byte_size; - break; + ProfEnd(); + + { + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Alias) { + for (RDIM_Type *t = type->direct_type; t != 0; t = t->direct_type) { + if (t->byte_size != 0) { + type->byte_size = t->byte_size; + break; + } } } } } } - } - - { - RDIM_TypeNode *type_stack = 0; - RDIM_TypeNode *free_types = 0; - - for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { - for (U64 i = 0; i < chunk_n->count; ++i) { - RDIM_Type *type = &chunk_n->v[i]; - if (type->kind == RDI_TypeKind_Array) { - if (type->byte_size != 0) - continue; - - RDIM_Type *t; - for (t = type; t != 0 && t->kind == RDI_TypeKind_Array; t = t->direct_type) { - RDIM_TypeNode *f = free_types; - if (f == 0) { - f = push_array(scratch.arena, RDIM_TypeNode, 1); - } else { - SLLStackPop(free_types); + + { + RDIM_TypeNode *type_stack = 0; + RDIM_TypeNode *free_types = 0; + + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Array) { + if (type->byte_size != 0) + continue; + + RDIM_Type *t; + for (t = type; t != 0 && t->kind == RDI_TypeKind_Array; t = t->direct_type) { + RDIM_TypeNode *f = free_types; + if (f == 0) { + f = push_array(scratch.arena, RDIM_TypeNode, 1); + } else { + SLLStackPop(free_types); + } + f->v = t; + SLLStackPush(type_stack, f); } - f->v = t; - SLLStackPush(type_stack, f); - } - - U64 base_type_size = 0; - if (t) { - base_type_size = t->byte_size; - } - - U64 array_size = base_type_size; - while (type_stack) { - if (type_stack->v->count) { - array_size *= type_stack->v->count; - } else { - array_size += type_stack->v->byte_size; + + U64 base_type_size = 0; + if (t) { + base_type_size = t->byte_size; } - SLLStackPop(type_stack); + + U64 array_size = base_type_size; + while (type_stack) { + if (type_stack->v->count) { + array_size *= type_stack->v->count; + } else { + array_size += type_stack->v->byte_size; + } + SLLStackPop(type_stack); + } + + type->count = 0; + type->byte_size = array_size; + + // recycle frames + free_types = type_stack; + type_stack = 0; } - - type->count = 0; - type->byte_size = array_size; - - // recycle frames - free_types = type_stack; - type_stack = 0; } } } } - - //////////////////////////////// - + + lane_sync(); + RDIM_BakeParams bake_params = {0}; bake_params.top_level_info = top_level_info; bake_params.binary_sections = binary_sections; @@ -2123,7 +2120,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) bake_params.procedures = procs; bake_params.scopes = scopes; bake_params.inline_sites = inline_sites; - + scratch_end(scratch); return bake_params; } diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 9eeb54f9..1ad35a13 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -17,10 +17,10 @@ struct D2R_ConvertParams typedef struct D2R_TypeTable { - HashTable *ht; - RDIM_TypeChunkList *types; - U64 type_chunk_cap; - RDIM_Type *varg_type; + HashTable *ht; + RDIM_TypeChunkList *types; + U64 type_chunk_cap; + RDIM_Type **builtin_types; } D2R_TypeTable; typedef struct D2R_TagNode From c4bf855af92e28735c04b9440a69f5971863b116 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 14:54:33 -0700 Subject: [PATCH 274/302] extend artifact cache nodes with last requested vs. last completed gen; pass last requested gen to artifact creation to support cancellation --- src/artifact_cache/artifact_cache.c | 16 +++++++++------- src/artifact_cache/artifact_cache.h | 8 ++++++-- src/ctrl/ctrl_core.c | 4 ++-- src/ctrl/ctrl_core.h | 4 ++-- src/disasm/disasm.c | 2 +- src/disasm/disasm.h | 2 +- src/file_stream/file_stream.c | 2 +- src/file_stream/file_stream.h | 2 +- src/raddbg/raddbg_views.c | 4 ++-- src/text/text.c | 2 +- src/text/text.h | 2 +- 11 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 3c774b4a..94a64706 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -81,7 +81,8 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 { if(str8_match(n->key, key, 0)) { - B32 is_stale = (n->gen != params->gen); + ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen); + B32 is_stale = (n->last_completed_gen != params->gen); if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh))) { got_artifact = 1; @@ -159,6 +160,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } n->v.key = str8_copy(req_batch->arena, key); n->v.gen = params->gen; + n->v.last_requested_gen = &node->last_requested_gen; n->v.create = params->create; } cond_var_broadcast(async_tick_start_cond_var); @@ -166,10 +168,10 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 } // rjf: get value from node, if possible - if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time)) + if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time)) { got_artifact = 1; - artifact_is_stale = (node->gen == params->gen); + artifact_is_stale = (node->last_completed_gen == params->gen); artifact = node->val; access_touch(access, &node->access_pt, stripe->cv); } @@ -327,7 +329,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, &retry); + AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry); // rjf: retry? -> resubmit request if(retry && lane_idx() == 0) @@ -377,7 +379,7 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - n->gen = r->gen; + n->last_completed_gen = r->gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_inc_eval(&n->completion_count); @@ -408,7 +410,7 @@ ac_async_tick(void) // rjf: compute val B32 retry = 0; - AC_Artifact val = r->create(r->key, &retry); + AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry); // rjf: retry? -> resubmit request if(retry) @@ -458,7 +460,7 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - n->gen = r->gen; + n->last_completed_gen = r->gen; n->val = val; ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_inc_eval(&n->completion_count); diff --git a/src/artifact_cache/artifact_cache.h b/src/artifact_cache/artifact_cache.h index 2f874679..6d14a48e 100644 --- a/src/artifact_cache/artifact_cache.h +++ b/src/artifact_cache/artifact_cache.h @@ -16,7 +16,7 @@ struct AC_Artifact //////////////////////////////// //~ rjf: Artifact Computation Function Types -typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *retry_out); +typedef AC_Artifact AC_CreateFunctionType(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); typedef void AC_DestroyFunctionType(AC_Artifact artifact); typedef U32 AC_Flags; @@ -48,6 +48,7 @@ struct AC_Request { String8 key; U64 gen; + U64 *last_requested_gen; AC_CreateFunctionType *create; }; @@ -66,7 +67,8 @@ struct AC_Node // rjf: key/gen/value String8 key; - U64 gen; + U64 last_requested_gen; + U64 last_completed_gen; AC_Artifact val; // rjf: metadata @@ -74,6 +76,8 @@ struct AC_Node U64 working_count; U64 completion_count; U64 evict_threshold_us; + B32 cancelled; + U64 _unused_; }; typedef struct AC_Slot AC_Slot; diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 9271ca3f..849e225a 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7464,7 +7464,7 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) //~ rjf: Process Memory Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_memory_artifact_create(String8 key, B32 *retry_out) +ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { AC_Artifact artifact = {0}; { @@ -7631,7 +7631,7 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, //~ rjf: Call Stack Artifact Cache Hooks / Lookups internal AC_Artifact -ctrl_call_stack_artifact_create(String8 key, B32 *retry_out) +ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { AC_Artifact artifact = {0}; { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 44060551..216aad93 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1253,14 +1253,14 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *retry_out); +internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); internal C_Key ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups -internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *retry_out); +internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStack ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index 56a9572f..d5905f7f 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -265,7 +265,7 @@ struct DASM_Artifact }; internal AC_Artifact -dasm_artifact_create(String8 key, B32 *retry_out) +dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { DASM_Artifact *artifact = 0; if(lane_idx() == 0) diff --git a/src/disasm/disasm.h b/src/disasm/disasm.h index cd346fd7..7ccd09f8 100644 --- a/src/disasm/disasm.h +++ b/src/disasm/disasm.h @@ -197,7 +197,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact dasm_artifact_create(String8 key, B32 *retry_out); +internal AC_Artifact dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void dasm_artifact_destroy(AC_Artifact artifact); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index d099f0c1..f68da6f5 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -32,7 +32,7 @@ fs_change_gen(void) //~ rjf: Cache Interaction internal AC_Artifact -fs_artifact_create(String8 key, B32 *retry_out) +fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 4ecc10ff..9622e48c 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -55,7 +55,7 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Artifact Cache Hooks / Accessing API -internal AC_Artifact fs_artifact_create(String8 key, B32 *retry_out); +internal AC_Artifact fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void fs_artifact_destroy(AC_Artifact artifact); internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index ab6efa48..673ed4be 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -3750,7 +3750,7 @@ struct RD_BitmapCanvasBoxDrawData }; internal AC_Artifact -rd_bitmap_artifact_create(String8 key, B32 *retry_out) +rd_bitmap_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { Access *access = access_open(); @@ -4364,7 +4364,7 @@ struct RD_Geo3DBoxDrawData }; internal AC_Artifact -rd_geo3d_artifact_create(String8 key, B32 *retry_out) +rd_geo3d_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { Access *access = access_open(); U128 hash = {0}; diff --git a/src/text/text.c b/src/text/text.c index ef19c3a3..ba628572 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1969,7 +1969,7 @@ struct TXT_ArtifactCreateShared }; internal AC_Artifact -txt_artifact_create(String8 key, B32 *retry_out) +txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); diff --git a/src/text/text.h b/src/text/text.h index 45f9a2f3..1c31aa52 100644 --- a/src/text/text.h +++ b/src/text/text.h @@ -203,7 +203,7 @@ internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt //////////////////////////////// //~ rjf: Artifact Cache Hooks / Lookups -internal AC_Artifact txt_artifact_create(String8 key, B32 *retry_out); +internal AC_Artifact txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void txt_artifact_destroy(AC_Artifact artifact); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); From 366c63e3ce6ad3fe2718de89267454a8062ecdcc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 15:35:22 -0700 Subject: [PATCH 275/302] extend artifact cache loop with an early-out cancellation path, when new high priority requests have been pushed, while low priority ones are still being worked on --- src/artifact_cache/artifact_cache.c | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 94a64706..5606adfe 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -319,7 +319,17 @@ ac_async_tick(void) lane_sync(); RequestBatchTask *task = &tasks[task_idx]; + //- rjf: set up cancellation signal + U64 cancelled = 0; + U64 *cancelled_ptr = 0; + if(lane_idx() == 0) + { + cancelled_ptr = &cancelled; + } + lane_sync_u64(&cancelled_ptr, 0); + //- rjf: do all wide requests for this priority + U64 done_wide_count = 0; ProfScope("wide requests (p%I64u)", task_idx) { for EachIndex(idx, task->wide_count) @@ -327,6 +337,21 @@ ac_async_tick(void) lane_sync(); AC_Request *r = &task->wide[idx]; + // rjf: any new higher priority tasks? -> cancel + if(task_idx == 1 && idx != 0) MutexScope(ac_shared->req_batches[0].mutex) + { + if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) + { + ins_atomic_u64_eval_assign(cancelled_ptr, 1); + } + } + + // rjf: cancelled? -> exit + if(ins_atomic_u64_eval(cancelled_ptr)) + { + break; + } + // rjf: compute val B32 retry = 0; AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry); @@ -388,11 +413,16 @@ ac_async_tick(void) } cond_var_broadcast(stripe->cv); } + + // rjf: increment count + lane_sync(); + done_wide_count += 1; } } lane_sync(); //- rjf: do all thin requests for this priority + U64 done_thin_count = 0; ProfScope("thin requests (p%I64u)", task_idx) { U64 req_take_counter = 0; @@ -404,6 +434,22 @@ ac_async_tick(void) lane_sync_u64(&req_take_counter_ptr, 0); for(;;) { + // rjf: any new higher priority tasks? -> cancel + if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) != 0) MutexScope(ac_shared->req_batches[0].mutex) + { + if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) + { + ins_atomic_u64_eval_assign(cancelled_ptr, 1); + } + } + + // rjf: cancelled? -> exit + if(ins_atomic_u64_eval(cancelled_ptr)) + { + break; + } + + // rjf: take next task U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1; if(req_idx >= task->thin_count) { break; } AC_Request *r = &task->thin[req_idx]; @@ -471,6 +517,39 @@ ac_async_tick(void) } } lane_sync(); + done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr); + lane_sync(); + } + + //- rjf: cancelled early, unfinished tasks? -> defer to next tick + if(lane_idx() == 0 && task_idx > 0) + { + AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; + MutexScope(batch->mutex) + { + // rjf: push leftover wide tasks + for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1) + { + AC_Request *r = &task->wide[idx]; + AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1); + SLLQueuePush(batch->first_wide, batch->last_wide, n); + batch->wide_count += 1; + MemoryCopyStruct(&n->v, r); + n->v.key = str8_copy(batch->arena, n->v.key); + } + + // rjf: push leftover thin tasks + for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1) + { + AC_Request *r = &task->thin[idx]; + AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1); + SLLQueuePush(batch->first_thin, batch->last_thin, n); + batch->thin_count += 1; + MemoryCopyStruct(&n->v, r); + n->v.key = str8_copy(batch->arena, n->v.key); + } + } + ins_atomic_u32_eval_assign(&async_loop_again, 1); } lane_sync(); } From d1845bf51fccba3d4a756040e07d277a4581aee8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 15:52:58 -0700 Subject: [PATCH 276/302] no_inline on entry_point --- src/base/base_core.h | 12 ++++++++++++ src/os/core/os_core.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index e1123db9..e9a166f2 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -45,12 +45,24 @@ # define thread_static __declspec(thread) #elif COMPILER_CLANG || COMPILER_GCC # define thread_static __thread +#else +# error thread_static not defined for this compiler. #endif #if COMPILER_MSVC # define force_inline __forceinline #elif COMPILER_CLANG || COMPILER_GCC # define force_inline __attribute__((always_inline)) +#else +# error force_inline not defined for this compiler. +#endif + +#if COMPILER_MSVC +# define no_inline __declspec(noinline) +#elif COMPILER_CLANG || COMPILER_GCC +# define no_inline __attribute__((noinline)) +#else +# error no_inline not defined for this compiler. #endif //////////////////////////////// diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index a35852a6..317f1d05 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -319,7 +319,7 @@ internal Guid os_make_guid(void); #if BUILD_ENTRY_DEFINING_UNIT raddbg_entry_point(entry_point); -internal void entry_point(CmdLine *cmdline); +internal no_inline void entry_point(CmdLine *cmdline); #endif #endif // OS_CORE_H From b1b03ebd56758cc345026bd3f821f5d40237c9b6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 16:38:42 -0700 Subject: [PATCH 277/302] turn on opt:ref and opt:icf for all builds --- build.bat | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.bat b/build.bat index 3513251e..d3a3f453 100644 --- a/build.bat +++ b/build.bat @@ -67,7 +67,7 @@ if "%pgo%"=="1" ( set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags% set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% -set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo +set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf set cl_out= /out: set cl_linker= set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 @@ -168,4 +168,3 @@ if "%pgo_run%"=="1" ( ) call %0 %* ) - From 88eddce324417ab4ea6df8ee9000bd7af520f3be Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 16:42:26 -0700 Subject: [PATCH 278/302] same for clang --- build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.bat b/build.bat index d3a3f453..81427182 100644 --- a/build.bat +++ b/build.bat @@ -73,7 +73,7 @@ set cl_linker= set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% -set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" +set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf set clang_out= -o set clang_linker= -Xlinker From 9ad7361cb907c3b131ac54cda7299a7e6e687aea Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 25 Sep 2025 17:07:02 -0700 Subject: [PATCH 279/302] thin out needed entities for call stack build; fix unnecessary re-loops on async threads --- src/artifact_cache/artifact_cache.c | 6 +++- src/ctrl/ctrl_core.c | 54 +++++++++++++++++------------ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 5606adfe..3952cf37 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -524,6 +524,7 @@ ac_async_tick(void) //- rjf: cancelled early, unfinished tasks? -> defer to next tick if(lane_idx() == 0 && task_idx > 0) { + B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count); AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; MutexScope(batch->mutex) { @@ -549,7 +550,10 @@ ac_async_tick(void) n->v.key = str8_copy(batch->arena, n->v.key); } } - ins_atomic_u32_eval_assign(&async_loop_again, 1); + if(need_another_try) + { + ins_atomic_u32_eval_assign(&async_loop_again, 1); + } } lane_sync(); } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 849e225a..2623ea09 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7663,34 +7663,42 @@ ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *r { rec = ctrl_entity_rec_depth_first_pre(src_e, src_process); + // rjf: determine if we need this entity + B32 need_this_entity = (ctrl_handle_match(thread_handle, src_e->handle) || src_e->kind == CTRL_EntityKind_Module || src_e->kind == CTRL_EntityKind_Process); + // rjf: copy this entity - CTRL_Entity *dst_e = push_array(scratch.arena, CTRL_Entity, 1); + CTRL_Entity *dst_e = &ctrl_entity_nil; + if(need_this_entity) { - dst_e->first = dst_e->last = dst_e->next = dst_e->prev = &ctrl_entity_nil; - dst_e->parent = dst_parent; - dst_e->kind = src_e->kind; - dst_e->arch = src_e->arch; - dst_e->is_frozen = src_e->is_frozen; - dst_e->is_soloed = src_e->is_soloed; - dst_e->rgba = src_e->rgba; - dst_e->handle = src_e->handle; - dst_e->id = src_e->id; - dst_e->vaddr_range = src_e->vaddr_range; - dst_e->stack_base = src_e->stack_base; - dst_e->timestamp = src_e->timestamp; - dst_e->bp_flags = src_e->bp_flags; - dst_e->string = push_str8_copy(scratch.arena, src_e->string); - } - if(dst_parent == &ctrl_entity_nil) - { - dst_ctx->root = dst_e; - } - else - { - DLLPushBack_NPZ(&ctrl_entity_nil, dst_parent->first, dst_parent->last, dst_e, next, prev); + dst_e = push_array(scratch.arena, CTRL_Entity, 1); + { + dst_e->first = dst_e->last = dst_e->next = dst_e->prev = &ctrl_entity_nil; + dst_e->parent = dst_parent; + dst_e->kind = src_e->kind; + dst_e->arch = src_e->arch; + dst_e->is_frozen = src_e->is_frozen; + dst_e->is_soloed = src_e->is_soloed; + dst_e->rgba = src_e->rgba; + dst_e->handle = src_e->handle; + dst_e->id = src_e->id; + dst_e->vaddr_range = src_e->vaddr_range; + dst_e->stack_base = src_e->stack_base; + dst_e->timestamp = src_e->timestamp; + dst_e->bp_flags = src_e->bp_flags; + dst_e->string = push_str8_copy(scratch.arena, src_e->string); + } + if(dst_parent == &ctrl_entity_nil) + { + dst_ctx->root = dst_e; + } + else + { + DLLPushBack_NPZ(&ctrl_entity_nil, dst_parent->first, dst_parent->last, dst_e, next, prev); + } } // rjf: insert into hash map + if(dst_e != &ctrl_entity_nil) { U64 hash = ctrl_hash_from_handle(dst_e->handle); U64 slot_idx = hash%dst_ctx->hash_slots_count; From cd7e2d3f892a2079e17e4dfe471213fc629c8286 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 11:37:07 -0700 Subject: [PATCH 280/302] breakpad dumping: include pdb name if missing exe name, include pdb guid if no exe hash --- src/artifact_cache/artifact_cache.c | 2 ++ src/ctrl/ctrl_core.c | 21 ++++++++++++++++++++ src/ctrl/ctrl_core.h | 7 +++++++ src/lib_rdi/rdi.c | 12 ++++++++---- src/radbin/radbin.c | 30 ++++++++++++++++++++++++++++- src/rdi/rdi.mdesk | 12 ++++++++---- 6 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 3952cf37..b9f14027 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -26,6 +26,7 @@ ac_init(void) internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us) { + ProfBeginFunction(); AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1]; //- rjf: create function -> cache @@ -193,6 +194,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6 params->stale_out[0] = artifact_is_stale; } + ProfEnd(); return artifact; } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 2623ea09..e9af43b6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7822,3 +7822,24 @@ ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 h } return result; } + +//////////////////////////////// +//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups + +internal AC_Artifact +ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +{ + +} + +internal void +ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact) +{ + +} + +internal CTRL_CallStackTree +ctrl_call_stack_tree_new(Access *access, U64 endt_us) +{ + +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 216aad93..b2d72f6d 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -1264,4 +1264,11 @@ internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 * internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); internal CTRL_CallStack ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); +//////////////////////////////// +//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups + +internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact); +internal CTRL_CallStackTree ctrl_call_stack_tree_new(Access *access, U64 endt_us); + #endif // CTRL_CORE_H diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 7d6ffc4c..7f2e6515 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -133,11 +133,15 @@ struct {RDI_U8 *str; RDI_U64 size;} rdi_eval_conversion_kind_message_string_tabl RDI_PROC RDI_U64 rdi_hash(RDI_U8 *ptr, RDI_U64 size) { - RDI_U64 result = 5381; - RDI_U8 *opl = ptr + size; - for(;ptr < opl; ptr += 1) + RDI_U64 result = 0; + if(size != 0) { - result = ((result << 5) + result) + *ptr; + result = 5381; + RDI_U8 *opl = ptr + size; + for(;ptr < opl; ptr += 1) + { + result = ((result << 5) + result) + *ptr; + } } return result; } diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index dfc84dc1..9f81bae8 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -807,7 +807,35 @@ rb_thread_entry_point(void *p) //- rjf: dump MODULE record if(lane_idx() == 0) { - str8_list_pushf(arena, &p2b_shared->dump, "MODULE windows x86_64 %I64x %S\n", bake_params.top_level_info.exe_hash, bake_params.top_level_info.exe_name); + // rjf: pick name to identify module + String8 module_name_string = bake_params.top_level_info.exe_name; + if(module_name_string.size == 0 && input_files.first != 0) + { + module_name_string = input_files.first->v->path; + } + + // rjf: pick string for unique code + String8 unique_identifier_string = {0}; + if(unique_identifier_string.size == 0 && bake_params.top_level_info.exe_hash != 0) + { + unique_identifier_string = str8f(arena, "%I64x", bake_params.top_level_info.exe_hash); + } + if(unique_identifier_string.size == 0 && input_files.first != 0 && input_files.first->v->format == RB_FileFormat_PDB) + { + Temp scratch = scratch_begin(&arena, 1); + String8 msf_data = input_files.first->v->data; + MSF_RawStreamTable *st = msf_raw_stream_table_from_data(scratch.arena, msf_data); + String8 info_data = msf_data_from_stream_number(scratch.arena, msf_data, st, PDB_FixedStream_Info); + PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); + if(info != 0) + { + unique_identifier_string = string_from_guid(arena, info->auth_guid); + } + scratch_end(scratch); + } + + // rjf: push record + str8_list_pushf(arena, &p2b_shared->dump, "MODULE windows x86_64 %S %S\n", unique_identifier_string, module_name_string); } //- rjf: dump FILE records diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 68876a09..8abb24e8 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1492,11 +1492,15 @@ RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConver RDI_PROC RDI_U64 rdi_hash(RDI_U8 *ptr, RDI_U64 size) { - RDI_U64 result = 5381; - RDI_U8 *opl = ptr + size; - for(;ptr < opl; ptr += 1) + RDI_U64 result = 0; + if(size != 0) { - result = ((result << 5) + result) + *ptr; + result = 5381; + RDI_U8 *opl = ptr + size; + for(;ptr < opl; ptr += 1) + { + result = ((result << 5) + result) + *ptr; + } } return result; } From 9033ad8a2e290588039115977703532d12f36bc8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 11:44:42 -0700 Subject: [PATCH 281/302] no dashes in guid formatting in breakpad output; also include age --- src/radbin/radbin.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 9f81bae8..ba1640c4 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -827,9 +827,23 @@ rb_thread_entry_point(void *p) MSF_RawStreamTable *st = msf_raw_stream_table_from_data(scratch.arena, msf_data); String8 info_data = msf_data_from_stream_number(scratch.arena, msf_data, st, PDB_FixedStream_Info); PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); - if(info != 0) + if(info != 0 && info_data.size >= sizeof(PDB_InfoHeader)) { - unique_identifier_string = string_from_guid(arena, info->auth_guid); + PDB_InfoHeader *info_header = (PDB_InfoHeader *)info_data.str; + Guid guid = info->auth_guid; + unique_identifier_string = str8f(arena, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%u", + guid.data1, + guid.data2, + guid.data3, + guid.data4[0], + guid.data4[1], + guid.data4[2], + guid.data4[3], + guid.data4[4], + guid.data4[5], + guid.data4[6], + guid.data4[7], + info_header->age); } scratch_end(scratch); } From 99195282f1395412fae223ea56cad332b9aa6018 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 11:57:08 -0700 Subject: [PATCH 282/302] async call stack tree computation -> artifact cache --- src/ctrl/ctrl_core.c | 130 ++++++++++++++++++++++++++++++++++++++- src/raddbg/raddbg_eval.c | 2 +- 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index e9af43b6..74a31f02 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -7829,17 +7829,143 @@ ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 h internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { + Temp scratch = scratch_begin(0, 0); + Access *access = access_open(); + //- rjf: gather list of all thread handles + U64 threads_count = 0; + CTRL_Handle *threads = 0; + CTRL_Handle *threads_processes = 0; + Arch *threads_arches = 0; + MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + { + CTRL_EntityCtx *ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_EntityArray thread_entities = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Thread); + threads_count = thread_entities.count; + threads = push_array(scratch.arena, CTRL_Handle, threads_count); + threads_processes = push_array(scratch.arena, CTRL_Handle, threads_count); + threads_arches = push_array(scratch.arena, Arch, threads_count); + for EachIndex(idx, threads_count) + { + threads[idx] = thread_entities.v[idx]->handle; + threads_processes[idx] = thread_entities.v[idx]->parent->handle; + threads_arches[idx] = thread_entities.v[idx]->arch; + } + } + + //- rjf: gather all callstacks + B32 stale = 0; + U64 pre_mem_gen = ctrl_mem_gen(); + U64 pre_reg_gen = ctrl_reg_gen(); + CTRL_CallStack *call_stacks = push_array(scratch.arena, CTRL_CallStack, threads_count); + { + for EachIndex(idx, threads_count) + { + call_stacks[idx] = ctrl_call_stack_from_thread_new(access, threads[idx], 0, 0); + if(call_stacks[idx].concrete_frames_count == 0) + { + stale = 1; + break; + } + } + } + U64 post_mem_gen = ctrl_mem_gen(); + U64 post_reg_gen = ctrl_reg_gen(); + stale = (stale || pre_mem_gen != post_mem_gen || pre_reg_gen != post_reg_gen); + + //- rjf: build call stack tree + Arena *arena = 0; + CTRL_CallStackTree *tree = 0; + if(!stale) + { + U64 id_gen = 0; + arena = arena_alloc(); + tree = push_array(arena, CTRL_CallStackTree, 1); + tree->root = push_array(arena, CTRL_CallStackTreeNode, 1); + MemoryCopyStruct(tree->root, &ctrl_call_stack_tree_node_nil); + tree->root->id = id_gen; + tree->slots_count = Max(1, threads_count); + tree->slots = push_array(arena, CTRL_CallStackTreeNode *, tree->slots_count); + id_gen += 1; + for EachIndex(thread_idx, threads_count) + { + CTRL_Handle thread = threads[thread_idx]; + CTRL_Handle process = threads_processes[thread_idx]; + Arch arch = threads_arches[thread_idx]; + CTRL_CallStack call_stack = call_stacks[thread_idx]; + CTRL_CallStackTreeNode *thread_node = tree->root; + for EachIndex(frame_idx, call_stack.frames_count) + { + U64 vaddr = regs_rip_from_arch_block(arch, call_stack.frames[frame_idx].regs); + U64 depth = call_stack.frames[frame_idx].inline_depth; + CTRL_CallStackTreeNode *next_node = &ctrl_call_stack_tree_node_nil; + for(CTRL_CallStackTreeNode *child = thread_node->first; child != &ctrl_call_stack_tree_node_nil; child = child->next) + { + if(ctrl_handle_match(child->process, process) && child->vaddr == vaddr && child->depth == depth) + { + next_node = child; + break; + } + } + if(next_node == &ctrl_call_stack_tree_node_nil) + { + next_node = push_array(arena, CTRL_CallStackTreeNode, 1); + MemoryCopyStruct(next_node, &ctrl_call_stack_tree_node_nil); + next_node->id = id_gen; + SLLStackPush_N(tree->slots[next_node->id%tree->slots_count], next_node, hash_next); + id_gen += 1; + SLLQueuePush_NZ(&ctrl_call_stack_tree_node_nil, thread_node->first, thread_node->last, next_node, next); + next_node->parent = thread_node; + thread_node->child_count += 1; + } + thread_node = next_node; + } + ctrl_handle_list_push(arena, &thread_node->threads, &thread); + for(CTRL_CallStackTreeNode *n = thread_node; n != &ctrl_call_stack_tree_node_nil; n = n->parent) + { + n->all_descendant_threads_count += 1; + } + } + } + + //- rjf: produce artifact + AC_Artifact artifact = {0}; + { + artifact.u64[0] = (U64)arena; + artifact.u64[1] = (U64)tree; + } + + //- rjf: retry on stale + if(stale) + { + retry_out[0] = 1; + } + + access_close(access); + scratch_end(scratch); + return artifact; } internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact) { - + Arena *arena = (Arena *)artifact.u64[0]; + if(arena != 0) + { + arena_release(arena); + } } internal CTRL_CallStackTree ctrl_call_stack_tree_new(Access *access, U64 endt_us) { - + CTRL_CallStackTree result = {&ctrl_call_stack_tree_node_nil}; + { + AC_Artifact artifact = ac_artifact_from_key(access, str8_zero(), ctrl_call_stack_tree_artifact_create, ctrl_call_stack_tree_artifact_destroy, endt_us); + if(artifact.u64[1] != 0) + { + MemoryCopyStruct(&result, (CTRL_CallStackTree *)artifact.u64[1]); + } + } + return result; } diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index d6b98a8b..a2264e71 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -1571,7 +1571,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree) if(!rd_state->got_frame_call_stack_tree) { rd_state->got_frame_call_stack_tree = 1; - rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_ctrl_scope, 0); + rd_state->frame_call_stack_tree = ctrl_call_stack_tree_new(rd_state->frame_access, 0); } RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1); accel->node = &ctrl_call_stack_tree_node_nil; From b2acc13fb8edc9bc6f92cbd368d6036fe1d321c3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 12:00:25 -0700 Subject: [PATCH 283/302] eliminate old async call stack computation / call stack cache code --- src/ctrl/ctrl_core.c | 607 --------------------------------------- src/ctrl/ctrl_core.h | 117 -------- src/raddbg/raddbg_core.c | 4 - src/raddbg/raddbg_core.h | 1 - 4 files changed, 729 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 74a31f02..b0e7de5d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1432,70 +1432,6 @@ ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *lis } } -//////////////////////////////// -//~ rjf: Cache Accessing Scopes - -internal CTRL_Scope * -ctrl_scope_open(void) -{ - if(ctrl_tctx == 0) - { - Arena *arena = arena_alloc(); - ctrl_tctx = push_array(arena, CTRL_TCTX, 1); - ctrl_tctx->arena = arena; - } - CTRL_Scope *scope = ctrl_tctx->free_scope; - if(scope != 0) - { - SLLStackPop(ctrl_tctx->free_scope); - } - else - { - scope = push_array_no_zero(ctrl_tctx->arena, CTRL_Scope, 1); - } - MemoryZeroStruct(scope); - return scope; -} - -internal void -ctrl_scope_close(CTRL_Scope *scope) -{ - for(CTRL_ScopeCallStackTouch *t = scope->first_call_stack_touch, *next = 0; t != 0; t = next) - { - next = t->next; - ins_atomic_u64_dec_eval(&t->node->scope_touch_count); - cond_var_broadcast(t->stripe->cv); - SLLStackPush(ctrl_tctx->free_call_stack_touch, t); - } - for(U64 idx = 0; idx < scope->call_stack_tree_touch_count; idx += 1) - { - ins_atomic_u64_dec_eval(&ctrl_state->call_stack_tree_cache.scope_touch_count); - } - if(scope->call_stack_tree_touch_count != 0) - { - cond_var_broadcast(ctrl_state->call_stack_tree_cache.cv); - } - SLLStackPush(ctrl_tctx->free_scope, scope); -} - -internal void -ctrl_scope_touch_call_stack_node__stripe_r_guarded(CTRL_Scope *scope, CTRL_CallStackCacheStripe *stripe, CTRL_CallStackCacheNode *node) -{ - ins_atomic_u64_inc_eval(&node->scope_touch_count); - CTRL_ScopeCallStackTouch *touch = ctrl_tctx->free_call_stack_touch; - if(touch != 0) - { - SLLStackPop(ctrl_tctx->free_call_stack_touch); - } - else - { - touch = push_array(ctrl_tctx->arena, CTRL_ScopeCallStackTouch, 1); - } - SLLQueuePush(scope->first_call_stack_touch, scope->last_call_stack_touch, touch); - touch->stripe = stripe; - touch->node = node; -} - //////////////////////////////// //~ rjf: Main Layer Initialization @@ -1540,16 +1476,6 @@ ctrl_init(void) ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); } - ctrl_state->call_stack_cache.slots_count = 1024; - ctrl_state->call_stack_cache.slots = push_array(arena, CTRL_CallStackCacheSlot, ctrl_state->call_stack_cache.slots_count); - ctrl_state->call_stack_cache.stripes_count = os_get_system_info()->logical_processor_count; - ctrl_state->call_stack_cache.stripes = push_array(arena, CTRL_CallStackCacheStripe, ctrl_state->call_stack_cache.stripes_count); - for(U64 idx = 0; idx < ctrl_state->call_stack_cache.stripes_count; idx += 1) - { - ctrl_state->call_stack_cache.stripes[idx].arena = arena_alloc(); - ctrl_state->call_stack_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); - ctrl_state->call_stack_cache.stripes[idx].cv = cond_var_alloc(); - } ctrl_state->module_image_info_cache.slots_count = 1024; ctrl_state->module_image_info_cache.slots = push_array(arena, CTRL_ModuleImageInfoCacheSlot, ctrl_state->module_image_info_cache.slots_count); ctrl_state->module_image_info_cache.stripes_count = os_get_system_info()->logical_processor_count; @@ -1600,10 +1526,6 @@ ctrl_init(void) ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); ctrl_state->u2ms_ring_mutex = mutex_alloc(); ctrl_state->u2ms_ring_cv = cond_var_alloc(); - ctrl_state->u2csb_ring_size = KB(64); - ctrl_state->u2csb_ring_base = push_array(arena, U8, ctrl_state->u2csb_ring_size); - ctrl_state->u2csb_ring_mutex = mutex_alloc(); - ctrl_state->u2csb_ring_cv = cond_var_alloc(); ctrl_state->ctrl_thread_log = log_alloc(); ctrl_state->ctrl_thread = thread_launch(ctrl_thread__entry_point, 0); } @@ -3428,157 +3350,6 @@ ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U return f; } -//////////////////////////////// -//~ rjf: Call Stack Cache Functions - -internal CTRL_CallStack -ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us) -{ - CTRL_CallStack call_stack = {0}; - CTRL_CallStackCache *cache = &ctrl_state->call_stack_cache; - - ////////////////////////////// - //- rjf: unpack thread - // - U64 hash = ctrl_hash_from_handle(thread_handle); - U64 slot_idx = hash%cache->slots_count; - U64 stripe_idx = slot_idx%cache->stripes_count; - CTRL_CallStackCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_CallStackCacheStripe *stripe = &cache->stripes[stripe_idx]; - U64 reg_gen = ctrl_reg_gen(); - U64 mem_gen = ctrl_mem_gen(); - - ////////////////////////////// - //- rjf: loop: try to grab cached call stack; request; wait - // - B32 can_request = !ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - for(U64 retry_idx = 0;; retry_idx += 1) - { - //- rjf: [read-only] try to look for current call stack; wait if working - B32 node_exists = 0; - B32 node_stale = 1; - B32 node_working = 0; - MutexScopeR(stripe->rw_mutex) for(;;) - { - CTRL_CallStackCacheNode *node = 0; - for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->thread, thread_handle)) - { - node = n; - node_exists = 1; - node_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen); - node_working = (n->working_count > 0); - break; - } - } - if(node_exists && (!can_request || !node_stale || os_now_microseconds() >= endt_us)) - { - call_stack = node->call_stack; - ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, node); - break; - } - else if(node_working) - { - cond_var_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - else - { - break; - } - } - - //- rjf: out of time, or got new result => exit - if((retry_idx > 0 && os_now_microseconds() >= endt_us) || !node_stale) - { - break; - } - - //- rjf: [write] node does not exist => create; request if new or stale - B32 need_request = (!node_exists || node_stale); - CTRL_CallStackCacheNode *node_to_request = 0; - if(can_request && need_request) MutexScopeW(stripe->rw_mutex) - { - CTRL_CallStackCacheNode *node = 0; - for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->thread, thread_handle)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1); - DLLPushBack(slot->first, slot->last, node); - node->thread = thread_handle; - } - if(node->working_count == 0) - { - node->working_count += 1; - node_to_request = node; - } - } - - //- rjf: request if needed - if(node_to_request != 0) - { - if(ctrl_u2csb_enqueue_req(thread_handle, endt_us)) - { - async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); - } - else MutexScopeW(stripe->rw_mutex) - { - node_to_request->working_count -= 1; - } - } - } - - return call_stack; -} - -//////////////////////////////// -//~ rjf: Call Stack Tree Cache Functions - -internal CTRL_CallStackTree -ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us) -{ - CTRL_CallStackTree result = {&ctrl_call_stack_tree_node_nil}; - { - U64 reg_gen = ctrl_reg_gen(); - U64 mem_gen = ctrl_mem_gen(); - CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; - MutexScopeR(cache->rw_mutex) for(;;) - { - // rjf: unpack cache/time state - B32 is_stale = (cache->reg_gen != reg_gen || cache->mem_gen != mem_gen); - B32 out_of_time = (os_now_microseconds() >= endt_us); - - // rjf: is stale? -> request new calculation - if(is_stale && !ins_atomic_u64_eval_cond_assign(&cache->request_count, 1, 0)) - { - rw_mutex_drop_r(cache->rw_mutex); - async_push_work(ctrl_call_stack_tree_build_work); - rw_mutex_take_r(cache->rw_mutex); - } - - // rjf: is not stale, or we're out of time? -> grab cached result & touch, exit - if(!is_stale || out_of_time) - { - result = cache->tree; - ins_atomic_u64_inc_eval(&cache->scope_touch_count); - scope->call_stack_tree_touch_count += 1; - break; - } - - // rjf: wait for new results - cond_var_wait_rw_r(cache->cv, cache->rw_mutex, endt_us); - } - } - return result; -} - //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -7082,384 +6853,6 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) return 0; } -//////////////////////////////// -//~ rjf: Asynchronous Unwinding Functions - -//- rjf: user -> memory stream communication - -internal B32 -ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us) -{ - B32 good = 0; - MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; - U64 available_size = ctrl_state->u2csb_ring_size - unconsumed_size; - if(available_size >= sizeof(thread)) - { - good = 1; - ctrl_state->u2csb_ring_write_pos += ring_write_struct(ctrl_state->u2csb_ring_base, ctrl_state->u2csb_ring_size, ctrl_state->u2csb_ring_write_pos, &thread); - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - cond_var_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, endt_us); - } - if(good) - { - cond_var_broadcast(ctrl_state->u2csb_ring_cv); - } - return good; -} - -internal void -ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread) -{ - MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; - if(unconsumed_size >= sizeof(*out_thread)) - { - ctrl_state->u2csb_ring_read_pos += ring_read_struct(ctrl_state->u2csb_ring_base, ctrl_state->u2csb_ring_size, ctrl_state->u2csb_ring_read_pos, out_thread); - break; - } - cond_var_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, max_U64); - } - cond_var_broadcast(ctrl_state->u2csb_ring_cv); -} - -//- rjf: entry point - -ASYNC_WORK_DEF(ctrl_call_stack_build_work) -{ - Temp scratch = scratch_begin(0, 0); - CTRL_CallStackCache *cache = &ctrl_state->call_stack_cache; - - //- rjf: get next request & unpack - CTRL_Handle thread_handle = {0}; - ctrl_u2csb_dequeue_req(&thread_handle); - U64 hash = ctrl_hash_from_handle(thread_handle); - U64 slot_idx = hash%cache->slots_count; - U64 stripe_idx = hash%cache->stripes_count; - CTRL_CallStackCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_CallStackCacheStripe *stripe = &cache->stripes[stripe_idx]; - - //- rjf: produce mini entity context for just this process - CTRL_EntityCtx *entity_ctx = push_array(scratch.arena, CTRL_EntityCtx, 1); - MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) - { - CTRL_EntityCtx *src_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; - CTRL_EntityCtx *dst_ctx = entity_ctx; - { - dst_ctx->root = &ctrl_entity_nil; - dst_ctx->hash_slots_count = 1024; - dst_ctx->hash_slots = push_array(scratch.arena, CTRL_EntityHashSlot, dst_ctx->hash_slots_count); - MemoryCopyArray(dst_ctx->entity_kind_counts, src_ctx->entity_kind_counts); - MemoryCopyArray(dst_ctx->entity_kind_alloc_gens, src_ctx->entity_kind_alloc_gens); - } - CTRL_Entity *src_thread = ctrl_entity_from_handle(src_ctx, thread_handle); - CTRL_Entity *src_process = ctrl_process_from_entity(src_thread); - { - CTRL_EntityRec rec = {0}; - CTRL_Entity *dst_parent = &ctrl_entity_nil; - for(CTRL_Entity *src_e = src_process; src_e != &ctrl_entity_nil; src_e = rec.next) - { - rec = ctrl_entity_rec_depth_first_pre(src_e, src_process); - - // rjf: copy this entity - CTRL_Entity *dst_e = push_array(scratch.arena, CTRL_Entity, 1); - { - dst_e->first = dst_e->last = dst_e->next = dst_e->prev = &ctrl_entity_nil; - dst_e->parent = dst_parent; - dst_e->kind = src_e->kind; - dst_e->arch = src_e->arch; - dst_e->is_frozen = src_e->is_frozen; - dst_e->is_soloed = src_e->is_soloed; - dst_e->rgba = src_e->rgba; - dst_e->handle = src_e->handle; - dst_e->id = src_e->id; - dst_e->vaddr_range = src_e->vaddr_range; - dst_e->stack_base = src_e->stack_base; - dst_e->timestamp = src_e->timestamp; - dst_e->bp_flags = src_e->bp_flags; - dst_e->string = push_str8_copy(scratch.arena, src_e->string); - } - if(dst_parent == &ctrl_entity_nil) - { - dst_ctx->root = dst_e; - } - else - { - DLLPushBack_NPZ(&ctrl_entity_nil, dst_parent->first, dst_parent->last, dst_e, next, prev); - } - - // rjf: insert into hash map - { - U64 hash = ctrl_hash_from_handle(dst_e->handle); - U64 slot_idx = hash%dst_ctx->hash_slots_count; - CTRL_EntityHashSlot *slot = &dst_ctx->hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->entity->handle, dst_e->handle)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(scratch.arena, CTRL_EntityHashNode, 1); - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->entity = dst_e; - } - } - - // rjf: push/pop - if(rec.push_count) - { - dst_parent = dst_e; - } - else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - dst_parent = dst_parent->parent; - } - } - } - } - - //- rjf: do task - { - CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); - CTRL_Entity *process = ctrl_process_from_entity(thread); - - //- rjf: compute unwind to find list of all concrete frames, then - // call stack, to determine list of all concrete & inline frames - Arena *arena = arena_alloc(); - U64 pre_reg_gen = 0; - U64 post_reg_gen = 0; - U64 pre_mem_gen = 0; - U64 post_mem_gen = 0; - CTRL_Unwind unwind = {0}; - CTRL_CallStack call_stack = {0}; - { - pre_reg_gen = ctrl_reg_gen(); - pre_mem_gen = ctrl_mem_gen(); - unwind = ctrl_unwind_from_thread(arena, entity_ctx, thread_handle, os_now_microseconds()+5000); - call_stack = ctrl_call_stack_from_unwind(arena, process, &unwind); - post_reg_gen = ctrl_reg_gen(); - post_mem_gen = ctrl_mem_gen(); - } - - //- rjf: store new results in cache - Arena *last_arena = arena; - if(pre_reg_gen == post_reg_gen && - pre_mem_gen == post_mem_gen) - { - B32 found = 0; - B32 committed = 0; - MutexScopeW(stripe->rw_mutex) for(;;) - { - // rjf: try to find node & commit - for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->thread, thread_handle)) - { - found = 1; - if(n->scope_touch_count == 0) - { - committed = 1; - if(unwind.flags == 0 || call_stack.frames_count >= n->call_stack.frames_count) - { - last_arena = n->arena; - n->arena = arena; - n->call_stack = call_stack; - } - if(unwind.flags == 0) - { - n->reg_gen = pre_reg_gen; - n->mem_gen = pre_mem_gen; - } - } - break; - } - } - - // rjf: not found, or committed? -> abort - if(!found || committed) - { - break; - } - - // rjf: found, not committed? -> wait & retry - if(found && !committed) - { - cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+10); - } - } - } - - //- rjf: release last results - if(last_arena != 0) - { - arena_release(last_arena); - } - - //- rjf: mark work as done - MutexScopeW(stripe->rw_mutex) for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->thread, thread_handle)) - { - ins_atomic_u64_dec_eval(&n->working_count); - break; - } - } - - //- rjf: broadcast update - cond_var_broadcast(stripe->cv); - if(ctrl_state->wakeup_hook != 0) - { - ctrl_state->wakeup_hook(); - } - } - - scratch_end(scratch); - return 0; -} - -//////////////////////////////// -//~ rjf: Asynchronous Call Stack Tree Building Functions - -ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work) -{ - Temp scratch = scratch_begin(0, 0); - CTRL_Scope *ctrl_scope = ctrl_scope_open(); - - //- rjf: gather list of all thread handles - U64 threads_count = 0; - CTRL_Handle *threads = 0; - CTRL_Handle *threads_processes = 0; - Arch *threads_arches = 0; - MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) - { - CTRL_EntityCtx *ctx = &ctrl_state->ctrl_thread_entity_store->ctx; - CTRL_EntityArray thread_entities = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Thread); - threads_count = thread_entities.count; - threads = push_array(scratch.arena, CTRL_Handle, threads_count); - threads_processes = push_array(scratch.arena, CTRL_Handle, threads_count); - threads_arches = push_array(scratch.arena, Arch, threads_count); - for EachIndex(idx, threads_count) - { - threads[idx] = thread_entities.v[idx]->handle; - threads_processes[idx] = thread_entities.v[idx]->parent->handle; - threads_arches[idx] = thread_entities.v[idx]->arch; - } - } - - //- rjf: gather all callstacks - U64 pre_mem_gen = ctrl_mem_gen(); - U64 pre_reg_gen = ctrl_reg_gen(); - CTRL_CallStack *call_stacks = push_array(scratch.arena, CTRL_CallStack, threads_count); - { - for EachIndex(idx, threads_count) - { - call_stacks[idx] = ctrl_call_stack_from_thread(ctrl_scope, threads[idx], 0, os_now_microseconds()+1000); - } - } - U64 post_mem_gen = ctrl_mem_gen(); - U64 post_reg_gen = ctrl_reg_gen(); - - //- rjf: build call stack tree - Arena *arena = 0; - CTRL_CallStackTree tree = {&ctrl_call_stack_tree_node_nil}; - if(pre_mem_gen == post_mem_gen && - pre_reg_gen == post_reg_gen) - { - U64 id_gen = 0; - arena = arena_alloc(); - tree.root = push_array(arena, CTRL_CallStackTreeNode, 1); - MemoryCopyStruct(tree.root, &ctrl_call_stack_tree_node_nil); - tree.root->id = id_gen; - tree.slots_count = Max(1, threads_count); - tree.slots = push_array(arena, CTRL_CallStackTreeNode *, tree.slots_count); - id_gen += 1; - for EachIndex(thread_idx, threads_count) - { - CTRL_Handle thread = threads[thread_idx]; - CTRL_Handle process = threads_processes[thread_idx]; - Arch arch = threads_arches[thread_idx]; - CTRL_CallStack call_stack = call_stacks[thread_idx]; - CTRL_CallStackTreeNode *thread_node = tree.root; - for EachIndex(frame_idx, call_stack.frames_count) - { - U64 vaddr = regs_rip_from_arch_block(arch, call_stack.frames[frame_idx].regs); - U64 depth = call_stack.frames[frame_idx].inline_depth; - CTRL_CallStackTreeNode *next_node = &ctrl_call_stack_tree_node_nil; - for(CTRL_CallStackTreeNode *child = thread_node->first; child != &ctrl_call_stack_tree_node_nil; child = child->next) - { - if(ctrl_handle_match(child->process, process) && child->vaddr == vaddr && child->depth == depth) - { - next_node = child; - break; - } - } - if(next_node == &ctrl_call_stack_tree_node_nil) - { - next_node = push_array(arena, CTRL_CallStackTreeNode, 1); - MemoryCopyStruct(next_node, &ctrl_call_stack_tree_node_nil); - next_node->id = id_gen; - SLLStackPush_N(tree.slots[next_node->id%tree.slots_count], next_node, hash_next); - id_gen += 1; - SLLQueuePush_NZ(&ctrl_call_stack_tree_node_nil, thread_node->first, thread_node->last, next_node, next); - next_node->parent = thread_node; - thread_node->child_count += 1; - } - thread_node = next_node; - } - ctrl_handle_list_push(arena, &thread_node->threads, &thread); - for(CTRL_CallStackTreeNode *n = thread_node; n != &ctrl_call_stack_tree_node_nil; n = n->parent) - { - n->all_descendant_threads_count += 1; - } - } - } - - //- rjf: commit to cache - Arena *old_arena = 0; - CTRL_CallStackTreeCache *cache = &ctrl_state->call_stack_tree_cache; - if(tree.root != &ctrl_call_stack_tree_node_nil) - { - MutexScopeW(cache->rw_mutex) for(;;) - { - if(cache->scope_touch_count == 0) - { - old_arena = cache->arena; - cache->arena = arena; - cache->tree = tree; - cache->reg_gen = post_reg_gen; - cache->mem_gen = post_mem_gen; - cache->request_count -= 1; - break; - } - cond_var_wait_rw_w(cache->cv, cache->rw_mutex, max_U64); - } - } - cond_var_broadcast(cache->cv); - - //- rjf: release old arena - if(old_arena) - { - arena_release(old_arena); - } - - ctrl_scope_close(ctrl_scope); - scratch_end(scratch); - return 0; -} - //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b2d72f6d..fb2cf401 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -646,53 +646,6 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; -//////////////////////////////// -//~ rjf: Call Stack Cache Types - -typedef struct CTRL_CallStackCacheNode CTRL_CallStackCacheNode; -struct CTRL_CallStackCacheNode -{ - CTRL_CallStackCacheNode *next; - CTRL_CallStackCacheNode *prev; - - // rjf: key - CTRL_Handle thread; - U64 reg_gen; - U64 mem_gen; - - // rjf: counters - U64 scope_touch_count; - U64 working_count; - - // rjf: value - Arena *arena; - CTRL_CallStack call_stack; -}; - -typedef struct CTRL_CallStackCacheSlot CTRL_CallStackCacheSlot; -struct CTRL_CallStackCacheSlot -{ - CTRL_CallStackCacheNode *first; - CTRL_CallStackCacheNode *last; -}; - -typedef struct CTRL_CallStackCacheStripe CTRL_CallStackCacheStripe; -struct CTRL_CallStackCacheStripe -{ - Arena *arena; - RWMutex rw_mutex; - CondVar cv; -}; - -typedef struct CTRL_CallStackCache CTRL_CallStackCache; -struct CTRL_CallStackCache -{ - U64 slots_count; - CTRL_CallStackCacheSlot *slots; - U64 stripes_count; - CTRL_CallStackCacheStripe *stripes; -}; - //////////////////////////////// //~ rjf: Module Image Info Cache Types @@ -780,34 +733,6 @@ struct CTRL_EvalScope E_InterpretCtx interpret_ctx; }; -//////////////////////////////// -//~ rjf: Control Cache Accessing Scopes - -typedef struct CTRL_ScopeCallStackTouch CTRL_ScopeCallStackTouch; -struct CTRL_ScopeCallStackTouch -{ - CTRL_ScopeCallStackTouch *next; - CTRL_CallStackCacheStripe *stripe; - CTRL_CallStackCacheNode *node; -}; - -typedef struct CTRL_Scope CTRL_Scope; -struct CTRL_Scope -{ - CTRL_Scope *next; - CTRL_ScopeCallStackTouch *first_call_stack_touch; - CTRL_ScopeCallStackTouch *last_call_stack_touch; - U64 call_stack_tree_touch_count; -}; - -typedef struct CTRL_TCTX CTRL_TCTX; -struct CTRL_TCTX -{ - Arena *arena; - CTRL_Scope *free_scope; - CTRL_ScopeCallStackTouch *free_call_stack_touch; -}; - //////////////////////////////// //~ rjf: Module Requirement Cache Types @@ -857,7 +782,6 @@ struct CTRL_State // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; - CTRL_CallStackCache call_stack_cache; CTRL_ModuleImageInfoCache module_image_info_cache; CTRL_CallStackTreeCache call_stack_tree_cache; @@ -921,14 +845,6 @@ struct CTRL_State U64 u2ms_ring_read_pos; Mutex u2ms_ring_mutex; CondVar u2ms_ring_cv; - - // rjf: user -> call stack builder ring buffer - U64 u2csb_ring_size; - U8 *u2csb_ring_base; - U64 u2csb_ring_write_pos; - U64 u2csb_ring_read_pos; - Mutex u2csb_ring_mutex; - CondVar u2csb_ring_cv; }; //////////////////////////////// @@ -951,7 +867,6 @@ read_only global CTRL_CallStackTreeNode ctrl_call_stack_tree_node_nil = &ctrl_call_stack_tree_node_nil, &ctrl_call_stack_tree_node_nil, }; -thread_static CTRL_TCTX *ctrl_tctx = 0; thread_static CTRL_EntityCtxLookupAccel *ctrl_entity_ctx_lookup_accel = 0; //////////////////////////////// @@ -1078,13 +993,6 @@ internal CTRL_Entity *ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id); //- rjf: applying events to entity caches internal void ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *list); -//////////////////////////////// -//~ rjf: Cache Accessing Scopes - -internal CTRL_Scope *ctrl_scope_open(void); -internal void ctrl_scope_close(CTRL_Scope *scope); -internal void ctrl_scope_touch_call_stack_node__stripe_r_guarded(CTRL_Scope *scope, CTRL_CallStackCacheStripe *stripe, CTRL_CallStackCacheNode *node); - //////////////////////////////// //~ rjf: Main Layer Initialization @@ -1153,16 +1061,6 @@ internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, internal CTRL_CallStack ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *base_unwind); internal CTRL_CallStackFrame *ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U64 unwind_count, U64 inline_depth); -//////////////////////////////// -//~ rjf: Call Stack Cache Functions - -internal CTRL_CallStack ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); - -//////////////////////////////// -//~ rjf: Call Stack Tree Cache Functions - -internal CTRL_CallStackTree ctrl_call_stack_tree(CTRL_Scope *scope, U64 endt_us); - //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -1235,21 +1133,6 @@ internal void ctrl_u2ms_dequeue_req(C_Key *out_key, CTRL_Handle *out_process, Rn //- rjf: entry point ASYNC_WORK_DEF(ctrl_mem_stream_work); -//////////////////////////////// -//~ rjf: Asynchronous Call Stack Building Functions - -//- rjf: user -> memory stream communication -internal B32 ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us); -internal void ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread); - -//- rjf: entry point -ASYNC_WORK_DEF(ctrl_call_stack_build_work); - -//////////////////////////////// -//~ rjf: Asynchronous Call Stack Tree Building Functions - -ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work); - //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 6ddf6c8c..05d4fd96 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11497,10 +11497,8 @@ rd_frame(void) // Access *frame_access_restore = rd_state->frame_access; DI_Scope *frame_di_scope_restore = rd_state->frame_di_scope; - CTRL_Scope *frame_ctrl_scope_restore = rd_state->frame_ctrl_scope; rd_state->frame_access = access_open(); rd_state->frame_di_scope = di_scope_open(); - rd_state->frame_ctrl_scope = ctrl_scope_open(); rd_state->got_frame_call_stack_tree = 0; ////////////////////////////// @@ -17327,10 +17325,8 @@ rd_frame(void) // access_close(rd_state->frame_access); di_scope_close(rd_state->frame_di_scope); - ctrl_scope_close(rd_state->frame_ctrl_scope); rd_state->frame_access = frame_access_restore; rd_state->frame_di_scope = frame_di_scope_restore; - rd_state->frame_ctrl_scope = frame_ctrl_scope_restore; ////////////////////////////// //- rjf: submit rendering to all windows diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 388be833..c58aff29 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -601,7 +601,6 @@ struct RD_State F32 frame_dt; Access *frame_access; DI_Scope *frame_di_scope; - CTRL_Scope *frame_ctrl_scope; CTRL_CallStackTree frame_call_stack_tree; B32 got_frame_call_stack_tree; From ad9c67ae4342fd66d250159851619803854d31ba Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 13:44:19 -0700 Subject: [PATCH 284/302] eliminate old caches from ctrl layer --- src/ctrl/ctrl_core.c | 933 +++++++------------------------ src/ctrl/ctrl_core.h | 150 +---- src/dbg_engine/dbg_engine_core.c | 4 +- src/raddbg/raddbg_core.c | 10 +- src/raddbg/raddbg_eval.c | 4 +- src/raddbg/raddbg_views.c | 4 +- src/raddbg/raddbg_widgets.c | 2 +- 7 files changed, 230 insertions(+), 877 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index b0e7de5d..30ce342c 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1458,15 +1458,6 @@ ctrl_init(void) e_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); } } - ctrl_state->process_memory_cache.slots_count = 256; - ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); - ctrl_state->process_memory_cache.stripes_count = os_get_system_info()->logical_processor_count; - ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); - for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) - { - ctrl_state->process_memory_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); - ctrl_state->process_memory_cache.stripes[idx].cv = cond_var_alloc(); - } ctrl_state->thread_reg_cache.slots_count = 1024; ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); ctrl_state->thread_reg_cache.stripes_count = os_get_system_info()->logical_processor_count; @@ -1485,9 +1476,6 @@ ctrl_init(void) ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc(); ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = rw_mutex_alloc(); } - ctrl_state->call_stack_tree_cache.tree.root = &ctrl_call_stack_tree_node_nil; - ctrl_state->call_stack_tree_cache.cv = cond_var_alloc(); - ctrl_state->call_stack_tree_cache.rw_mutex = rw_mutex_alloc(); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = mutex_alloc(); @@ -1520,12 +1508,6 @@ ctrl_init(void) ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); } } - ctrl_state->mem_req_mutex = mutex_alloc(); - ctrl_state->mem_req_arena = arena_alloc(); - ctrl_state->u2ms_ring_size = KB(64); - ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); - ctrl_state->u2ms_ring_mutex = mutex_alloc(); - ctrl_state->u2ms_ring_cv = cond_var_alloc(); ctrl_state->ctrl_thread_log = log_alloc(); ctrl_state->ctrl_thread = thread_launch(ctrl_thread__entry_point, 0); } @@ -1539,466 +1521,6 @@ ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) ctrl_state->wakeup_hook = wakeup_hook; } -//////////////////////////////// -//~ rjf: Process Memory Functions - -//- rjf: process memory cache key reading - -internal C_Key -ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) -{ - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - - //- rjf: unpack process key - U64 process_hash = ctrl_hash_from_handle(process); - U64 process_slot_idx = process_hash%cache->slots_count; - U64 process_stripe_idx = process_slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; - CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; - - //- rjf: get the content root for this process; construct process node if it - // doesn't exist - C_Root root = {0}; - { - for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) - { - B32 node_found = 0; - RWMutexScope(process_stripe->rw_mutex, write_mode) - { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->handle, process)) - { - node_found = 1; - root = n->root; - break; - } - } - } - if(write_mode && !node_found) - { - node_found = 1; - Arena *node_arena = arena_alloc(); - CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); - DLLPushBack(process_slot->first, process_slot->last, node); - node->arena = node_arena; - node->handle = process; - node->root = c_root_alloc(); - node->range_hash_slots_count = 1024; - node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); - root = node->root; - } - if(node_found) - { - break; - } - } - } - - //- rjf: form ID for this process memory query - C_ID id = {0}; - { - id.u128[0].u64[0] = vaddr_range.min & 0x00ffffffffffffffull; - id.u128[0].u64[1] = vaddr_range.max & 0x00ffffffffffffffull; - if(zero_terminated) - { - id.u128[0].u64[0] |= (1ull << 63); - } - } - U64 range_hash = u64_hash_from_str8(str8_struct(&id)); - - //- rjf: form full key - C_Key key = c_key_make(root, id); - - //- rjf: loop: try to look for current results, request if not there, wait if we can, repeat until we can't - U64 mem_gen = ctrl_mem_gen(); - B32 key_is_stale = 0; - for(;;) - { - //- rjf: step 1: [read-only] try to look for current results for key's ID; wait if working & retry - B32 id_exists = 0; - B32 id_stale = 0; - B32 id_working = 0; - MutexScopeR(process_stripe->rw_mutex) for(;;) - { - for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) - { - if(ctrl_handle_match(process_n->handle, process)) - { - U64 range_slot_idx = range_hash%process_n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - if(c_id_match(n->id, id)) - { - id_exists = 1; - id_stale = (n->mem_gen < mem_gen); - id_working = (n->working_count != 0); - goto end_fast_lookup; - } - } - } - } - end_fast_lookup:; - if(!id_stale || !id_working || os_now_microseconds() >= endt_us) - { - break; - } - else - { - cond_var_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); - } - } - key_is_stale = id_stale; - - //- rjf: step 2: if the ID exists and is not stale, then we're done; - // the hash store contains the most up-to-date representation of the - // process memory for this key. - if(id_exists && !id_stale) - { - break; - } - - //- rjf: step 3: if the ID does not exist in the process' cache, then we - // need to build a node for it. if that, or if the ID is stale, then also - // request that that range is streamed & wait for its result (for as long - // as we have.) - B32 requested = 0; - if(!id_exists || (id_exists && id_stale && !id_working)) - { - B32 node_needs_stream = 0; - MutexScopeW(process_stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) - { - if(ctrl_handle_match(process_n->handle, process)) - { - U64 range_slot_idx = range_hash%process_n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; - CTRL_ProcessMemoryRangeHashNode *range_n = 0; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - if(c_id_match(n->id, id)) - { - range_n = n; - break; - } - } - if(range_n == 0) - { - range_n = push_array(process_n->arena, CTRL_ProcessMemoryRangeHashNode, 1); - SLLQueuePush(range_slot->first, range_slot->last, range_n); - range_n->vaddr_range = vaddr_range; - range_n->zero_terminated = zero_terminated; - range_n->id = id; - node_needs_stream = 1; - } - else - { - node_needs_stream = (range_n->mem_gen < mem_gen && range_n->working_count == 0); - } - if(node_needs_stream) - { - range_n->working_count += 1; - } - break; - } - } - } - if(node_needs_stream) - { - if(ctrl_u2ms_enqueue_req(key, process, vaddr_range, zero_terminated, endt_us)) - { - // NOTE(rjf): debugging -#if 0 - raddbg_log("[0x%I64x, 0x%I64x) push: (gen: %I64u)\n", vaddr_range.min, vaddr_range.max, mem_gen); -#endif - async_push_work(ctrl_mem_stream_work); - requested = 1; - } - else MutexScopeW(process_stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) - { - if(ctrl_handle_match(process_n->handle, process)) - { - U64 range_slot_idx = range_hash%process_n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; - CTRL_ProcessMemoryRangeHashNode *range_n = 0; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - if(c_id_match(n->id, id)) - { - n->working_count -= 1; - break; - } - } - } - } - } - } - } - - //- rjf: step 4: if we didn't request, and if we aren't working, then exit - if(!requested) - { - break; - } - - //- rjf: step 5: exit if out of time - if(os_now_microseconds() >= endt_us) - { - break; - } - } - if(out_is_stale) - { - *out_is_stale = key_is_stale; - } - return key; -} - -//- rjf: process memory cache reading helpers - -internal CTRL_ProcessMemorySlice -ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us) -{ - ProfBeginFunction(); - CTRL_ProcessMemorySlice result = {0}; - if(range.max > range.min && - dim_1u64(range) <= MB(256) && - range.min <= 0x000FFFFFFFFFFFFFull && - range.max <= 0x000FFFFFFFFFFFFFull) - { - Temp scratch = scratch_begin(&arena, 1); - Access *access = access_open(); - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - - //- rjf: unpack address range, prepare per-touched-page info - U64 page_size = KB(4); - Rng1U64 page_range = r1u64(AlignDownPow2(range.min, page_size), AlignPow2(range.max, page_size)); - U64 page_count = dim_1u64(page_range)/page_size; - U128 *page_hashes = push_array(scratch.arena, U128, page_count); - U128 *page_last_hashes = push_array(scratch.arena, U128, page_count); - - //- rjf: gather hashes & last-hashes for each page - ProfScope("gather hashes & last-hashes for each page") - { - for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) - { - U64 page_base_vaddr = page_range.min + page_idx*page_size; - B32 page_is_stale = 0; - C_Key page_key = ctrl_key_from_process_vaddr_range_new(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); - U128 page_hash = c_hash_from_key(page_key, 0); - U128 page_last_hash = c_hash_from_key(page_key, 1); - result.stale = (result.stale || page_is_stale); - page_hashes[page_idx] = page_hash; - page_last_hashes[page_idx] = page_last_hash; - } - } - - //- rjf: setup output buffers - void *read_out = push_array(arena, U8, dim_1u64(range)); - U64 *byte_bad_flags = push_array(arena, U64, (dim_1u64(range)+63)/64); - U64 *byte_changed_flags = push_array(arena, U64, (dim_1u64(range)+63)/64); - - //- rjf: iterate pages, fill output - ProfScope("iterate pages, fill output") - { - U64 write_off = 0; - for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) - { - // rjf: read data for this page - String8 data = c_data_from_hash(access, page_hashes[page_idx]); - Rng1U64 data_vaddr_range = r1u64(page_range.min + page_idx*page_size, page_range.min + page_idx*page_size+data.size); - - // rjf: skip/chop bytes which are irrelevant for the actual requested read - String8 in_range_data = data; - if(page_idx == page_count-1 && data_vaddr_range.max > range.max) - { - in_range_data = str8_chop(in_range_data, data_vaddr_range.max-range.max); - } - if(page_idx == 0 && range.min > data_vaddr_range.min) - { - in_range_data = str8_skip(in_range_data, range.min-data_vaddr_range.min); - } - - // rjf: write this chunk - MemoryCopy((U8*)read_out+write_off, in_range_data.str, in_range_data.size); - - // rjf; if this page's data doesn't fill the entire range, mark - // missing bytes as bad - if(data.size < page_size) ProfScope("mark missing bytes as bad") - { - Rng1U64 invalid_range = r1u64(data_vaddr_range.min+data.size, data_vaddr_range.min + page_size); - Rng1U64 in_range_invalid_range = intersect_1u64(invalid_range, range); - for(U64 invalid_vaddr = in_range_invalid_range.min; - invalid_vaddr < in_range_invalid_range.max; - invalid_vaddr += 1) - { - U64 idx_in_range = invalid_vaddr - range.min; - byte_bad_flags[idx_in_range/64] |= (1ull<<(idx_in_range%64)); - } - } - - // rjf: if this page's hash & last_hash don't match, diff each byte & - // fill out changed flags - if(!u128_match(page_hashes[page_idx], page_last_hashes[page_idx])) ProfScope("hashes don't match; diff each byte") - { - String8 last_data = c_data_from_hash(access, page_last_hashes[page_idx]); - String8 in_range_last_data = last_data; - if(page_idx == page_count-1 && data_vaddr_range.max > range.max) - { - in_range_last_data = str8_chop(in_range_last_data, data_vaddr_range.max-range.max); - } - if(page_idx == 0 && range.min > data_vaddr_range.min) - { - in_range_last_data = str8_skip(in_range_last_data, range.min-data_vaddr_range.min); - } - for(U64 idx = 0; idx < in_range_data.size; idx += 1) - { - U8 last_byte = idx < in_range_last_data.size ? in_range_last_data.str[idx] : 0; - U8 now_byte = idx < in_range_data.size ? in_range_data.str[idx] : 0; - if(last_byte != now_byte) - { - U64 idx_in_read_out = write_off+idx; - byte_changed_flags[idx_in_read_out/64] |= (1ull<<(idx_in_read_out%64)); - } - } - } - - // rjf: increment past this chunk - U64 bytes_to_skip = page_size; - if(page_idx == 0 && range.min > data_vaddr_range.min) - { - bytes_to_skip -= (range.min-data_vaddr_range.min); - } - write_off += bytes_to_skip; - } - } - - //- rjf: fill result - result.data.str = (U8*)read_out; - result.data.size = dim_1u64(range); - result.byte_bad_flags = byte_bad_flags; - result.byte_changed_flags = byte_changed_flags; - if(byte_bad_flags != 0) - { - for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) - { - result.any_byte_bad = result.any_byte_bad || !!result.byte_bad_flags[idx]; - } - } - if(byte_changed_flags != 0) - { - for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) - { - result.any_byte_changed = result.any_byte_changed || !!result.byte_changed_flags[idx]; - } - } - - access_close(access); - scratch_end(scratch); - } - ProfEnd(); - return result; -} - -internal B32 -ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) -{ - Temp scratch = scratch_begin(0, 0); - U64 needed_size = dim_1u64(range); - CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, endt_us); - B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); - if(good) - { - MemoryCopy(out, slice.data.str, needed_size); - } - if(slice.stale && is_stale_out) - { - *is_stale_out = 1; - } - scratch_end(scratch); - return good; -} - -//- rjf: process memory writing - -internal B32 -ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) -{ - ProfBeginFunction(); - B32 result = dmn_process_write(process.dmn_handle, range, src); - - //- rjf: success -> bump generation - if(result) - { - ins_atomic_u64_inc_eval(&ctrl_state->mem_gen); - } - - //- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless - // writes within calling frame's "view" of the memory, at the expense of a small amount of - // time. - if(result) - { - Temp scratch = scratch_begin(0, 0); - U64 endt_us = os_now_microseconds()+5000; - - //- rjf: gather tasks for all affected cached regions - typedef struct Task Task; - struct Task - { - Task *next; - CTRL_Handle process; - Rng1U64 range; - }; - Task *first_task = 0; - Task *last_task = 0; - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - MutexScopeW(stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->next) - { - for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) - { - CTRL_ProcessMemoryRangeHashSlot *range_slot = &proc_n->range_hash_slots[range_hash_idx]; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - Rng1U64 intersection_w_range = intersect_1u64(range, n->vaddr_range); - if(dim_1u64(intersection_w_range) != 0 && dim_1u64(n->vaddr_range) <= KB(64)) - { - Task *task = push_array(scratch.arena, Task, 1); - task->process = proc_n->handle; - task->range = n->vaddr_range; - SLLQueuePush(first_task, last_task, task); - } - } - } - } - } - } - - //- rjf: for all tasks, wait for up-to-date results - for(Task *task = first_task; task != 0; task = task->next) - { - Temp temp = temp_begin(scratch.arena); - ctrl_process_memory_slice_from_vaddr_range(temp.arena, task->process, task->range, endt_us); - temp_end(temp); - } - - scratch_end(scratch); - } - - ProfEnd(); - return result; -} - //////////////////////////////// //~ rjf: Thread Register Functions @@ -4828,27 +4350,6 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, } } - //- rjf: clear process memory cache, if we've just started a lone process - if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1) - { - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - MutexScopeW(stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - arena_clear(n->arena); - } - } - MemoryZeroStruct(slot); - } - } - //- rjf: out of queued up demon events -> clear event arena if(ctrl_state->first_dmn_event_node == 0) { @@ -6629,230 +6130,6 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ProfEnd(); } -//////////////////////////////// -//~ rjf: Asynchronous Memory Streaming Functions - -//- rjf: user -> memory stream communication - -internal B32 -ctrl_u2ms_enqueue_req(C_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) -{ - B32 good = 0; - MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; - U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; - if(available_size >= sizeof(key)+sizeof(process)+sizeof(vaddr_range)+sizeof(zero_terminated)) - { - good = 1; - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &key); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated); - break; - } - if(os_now_microseconds() >= endt_us) {break;} - cond_var_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); - } - cond_var_broadcast(ctrl_state->u2ms_ring_cv); - return good; -} - -internal void -ctrl_u2ms_dequeue_req(C_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) -{ - MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; - if(unconsumed_size >= sizeof(*out_key)+sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated)) - { - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_key); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); - break; - } - cond_var_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); - } - cond_var_broadcast(ctrl_state->u2ms_ring_cv); -} - -//- rjf: entry point - -ASYNC_WORK_DEF(ctrl_mem_stream_work) -{ -#define CTRL_MEM_STREAM_WORK_DEBUG 0 - ProfBeginFunction(); - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - - //- rjf: unpack next request - C_Key key = {0}; - CTRL_Handle process = {0}; - Rng1U64 vaddr_range = {0}; - B32 zero_terminated = 0; - ctrl_u2ms_dequeue_req(&key, &process, &vaddr_range, &zero_terminated); - ProfBegin("memory stream request"); - - //- rjf: unpack process key - U64 process_hash = ctrl_hash_from_handle(process); - U64 process_slot_idx = process_hash%cache->slots_count; - U64 process_stripe_idx = process_slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx]; - CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx]; - - //- rjf: unpack address range hash cache key - U64 range_hash = u64_hash_from_str8(str8_struct(&key.id)); - - //- rjf: clamp vaddr range - Rng1U64 vaddr_range_clamped = vaddr_range; - { - vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); - U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); - vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); - } - - //- rjf: task was taken -> read memory - U64 range_size = 0; - Arena *range_arena = 0; - void *range_base = 0; - U64 zero_terminated_size = 0; - U64 pre_read_mem_gen = ctrl_mem_gen(); - B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); -#if CTRL_MEM_STREAM_WORK_DEBUG - Log *log = log_alloc(); - log_select(log); - log_scope_begin(); -#endif - { - range_size = dim_1u64(vaddr_range_clamped); - U64 page_size = os_get_system_info()->page_size; - U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); - range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); - if(range_arena == 0) - { - range_size = 0; - } - else - { - range_base = push_array_no_zero(range_arena, U8, range_size); - U64 bytes_read = 0; - U64 retry_count = 0; - U64 retry_limit = range_size > page_size ? 64 : 0; - for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; - retry_count <= retry_limit; - retry_count += 1) - { - bytes_read = dmn_process_read(process.dmn_handle, vaddr_range_clamped_retry, range_base); - if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) - { - U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; - vaddr_range_clamped_retry.max -= diff; - vaddr_range_clamped_retry.max = AlignDownPow2(vaddr_range_clamped_retry.max, page_size); - if(diff == 0) - { - break; - } - } - else - { - break; - } - } - if(bytes_read == 0) - { - arena_release(range_arena); - range_base = 0; - range_size = 0; - range_arena = 0; - } - else if(bytes_read < range_size) - { - MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read); - } - zero_terminated_size = range_size; - if(zero_terminated) - { - for(U64 idx = 0; idx < bytes_read; idx += 1) - { - if(((U8 *)range_base)[idx] == 0) - { - zero_terminated_size = idx; - break; - } - } - } - } - } - U64 post_read_mem_gen = ctrl_mem_gen(); - B32 post_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); - // NOTE(rjf): debugging -#if CTRL_MEM_STREAM_WORK_DEBUG - { - Temp scratch = scratch_begin(0, 0); - String8 sample_data_str = str8_lit("no data"); - if(range_base != 0) - { - String8 sample_data = str8((U8*)range_base + 0x100, 16); - String8List sample_data_strs = numeric_str8_list_from_data(scratch.arena, 16, sample_data, 1); - sample_data_str = str8_list_join(scratch.arena, &sample_data_strs, &(StringJoin){.sep = str8_lit(", ")}); - } - LogScopeResult log = log_scope_end(scratch.arena); - raddbg_log("[0x%I64x, 0x%I64x) { pre_gen: %I64u, post_gen: %I64u, pre_run: %i, post_run: %i, bytes: [%S], info:```%S``` }\n", vaddr_range.min, vaddr_range.max, pre_read_mem_gen, post_read_mem_gen, pre_run_state, post_run_state, sample_data_str, log.strings[LogMsgKind_Info]); - scratch_end(scratch); - } -#endif - - //- rjf: read successful -> submit to hash store - U128 hash = {0}; - if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen) - { - hash = c_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size)); - } - else if(range_arena != 0) - { - arena_release(range_arena); - } - - //- rjf: commit new info to cache - MutexScopeW(process_stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->handle, process)) - { - U64 range_slot_idx = range_hash%n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) - { - if(c_id_match(range_n->id, key.id)) - { - if(pre_read_mem_gen == post_read_mem_gen) - { - range_n->mem_gen = post_read_mem_gen; - } - range_n->working_count -= 1; - goto commit__break_all; - } - } - } - } - commit__break_all:; - } - - //- rjf: broadcast changes - cond_var_broadcast(process_stripe->cv); - if(!u128_match(u128_zero(), hash)) - { - if(ctrl_state->wakeup_hook != 0) - { - ctrl_state->wakeup_hook(); - } - } - ProfEnd(); - ProfEnd(); - return 0; -} - //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups @@ -6995,7 +6272,7 @@ ctrl_memory_artifact_destroy(AC_Artifact artifact) } internal C_Key -ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) +ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) { ProfBeginFunction(); struct @@ -7020,6 +6297,208 @@ ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, return content_key; } +//- rjf: process memory reading helpers + +internal CTRL_ProcessMemorySlice +ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us) +{ + ProfBeginFunction(); + CTRL_ProcessMemorySlice result = {0}; + if(range.max > range.min && + dim_1u64(range) <= MB(256) && + range.min <= 0x000FFFFFFFFFFFFFull && + range.max <= 0x000FFFFFFFFFFFFFull) + { + Temp scratch = scratch_begin(&arena, 1); + Access *access = access_open(); + + //- rjf: unpack address range, prepare per-touched-page info + U64 page_size = KB(4); + Rng1U64 page_range = r1u64(AlignDownPow2(range.min, page_size), AlignPow2(range.max, page_size)); + U64 page_count = dim_1u64(page_range)/page_size; + U128 *page_hashes = push_array(scratch.arena, U128, page_count); + U128 *page_last_hashes = push_array(scratch.arena, U128, page_count); + + //- rjf: gather hashes & last-hashes for each page + ProfScope("gather hashes & last-hashes for each page") + { + for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) + { + U64 page_base_vaddr = page_range.min + page_idx*page_size; + B32 page_is_stale = 0; + C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); + U128 page_hash = c_hash_from_key(page_key, 0); + U128 page_last_hash = c_hash_from_key(page_key, 1); + result.stale = (result.stale || page_is_stale); + page_hashes[page_idx] = page_hash; + page_last_hashes[page_idx] = page_last_hash; + } + } + + //- rjf: setup output buffers + void *read_out = push_array(arena, U8, dim_1u64(range)); + U64 *byte_bad_flags = push_array(arena, U64, (dim_1u64(range)+63)/64); + U64 *byte_changed_flags = push_array(arena, U64, (dim_1u64(range)+63)/64); + + //- rjf: iterate pages, fill output + ProfScope("iterate pages, fill output") + { + U64 write_off = 0; + for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) + { + // rjf: read data for this page + String8 data = c_data_from_hash(access, page_hashes[page_idx]); + Rng1U64 data_vaddr_range = r1u64(page_range.min + page_idx*page_size, page_range.min + page_idx*page_size+data.size); + + // rjf: skip/chop bytes which are irrelevant for the actual requested read + String8 in_range_data = data; + if(page_idx == page_count-1 && data_vaddr_range.max > range.max) + { + in_range_data = str8_chop(in_range_data, data_vaddr_range.max-range.max); + } + if(page_idx == 0 && range.min > data_vaddr_range.min) + { + in_range_data = str8_skip(in_range_data, range.min-data_vaddr_range.min); + } + + // rjf: write this chunk + MemoryCopy((U8*)read_out+write_off, in_range_data.str, in_range_data.size); + + // rjf; if this page's data doesn't fill the entire range, mark + // missing bytes as bad + if(data.size < page_size) ProfScope("mark missing bytes as bad") + { + Rng1U64 invalid_range = r1u64(data_vaddr_range.min+data.size, data_vaddr_range.min + page_size); + Rng1U64 in_range_invalid_range = intersect_1u64(invalid_range, range); + for(U64 invalid_vaddr = in_range_invalid_range.min; + invalid_vaddr < in_range_invalid_range.max; + invalid_vaddr += 1) + { + U64 idx_in_range = invalid_vaddr - range.min; + byte_bad_flags[idx_in_range/64] |= (1ull<<(idx_in_range%64)); + } + } + + // rjf: if this page's hash & last_hash don't match, diff each byte & + // fill out changed flags + if(!u128_match(page_hashes[page_idx], page_last_hashes[page_idx])) ProfScope("hashes don't match; diff each byte") + { + String8 last_data = c_data_from_hash(access, page_last_hashes[page_idx]); + String8 in_range_last_data = last_data; + if(page_idx == page_count-1 && data_vaddr_range.max > range.max) + { + in_range_last_data = str8_chop(in_range_last_data, data_vaddr_range.max-range.max); + } + if(page_idx == 0 && range.min > data_vaddr_range.min) + { + in_range_last_data = str8_skip(in_range_last_data, range.min-data_vaddr_range.min); + } + for(U64 idx = 0; idx < in_range_data.size; idx += 1) + { + U8 last_byte = idx < in_range_last_data.size ? in_range_last_data.str[idx] : 0; + U8 now_byte = idx < in_range_data.size ? in_range_data.str[idx] : 0; + if(last_byte != now_byte) + { + U64 idx_in_read_out = write_off+idx; + byte_changed_flags[idx_in_read_out/64] |= (1ull<<(idx_in_read_out%64)); + } + } + } + + // rjf: increment past this chunk + U64 bytes_to_skip = page_size; + if(page_idx == 0 && range.min > data_vaddr_range.min) + { + bytes_to_skip -= (range.min-data_vaddr_range.min); + } + write_off += bytes_to_skip; + } + } + + //- rjf: fill result + result.data.str = (U8*)read_out; + result.data.size = dim_1u64(range); + result.byte_bad_flags = byte_bad_flags; + result.byte_changed_flags = byte_changed_flags; + if(byte_bad_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_bad = result.any_byte_bad || !!result.byte_bad_flags[idx]; + } + } + if(byte_changed_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_changed = result.any_byte_changed || !!result.byte_changed_flags[idx]; + } + } + + access_close(access); + scratch_end(scratch); + } + ProfEnd(); + return result; +} + +internal B32 +ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + U64 needed_size = dim_1u64(range); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, endt_us); + B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); + if(good) + { + MemoryCopy(out, slice.data.str, needed_size); + } + if(slice.stale && is_stale_out) + { + *is_stale_out = 1; + } + scratch_end(scratch); + return good; +} + +//- rjf: process memory writing + +internal B32 +ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) +{ + ProfBeginFunction(); + B32 result = dmn_process_write(process.dmn_handle, range, src); + + //- rjf: success -> bump generation + if(result) + { + ins_atomic_u64_inc_eval(&ctrl_state->mem_gen); + } + + //- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless + // writes within calling frame's "view" of the memory, at the expense of a small amount of + // time. + if(result) + { + U64 endt_us = os_now_microseconds()+5000; + U64 page_size = os_get_system_info()->page_size; + Rng1U64 page_range = r1u64(range.min/page_size, range.max/page_size); + for EachInRange(page_idx, page_range) + { + Temp scratch = scratch_begin(0, 0); + ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), endt_us); + scratch_end(scratch); + if(os_now_microseconds() >= endt_us) + { + break; + } + } + } + + ProfEnd(); + return result; +} + //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups @@ -7200,7 +6679,7 @@ ctrl_call_stack_artifact_destroy(AC_Artifact artifact) } internal CTRL_CallStack -ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us) +ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us) { CTRL_CallStack result = {0}; { @@ -7254,7 +6733,7 @@ ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B { for EachIndex(idx, threads_count) { - call_stacks[idx] = ctrl_call_stack_from_thread_new(access, threads[idx], 0, 0); + call_stacks[idx] = ctrl_call_stack_from_thread(access, threads[idx], 0, 0); if(call_stacks[idx].concrete_frames_count == 0) { stale = 1; @@ -7350,7 +6829,7 @@ ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact) } internal CTRL_CallStackTree -ctrl_call_stack_tree_new(Access *access, U64 endt_us) +ctrl_call_stack_tree(Access *access, U64 endt_us) { CTRL_CallStackTree result = {&ctrl_call_stack_tree_node_nil}; { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index fb2cf401..56762142 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -535,68 +535,7 @@ struct CTRL_EventList }; //////////////////////////////// -//~ rjf: Process Memory Cache Types - -typedef struct CTRL_ProcessMemoryRangeHashNode CTRL_ProcessMemoryRangeHashNode; -struct CTRL_ProcessMemoryRangeHashNode -{ - CTRL_ProcessMemoryRangeHashNode *next; - - // rjf: key - Rng1U64 vaddr_range; - B32 zero_terminated; - C_ID id; - - // rjf: staleness info - U64 mem_gen; - - // rjf: metadata - U64 working_count; - U64 last_time_requested_us; - U64 last_user_clock_idx_touched; -}; - -typedef struct CTRL_ProcessMemoryRangeHashSlot CTRL_ProcessMemoryRangeHashSlot; -struct CTRL_ProcessMemoryRangeHashSlot -{ - CTRL_ProcessMemoryRangeHashNode *first; - CTRL_ProcessMemoryRangeHashNode *last; -}; - -typedef struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode; -struct CTRL_ProcessMemoryCacheNode -{ - CTRL_ProcessMemoryCacheNode *next; - CTRL_ProcessMemoryCacheNode *prev; - Arena *arena; - CTRL_Handle handle; - C_Root root; - U64 range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; -}; - -typedef struct CTRL_ProcessMemoryCacheSlot CTRL_ProcessMemoryCacheSlot; -struct CTRL_ProcessMemoryCacheSlot -{ - CTRL_ProcessMemoryCacheNode *first; - CTRL_ProcessMemoryCacheNode *last; -}; - -typedef struct CTRL_ProcessMemoryCacheStripe CTRL_ProcessMemoryCacheStripe; -struct CTRL_ProcessMemoryCacheStripe -{ - RWMutex rw_mutex; - CondVar cv; -}; - -typedef struct CTRL_ProcessMemoryCache CTRL_ProcessMemoryCache; -struct CTRL_ProcessMemoryCache -{ - U64 slots_count; - CTRL_ProcessMemoryCacheSlot *slots; - U64 stripes_count; - CTRL_ProcessMemoryCacheStripe *stripes; -}; +//~ rjf: Process Memory Types typedef struct CTRL_ProcessMemorySlice CTRL_ProcessMemorySlice; struct CTRL_ProcessMemorySlice @@ -688,22 +627,6 @@ struct CTRL_ModuleImageInfoCache CTRL_ModuleImageInfoCacheStripe *stripes; }; -//////////////////////////////// -//~ rjf: Call Stack Tree Cache Types - -typedef struct CTRL_CallStackTreeCache CTRL_CallStackTreeCache; -struct CTRL_CallStackTreeCache -{ - Arena *arena; - CTRL_CallStackTree tree; - CondVar cv; - RWMutex rw_mutex; - U64 reg_gen; - U64 mem_gen; - U64 scope_touch_count; - U64 request_count; -}; - //////////////////////////////// //~ rjf: Touched Debug Info Directory Cache @@ -753,22 +676,6 @@ typedef CTRL_WAKEUP_FUNCTION_DEF(CTRL_WakeupFunctionType); //////////////////////////////// //~ rjf: Main State Types -typedef struct CTRL_MemRequest CTRL_MemRequest; -struct CTRL_MemRequest -{ - C_Key key; - CTRL_Handle process; - Rng1U64 vaddr_range; - B32 zero_terminated; -}; - -typedef struct CTRL_MemRequestNode CTRL_MemRequestNode; -struct CTRL_MemRequestNode -{ - CTRL_MemRequestNode *next; - CTRL_MemRequest v; -}; - typedef struct CTRL_State CTRL_State; struct CTRL_State { @@ -780,10 +687,8 @@ struct CTRL_State E_String2NumMap arch_string2alias_tables[Arch_COUNT]; // rjf: caches - CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; CTRL_ModuleImageInfoCache module_image_info_cache; - CTRL_CallStackTreeCache call_stack_tree_cache; // rjf: generations U64 run_gen; @@ -830,21 +735,6 @@ struct CTRL_State CTRL_ModuleReqCacheNode **module_req_cache_slots; String8List msg_user_bp_touched_files; String8List msg_user_bp_touched_symbols; - - // rjf: memory requests - Mutex mem_req_mutex; - Arena *mem_req_arena; - CTRL_MemRequestNode *first_mem_req; - CTRL_MemRequestNode *last_mem_req; - U64 mem_req_count; - - // rjf: user -> memstream ring buffer - U64 u2ms_ring_size; - U8 *u2ms_ring_base; - U64 u2ms_ring_write_pos; - U64 u2ms_ring_read_pos; - Mutex u2ms_ring_mutex; - CondVar u2ms_ring_cv; }; //////////////////////////////// @@ -1003,20 +893,6 @@ internal void ctrl_init(void); internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); -//////////////////////////////// -//~ rjf: Process Memory Functions - -//- rjf: process memory cache key reading -internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); - -//- rjf: process memory cache reading helpers -internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); -internal B32 ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); -#define ctrl_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) - -//- rjf: process memory writing -internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); - //////////////////////////////// //~ rjf: Thread Register Functions @@ -1123,35 +999,33 @@ internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); -//////////////////////////////// -//~ rjf: Asynchronous Memory Streaming Functions - -//- rjf: user -> memory stream communication -internal B32 ctrl_u2ms_enqueue_req(C_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); -internal void ctrl_u2ms_dequeue_req(C_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); - -//- rjf: entry point -ASYNC_WORK_DEF(ctrl_mem_stream_work); - //////////////////////////////// //~ rjf: Process Memory Artifact Cache Hooks / Lookups internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void ctrl_memory_artifact_destroy(AC_Artifact artifact); -internal C_Key ctrl_key_from_process_vaddr_range_new(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); +internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); + +//- rjf: process memory reading helpers +internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); +internal B32 ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); +#define ctrl_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) + +//- rjf: process memory writing +internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); //////////////////////////////// //~ rjf: Call Stack Artifact Cache Hooks / Lookups internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact); -internal CTRL_CallStack ctrl_call_stack_from_thread_new(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); +internal CTRL_CallStack ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us); //////////////////////////////// //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact); -internal CTRL_CallStackTree ctrl_call_stack_tree_new(Access *access, U64 endt_us); +internal CTRL_CallStackTree ctrl_call_stack_tree(Access *access, U64 endt_us); #endif // CTRL_CORE_H diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index 1203a9c6..d5e2ad00 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1209,7 +1209,7 @@ d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) else { Access *access = access_open(); - CTRL_CallStack callstack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, 0); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(access, thread->handle, 1, 0); if(callstack.concrete_frames_count != 0) { result = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[unwind_count%callstack.concrete_frames_count]->regs); @@ -1889,7 +1889,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P Access *access = access_open(); // rjf: thread => call stack - CTRL_CallStack callstack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(access, thread->handle, 1, os_now_microseconds()+10000); // rjf: use first unwind frame to generate trap if(callstack.concrete_frames_count > 1) diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 05d4fd96..ba173b7a 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1817,7 +1817,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) case CTRL_EntityKind_Thread: { Access *access = access_open(); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, 1, rd_state->frame_eval_memread_endt_us); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, entity->handle, 1, rd_state->frame_eval_memread_endt_us); U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count; if(concrete_frame_idx < call_stack.concrete_frames_count) { @@ -2160,7 +2160,7 @@ rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) { - result = ctrl_key_from_process_vaddr_range_new(entity->handle, range, zero_terminated, 0, 0); + result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0); } }break; } @@ -6469,7 +6469,7 @@ rd_window_frame(void) Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process); B32 call_stack_high_priority = ctrl_handle_match(ctrl_entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, ctrl_entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, ctrl_entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(call_stack.frames_count != 0) { ui_spacer(ui_em(1.5f, 1.f)); @@ -16258,7 +16258,7 @@ rd_frame(void) { Access *access = access_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); if(frame == 0) { @@ -16277,7 +16277,7 @@ rd_frame(void) { Access *access = access_open(); CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, thread->handle, 1, os_now_microseconds()+10000); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, thread->handle, 1, os_now_microseconds()+10000); CTRL_CallStackFrame *current_frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); CTRL_CallStackFrame *next_frame = current_frame; if(current_frame != 0) switch(kind) diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index a2264e71..7b4f8088 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -968,7 +968,7 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack) B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); accel->arch = entity->arch; accel->process = ctrl_process_from_entity(entity)->handle; - accel->call_stack = ctrl_call_stack_from_thread_new(rd_state->frame_access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); } scratch_end(scratch); } @@ -1571,7 +1571,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree) if(!rd_state->got_frame_call_stack_tree) { rd_state->got_frame_call_stack_tree = 1; - rd_state->frame_call_stack_tree = ctrl_call_stack_tree_new(rd_state->frame_access, 0); + rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_access, 0); } RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1); accel->node = &ctrl_call_stack_tree_node_nil; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 673ed4be..51ff0c13 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1030,7 +1030,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) info.callstack_thread = entity; U64 frame_num = ev_block_num_from_id(block, key.child_id); B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); if(1 <= frame_num && frame_num <= call_stack.frames_count) { CTRL_CallStackFrame *f = &call_stack.frames[frame_num-1]; @@ -2933,7 +2933,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory) Access *access = access_open(); CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *selected_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); - CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread_new(access, selected_thread->handle, 1, 0); + CTRL_CallStack selected_call_stack = ctrl_call_stack_from_thread(access, selected_thread->handle, 1, 0); CTRL_Entity *eval_process = &ctrl_entity_nil; if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity) { diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index ccffbfef..77cde640 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -552,7 +552,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); Arch arch = entity->arch; B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); - CTRL_CallStack call_stack = ctrl_call_stack_from_thread_new(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(access, entity->handle, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); B32 did_first_known = 0; for(U64 idx = 0, limit = 10; idx < call_stack.frames_count && idx < limit; From 5fa3efe76a2d8d07324f13993763aee29090a4fb Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 15:09:47 -0700 Subject: [PATCH 285/302] bugfix evictions, correctly maintain downstream content hash counts --- src/artifact_cache/artifact_cache.c | 2 +- src/content/content.c | 5 ++--- src/ctrl/ctrl_core.c | 6 +++--- src/disasm/disasm.c | 6 ++++++ src/raddbg/raddbg_views.c | 3 +-- src/text/text.c | 10 ++++++++-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index b9f14027..514463b5 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -437,7 +437,7 @@ ac_async_tick(void) for(;;) { // rjf: any new higher priority tasks? -> cancel - if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) != 0) MutexScope(ac_shared->req_batches[0].mutex) + if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2) MutexScope(ac_shared->req_batches[0].mutex) { if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0) { diff --git a/src/content/content.c b/src/content/content.c index a7c2363b..8e554b94 100644 --- a/src/content/content.c +++ b/src/content/content.c @@ -356,7 +356,7 @@ c_close_key(C_Key key) history_idx < C_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) { - U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; + U128 hash = n->hash_history[(n->hash_history_gen-1-history_idx) % ArrayCount(n->hash_history)]; U64 hash_slot_idx = hash.u64[1]%c_shared->blob_slots_count; U64 hash_stripe_idx = hash_slot_idx%c_shared->blob_stripes_count; C_BlobSlot *hash_slot = &c_shared->blob_slots[hash_slot_idx]; @@ -500,9 +500,8 @@ c_async_tick(void) { next = n->next; U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); - U64 scope_ref_count = ins_atomic_u64_eval(&n->access_pt.access_refcount); U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) + if(access_pt_is_expired(&n->access_pt, .time = 5000000) && key_ref_count == 0 && downstream_ref_count == 0) { slot_has_work = 1; if(!write_mode) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 30ce342c..8a0b1b2d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6166,7 +6166,7 @@ ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); { range_size = dim_1u64(vaddr_range_clamped); - U64 page_size = os_get_system_info()->page_size; + U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size); range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE); if(range_arena == 0) @@ -6289,7 +6289,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 .gen = ctrl_mem_gen(), .slots_count = 2048, .stale_out = out_is_stale, - .evict_threshold_us = 30000000); + .evict_threshold_us = 10000000); C_Key content_key = {0}; MemoryCopyStruct(&content_key, &artifact); access_close(access); @@ -6481,7 +6481,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) if(result) { U64 endt_us = os_now_microseconds()+5000; - U64 page_size = os_get_system_info()->page_size; + U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process Rng1U64 page_range = r1u64(range.min/page_size, range.max/page_size); for EachInRange(page_idx, page_range) { diff --git a/src/disasm/disasm.c b/src/disasm/disasm.c index d5905f7f..6143ceab 100644 --- a/src/disasm/disasm.c +++ b/src/disasm/disasm.c @@ -262,6 +262,7 @@ struct DASM_Artifact { Arena *arena; DASM_Info info; + U128 data_hash; }; internal AC_Artifact @@ -470,12 +471,16 @@ dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) retry_out[0] = 1; } + //- rjf: mark dependency on data hash + c_hash_downstream_inc(hash); + //- rjf: fill result if(info_arena != 0) { artifact = push_array(info_arena, DASM_Artifact, 1); artifact->arena = info_arena; artifact->info = info; + artifact->data_hash = hash; } di_scope_close(di_scope); @@ -494,6 +499,7 @@ dasm_artifact_destroy(AC_Artifact artifact) DASM_Artifact *dasm_artifact = (DASM_Artifact *)artifact.u64[0]; if(dasm_artifact == 0) { return; } c_close_key(dasm_artifact->info.text_key); + c_hash_downstream_dec(dasm_artifact->data_hash); arena_release(dasm_artifact->arena); } diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 51ff0c13..b1ced1c3 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1461,8 +1461,7 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row) F32 next_pct = 0; #define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_CallStackFrame, row->eval, .default_pct = 0.05f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.55f, .pct = take_pct()); - rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "hex((uint64)$)"), .default_pct = 0.20f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.75f, .pct = take_pct()); rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, (module == &ctrl_entity_nil ? (E_Eval)zero_struct : module_eval), .default_pct = 0.20f, .pct = take_pct()); #undef take_pct diff --git a/src/text/text.c b/src/text/text.c index ba628572..dd59b33a 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -1957,6 +1957,7 @@ typedef struct TXT_Artifact TXT_Artifact; struct TXT_Artifact { Arena *arena; + U128 data_hash; TXT_TextInfo info; }; @@ -2220,12 +2221,16 @@ txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) lane_sync(); } + //- rjf: mark dependency on hash + c_hash_downstream_inc(hash); + //- rjf: package as artifact if(lane_idx() == 0 && shared->arena != 0) { shared->artifact = push_array(shared->arena, TXT_Artifact, 1); - shared->artifact->arena = shared->arena; - shared->artifact->info = shared->info; + shared->artifact->arena = shared->arena; + shared->artifact->data_hash = hash; + shared->artifact->info = shared->info; } lane_sync(); @@ -2242,6 +2247,7 @@ txt_artifact_destroy(AC_Artifact artifact) { TXT_Artifact *txt_artifact = (TXT_Artifact *)artifact.u64[0]; if(txt_artifact == 0) { return; } + c_hash_downstream_dec(txt_artifact->data_hash); arena_release(txt_artifact->arena); } From eda4f6bafa06415b379ce1a68b37f11d493d5af8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 15:32:13 -0700 Subject: [PATCH 286/302] preserve & visualize restrict type modifiers in eval --- src/eval/eval_core.h | 19 ++++++++++--------- src/eval/eval_types.c | 8 ++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index 0de42d9d..dce2082c 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -379,15 +379,16 @@ enum { E_TypeFlag_Const = (1<<0), E_TypeFlag_Volatile = (1<<1), - E_TypeFlag_IsPlainText = (1<<2), - E_TypeFlag_IsCodeText = (1<<3), - E_TypeFlag_IsPathText = (1<<4), - E_TypeFlag_IsNotText = (1<<5), - E_TypeFlag_EditableChildren = (1<<6), - E_TypeFlag_InheritedByMembers = (1<<7), - E_TypeFlag_InheritedByElements = (1<<8), - E_TypeFlag_ArrayLikeExpansion = (1<<9), - E_TypeFlag_StubSingleLineExpansion = (1<<10), + E_TypeFlag_Restrict = (1<<2), + E_TypeFlag_IsPlainText = (1<<3), + E_TypeFlag_IsCodeText = (1<<4), + E_TypeFlag_IsPathText = (1<<5), + E_TypeFlag_IsNotText = (1<<6), + E_TypeFlag_EditableChildren = (1<<7), + E_TypeFlag_InheritedByMembers = (1<<8), + E_TypeFlag_InheritedByElements = (1<<9), + E_TypeFlag_ArrayLikeExpansion = (1<<10), + E_TypeFlag_StubSingleLineExpansion = (1<<11), }; typedef struct E_Member E_Member; diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 7d208b95..8ecc605d 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -886,6 +886,10 @@ e_push_type_from_key(Arena *arena, E_TypeKey key) { flags |= E_TypeFlag_Volatile; } + if(rdi_type->flags & RDI_TypeModifierFlag_Restrict) + { + flags |= E_TypeFlag_Restrict; + } type = push_array(arena, E_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; @@ -1679,6 +1683,10 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr { str8_list_push(arena, out, str8_lit("volatile ")); } + if(type->flags & E_TypeFlag_Restrict) + { + str8_list_push(arena, out, str8_lit("restrict ")); + } }break; case E_TypeKind_Variadic: From d7fc7d1fa97f80285d11eea243d18f64969cc0bc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Sep 2025 16:23:17 -0700 Subject: [PATCH 287/302] handle aliases gracefully in eval expansion & string iterator --- src/eval/eval_types.c | 3 ++- src/eval_visualization/eval_visualization_core.c | 1 + src/raddbg/raddbg_core.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 8ecc605d..f4ddca7f 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -1953,7 +1953,8 @@ e_default_expansion_type_from_key(E_TypeKey root_key) // want to ignore them. // else if(kind == E_TypeKind_Lens || - kind == E_TypeKind_Modifier) + kind == E_TypeKind_Modifier || + kind == E_TypeKind_Alias) { done = 0; } diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index 295b3237..6d2c04ac 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -1757,6 +1757,7 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) ////////////////////////// //- rjf: modifiers / no-ops // + case E_TypeKind_Alias: case E_TypeKind_Modifier: case E_TypeKind_MetaDescription: case E_TypeKind_MetaDisplayName: diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index ba173b7a..e59dc2e3 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -12723,6 +12723,7 @@ rd_frame(void) ctx->reg_unwind_count = unwind_count; ctx->module_base = push_array(scratch.arena, U64, 1); ctx->module_base[0] = module->vaddr_range.min; + ctx->frame_base = push_array(scratch.arena, U64, 1); ctx->tls_base = push_array(scratch.arena, U64, 1); ctx->tls_base[0] = d_query_cached_tls_base_vaddr_from_process_root_rip(process, tls_root_vaddr, rip_vaddr); } From eb4e6d2883112bf0183a49e44b309af6bbeaec5d Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Tue, 23 Sep 2025 10:08:49 -0700 Subject: [PATCH 288/302] alloc slots for null --- src/linker/lnk_debug_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index faf449a1..d277bee8 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -541,8 +541,8 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla String8Array ts_path_arr; Rng1U64 **external_ti_ranges; CV_DebugT **external_leaves; - U64 *obj_to_ts_idx_arr = push_array_no_zero(tp_arena->v[0], U64, external_count); - U64List *ts_to_obj_arr = push_array(tp_arena->v[0], U64List, external_count); + U64 *obj_to_ts_idx_arr = push_array_no_zero(tp_arena->v[0], U64, external_count + 1); + U64List *ts_to_obj_arr = push_array(tp_arena->v[0], U64List, external_count + 1); { HashTable *type_server_path_ht = hash_table_init(scratch.arena, 256); HashTable *ignored_path_ht = hash_table_init(scratch.arena, 256); From 7084320a835aa50310ae197e55780fe1eb46b863 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 25 Sep 2025 14:29:11 -0700 Subject: [PATCH 289/302] helper for finding parent type --- src/rdi_from_dwarf/rdi_from_dwarf.c | 29 +++++++++++++---------------- src/rdi_from_dwarf/rdi_from_dwarf.h | 10 +++++----- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index b2554e34..e6f71687 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -106,7 +106,7 @@ d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 internal RDIM_Type * d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) { - RDIM_Type *type = 0; + RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_NULL]; // find attrib DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); @@ -127,14 +127,19 @@ d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, D } else { Assert(!"unexpected attrib class"); } - } else if (attrib->attrib_kind == DW_AttribKind_Null) { - // TODO(rjf): - // type = rdim_builtin_type_from_kind(*type_table->types, RDI_TypeKind_NULL); } return type; } +internal RDIM_Type * +d2r_infer_parent_type(DW_CompUnit *cu, D2R_TagNode *tag_stack) +{ + D2R_TagNode *parent = tag_stack->next; + RDIM_Type *type = hash_table_search_u64_raw(cu->tag_ht, parent->cur_node->tag.info_off); + return type; +} + internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) { @@ -1437,8 +1442,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - tag_stack->type = type; } } break; case DW_TagKind_StructureType: { @@ -1459,8 +1462,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) type->kind = RDI_TypeKind_Struct; type->udt = udt; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - - tag_stack->type = type; } } break; case DW_TagKind_UnionType: { @@ -1481,8 +1482,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) type->kind = RDI_TypeKind_Union; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; - - tag_stack->type = type; } } break; case DW_TagKind_EnumerationType: { @@ -1503,8 +1502,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) type->kind = RDI_TypeKind_Enum; type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); type->udt = udt; - - tag_stack->type = type; } } break; case DW_TagKind_SubroutineType: { @@ -1788,7 +1785,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) AssertAlways(!"unexpected parent tag"); } - RDIM_Type *parent = tag_stack->next->type; + RDIM_Type *parent = d2r_infer_parent_type(cu, tag_stack); RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); member->kind = RDI_MemberKind_Base; member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); @@ -1801,7 +1798,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) AssertAlways(!"unexpected parent tag"); } - RDIM_Type *type = tag_stack->next->type; + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); member->val = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_ConstValue); @@ -1822,7 +1819,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) AssertAlways(!"UDT member with multiple locations are not supported"); } - RDIM_Type *type = tag_stack->next->type; + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); member->kind = RDI_MemberKind_DataField; member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); @@ -1886,7 +1883,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) //default: InvalidPath; break; } - RDIM_Type *type = tag_stack->next->type; + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); member->kind = member_kind; member->type = type; diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 1ad35a13..002724de 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -27,7 +27,6 @@ typedef struct D2R_TagNode { struct D2R_TagNode *next; DW_TagNode *cur_node; - RDIM_Type *type; RDIM_Scope *scope; } D2R_TagNode; @@ -49,11 +48,12 @@ internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v); //////////////////////////////// //~ rjf: Type Conversion Helpers -internal RDIM_Type *d2r_create_type(Arena *arena, D2R_TypeTable *type_table); -internal RDIM_Type *d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); -internal RDIM_Type *d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal RDIM_Type * d2r_create_type(Arena *arena, D2R_TypeTable *type_table); +internal RDIM_Type * d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); +internal RDIM_Type * d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal RDIM_Type * d2r_infer_parent_type(DW_CompUnit *cu, D2R_TagNode *tag_stack); internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag); -internal RDIM_Type **d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); +internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size); internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size); internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x); From 5709fb54dd35d0ba7c7e412abbef71bed5e487b5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 25 Sep 2025 14:54:08 -0700 Subject: [PATCH 290/302] simplify debug info conversion loop --- src/rdi_from_dwarf/rdi_from_dwarf.c | 1134 +++++++++++++-------------- 1 file changed, 565 insertions(+), 569 deletions(-) diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index e6f71687..3fcdd51a 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1385,20 +1385,18 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) continue; } - // get unit's contribution ranges + String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); + String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); + DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); RDIM_Rng1U64ChunkList cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); - String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); - String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); - DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); unit->unit_name = cu_name; unit->compiler_name = cu_prod; - unit->source_file = str8_zero(); - unit->object_file = str8_zero(); - unit->archive_file = str8_zero(); + unit->source_file = str8_zero(); // TODO + unit->object_file = str8_zero(); // TODO + unit->archive_file = str8_zero(); // TODO unit->build_path = cu_dir; unit->language = d2r_rdi_language_from_dw_language(cu_lang); unit->line_table = cu_line_tables_rdi[cu_idx]; @@ -1414,497 +1412,423 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); tag_stack->cur_node = tag_tree.root; - while (tag_stack) { - while (tag_stack->cur_node) { - DW_TagNode *cur_node = tag_stack->cur_node; - DW_Tag tag = cur_node->tag; - B32 visit_children = 1; + while (tag_stack && tag_stack->cur_node) { + DW_TagNode *cur_node = tag_stack->cur_node; + DW_Tag tag = cur_node->tag; + B32 visit_children = 1; - switch (tag.kind) { - case DW_TagKind_Null: { - InvalidPath; - } break; - case DW_TagKind_ClassType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + switch (tag.kind) { + case DW_TagKind_Null: { + InvalidPath; + } break; + case DW_TagKind_ClassType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteClass; - - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Class; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } - } break; - case DW_TagKind_StructureType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteStruct; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Struct; - type->udt = udt; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - } - } break; - case DW_TagKind_UnionType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteUnion; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Union; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - } - } break; - case DW_TagKind_EnumerationType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteEnum; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Enum; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - } - } break; - case DW_TagKind_SubroutineType: { - // collect parameters - RDIM_TypeList param_list = {0}; - for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind == DW_TagKind_FormalParameter) { - RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_AttribKind_Type); - rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); - } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); - } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } - } - - // init proceudre type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; - type->direct_type = ret_type; - type->count = param_list.count; - type->param_types = rdim_array_from_type_list(arena, param_list); + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteClass; + Assert(!cur_node->first_child); visit_children = 0; - } break; - case DW_TagKind_Typedef: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_BaseType: { - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Encoding); - U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); + } + } break; + case DW_TagKind_StructureType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - // convert base type encoding to RDI version - RDI_TypeKind kind = RDI_TypeKind_NULL; - switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling - } + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteStruct; - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - type->direct_type = type_table->builtin_types[kind]; - } break; - case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_AddressClass)); - - U64 byte_size = arch_addr_size; - if (cu->version == DW_Version_5 || cu->relaxed) { - dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); - } - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Ptr; - type->byte_size = byte_size; - type->direct_type = direct_type; - } break; - case DW_TagKind_RestrictType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Restrict; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Volatile; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Const; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_ArrayType: { - // * DWARF vs RDI Array Type Graph * - // - // For example lets take following decl: - // - // int (*foo[2])[3][4]; - // - // This compiles to in DWARF: - // - // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] - // \ - // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] -> DW_TagKind_Subrange [4] - // \ - // -> (B1) DW_TAG_BaseType (int) - // - // RDI expects: - // - // foo -> Array (2) -> Pointer -> Array (3) -> Array (4) -> int - // - // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and - // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. - // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from - // B to A. - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Array; - type->direct_type = 0; - - U64 subrange_count = 0; - RDIM_Type *t = type; - for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind != DW_TagKind_SubrangeType) { - // TODO: error handling - AssertAlways(!"unexpected tag"); - continue; - } - - if (subrange_count > 0) { - // init array type node - RDIM_Type *s = d2r_create_type(arena, type_table); - s->kind = RDI_TypeKind_Array; - s->direct_type = 0; - - // append new array type node - t->direct_type = s; - t = s; - } - - // resolve array lower bound - U64 lower_bound = 0; - if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound)) { - lower_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound); - } else { - lower_bound = dw_pick_default_lower_bound(cu_lang); - } - - // resolve array upper bound - U64 upper_bound = 0; - if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_Count)) { - U64 count = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_Count); - upper_bound = lower_bound + count; - } else if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound)) { - upper_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound); - // turn upper bound into exclusive range - upper_bound += 1; - } else { - // zero size array - } - - t->count = upper_bound - lower_bound; - ++subrange_count; - } - - Assert(t->direct_type == 0); - t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - visit_children = 0; - } break; - case DW_TagKind_SubrangeType: { // TODO: error handling - AssertAlways(!"unexpected tag"); - } break; - case DW_TagKind_Inheritance: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_StructureType && - parent_node->tag.kind != DW_TagKind_ClassType) { + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Struct; + type->udt = udt; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + } + } break; + case DW_TagKind_UnionType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + } + } break; + case DW_TagKind_EnumerationType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + + B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteEnum; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + } + } break; + case DW_TagKind_SubroutineType: { + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_TagKind_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_AttribKind_Type); + rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { + rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); + } else { // TODO: error handling - AssertAlways(!"unexpected parent tag"); + AssertAlways(!"unexpected tag"); } + } - RDIM_Type *parent = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation)); + // init proceudre type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + + visit_children = 0; + } break; + case DW_TagKind_Typedef: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + } break; + case DW_TagKind_BaseType: { + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Encoding); + U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } } break; - case DW_TagKind_Enumerator: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_EnumerationType) { + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + type->direct_type = type_table->builtin_types[kind]; + } break; + case DW_TagKind_PointerType: { + RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Allocated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Associated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); + } + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_TagKind_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + } break; + case DW_TagKind_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + } break; + case DW_TagKind_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + } break; + case DW_TagKind_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3][4]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] -> DW_TagKind_Subrange [4] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array (2) -> Pointer -> Array (3) -> Array (4) -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Array; + type->direct_type = 0; + + U64 subrange_count = 0; + RDIM_Type *t = type; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_TagKind_SubrangeType) { // TODO: error handling - AssertAlways(!"unexpected parent tag"); + AssertAlways(!"unexpected tag"); + continue; } - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - member->val = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_ConstValue); - } break; - case DW_TagKind_Member: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_StructureType && - parent_node->tag.kind != DW_TagKind_ClassType && - parent_node->tag.kind != DW_TagKind_UnionType && - parent_node->tag.kind != DW_TagKind_EnumerationType) { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); + if (subrange_count > 0) { + // init array type node + RDIM_Type *s = d2r_create_type(arena, type_table); + s->kind = RDI_TypeKind_Array; + s->direct_type = 0; + + // append new array type node + t->direct_type = s; + t = s; } - DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_AttribKind_DataMemberLocation); - DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); - if (data_member_location_class == DW_AttribClass_LocList) { - AssertAlways(!"UDT member with multiple locations are not supported"); + // resolve array lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound)) { + lower_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); } - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = RDI_MemberKind_DataField; - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - member->off = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation); - } break; - case DW_TagKind_SubProgram: { - DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_AttribKind_Inline); - switch (inl) { - case DW_Inl_NotInlined: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *container_type = 0; - if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); - } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_ClassType || parent_tag_kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag_kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - tag_stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - visit_children = 0; - } break; - default: InvalidPath; break; + // resolve array upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_Count)) { + U64 count = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound)) { + upper_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero size array } - } break; - case DW_TagKind_InlinedSubroutine: { + + t->count = upper_bound - lower_bound; + ++subrange_count; + } + + Assert(t->direct_type == 0); + t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + + visit_children = 0; + } break; + case DW_TagKind_SubrangeType: { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } break; + case DW_TagKind_Inheritance: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_TagKind_StructureType && + parent_node->tag.kind != DW_TagKind_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = d2r_infer_parent_type(cu, tag_stack); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation)); + } break; + case DW_TagKind_Enumerator: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_TagKind_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); + RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); + member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + member->val = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_ConstValue); + } break; + case DW_TagKind_Member: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_TagKind_StructureType && + parent_node->tag.kind != DW_TagKind_ClassType && + parent_node->tag.kind != DW_TagKind_UnionType && + parent_node->tag.kind != DW_TagKind_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_AttribKind_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = RDI_MemberKind_DataField; + member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + member->off = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation); + } break; + case DW_TagKind_SubProgram: { + DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_AttribKind_Inline); + switch (inl) { + case DW_Inl_NotInlined: { U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); // get return type RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); @@ -1918,118 +1842,190 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) proc_type->param_types = params; // get container type - RDIM_Type *owner = 0; + RDIM_Type *container_type = 0; if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { - owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); + container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); } - // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); - inline_site->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - inline_site->type = proc_type; - inline_site->owner = owner; - inline_site->line_table = 0; + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); // make scope Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - root_scope->inline_site = inline_site; - } break; - case DW_TagKind_Variable: { - String8 name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + root_scope->symbol = proc; + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_SubProgram || - parent_tag_kind == DW_TagKind_InlinedSubroutine || - parent_tag_kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *scope = tag_stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); - } else { - - // NOTE: due to a bug in clang in stb_sprint.h local variables - // are declared in global scope without a name - if (name.size == 0) { - break; + if (parent_tag_kind == DW_TagKind_ClassType || parent_tag_kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; } - RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); - gvar->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); - gvar->name = name; - gvar->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); - gvar->type = type; - //gvar->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, global_scope, image_base, arch, tag, DW_AttribKind_Location); - gvar->container_symbol = 0; - gvar->container_type = 0; // TODO: NotImplemented; + RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag_kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); } + + tag_stack->scope = root_scope; } break; - case DW_TagKind_FormalParameter: { - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine) { - RDIM_Scope *scope = tag_stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); - } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); - } + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + visit_children = 0; } break; - case DW_TagKind_LexicalBlock: { - if (tag_stack->next->cur_node->tag.kind == DW_TagKind_SubProgram || - tag_stack->next->cur_node->tag.kind == DW_TagKind_InlinedSubroutine || - tag_stack->next->cur_node->tag.kind == DW_TagKind_LexicalBlock) { - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - } - } break; - case DW_TagKind_CallSite: { - // TODO - } break; - case DW_TagKind_CallSiteParameter: { - // TODO - } break; - case DW_TagKind_Label: - case DW_TagKind_CompileUnit: - case DW_TagKind_UnspecifiedParameters: - break; - case DW_TagKind_Namespace: break; - case DW_TagKind_ImportedDeclaration: break; - case DW_TagKind_PtrToMemberType: break; - case DW_TagKind_TemplateTypeParameter: break; - case DW_TagKind_ReferenceType: break; - default: NotImplemented; break; + default: InvalidPath; break; + } + } break; + case DW_TagKind_InlinedSubroutine: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *owner = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { + owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); } - if (tag_stack->cur_node->first_child && visit_children) { - D2R_TagNode *frame = free_tags; - if (frame) { - SLLStackPop(free_tags); - MemoryZeroStruct(frame); - } else { - frame = push_array(scratch.arena, D2R_TagNode, 1); - } - frame->cur_node = tag_stack->cur_node->first_child; - SLLStackPush(tag_stack, frame); + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->inline_site = inline_site; + } break; + case DW_TagKind_Variable: { + String8 name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_TagKind_SubProgram || + parent_tag_kind == DW_TagKind_InlinedSubroutine || + parent_tag_kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); } else { - tag_stack->cur_node = tag_stack->cur_node->sibling; + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { break; } + + RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); + gvar->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); + gvar->name = name; + gvar->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); + gvar->type = type; + //gvar->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, global_scope, image_base, arch, tag, DW_AttribKind_Location); + gvar->container_symbol = 0; + gvar->container_type = 0; // TODO: NotImplemented; } + } break; + case DW_TagKind_FormalParameter: { + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_TagKind_LexicalBlock: { + if (tag_stack->next->cur_node->tag.kind == DW_TagKind_SubProgram || + tag_stack->next->cur_node->tag.kind == DW_TagKind_InlinedSubroutine || + tag_stack->next->cur_node->tag.kind == DW_TagKind_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + } + } break; + case DW_TagKind_CallSite: { + // TODO + } break; + case DW_TagKind_CallSiteParameter: { + // TODO + } break; + case DW_TagKind_Label: + case DW_TagKind_CompileUnit: + case DW_TagKind_UnspecifiedParameters: + break; + case DW_TagKind_Namespace: break; + case DW_TagKind_ImportedDeclaration: break; + case DW_TagKind_PtrToMemberType: break; + case DW_TagKind_TemplateTypeParameter: break; + case DW_TagKind_ReferenceType: break; + default: NotImplemented; break; } - // recycle free frame - D2R_TagNode *frame = tag_stack; - SLLStackPop(tag_stack); - SLLStackPush(free_tags, frame); - - if (tag_stack) { + if (tag_stack->cur_node->first_child && visit_children) { + D2R_TagNode *frame = free_tags; + if (frame) { + SLLStackPop(free_tags); + MemoryZeroStruct(frame); + } else { + frame = push_array(comp_temp.arena, D2R_TagNode, 1); + } + frame->cur_node = tag_stack->cur_node->first_child; + SLLStackPush(tag_stack, frame); + } else { tag_stack->cur_node = tag_stack->cur_node->sibling; } + + if (tag_stack->cur_node == 0) { + // recycle free frame + D2R_TagNode *frame = tag_stack; + SLLStackPop(tag_stack); + SLLStackPush(free_tags, frame); + + if (tag_stack) { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } } temp_end(comp_temp); From c5fe329c05ae23f80b9b548b9723beef0d6f7a80 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 26 Sep 2025 15:49:46 -0700 Subject: [PATCH 291/302] fix return status for file writes --- src/os/core/os_core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index 04ede12a..670f8486 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -80,7 +80,6 @@ os_write_data_list_to_file_path(String8 path, String8List list) U64 write_buffer_write_pos = 0; U64 write_buffer_read_pos = 0; U64 file_off = 0; - U64 total_bytes_written = 0; { for(String8Node *n = list.first; n != 0; n = n->next) { @@ -90,7 +89,11 @@ os_write_data_list_to_file_path(String8 path, String8List list) U64 write_buffer_available_size = (write_buffer_size - write_buffer_unconsumed_size); if(write_buffer_available_size == 0) { - os_file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer); + U64 file_write_size = os_file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer); + if(file_write_size != write_buffer_size) + { + goto dbl_break; + } file_off += write_buffer_size; write_buffer_read_pos += write_buffer_size; } @@ -104,10 +107,12 @@ os_write_data_list_to_file_path(String8 path, String8List list) } if(write_buffer_write_pos > write_buffer_read_pos) { - total_bytes_written += os_file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer); + U64 file_write_size = os_file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer); + file_off += file_write_size; } } - good = (total_bytes_written == list.total_size); + dbl_break:; + good = (file_off == list.total_size); os_file_close(file); scratch_end(scratch); } From 07d77a0e7983b08704fafb730669038cb557fea8 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 26 Sep 2025 15:51:18 -0700 Subject: [PATCH 292/302] report unsuccessful writes --- src/radbin/radbin.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index ba1640c4..77d59968 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -1177,8 +1177,15 @@ rb_thread_entry_point(void *p) { if(output_path.size != 0) ProfScope("write outputs [file]") { - os_write_data_list_to_file_path(output_path, output_blobs); - log_infof("Results written to %S", output_path); + B32 is_written = os_write_data_list_to_file_path(output_path, output_blobs); + if(is_written) + { + log_infof("Results written to %S", output_path); + } + else + { + log_user_errorf("ERROR: failed to write file %S\n", output_path); + } } else ProfScope("write outputs [stdout]") { From 8bf0a3de5b345f02f6997cd2c1003fbb7590d5fd Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 29 Sep 2025 00:11:27 -0700 Subject: [PATCH 293/302] split conversion pass into three (types, udts, and symbols) and use new locations chunk list --- src/dwarf/dwarf_parse.c | 2 + src/dwarf/dwarf_parse.h | 1 + src/lib_rdi_make/rdi_make.c | 20 +- src/rdi_from_dwarf/rdi_from_dwarf.c | 1947 +++++++++++++++------------ src/rdi_from_dwarf/rdi_from_dwarf.h | 103 +- 5 files changed, 1155 insertions(+), 918 deletions(-) diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index 70db8920..09e6a6a9 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -1999,6 +1999,8 @@ dw_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind k } else { result = dw_interp_const_u64(attrib->form_kind, attrib->form); } + } else if (attrib_class == DW_AttribClass_Address) { + result = dw_address_from_attrib(input, cu, attrib); } else if (attrib_class == DW_AttribClass_Reference) { NotImplemented; } else if (attrib_class != DW_AttribClass_Null) { diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index 28736331..fe98b90e 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -132,6 +132,7 @@ typedef struct DW_Tag DW_TagKind kind; DW_AttribList attribs; U64 info_off; + U8 v[1]; } DW_Tag; typedef struct DW_TagNode diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 6295b5fb..2b4ceacd 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -1130,16 +1130,22 @@ rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope return local; } +RDI_PROC RDIM_LocationCase * +rdim_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationCaseList *list, RDIM_Location *location, RDIM_Rng1U64 voff_range) +{ + RDIM_LocationCase *n = rdim_push_array(arena, RDIM_LocationCase, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + n->location = location; + n->voff_range = voff_range; + scopes->location_case_count += 1; + return n; +} + RDI_PROC RDIM_LocationCase * rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *location, RDIM_Rng1U64 voff_range) { - RDIM_LocationCase *loc_case = rdim_push_array(arena, RDIM_LocationCase, 1); - RDIM_SLLQueuePush(local->location_cases.first, local->location_cases.last, loc_case); - local->location_cases.count += 1; - loc_case->location = location; - loc_case->voff_range = voff_range; - scopes->location_case_count += 1; - return loc_case; + return rdim_push_location_case(arena, scopes, &local->location_cases, location, voff_range); } //////////////////////////////// diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index 3fcdd51a..25645a49 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -7,6 +7,58 @@ // however it is optional and in case it is missing converter has to generate the ranges from scopes. // [ ] Error handling +//////////////////////////////// + +static const U64 UNIT_CHUNK_CAP = 256; +static const U64 UDT_CHUNK_CAP = 256; +static const U64 TYPE_CHUNK_CAP = 256; +static const U64 SRC_FILE_CAP = 256; +static const U64 LINE_TABLE_CAP = 256; +static const U64 LOCATIONS_CAP = 256; +static const U64 GVAR_CHUNK_CAP = 256; +static const U64 TVAR_CHUNK_CAP = 256; +static const U64 PROC_CHUNK_CAP = 256; +static const U64 SCOPE_CHUNK_CAP = 256; +static const U64 INLINE_SITE_CHUNK_CAP = 256; + +RDIM_TopLevelInfo top_level_info = {0}; +RDIM_BinarySectionList binary_sections = {0}; +RDIM_UnitChunkList units = {0}; +RDIM_UDTChunkList udts = {0}; +RDIM_TypeChunkList types = {0}; +RDIM_SrcFileChunkList src_files = {0}; +RDIM_LineTableChunkList line_tables = {0}; +RDIM_LocationChunkList locations = {0}; +RDIM_SymbolChunkList gvars = {0}; +RDIM_SymbolChunkList tvars = {0}; +RDIM_SymbolChunkList procs = {0}; +RDIM_ScopeChunkList scopes = {0}; +RDIM_InlineSiteChunkList inline_sites = {0}; + +//////////////////////////////// + +internal B32 +rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc) +{ + B32 is_static = 1; + RDI_EvalOp dynamic_ops[] = { RDI_EvalOp_MemRead, RDI_EvalOp_RegRead, RDI_EvalOp_RegReadDyn, RDI_EvalOp_CFA }; + for EachNode (n, RDIM_EvalBytecodeOp, bc.first_op) { + for EachIndex(i, ArrayCount(dynamic_ops)) { + is_static = 0; + goto exit; + } + } + exit:; + return is_static; +} + +internal U64 +rdim_do_static_bytecode_eval(RDIM_EvalBytecode bc, U64 image_base) +{ + NotImplemented; + return 0; +} + //////////////////////////////// //~ rjf: Enum Conversion Helpers @@ -90,23 +142,28 @@ d2r_create_type(Arena *arena, D2R_TypeTable *type_table) } internal RDIM_Type * -d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) +d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) { - RDIM_Type *type = 0; - KeyValuePair *is_type_present = hash_table_search_u64(type_table->ht, info_off); - if (is_type_present) { - type = is_type_present->value_raw; - } else { - type = d2r_create_type(arena, type_table); - hash_table_push_u64_raw(arena, type_table->ht, info_off, type); + RDIM_Type *type = d2r_create_type(arena, type_table); + Assert(hash_table_search_u64_raw(type_table->ht, info_off) == 0); + hash_table_push_u64_raw(arena, type_table->ht, info_off, type); + return type; +} + +internal RDIM_Type * +d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off) +{ + RDIM_Type *type = hash_table_search_u64_raw(type_table->ht, info_off); + if (type == 0) { + type = type_table->builtin_types[RDI_TypeKind_NULL]; } return type; } internal RDIM_Type * -d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) { - RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_NULL]; + RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_Void]; // find attrib DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); @@ -122,8 +179,8 @@ d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, D // TODO: support for external compile unit references AssertAlways(ref.cu == cu); - // find or create type - type = d2r_find_or_create_type_from_offset(arena, type_table, ref.info_off); + // find type + type = d2r_type_from_offset(type_table, ref.info_off); } else { Assert(!"unexpected attrib class"); } @@ -132,14 +189,6 @@ d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, D return type; } -internal RDIM_Type * -d2r_infer_parent_type(DW_CompUnit *cu, D2R_TagNode *tag_stack) -{ - D2R_TagNode *parent = tag_stack->next; - RDIM_Type *type = hash_table_search_u64_raw(cu->tag_ht, parent->cur_node->tag.info_off); - return type; -} - internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) { @@ -147,39 +196,45 @@ d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 imag Rng1U64List ranges = dw_rnglist_from_tag_attrib_kind(arena, input, cu, tag, DW_AttribKind_Ranges); // debase ranges - for (Rng1U64Node *range_n = ranges.first; range_n != 0; range_n = range_n->next) { + for EachNode(r, Rng1U64Node, ranges.first) { // TODO: error handling - AssertAlways(range_n->v.min >= image_base); - AssertAlways(range_n->v.max >= image_base); - range_n->v.min -= image_base; - range_n->v.max -= image_base; + AssertAlways(r->v.min >= image_base); + AssertAlways(r->v.max >= image_base); + r->v.min -= image_base; + r->v.max -= image_base; } // collect contiguous range - DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_LowPc); - DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); - if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { - U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); - - U64 hi_pc; - DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); - if (hi_pc_class == DW_AttribClass_Address) { - hi_pc = dw_address_from_attrib(input, cu, hi_pc_attrib); - } else if (hi_pc_class == DW_AttribClass_Const) { - hi_pc = dw_const_u64_from_attrib(input, cu, hi_pc_attrib); - hi_pc += lo_pc; - } else { - AssertAlways(!"undefined attrib encoding"); + { + DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_LowPc); + DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_HighPc); + if (lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null) { + U64 lo_pc = dw_address_from_attrib(input, cu, lo_pc_attrib); + + U64 hi_pc = 0; + DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); + if (hi_pc_class == DW_AttribClass_Address) { + hi_pc = dw_address_from_attrib(input, cu, hi_pc_attrib); + } else if (hi_pc_class == DW_AttribClass_Const) { + hi_pc = dw_const_u64_from_attrib(input, cu, hi_pc_attrib); + hi_pc += lo_pc; + } else { + AssertAlways(!"unexpected attribute encoding"); + } + + if (lo_pc >= image_base && hi_pc >= image_base) { + if (lo_pc < hi_pc) { + rng1u64_list_push(arena, &ranges, rng_1u64(lo_pc - image_base, hi_pc - image_base)); + } else { + // TODO: error handling + } + } else { + // invalid low and hi PC are likely are caused by an optimization pass during linking + } + } else if (lo_pc_attrib->attrib_kind == DW_AttribKind_Null && hi_pc_attrib->attrib_kind != DW_AttribKind_Null || + lo_pc_attrib->attrib_kind != DW_AttribKind_Null && hi_pc_attrib->attrib_kind == DW_AttribKind_Null) { + // TODO: error handling } - - // TODO: error handling - AssertAlways(lo_pc >= image_base); - AssertAlways(hi_pc >= image_base); - AssertAlways(lo_pc <= hi_pc); - - U64 lo_voff = lo_pc - image_base; - U64 hi_voff = hi_pc - image_base; - rng1u64_list_push(arena, &ranges, rng_1u64(lo_voff, hi_voff)); } return ranges; @@ -195,7 +250,7 @@ d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input for (DW_TagNode *i = cur_node->first_child; i != 0; i = i->sibling) { if (i->tag.kind == DW_TagKind_FormalParameter) { RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); - n->v = d2r_type_from_attrib(arena, type_table, input, cu, i->tag, DW_AttribKind_Type); + n->v = d2r_type_from_attrib(type_table, input, cu, i->tag, DW_AttribKind_Type); SLLQueuePush(list.first, list.last, n); ++list.count; } else if (i->tag.kind == DW_TagKind_UnspecifiedParameters) { @@ -309,9 +364,9 @@ d2r_bytecode_from_expression(Arena *arena, }; struct Frame *stack = 0; #define push_of_type(type) do { \ -struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ -f->value_type = d2r_type_group_from_type_kind(type); \ -SLLStackPush(stack, f); \ + struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ + f->value_type = d2r_type_group_from_type_kind(type); \ + SLLStackPush(stack, f); \ } while (0) #define pop_type() stack->value_type; SLLStackPop(stack) #define peek_type() stack->value_type @@ -857,6 +912,13 @@ SLLStackPush(stack, f); \ rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); } break; + case DW_ExprOp_GNU_PushTlsAddress: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Sub, peek_type()); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_TLSOff, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, peek_type()); + } break; + default: InvalidPath; break; } } @@ -869,38 +931,41 @@ SLLStackPush(stack, f); \ } internal RDIM_Location * -d2r_transpile_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr) +d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr) { RDIM_Location *loc = 0; if (expr.size) { B32 is_addr = 0; RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &is_addr); - loc = push_array(arena, RDIM_Location, 1); - loc->info.kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; - loc->info.bytecode = bytecode; + RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); + loc_info->kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; + loc_info->bytecode = bytecode; + + loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); } return loc; } internal RDIM_Location * -d2r_location_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind) +d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind) { String8 expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, kind); - RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); return location; } internal RDIM_LocationCaseList -d2r_locset_from_attrib(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag, - DW_AttribKind kind) +d2r_locset_from_attrib(Arena *arena, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + RDIM_LocationChunkList *locations, + DW_Input *input, + DW_CompUnit *cu, + U64 image_base, + Arch arch, + DW_Tag tag, + DW_AttribKind kind) { RDIM_LocationCaseList locset = {0}; @@ -915,11 +980,10 @@ d2r_locset_from_attrib(Arena *arena, DW_LocList loclist = dw_loclist_from_attrib(scratch.arena, input, cu, attrib); // convert location list to RDIM location set - for (DW_LocNode *loc_n = loclist.first; loc_n != 0; loc_n = loc_n->next) { - RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, loc_n->v.expr); + for EachNode(loc_n, DW_LocNode, loclist.first) { + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, loc_n->v.expr); RDIM_Rng1U64 voff_range = { .min = loc_n->v.range.min - image_base, .max = loc_n->v.range.max - image_base }; - // rdim_location_set_push_case(arena, scopes, &locset, voff_range, location); - // TODO(rjf): need to use rdim_local_push_location_case here + rdim_push_location_case(arena, scopes, &locset, location, voff_range); } scratch_end(scratch); @@ -928,10 +992,9 @@ d2r_locset_from_attrib(Arena *arena, String8 expr = dw_exprloc_from_attrib(input, cu, attrib); // convert expression and inherit life-time ranges from enclosed scope - RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); - for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { - // rdim_location_set_push_case(arena, scopes, &locset, range_n->v, location); - // TODO(rjf): need to use rdim_local_push_location_case here + RDIM_Location *location = d2r_transpile_expression(arena, locations, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { + rdim_push_location_case(arena, scopes, &locset, location, range_n->v); } } else if (attrib_class != DW_AttribClass_Null) { AssertAlways(!"unexpected attrib class"); @@ -941,14 +1004,15 @@ d2r_locset_from_attrib(Arena *arena, } internal RDIM_LocationCaseList -d2r_var_locset_from_tag(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag) +d2r_var_locset_from_tag(Arena *arena, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + RDIM_LocationChunkList *locations, + DW_Input *input, + DW_CompUnit *cu, + U64 image_base, + Arch arch, + DW_Tag tag) { RDIM_LocationCaseList locset = {0}; @@ -969,18 +1033,17 @@ d2r_var_locset_from_tag(Arena *arena, rdim_bytecode_push_uconst(arena, &bc, const_value); // fill out location - // TODO(rjf): these need to be pushed into a RDIM_LocationChunkList - RDIM_Location *loc = push_array(arena, RDIM_Location, 1); - loc->info.kind = RDI_LocationKind_ValBytecodeStream; - loc->info.bytecode = bc; - + RDIM_LocationInfo *loc_info = push_array(arena, RDIM_LocationInfo, 1); + loc_info->kind = RDI_LocationKind_ValBytecodeStream; + loc_info->bytecode = bc; + RDIM_Location *loc = rdim_location_chunk_list_push_new(arena, locations, LOCATIONS_CAP, loc_info); + // push location cases - for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { - // rdim_location_set_push_case(arena, scopes, &locset, range_n->v, loc); - // TODO(rjf): need to use rdim_local_push_location_case here + for EachNode(range_n, RDIM_Rng1U64Node, curr_scope->voff_ranges.first) { + rdim_push_location_case(arena, scopes, &locset, loc, range_n->v); } } else if (has_location) { - locset = d2r_locset_from_attrib(arena, input, cu, scopes, curr_scope, image_base, arch, tag, DW_AttribKind_Location); + locset = d2r_locset_from_attrib(arena, scopes, curr_scope, locations, input, cu, image_base, arch, tag, DW_AttribKind_Location); } return locset; @@ -999,22 +1062,18 @@ d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) cm.info_off_arr = push_array(arena, U64, unit_range_list.count); cm.voff_range_arr = push_array(arena, RDIM_Rng1U64ChunkList, unit_range_list.count); - for (Rng1U64Node *range_n = unit_range_list.first; range_n != 0; range_n = range_n->next) { + for EachNode(range_n, Rng1U64Node, unit_range_list.first) { String8 unit_data = str8_substr(aranges_data, range_n->v); U64 unit_cursor = 0; U64 unit_length = 0; U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, unit_cursor, &unit_length); - if (unit_length_size == 0) { - continue; - } + if (unit_length_size == 0) { continue; } unit_cursor += unit_length_size; DW_Version version = 0; U64 version_size = str8_deserial_read_struct(unit_data, unit_cursor, &version); - if (version_size == 0) { - continue; - } + if (version_size == 0) { continue; } unit_cursor += version; if (version != DW_Version_2) { @@ -1025,23 +1084,17 @@ d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) DW_Format unit_format = DW_FormatFromSize(unit_length); U64 cu_info_off = 0; U64 cu_info_off_size = str8_deserial_read_dwarf_uint(unit_data, unit_cursor, unit_format, &cu_info_off); - if (cu_info_off_size == 0) { - continue; - } + if (cu_info_off_size == 0) { continue; } unit_cursor += cu_info_off_size; U8 address_size = 0; U64 address_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &address_size); - if (address_size_size == 0) { - continue; - } + if (address_size_size == 0) { continue; } unit_cursor += address_size_size; U8 segment_selector_size = 0; U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &segment_selector_size); - if (segment_selector_size_size == 0) { - continue; - } + if (segment_selector_size_size == 0) { continue; } unit_cursor += segment_selector_size_size; U64 tuple_size = address_size * 2 + segment_selector_size; @@ -1058,9 +1111,8 @@ d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) unit_cursor += str8_deserial_read(unit_data, unit_cursor, &address, address_size, address_size); unit_cursor += str8_deserial_read(unit_data, unit_cursor, &length, address_size, address_size); - if (address == 0 && length == 0) { - break; - } + if (address == 0 && length == 0) { break; } + if (address == 0) { continue; } // TODO: error handling AssertAlways(address >= image_base); @@ -1090,7 +1142,7 @@ internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) { RDIM_Rng1U64ChunkList voff_ranges = {0}; - U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); + U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); if (voff_list_idx < map.count) { voff_ranges = map.voff_range_arr[voff_list_idx]; } @@ -1098,13 +1150,13 @@ d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) } internal RDIM_Scope * -d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagNode *tag_stack, Rng1U64List ranges) +d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges) { // fill out scope RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, scopes, scope_chunk_cap); // push ranges - for (Rng1U64Node *i = ranges.first; i != 0; i = i->next) { + for EachNode(i, Rng1U64Node, ranges.first) { rdim_scope_push_voff_range(arena, scopes, scope, (RDIM_Rng1U64){.min = i->v.min, i->v.max}); } @@ -1112,7 +1164,7 @@ d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D tag_stack->scope = scope; // update scope hierarchy - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + DW_TagKind parent_tag_kind = tag_stack->next->node->tag.kind; if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine || parent_tag_kind == DW_TagKind_LexicalBlock) { RDIM_Scope *parent = tag_stack->next->scope; @@ -1130,30 +1182,868 @@ d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D //////////////////////////////// //~ rjf: Main Conversion Entry Point - -static const U64 UNIT_CHUNK_CAP = 256; -static const U64 UDT_CHUNK_CAP = 256; -static const U64 TYPE_CHUNK_CAP = 256; -static const U64 GVAR_CHUNK_CAP = 256; -static const U64 TVAR_CHUNK_CAP = 256; -static const U64 PROC_CHUNK_CAP = 256; -static const U64 SCOPE_CHUNK_CAP = 256; -static const U64 INLINE_SITE_CHUNK_CAP = 256; -static const U64 SRC_FILE_CAP = 256; -static const U64 LINE_TABLE_CAP = 256; -RDIM_TopLevelInfo top_level_info = {0}; -RDIM_BinarySectionList binary_sections = {0}; -RDIM_UnitChunkList units = {0}; -RDIM_UDTChunkList udts = {0}; -RDIM_TypeChunkList types = {0}; -RDIM_SymbolChunkList gvars = {0}; -RDIM_SymbolChunkList tvars = {0}; -RDIM_SymbolChunkList procs = {0}; -RDIM_ScopeChunkList scopes = {0}; -RDIM_InlineSiteChunkList inline_sites = {0}; -RDIM_SrcFileChunkList src_files = {0}; -RDIM_LineTableChunkList line_tables = {0}; +internal D2R_TagIterator * +d2r_tag_iterator_init(Arena *arena, DW_TagNode *root) +{ + D2R_TagIterator *iter = push_array(arena, D2R_TagIterator, 1); + iter->free_list = 0; + iter->stack = push_array(arena, D2R_TagFrame, 1); + iter->stack->node = push_array(arena, DW_TagNode, 1); + *iter->stack->node = *root; + iter->stack->node->sibling = 0; + iter->visit_children = 1; + iter->tag_node = root; + return iter; +} + +internal void +d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter) +{ + // descend to first child + if (iter->visit_children) { + if (iter->stack->node->first_child) { + D2R_TagFrame *f = iter->free_list; + if (f) { SLLStackPop(iter->free_list); MemoryZeroStruct(f); } + else { f = push_array(arena, D2R_TagFrame, 1); } + f->node = iter->stack->node->first_child; + SLLStackPush(iter->stack, f); + goto exit; + } + } + + while (iter->stack) { + // go to sibling + iter->stack->node = iter->stack->node->sibling; + if (iter->stack->node) { break; } + + // no more siblings, go up + D2R_TagFrame *f = iter->stack; + SLLStackPop(iter->stack); + SLLStackPush(iter->free_list, f); + } + +exit:; + // update iterator + iter->visit_children = 1; + iter->tag_node = iter->stack ? iter->stack->node : 0; +} + +internal void +d2r_tag_iterator_skip_children(D2R_TagIterator *iter) +{ + iter->visit_children = 0; +} + +internal DW_TagNode * +d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter) +{ + return iter->stack->next->node; +} + +internal DW_Tag +d2r_tag_iterator_parent_tag(D2R_TagIterator *iter) +{ + DW_TagNode *tag_node = d2r_tag_iterator_parent_tag_node(iter); + return tag_node->tag; +} + +internal void +d2r_flag_converted_tag(DW_TagNode *tag_node) +{ + tag_node->tag.v[0] = 1; +} + +internal B8 +d2r_is_tag_converted(DW_TagNode *tag_node) +{ + return tag_node->tag.v[0]; +} + +internal RDIM_Type * +d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_Tag tag, DW_AttribKind kind) +{ + RDIM_Type *type = type_table->builtin_types[RDI_TypeKind_Void]; + + // find attrib + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + + // does tag have this attribute? + if (attrib->attrib_kind == kind) { + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + + if (value_class == DW_AttribClass_Reference) { + // resolve reference + DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); + + // TODO: support for external compile unit references + AssertAlways(ref.cu == cu); + + // find type + type = d2r_type_from_offset(type_table, ref.info_off); + + // was type converted? + if (type == 0) { + // issue type conversion + DW_TagNode *ref_node = dw_tag_node_from_info_off(cu, ref.info_off); + d2r_convert_types(arena, type_table, input, cu, cu_lang, arch_addr_size, ref_node); + + // if we do not have a converted type at this point then debug info is malformed + type = d2r_type_from_offset(type_table, ref.info_off); + Assert(type); + } + } else { + Assert(!"unexpected attrib class"); + } + } + + return type; +} + +internal void +d2r_convert_types(Arena *arena, + D2R_TypeTable *type_table, + DW_Input *input, + DW_CompUnit *cu, + DW_Language cu_lang, + U64 arch_addr_size, + DW_TagNode *root) +{ + Temp scratch = scratch_begin(&arena, 1); + for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { + DW_TagNode *tag_node = it->tag_node; + DW_Tag tag = tag_node->tag; + + // skip converted tags + if (d2r_is_tag_converted(tag_node)) { + d2r_tag_iterator_skip_children(it); + continue; + } + // mark the tag as converted here, because during conversion we may recurse on the same tag + d2r_flag_converted_tag(tag_node); + + switch (tag.kind) { + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_IncompleteClass; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteStruct; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Struct; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_IncompleteEnum; + // TODO: error handling + Assert(!tag_node->first_child); + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *enum_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(input, cu, tag); + type->direct_type = enum_base_type; + } + } break; + case DW_TagKind_SubroutineType: { + RDIM_Type *ret_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_TagKind_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(type_table, input, cu, n->tag, DW_AttribKind_Type); + rdim_type_list_push(scratch.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { + rdim_type_list_push(scratch.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); + } else { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_Typedef: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->direct_type = direct_type; + for (RDIM_Type *n = direct_type; n != 0; n = n->direct_type) { + if (n->byte_size) { + type->byte_size = n->byte_size; + break; + } + } + } break; + case DW_TagKind_BaseType: { + DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Encoding); + U64 byte_size = dw_byte_size_from_tag(input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + type->direct_type = type_table->builtin_types[kind]; + type->byte_size = byte_size; + } break; + case DW_TagKind_PointerType: { + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Allocated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Associated)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); + } + + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_TagKind_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = direct_type; + } break; + case DW_TagKind_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = direct_type; + } break; + case DW_TagKind_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Name)); + Assert(!dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Alignment)); + + RDIM_Type *direct_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *type = d2r_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = direct_type; + } break; + case DW_TagKind_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array[2] -> Pointer -> Array[3] -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + struct SubrangeNode { struct SubrangeNode *next; U64 count; }; + struct SubrangeNode *subrange_stack = 0; + for (DW_TagNode *n = tag_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_TagKind_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + // resolve lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_LowerBound)) { + lower_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_Count)) { + U64 count = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(input, cu, n->tag, DW_AttribKind_UpperBound)) { + upper_bound = dw_u64_from_attrib(input, cu, n->tag, DW_AttribKind_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero sized array + } + + struct SubrangeNode *s = push_array(scratch.arena, struct SubrangeNode, 1); + s->count = upper_bound - lower_bound; + SLLStackPush(subrange_stack, s); + } + + RDIM_Type *array_base_type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_Type *direct_type = array_base_type; + U64 size_cursor = array_base_type->byte_size; + for EachNode(s, struct SubrangeNode, subrange_stack) { + size_cursor *= s->count; + + RDIM_Type *t; + if (s->next) { t = d2r_create_type(arena, type_table); } + else { t = d2r_create_type_from_offset(arena, type_table, tag.info_off); } + + t->kind = RDI_TypeKind_Array; + t->direct_type = direct_type; + t->byte_size = size_cursor; + t->count = s->count; + + direct_type = t; + } + + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubrangeType: { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } break; + case DW_TagKind_Inheritance: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind != DW_TagKind_StructureType && parent_tag.kind != DW_TagKind_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_Type *type = d2r_find_or_convert_type(arena, type_table, input, cu, cu_lang, arch_addr_size, tag, DW_AttribKind_Type); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = type; + member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation)); + } break; + } + } + scratch_end(scratch); +} + +internal void +d2r_convert_udts(Arena *arena, + D2R_TypeTable *type_table, + DW_Input *input, + DW_CompUnit *cu, + DW_Language cu_lang, + U64 arch_addr_size, + DW_TagNode *root) +{ + Temp scratch = scratch_begin(&arena, 1); + for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { + DW_TagNode *tag_node = it->tag_node; + DW_Tag tag = tag_node->tag; + switch (tag.kind) { + case DW_TagKind_ClassType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_StructureType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_UnionType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_EnumerationType: { + B32 is_decl = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Declaration); + if (is_decl) { + d2r_tag_iterator_skip_children(it); + } else { + RDIM_Type *type = d2r_type_from_offset(type_table, tag.info_off); + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + type->udt = udt; + } + } break; + case DW_TagKind_Member: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + B32 is_parent_udt = parent_tag.kind == DW_TagKind_StructureType || + parent_tag.kind == DW_TagKind_ClassType || + parent_tag.kind == DW_TagKind_UnionType; + if (is_parent_udt) { + DW_Attrib *data_member_location = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *udt_member = rdim_udt_push_member(arena, &udts, parent_type->udt); + udt_member->kind = RDI_MemberKind_DataField; + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + udt_member->off = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_DataMemberLocation); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; + case DW_TagKind_Enumerator: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_EnumerationType) { + RDIM_Type *parent_type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTEnumVal *udt_member = rdim_udt_push_enum_val(arena, &udts, parent_type->udt); + udt_member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + udt_member->val = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ConstValue); + } else { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + } break; + } + } + scratch_end(scratch); +} + +internal void +d2r_convert_symbols(Arena *arena, + D2R_TypeTable *type_table, + RDIM_Scope *global_scope, + DW_Input *input, + DW_CompUnit *cu, + DW_Language cu_lang, + U64 arch_addr_size, + U64 image_base, + Arch arch, + DW_TagNode *root) +{ + Temp scratch = scratch_begin(&arena, 1); + for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, root); it->tag_node != 0; d2r_tag_iterator_next(scratch.arena, it)) { + DW_TagNode *tag_node = it->tag_node; + DW_Tag tag = tag_node->tag; + switch (tag.kind) { + case DW_TagKind_Null: { InvalidPath; } break; + case DW_TagKind_ClassType: + case DW_TagKind_StructureType: + case DW_TagKind_UnionType: { + // visit children to collect methods and variables + } break; + case DW_TagKind_EnumerationType: + case DW_TagKind_SubroutineType: + case DW_TagKind_Typedef: + case DW_TagKind_BaseType: + case DW_TagKind_PointerType: + case DW_TagKind_RestrictType: + case DW_TagKind_VolatileType: + case DW_TagKind_ConstType: + case DW_TagKind_ArrayType: + case DW_TagKind_SubrangeType: + case DW_TagKind_Inheritance: + case DW_TagKind_Enumerator: + case DW_TagKind_Member: { + d2r_tag_iterator_skip_children(it); + } break; + case DW_TagKind_SubProgram: { + DW_InlKind inl = dw_u64_from_attrib(input, cu, tag, DW_AttribKind_Inline); + switch (inl) { + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { + container_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + proc->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + proc->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->location_cases = d2r_locset_from_attrib(arena, &scopes, root_scope, &locations, input, cu, image_base, arch, tag, DW_AttribKind_FrameBase); + + // sub program with user-defined parent tag is a method + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_ClassType || parent_tag.kind == DW_TagKind_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; + } + + RDIM_Type *type = d2r_type_from_offset(type_table, parent_tag.info_off); + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + } else if (parent_tag.kind != DW_TagKind_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + it->stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + d2r_tag_iterator_skip_children(it); + } break; + default: InvalidPath; break; + } + } break; + case DW_TagKind_InlinedSubroutine: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, input, cu, tag_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *owner = 0; + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ContainingType)) { + owner = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_ContainingType); + } + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + root_scope->inline_site = inline_site; + } break; + case DW_TagKind_Variable: { + String8 name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + RDIM_Type *type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { break; } + + B32 is_thread_var = 0; + U64 voff = 0; + { + DW_Attrib *loc_attrib = dw_attrib_from_tag(input, cu, tag, DW_AttribKind_Location); + DW_AttribClass loc_class = dw_value_class_from_attrib(cu, loc_attrib); + if (loc_class == DW_AttribClass_ExprLoc) { + String8 expr = dw_exprloc_from_attrib(input, cu, loc_attrib); + B32 is_addr = 0; + RDIM_EvalBytecode bc = d2r_bytecode_from_expression(arena, input, image_base, arch_addr_size, arch, cu->addr_lu, expr, cu, &is_addr); + + for EachNode(n, RDIM_EvalBytecodeOp, bc.first_op) { + if (n->op == RDI_EvalOp_TLSOff) { + is_thread_var = 1; + break; + } + } + + if (is_addr) { + if (rdim_is_eval_bytecode_static(bc)) { + voff = rdim_do_static_bytecode_eval(bc, image_base); + } + } + } + } + + RDIM_SymbolChunkList *var_chunks; U64 var_chunks_cap; + if (is_thread_var) { var_chunks = &tvars; var_chunks_cap = TVAR_CHUNK_CAP; } + else { var_chunks = &gvars; var_chunks_cap = GVAR_CHUNK_CAP; } + + RDIM_Symbol *var = rdim_symbol_chunk_list_push(arena, var_chunks, var_chunks_cap); + var->is_extern = dw_flag_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_External); + var->name = name; + var->link_name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_LinkageName); + var->type = type; + var->offset = voff; + var->container_symbol = 0; + var->container_type = 0; // TODO: NotImplemented; + } + } break; + case DW_TagKind_FormalParameter: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || parent_tag.kind == DW_TagKind_InlinedSubroutine) { + RDIM_Scope *scope = it->stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Name); + param->type = d2r_type_from_attrib(type_table, input, cu, tag, DW_AttribKind_Type); + param->location_cases = d2r_var_locset_from_tag(arena, &scopes, scope, &locations, input, cu, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_TagKind_LexicalBlock: { + DW_Tag parent_tag = d2r_tag_iterator_parent_tag(it); + if (parent_tag.kind == DW_TagKind_SubProgram || + parent_tag.kind == DW_TagKind_InlinedSubroutine || + parent_tag.kind == DW_TagKind_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(scratch.arena, input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, it->stack, ranges); + } + } break; + case DW_TagKind_CallSite: { + // TODO + } break; + case DW_TagKind_CallSiteParameter: { + // TODO + } break; + case DW_TagKind_Label: + case DW_TagKind_CompileUnit: + case DW_TagKind_UnspecifiedParameters: + case DW_TagKind_Namespace: + case DW_TagKind_ImportedDeclaration: + case DW_TagKind_PtrToMemberType: + case DW_TagKind_TemplateTypeParameter: + case DW_TagKind_ReferenceType: { + // TODO: + } break; + default: NotImplemented; break; + } + } + scratch_end(scratch); +} internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params) @@ -1209,13 +2099,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) //////////////////////////////// - ProfBegin("Make Unit Contrib Map"); + ProfBegin("Parse Unit Contrib Map"); D2R_CompUnitContribMap cu_contrib_map = {0}; - if (input.sec[DW_Section_ARanges].data.size > 0) { + if (input.sec[DW_Section_ARanges].data.size) { cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); - } else { - // TODO: synthesize cu ranges from scopes - NotImplemented; } ProfEnd(); @@ -1233,7 +2120,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // converter can collect those & display as necessary. B32 is_parse_relaxed = 1; DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + for EachIndex(cu_idx, cu_ranges.count) { cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); } ProfEnd(); @@ -1242,7 +2129,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) ProfBegin("Parse Line Tables"); DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + for EachIndex(cu_idx, cu_ranges.count) { DW_CompUnit *cu = &cu_arr[cu_idx]; String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_StmtList); String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); @@ -1256,14 +2143,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) ProfBegin("Convert Line Tables"); HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + for EachIndex(cu_idx, cu_ranges.count) { cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); - for (U64 file_idx = 0; file_idx < file_table->count; ++file_idx) { + for EachIndex(file_idx, file_table->count) { DW_LineFile *file = &file_table->v[file_idx]; String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); String8List file_path_split = str8_split_path(scratch.arena, file_path); @@ -1278,10 +2165,8 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) src_file_map[file_idx] = src_file; } - for (DW_LineSeqNode *line_seq = line_table->first_seq; line_seq != 0; line_seq = line_seq->next) { - if (line_seq->count == 0) { - continue; - } + for EachNode(line_seq, DW_LineSeqNode, line_table->first_seq) { + if (line_seq->count == 0) { continue; } U64 *voffs = push_array(arena, U64, line_seq->count); U32 *line_nums = push_array(arena, U32, line_seq->count); @@ -1291,7 +2176,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) DW_LineNode *file_line_n = line_seq->first; U64 file_line_count = 0; - for (DW_LineNode *line_n = file_line_n; line_n != 0; line_n = line_n->next) { + for EachNode(line_n, DW_LineNode, file_line_n) { if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { U64 file_index = file_line_n->v.file_index; U64 *file_voffs = &voffs[line_idx]; @@ -1303,8 +2188,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; for (; file_line_n != sentinel; file_line_n = file_line_n->next) { if (file_line_n->v.line != prev_ln) { - // TODO: error handling - AssertAlways(file_line_n->v.address >= image_base); + if (file_line_n->v.address == 0) { continue; } voffs[line_idx] = file_line_n->v.address - image_base; line_nums[line_idx] = file_line_n->v.line; @@ -1322,7 +2206,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) file_line_count = 1; } else { - ++file_line_count; + file_line_count += 1; } } @@ -1333,7 +2217,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) U32 *file_line_nums = &line_nums[line_idx]; U16 *file_col_nums = 0; - for (; file_line_n != 0; file_line_n = file_line_n->next, ++line_idx) { + for (; file_line_n != 0; file_line_n = file_line_n->next, line_idx += 1) { // TODO: error handling AssertAlways(file_line_n->v.address >= image_base); voffs[line_idx] = file_line_n->v.address - image_base; @@ -1362,12 +2246,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) } builtin_types[RDI_TypeKind_Void]->byte_size = arch_addr_size; builtin_types[RDI_TypeKind_Handle]->byte_size = arch_addr_size; + builtin_types[RDI_TypeKind_Variadic] = rdim_type_chunk_list_push(arena, &types, TYPE_CHUNK_CAP); + builtin_types[RDI_TypeKind_Variadic]->kind = RDI_TypeKind_Variadic; //////////////////////////////// ProfBegin("Convert Units"); - for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + for EachIndex(cu_idx, cu_ranges.count) { Temp comp_temp = temp_begin(scratch.arena); DW_CompUnit *cu = &cu_arr[cu_idx]; @@ -1375,727 +2261,64 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) // parse and build tag tree DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); - // build tag hash table for abstract origin resolution - cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); + // skip DWO + { + if (cu->dwo_id) { goto next_cu; } - String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); - String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); - if (dwo_name.size || gnu_dwo_name.size || cu->dwo_id) { - // TODO: report that we dont support DWO - continue; + String8 dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_DwoName); + if (dwo_name.size) { goto next_cu; } + + String8 gnu_dwo_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_GNU_DwoName); + if (gnu_dwo_name.size) { goto next_cu; } } - String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); - String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); - DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); - RDIM_Rng1U64ChunkList cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); + // build (info offset -> tag) hash table to resolve tags with abstract origin + cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); - RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); - unit->unit_name = cu_name; - unit->compiler_name = cu_prod; - unit->source_file = str8_zero(); // TODO - unit->object_file = str8_zero(); // TODO - unit->archive_file = str8_zero(); // TODO - unit->build_path = cu_dir; - unit->language = d2r_rdi_language_from_dw_language(cu_lang); - unit->line_table = cu_line_tables_rdi[cu_idx]; - unit->voff_ranges = cu_voff_ranges; + // extract compile unit info + String8 cu_name = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Name); + String8 cu_dir = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_prod = dw_string_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Producer); + DW_Language cu_lang = dw_const_u64_from_tag_attrib_kind(&input, cu, cu->tag, DW_AttribKind_Language); + // init type table D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); type_table->ht = hash_table_init(comp_temp.arena, 0x4000); type_table->types = &types; type_table->type_chunk_cap = TYPE_CHUNK_CAP; type_table->builtin_types = builtin_types; - D2R_TagNode *free_tags = push_array(comp_temp.arena, D2R_TagNode, 1); - D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); - tag_stack->cur_node = tag_tree.root; + // convert debug info + d2r_convert_types(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); + d2r_convert_udts(arena, type_table, &input, cu, cu_lang, arch_addr_size, tag_tree.root); + d2r_convert_symbols(arena, type_table, global_scope, &input, cu, cu_lang, arch_addr_size, image_base, arch, tag_tree.root); - while (tag_stack && tag_stack->cur_node) { - DW_TagNode *cur_node = tag_stack->cur_node; - DW_Tag tag = cur_node->tag; - B32 visit_children = 1; - - switch (tag.kind) { - case DW_TagKind_Null: { - InvalidPath; - } break; - case DW_TagKind_ClassType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteClass; - - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Class; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } - } break; - case DW_TagKind_StructureType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteStruct; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Struct; - type->udt = udt; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - } - } break; - case DW_TagKind_UnionType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteUnion; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Union; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - } - } break; - case DW_TagKind_EnumerationType: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - - B32 is_decl = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Declaration); - if (is_decl) { - type->kind = RDI_TypeKind_IncompleteEnum; - - // TODO: error handling - Assert(!cur_node->first_child); - visit_children = 0; - } else { - RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); - udt->self_type = type; - - type->kind = RDI_TypeKind_Enum; - type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - type->udt = udt; - } - } break; - case DW_TagKind_SubroutineType: { - // collect parameters - RDIM_TypeList param_list = {0}; - for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind == DW_TagKind_FormalParameter) { - RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_AttribKind_Type); - rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); - } else if (n->tag.kind == DW_TagKind_UnspecifiedParameters) { - rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->builtin_types[RDI_TypeKind_Variadic]); - } else { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } - } - - // init proceudre type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Function; - type->byte_size = arch_addr_size; - type->direct_type = ret_type; - type->count = param_list.count; - type->param_types = rdim_array_from_type_list(arena, param_list); - - visit_children = 0; - } break; - case DW_TagKind_Typedef: { - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_BaseType: { - DW_ATE encoding = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Encoding); - U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); - - // convert base type encoding to RDI version - RDI_TypeKind kind = RDI_TypeKind_NULL; - switch (encoding) { - case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; - case DW_ATE_Address: kind = RDI_TypeKind_Void; break; - case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; - case DW_ATE_ComplexFloat: { - switch (byte_size) { - case 4: kind = RDI_TypeKind_ComplexF32; break; - case 8: kind = RDI_TypeKind_ComplexF64; break; - case 10: kind = RDI_TypeKind_ComplexF80; break; - case 16: kind = RDI_TypeKind_ComplexF128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Float: { - switch (byte_size) { - case 2: kind = RDI_TypeKind_F16; break; - case 4: kind = RDI_TypeKind_F32; break; - case 6: kind = RDI_TypeKind_F48; break; - case 8: kind = RDI_TypeKind_F64; break; - case 16: kind = RDI_TypeKind_F128; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Signed: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_S8; break; - case 2: kind = RDI_TypeKind_S16; break; - case 4: kind = RDI_TypeKind_S32; break; - case 8: kind = RDI_TypeKind_S64; break; - case 16: kind = RDI_TypeKind_S128; break; - case 32: kind = RDI_TypeKind_S256; break; - case 64: kind = RDI_TypeKind_S512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_SignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_Char8; break; - case 2: kind = RDI_TypeKind_Char16; break; - case 4: kind = RDI_TypeKind_Char32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_Unsigned: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_U8; break; - case 2: kind = RDI_TypeKind_U16; break; - case 4: kind = RDI_TypeKind_U32; break; - case 8: kind = RDI_TypeKind_U64; break; - case 16: kind = RDI_TypeKind_U128; break; - case 32: kind = RDI_TypeKind_U256; break; - case 64: kind = RDI_TypeKind_U512; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_UnsignedChar: { - switch (byte_size) { - case 1: kind = RDI_TypeKind_UChar8; break; - case 2: kind = RDI_TypeKind_UChar16; break; - case 4: kind = RDI_TypeKind_UChar32; break; - default: AssertAlways(!"unexpected size"); break; // TODO: error handling - } - } break; - case DW_ATE_ImaginaryFloat: { - NotImplemented; - } break; - case DW_ATE_PackedDecimal: { - NotImplemented; - } break; - case DW_ATE_NumericString: { - NotImplemented; - } break; - case DW_ATE_Edited: { - NotImplemented; - } break; - case DW_ATE_SignedFixed: { - NotImplemented; - } break; - case DW_ATE_UnsignedFixed: { - NotImplemented; - } break; - case DW_ATE_DecimalFloat: { - NotImplemented; - } break; - case DW_ATE_Utf: { - NotImplemented; - } break; - case DW_ATE_Ucs: { - NotImplemented; - } break; - case DW_ATE_Ascii: { - NotImplemented; - } break; - default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling - } - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Alias; - type->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - type->direct_type = type_table->builtin_types[kind]; - } break; - case DW_TagKind_PointerType: { - RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Allocated)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Associated)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_AddressClass)); - - U64 byte_size = arch_addr_size; - if (cu->version == DW_Version_5 || cu->relaxed) { - dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); - } - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Ptr; - type->byte_size = byte_size; - type->direct_type = direct_type; - } break; - case DW_TagKind_RestrictType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Restrict; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_VolatileType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Volatile; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_ConstType: { - // TODO: - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Name)); - Assert(!dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_Alignment)); - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Modifier; - type->byte_size = arch_addr_size; - type->flags = RDI_TypeModifierFlag_Const; - type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - } break; - case DW_TagKind_ArrayType: { - // * DWARF vs RDI Array Type Graph * - // - // For example lets take following decl: - // - // int (*foo[2])[3][4]; - // - // This compiles to in DWARF: - // - // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] - // \ - // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] -> DW_TagKind_Subrange [4] - // \ - // -> (B1) DW_TAG_BaseType (int) - // - // RDI expects: - // - // foo -> Array (2) -> Pointer -> Array (3) -> Array (4) -> int - // - // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and - // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. - // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from - // B to A. - - RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); - type->kind = RDI_TypeKind_Array; - type->direct_type = 0; - - U64 subrange_count = 0; - RDIM_Type *t = type; - for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { - if (n->tag.kind != DW_TagKind_SubrangeType) { - // TODO: error handling - AssertAlways(!"unexpected tag"); - continue; - } - - if (subrange_count > 0) { - // init array type node - RDIM_Type *s = d2r_create_type(arena, type_table); - s->kind = RDI_TypeKind_Array; - s->direct_type = 0; - - // append new array type node - t->direct_type = s; - t = s; - } - - // resolve array lower bound - U64 lower_bound = 0; - if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound)) { - lower_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_LowerBound); - } else { - lower_bound = dw_pick_default_lower_bound(cu_lang); - } - - // resolve array upper bound - U64 upper_bound = 0; - if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_Count)) { - U64 count = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_Count); - upper_bound = lower_bound + count; - } else if (dw_tag_has_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound)) { - upper_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_AttribKind_UpperBound); - // turn upper bound into exclusive range - upper_bound += 1; - } else { - // zero size array - } - - t->count = upper_bound - lower_bound; - ++subrange_count; - } - - Assert(t->direct_type == 0); - t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - visit_children = 0; - } break; - case DW_TagKind_SubrangeType: { - // TODO: error handling - AssertAlways(!"unexpected tag"); - } break; - case DW_TagKind_Inheritance: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_StructureType && - parent_node->tag.kind != DW_TagKind_ClassType) { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - - RDIM_Type *parent = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); - member->kind = RDI_MemberKind_Base; - member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - member->off = safe_cast_u32(dw_const_u32_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation)); - } break; - case DW_TagKind_Enumerator: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_EnumerationType) { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - member->val = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_ConstValue); - } break; - case DW_TagKind_Member: { - DW_TagNode *parent_node = tag_stack->next->cur_node; - if (parent_node->tag.kind != DW_TagKind_StructureType && - parent_node->tag.kind != DW_TagKind_ClassType && - parent_node->tag.kind != DW_TagKind_UnionType && - parent_node->tag.kind != DW_TagKind_EnumerationType) { - // TODO: error handling - AssertAlways(!"unexpected parent tag"); - } - - DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_AttribKind_DataMemberLocation); - DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); - if (data_member_location_class == DW_AttribClass_LocList) { - AssertAlways(!"UDT member with multiple locations are not supported"); - } - - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = RDI_MemberKind_DataField; - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - member->off = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_DataMemberLocation); - } break; - case DW_TagKind_SubProgram: { - DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_AttribKind_Inline); - switch (inl) { - case DW_Inl_NotInlined: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *container_type = 0; - if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { - container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); - } - - // get frame base expression - String8 frame_base_expr = dw_exprloc_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_FrameBase); - - // get proc container symbol - RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - root_scope->symbol = proc; - - // fill out proc - proc->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); - proc->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - proc->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); - proc->type = proc_type; - proc->container_symbol = 0; - proc->container_type = container_type; - proc->root_scope = root_scope; - proc->location_cases = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_AttribKind_FrameBase); - - // sub program with user-defined parent tag is a method - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_ClassType || parent_tag_kind == DW_TagKind_StructureType) { - RDI_MemberKind member_kind = RDI_MemberKind_NULL; - DW_VirtualityKind virtuality = dw_const_u64_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Virtuality); - switch (virtuality) { - case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; - case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; - case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal - //default: InvalidPath; break; - } - - RDIM_Type *type = d2r_infer_parent_type(cu, tag_stack); - RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); - member->kind = member_kind; - member->type = type; - member->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - } else if (parent_tag_kind != DW_TagKind_CompileUnit) { - //AssertAlways(!"unexpected tag"); - } - - tag_stack->scope = root_scope; - } break; - case DW_Inl_DeclaredNotInlined: - case DW_Inl_DeclaredInlined: - case DW_Inl_Inlined: { - visit_children = 0; - } break; - default: InvalidPath; break; - } - } break; - case DW_TagKind_InlinedSubroutine: { - U64 param_count = 0; - RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); - - // get return type - RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - // fill out proc type - RDIM_Type *proc_type = d2r_create_type(arena, type_table); - proc_type->kind = RDI_TypeKind_Function; - proc_type->byte_size = arch_addr_size; - proc_type->direct_type = ret_type; - proc_type->count = param_count; - proc_type->param_types = params; - - // get container type - RDIM_Type *owner = 0; - if (dw_tag_has_attrib(&input, cu, tag, DW_AttribKind_ContainingType)) { - owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_ContainingType); - } - - // fill out inline site - RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); - inline_site->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - inline_site->type = proc_type; - inline_site->owner = owner; - inline_site->line_table = 0; - - // make scope - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - root_scope->inline_site = inline_site; - } break; - case DW_TagKind_Variable: { - String8 name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_SubProgram || - parent_tag_kind == DW_TagKind_InlinedSubroutine || - parent_tag_kind == DW_TagKind_LexicalBlock) { - RDIM_Scope *scope = tag_stack->next->scope; - RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); - local->kind = RDI_LocalKind_Variable; - local->name = name; - local->type = type; - local->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); - } else { - - // NOTE: due to a bug in clang in stb_sprint.h local variables - // are declared in global scope without a name - if (name.size == 0) { break; } - - RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); - gvar->is_extern = dw_flag_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_External); - gvar->name = name; - gvar->link_name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_LinkageName); - gvar->type = type; - //gvar->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, global_scope, image_base, arch, tag, DW_AttribKind_Location); - gvar->container_symbol = 0; - gvar->container_type = 0; // TODO: NotImplemented; - } - } break; - case DW_TagKind_FormalParameter: { - DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; - if (parent_tag_kind == DW_TagKind_SubProgram || parent_tag_kind == DW_TagKind_InlinedSubroutine) { - RDIM_Scope *scope = tag_stack->next->scope; - RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); - param->kind = RDI_LocalKind_Parameter; - param->name = dw_string_from_tag_attrib_kind(&input, cu, tag, DW_AttribKind_Name); - param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_AttribKind_Type); - param->location_cases = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); - } else { - // TODO: error handling - AssertAlways(!"this is a local variable"); - } - } break; - case DW_TagKind_LexicalBlock: { - if (tag_stack->next->cur_node->tag.kind == DW_TagKind_SubProgram || - tag_stack->next->cur_node->tag.kind == DW_TagKind_InlinedSubroutine || - tag_stack->next->cur_node->tag.kind == DW_TagKind_LexicalBlock) { - Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); - d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); - } - } break; - case DW_TagKind_CallSite: { - // TODO - } break; - case DW_TagKind_CallSiteParameter: { - // TODO - } break; - case DW_TagKind_Label: - case DW_TagKind_CompileUnit: - case DW_TagKind_UnspecifiedParameters: - break; - case DW_TagKind_Namespace: break; - case DW_TagKind_ImportedDeclaration: break; - case DW_TagKind_PtrToMemberType: break; - case DW_TagKind_TemplateTypeParameter: break; - case DW_TagKind_ReferenceType: break; - default: NotImplemented; break; - } - - if (tag_stack->cur_node->first_child && visit_children) { - D2R_TagNode *frame = free_tags; - if (frame) { - SLLStackPop(free_tags); - MemoryZeroStruct(frame); - } else { - frame = push_array(comp_temp.arena, D2R_TagNode, 1); - } - frame->cur_node = tag_stack->cur_node->first_child; - SLLStackPush(tag_stack, frame); - } else { - tag_stack->cur_node = tag_stack->cur_node->sibling; - } - - if (tag_stack->cur_node == 0) { - // recycle free frame - D2R_TagNode *frame = tag_stack; - SLLStackPop(tag_stack); - SLLStackPush(free_tags, frame); - - if (tag_stack) { - tag_stack->cur_node = tag_stack->cur_node->sibling; - } - } + RDIM_Rng1U64ChunkList cu_voff_ranges = {0}; + if (cu_idx < cu_contrib_map.count) { + cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); + } else { + // TODO: synthesize cu ranges from scopes + NotImplemented; } + // convert compile unit + { + RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); + unit->unit_name = cu_name; + unit->compiler_name = cu_prod; + unit->source_file = str8_zero(); // TODO + unit->object_file = str8_zero(); // TODO + unit->archive_file = str8_zero(); // TODO + unit->build_path = cu_dir; + unit->language = d2r_rdi_language_from_dw_language(cu_lang); + unit->line_table = cu_line_tables_rdi[cu_idx]; + unit->voff_ranges = cu_voff_ranges; + } + + next_cu:; temp_end(comp_temp); } ProfEnd(); - - { - for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { - for (U64 i = 0; i < chunk_n->count; ++i) { - RDIM_Type *type = &chunk_n->v[i]; - if (type->kind == RDI_TypeKind_Alias) { - for (RDIM_Type *t = type->direct_type; t != 0; t = t->direct_type) { - if (t->byte_size != 0) { - type->byte_size = t->byte_size; - break; - } - } - } - } - } - } - - { - RDIM_TypeNode *type_stack = 0; - RDIM_TypeNode *free_types = 0; - - for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { - for (U64 i = 0; i < chunk_n->count; ++i) { - RDIM_Type *type = &chunk_n->v[i]; - if (type->kind == RDI_TypeKind_Array) { - if (type->byte_size != 0) - continue; - - RDIM_Type *t; - for (t = type; t != 0 && t->kind == RDI_TypeKind_Array; t = t->direct_type) { - RDIM_TypeNode *f = free_types; - if (f == 0) { - f = push_array(scratch.arena, RDIM_TypeNode, 1); - } else { - SLLStackPop(free_types); - } - f->v = t; - SLLStackPush(type_stack, f); - } - - U64 base_type_size = 0; - if (t) { - base_type_size = t->byte_size; - } - - U64 array_size = base_type_size; - while (type_stack) { - if (type_stack->v->count) { - array_size *= type_stack->v->count; - } else { - array_size += type_stack->v->byte_size; - } - SLLStackPop(type_stack); - } - - type->count = 0; - type->byte_size = array_size; - - // recycle frames - free_types = type_stack; - type_stack = 0; - } - } - } - } } lane_sync(); @@ -2108,6 +2331,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) bake_params.udts = udts; bake_params.src_files = src_files; bake_params.line_tables = line_tables; + bake_params.locations = locations; bake_params.global_variables = gvars; bake_params.thread_variables = tvars; bake_params.procedures = procs; @@ -2117,3 +2341,4 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) scratch_end(scratch); return bake_params; } + diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index 002724de..ae9155b0 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -6,13 +6,13 @@ typedef struct D2R_ConvertParams D2R_ConvertParams; struct D2R_ConvertParams { - String8 dbg_name; - String8 dbg_data; - String8 exe_name; - String8 exe_data; + String8 dbg_name; + String8 dbg_data; + String8 exe_name; + String8 exe_data; ExecutableImageKind exe_kind; - RDIM_SubsetFlags subset_flags; - B32 deterministic; + RDIM_SubsetFlags subset_flags; + B32 deterministic; }; typedef struct D2R_TypeTable @@ -23,12 +23,20 @@ typedef struct D2R_TypeTable RDIM_Type **builtin_types; } D2R_TypeTable; -typedef struct D2R_TagNode +typedef struct D2R_TagFrame { - struct D2R_TagNode *next; - DW_TagNode *cur_node; - RDIM_Scope *scope; -} D2R_TagNode; + DW_TagNode *node; + RDIM_Scope *scope; + struct D2R_TagFrame *next; +} D2R_TagFrame; + +typedef struct D2R_TagIterator +{ + D2R_TagFrame *free_list; + D2R_TagFrame *stack; + DW_TagNode *tag_node; + B32 visit_children; +} D2R_TagIterator; typedef struct D2R_CompUnitContribMap { @@ -43,59 +51,54 @@ typedef struct D2R_CompUnitContribMap internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v); internal RDI_RegCodeX86 d2r_rdi_reg_code_from_dw_reg_x86(DW_RegX86 v); internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64(DW_RegX64 v); -internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v); +internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg(Arch arch, DW_Reg v); //////////////////////////////// //~ rjf: Type Conversion Helpers -internal RDIM_Type * d2r_create_type(Arena *arena, D2R_TypeTable *type_table); -internal RDIM_Type * d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); -internal RDIM_Type * d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal RDIM_Type * d2r_infer_parent_type(DW_CompUnit *cu, D2R_TagNode *tag_stack); -internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag); -internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); -internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size); -internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size); +internal RDIM_Type * d2r_create_type(Arena *arena, D2R_TypeTable *type_table); +internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off); +internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off); +internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag); +internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out); +internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size); +internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size); internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x); //////////////////////////////// //~ rjf: Bytecode Conversion Helpers -internal RDIM_EvalBytecode -d2r_bytecode_from_expression(Arena *arena, - DW_Input *input, - U64 image_base, - U64 address_size, - Arch arch, - DW_ListUnit *addr_lu, - String8 expr, - DW_CompUnit *cu, - B32 *is_addr_out); -internal RDIM_Location *d2r_transpile_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); -internal RDIM_Location *d2r_location_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); -internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag, - DW_AttribKind kind); -internal RDIM_LocationCaseList d2r_var_locset_from_tag(Arena *arena, - DW_Input *input, - DW_CompUnit *cu, - RDIM_ScopeChunkList *scopes, - RDIM_Scope *curr_scope, - U64 image_base, - Arch arch, - DW_Tag tag); +internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, B32 *is_addr_out); +internal RDIM_Location * d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr); +internal RDIM_Location * d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); +internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind); +internal RDIM_LocationCaseList d2r_var_locset_from_tag(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag); //////////////////////////////// //~ rjf: Compilation Unit / Scope Conversion Helpers internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base); -internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off); +internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off); + +//////////////////////////////// +//~ Tag Iterator + +internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root); +internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter); +internal void d2r_tag_iterator_skip_children(D2R_TagIterator *iter); +internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter); +internal DW_Tag d2r_tag_iterator_parent_tag(D2R_TagIterator *iter); + +//////////////////////////////// +//~ Type/UDT/Symbol Conversion + +internal void d2r_flag_converted_tag(DW_TagNode *tag_node); +internal B8 d2r_is_tag_converted(DW_TagNode *tag_node); + +internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_TagNode *root); +internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, DW_TagNode *root); +internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, RDIM_Scope *global_scope, DW_Input *input, DW_CompUnit *cu, DW_Language cu_lang, U64 arch_addr_size, U64 image_base, Arch arch, DW_TagNode *root); //////////////////////////////// //~ rjf: Main Conversion Entry Point From 46527c846558d81801c4716907838cebeb74d18b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 14:12:33 -0700 Subject: [PATCH 294/302] checkpoint in new debug info layer: 16-byte key (set up to use GUIDs or otherwise unique keys at the base), better control over oversubscribing cores for conversion, better prioritization of conversions --- src/base/base_entry_point.c | 6 + src/dbg_info/dbg_info.c | 2 +- src/dbg_info/dbg_info2.c | 528 ++++++++++++++++++++++++++++++ src/dbg_info/dbg_info2.h | 199 +++++++++++ src/os/core/linux/os_core_linux.c | 6 +- src/os/core/os_core.h | 3 +- src/os/core/win32/os_core_win32.c | 19 +- src/raddbg/raddbg_main.c | 2 + src/tester/tester_main.c | 4 +- src/torture/torture.c | 8 +- 10 files changed, 753 insertions(+), 24 deletions(-) create mode 100644 src/dbg_info/dbg_info2.c create mode 100644 src/dbg_info/dbg_info2.h diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index d17dd15b..5037dbde 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -71,6 +71,9 @@ main_thread_base_entry_point(int arguments_count, char **arguments) #if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL) di_init(); #endif +#if defined(DBG_INFO2_H) && !defined(DI_INIT_MANUAL) + di2_init(); +#endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); #endif @@ -205,6 +208,9 @@ async_thread_entry_point(void *params) #endif #if defined(FILE_STREAM_H) fs_async_tick(); +#endif +#if defined(DBG_INFO2_H) + di2_async_tick(); #endif } diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index aff0da46..07a10bd5 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -1040,7 +1040,7 @@ ASYNC_WORK_DEF(di_parse_work) U64 start_wait_t = os_now_microseconds(); for(;;) { - B32 wait_done = os_process_join(process, os_now_microseconds()+1000); + B32 wait_done = os_process_join(process, os_now_microseconds()+1000, 0); if(wait_done) { rdi_file_is_up_to_date = 1; diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c new file mode 100644 index 00000000..604adb75 --- /dev/null +++ b/src/dbg_info/dbg_info2.c @@ -0,0 +1,528 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal DI2_Key +di2_key_zero(void) +{ + DI2_Key key = {0}; + return key; +} + +internal B32 +di2_key_match(DI2_Key a, DI2_Key b) +{ + B32 result = MemoryMatchStruct(&a, &b); + return result; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +di2_init(void) +{ + Arena *arena = arena_alloc(); + di2_shared = push_array(arena, DI2_Shared, 1); + di2_shared->arena = arena; + di2_shared->key_slots_count = 4096; + di2_shared->key_slots = push_array(arena, DI2_KeySlot, di2_shared->key_slots_count); + di2_shared->key_stripes = stripe_array_alloc(arena); + di2_shared->key_path_slots_count = 4096; + di2_shared->key_path_slots = push_array(arena, DI2_KeySlot, di2_shared->key_path_slots_count); + di2_shared->key_path_stripes = stripe_array_alloc(arena); + di2_shared->slots_count = 4096; + di2_shared->slots = push_array(arena, DI2_Slot, di2_shared->slots_count); + di2_shared->stripes = stripe_array_alloc(arena); + for EachElement(idx, di2_shared->req_batches) + { + di2_shared->req_batches[idx].mutex = mutex_alloc(); + di2_shared->req_batches[idx].arena = arena_alloc(); + } +} + +//////////////////////////////// +//~ rjf: Path * Timestamp Cache Submission & Lookup + +internal DI2_Key +di2_key_from_path_timestamp(String8 path, U64 min_timestamp) +{ + //- rjf: unpack key + U64 hash = u64_hash_from_str8(path); + U64 slot_idx = hash%di2_shared->key_slots_count; + DI2_KeySlot *slot = &di2_shared->key_slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->key_stripes, slot_idx); + + //- rjf: look up key, create if needed + DI2_Key key = {0}; + for(B32 write_mode = 0; write_mode <= 1; write_mode += 1) + { + // rjf: look up node, with this write mode, to find existing key computation + B32 found = 0; + RWMutexScope(stripe->rw_mutex, write_mode) + { + DI2_KeyNode *node = 0; + for(DI2_KeyNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0) && min_timestamp <= n->min_timestamp) + { + found = 1; + node = n; + key = node->key; + break; + } + } + if(!found && write_mode) + { + node = stripe->free; + if(node) + { + stripe->free = node->next; + } + else + { + node = push_array(stripe->arena, DI2_KeyNode, 1); + } + node->path = str8_copy(stripe->arena, path); + node->min_timestamp = min_timestamp; + node->key = key; + DLLPushBack(slot->first, slot->last, node); + } + } + + // rjf: found the key? abort + if(found) + { + break; + } + + // rjf: didn't find the key on our read lookup? compute the key before entering + // write mode + if(!found && !write_mode) + { + B32 made_key = 0; + + //- rjf: try to make key from file's contents + if(!made_key) + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); + FileProperties props = os_properties_from_file(file); + if(min_timestamp <= props.modified) + { + //- rjf: PDB magic => use GUID for key + if(!made_key) + { + B32 is_pdb = 0; + if(!is_pdb) + { + U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); + if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) + { + is_pdb = 1; + } + } + if(!is_pdb) + { + U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); + if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) + { + is_pdb = 1; + } + } + if(is_pdb) + { + // TODO(rjf) + } + } + } + os_file_close(file); + } + + //- rjf: fallback: hash from path/timestamp + if(!made_key) + { + made_key = 1; + U128 hash = u128_hash_from_seed_str8(min_timestamp, path); + MemoryCopy(&key, &hash, Min(sizeof(hash), sizeof(key))); + } + + //- rjf: made key -> store in (key -> path/timestamp) table + if(made_key) + { + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); + U64 key_slot_idx = key_hash%di2_shared->key_path_slots_count; + DI2_KeySlot *key_slot = &di2_shared->key_path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_path_stripes, key_slot_idx); + RWMutexScope(key_stripe->rw_mutex, 1) + { + DI2_KeyNode *node = 0; + for EachNode(n, DI2_KeyNode, key_slot->first) + { + if(di2_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = key_stripe->free; + if(node != 0) + { + key_stripe->free = node->next; + } + else + { + node = push_array(key_stripe->arena, DI2_KeyNode, 1); + } + DLLPushBack(key_slot->first, key_slot->last, node); + node->path = str8_copy(key_stripe->arena, path); + node->min_timestamp = min_timestamp; + node->key = key; + } + } + } + } + } + + return key; +} + +//////////////////////////////// +//~ rjf: Debug Info Opening / Closing + +internal void +di2_open(DI2_Key key) +{ + DI2_RequestBatch *batch = &di2_shared->req_batches[1]; + MutexScope(batch->mutex) + { + DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.key = key; + batch->count += 1; + } +} + +internal void +di2_close(DI2_Key key) +{ + // TODO(rjf) +} + +//////////////////////////////// +//~ rjf: Debug Info Lookups + +internal RDI_Parsed * +di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) +{ + RDI_Parsed *rdi = &rdi_parsed_nil; + { + // TODO(rjf) + } + return rdi; +} + +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void +di2_async_tick(void) +{ + Temp scratch = scratch_begin(0, 0); + + ////////////////////////////// + //- rjf: do single-lane update: pop requests, update tasks, gather RDI paths to parse wide + // + typedef struct ParseTask ParseTask; + struct ParseTask + { + DI2_Key key; + String8 rdi_path; + }; + ParseTask *parse_tasks = 0; + U64 parse_tasks_count = 0; + if(lane_idx() == 0) + { + typedef struct ParseTaskNode ParseTaskNode; + struct ParseTaskNode + { + ParseTaskNode *next; + ParseTask v; + }; + ParseTaskNode *first_parse_task = 0; + ParseTaskNode *last_parse_task = 0; + + //////////////////////////// + //- rjf: pop requests, high priority first, and generate conversion tasks for them + // + for EachElement(idx, di2_shared->req_batches) + { + DI2_RequestBatch *b = &di2_shared->req_batches[idx]; + MutexScope(b->mutex) + { + for EachNode(n, DI2_RequestNode, b->first) + { + DI2_LoadTask *t = di2_shared->free_load_task; + if(t) + { + SLLStackPop(di2_shared->free_load_task); + } + else + { + t = push_array_no_zero(di2_shared->arena, DI2_LoadTask, 1); + } + MemoryZeroStruct(t); + DLLPushBack(di2_shared->first_load_task, di2_shared->last_load_task, t); + t->key = n->v.key; + } + arena_clear(b->arena); + b->first = b->last = 0; + b->count = 0; + } + } + + //////////////////////////// + //- rjf: update tasks: configure, launch if we can, & retire if we can + // + for(DI2_LoadTask *t = di2_shared->first_load_task, *next = 0; t != 0; t = next) + { + next = t->next; + + //- rjf: unpack key + DI2_Key key = t->key; + U64 key_hash = u64_hash_from_str8(str8_struct(&key)); + U64 key_slot_idx = key_hash%di2_shared->key_slots_count; + DI2_KeySlot *key_slot = &di2_shared->key_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_stripes, key_slot_idx); + + //- rjf: get key's O.G. path + String8 og_path = {0}; + U64 og_min_timestamp = 0; + RWMutexScope(key_stripe->rw_mutex, 0) + { + for(DI2_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key)) + { + og_path = str8_copy(scratch.arena, n->path); + og_min_timestamp = n->min_timestamp; + break; + } + } + } + + //- rjf: analyze O.G. debug info + if(!t->og_analyzed) + { + t->og_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path); + FileProperties props = os_properties_from_file(file); + t->og_size = props.size; + U64 rdi_magic_maybe = 0; + if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 && + rdi_magic_maybe == RDI_MAGIC_CONSTANT) + { + t->og_is_rdi = 1; + } + os_file_close(file); + } + U64 og_size = t->og_size; + B32 og_is_rdi = t->og_is_rdi; + + //- rjf: compute key's RDI path + String8 rdi_path = {0}; + { + if(og_is_rdi) + { + rdi_path = og_path; + } + else + { + rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); + } + } + + //- rjf: determine if RDI is stale + if(!t->rdi_analyzed) + { + t->rdi_analyzed = 1; + OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path); + FileProperties props = os_properties_from_file(file); + if(props.modified < og_min_timestamp) + { + t->rdi_is_stale = 1; + } + else + { + t->rdi_is_stale = 1; + RDI_Header header = {0}; + if(os_file_read_struct(file, 0, &header) == sizeof(header)) + { + t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION); + } + } + os_file_close(file); + } + B32 rdi_is_stale = t->rdi_is_stale; + + //- rjf: calculate thread counts for conversion processes + if(!og_is_rdi && rdi_is_stale && t->thread_count == 0) + { + U64 thread_count = 1; + U64 max_thread_count = os_get_system_info()->logical_processor_count; + { + if(0){} + else if(og_size <= MB(4)) {thread_count = 1;} + else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} + else if(og_size <= MB(512)) {thread_count = max_thread_count/2;} + else {thread_count = max_thread_count;} + } + thread_count = Max(1, thread_count); + t->thread_count = thread_count; + } + + //- rjf: launch conversion processes + if(!og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI2_LoadTaskStatus_Active) + { + B32 should_compress = 0; + OS_ProcessLaunchParams params = {0}; + params.path = os_get_process_info()->binary_path; + params.inherit_env = 1; + params.consoleless = 1; + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--bin"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--quiet"); + if(should_compress) + { + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--compress"); + } + // str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); + t->process = os_process_launch(¶ms); + t->status = DI2_LoadTaskStatus_Active; + di2_shared->conversion_process_count += 1; + di2_shared->conversion_thread_count += t->thread_count; + } + + //- rjf: if active & process has completed, mark as done + { + U64 exit_code = 0; + if(t->status == DI2_LoadTaskStatus_Active && os_process_join(t->process, 0, &exit_code)) + { + t->status = DI2_LoadTaskStatus_Done; + } + } + + //- rjf: if the RDI for this task is not stale, then we're already done - mark this + // task as done & prepped for storing into the cache + if(!rdi_is_stale) + { + t->status = DI2_LoadTaskStatus_Done; + } + + //- rjf: if task is done, retire & recycle task; gather path to load + if(t->status == DI2_LoadTaskStatus_Done) + { + DLLRemove(di2_shared->first_load_task, di2_shared->last_load_task, t); + SLLStackPush(di2_shared->free_load_task, t); + di2_shared->conversion_process_count -= 1; + di2_shared->conversion_thread_count -= t->thread_count; + ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); + n->v.key = key; + n->v.rdi_path = rdi_path; + SLLQueuePush(first_parse_task, last_parse_task, n); + parse_tasks_count += 1; + } + } + + //////////////////////////// + //- rjf: join all parse tasks + // + parse_tasks = push_array(scratch.arena, ParseTask, parse_tasks_count); + { + U64 idx = 0; + for EachNode(n, ParseTaskNode, first_parse_task) + { + parse_tasks[idx] = n->v; + idx += 1; + } + } + } + lane_sync(); + + ////////////////////////////// + //- rjf: do wide load of all prepped RDIs + // + U64 parse_task_take_counter = 0; + U64 *parse_task_take_counter_ptr = 0; + if(lane_idx() == 0) + { + parse_task_take_counter_ptr = &parse_task_take_counter; + } + lane_sync_u64(&parse_task_take_counter_ptr, 0); + { + for(;;) + { + //- rjf: take next task + U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr); + if(parse_task_idx >= parse_tasks_count) + { + break; + } + + //- rjf: unpack task + DI2_Key key = parse_tasks[parse_task_idx].key; + String8 rdi_path = parse_tasks[parse_task_idx].rdi_path; + + //- rjf: open file + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + { + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); + } + + //- rjf: do initial parse of rdi + RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil; + { + RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); + (void)parse_status; + } + + //- rjf: decompress & re-parse, if necessary + Arena *rdi_parsed_arena = 0; + RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; + { + U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi_parsed_maybe_compressed); + if(decompressed_size > file_props.size) + { + rdi_parsed_arena = arena_alloc(); + U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); + rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi_parsed_maybe_compressed); + RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed); + (void)parse_status; + } + } + + //- rjf: commit parsed info to cache + { + // TODO(rjf) + } + } + } + lane_sync(); + + scratch_end(scratch); +} diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h new file mode 100644 index 00000000..01f5b0ab --- /dev/null +++ b/src/dbg_info/dbg_info2.h @@ -0,0 +1,199 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DBG_INFO2_H +#define DBG_INFO2_H + +//////////////////////////////// +//~ rjf: Unique Debug Info Key + +typedef struct DI2_Key DI2_Key; +struct DI2_Key +{ + U64 u64[2]; +}; + +//////////////////////////////// +//~ rjf: Debug Info Path / Timestamp => Key Cache Types + +typedef struct DI2_KeyNode DI2_KeyNode; +struct DI2_KeyNode +{ + DI2_KeyNode *next; + DI2_KeyNode *prev; + String8 path; + U64 min_timestamp; + DI2_Key key; +}; + +typedef struct DI2_KeySlot DI2_KeySlot; +struct DI2_KeySlot +{ + DI2_KeyNode *first; + DI2_KeyNode *last; +}; + +//////////////////////////////// +//~ rjf: Debug Info Cache Types + +typedef struct DI2_Node DI2_Node; +struct DI2_Node +{ + // rjf: links + DI2_Node *next; + DI2_Node *prev; + + // rjf: metadata + AccessPt access_pt; + U64 refcount; + U64 working_count; + U64 completion_count; + + // rjf: key + DI2_Key key; + + // rjf: value + OS_Handle file; + OS_Handle file_map; + void *file_base; + FileProperties file_props; + Arena *arena; + RDI_Parsed rdi; +}; + +typedef struct DI2_Slot DI2_Slot; +struct DI2_Slot +{ + DI2_Node *first; + DI2_Node *last; +}; + +//////////////////////////////// +//~ rjf: Requests + +typedef struct DI2_Request DI2_Request; +struct DI2_Request +{ + DI2_Key key; +}; + +typedef struct DI2_RequestNode DI2_RequestNode; +struct DI2_RequestNode +{ + DI2_RequestNode *next; + DI2_Request v; +}; + +typedef struct DI2_RequestBatch DI2_RequestBatch; +struct DI2_RequestBatch +{ + Mutex mutex; + Arena *arena; + DI2_RequestNode *first; + DI2_RequestNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Load Tasks + +typedef enum DI2_LoadTaskStatus +{ + DI2_LoadTaskStatus_Null, + DI2_LoadTaskStatus_Active, + DI2_LoadTaskStatus_Done, +} +DI2_LoadTaskStatus; + +typedef struct DI2_LoadTask DI2_LoadTask; +struct DI2_LoadTask +{ + DI2_LoadTask *next; + DI2_LoadTask *prev; + + DI2_Key key; + DI2_LoadTaskStatus status; + + B32 og_analyzed; + B32 og_is_rdi; + U64 og_size; + + B32 rdi_analyzed; + B32 rdi_is_stale; + + U64 thread_count; + OS_Handle process; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct DI2_Shared DI2_Shared; +struct DI2_Shared +{ + Arena *arena; + + // rjf: key -> path cache + U64 key_slots_count; + DI2_KeySlot *key_slots; + StripeArray key_stripes; + + // rjf: path -> key cache + U64 key_path_slots_count; + DI2_KeySlot *key_path_slots; + StripeArray key_path_stripes; + + // rjf: debug info cache + U64 slots_count; + DI2_Slot *slots; + StripeArray stripes; + + // rjf: requests + DI2_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority + + // rjf: conversion tasks + DI2_LoadTask *first_load_task; + DI2_LoadTask *last_load_task; + DI2_LoadTask *free_load_task; + U64 conversion_process_count; + U64 conversion_thread_count; +}; + +//////////////////////////////// +//~ rjf: Globals + +global DI2_Shared *di2_shared = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal DI2_Key di2_key_zero(void); +internal B32 di2_key_match(DI2_Key a, DI2_Key b); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void di2_init(void); + +//////////////////////////////// +//~ rjf: Path * Timestamp Cache Submission & Lookup + +internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 timestamp); + +//////////////////////////////// +//~ rjf: Debug Info Opening / Closing + +internal void di2_open(DI2_Key key); +internal void di2_close(DI2_Key key); + +//////////////////////////////// +//~ rjf: Debug Info Lookups + +internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us); + +//////////////////////////////// +//~ rjf: Asynchronous Tick + +internal void di2_async_tick(void); + +#endif // DBG_INFO2_H diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 9e01d5ef..8a22f460 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -774,13 +774,13 @@ os_process_launch(OS_ProcessLaunchParams *params) } internal B32 -os_process_join(OS_Handle handle, U64 endt_us) +os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out) { NotImplemented; } -internal B32 -os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out) +internal U64 +os_process_array_join(OS_HandleArray processes, U64 endt_us, U64 *exit_code_out) { NotImplemented; } diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 317f1d05..2731228f 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -244,8 +244,7 @@ internal void os_sleep_milliseconds(U32 msec); //~ rjf: @os_hooks Child Processes (Implemented Per-OS) internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params); -internal B32 os_process_join(OS_Handle handle, U64 endt_us); -internal B32 os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out); +internal B32 os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out); internal void os_process_detach(OS_Handle handle); internal B32 os_process_kill(OS_Handle handle); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 0e29fad9..d91b8088 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1061,28 +1061,21 @@ os_process_launch(OS_ProcessLaunchParams *params) } internal B32 -os_process_join(OS_Handle handle, U64 endt_us) +os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out) { HANDLE process = (HANDLE)(handle.u64[0]); DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); DWORD result = WaitForSingleObject(process, sleep_ms); - return (result == WAIT_OBJECT_0); -} - -internal B32 -os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out) -{ - B32 result = 0; - if(os_process_join(handle, endt_us)) + B32 process_joined = (result == WAIT_OBJECT_0); + if(process_joined && exit_code_out) { - DWORD exit_code; - if(GetExitCodeProcess((HANDLE)handle.u64[0], &exit_code)) + DWORD exit_code = 0; + if(GetExitCodeProcess(process, &exit_code)) { *exit_code_out = exit_code; - result = 1; } } - return result; + return process_joined; } internal B32 diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index a835cc51..14af7b95 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -249,6 +249,7 @@ #include "regs/regs.h" #include "regs/rdi/regs_rdi.h" #include "dbg_info/dbg_info.h" +#include "dbg_info/dbg_info2.h" #include "disasm/disasm.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" @@ -296,6 +297,7 @@ #include "regs/regs.c" #include "regs/rdi/regs_rdi.c" #include "dbg_info/dbg_info.c" +#include "dbg_info/dbg_info2.c" #include "disasm/disasm.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" diff --git a/src/tester/tester_main.c b/src/tester/tester_main.c index b221159e..4ee85062 100644 --- a/src/tester/tester_main.c +++ b/src/tester/tester_main.c @@ -114,7 +114,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) } for(OS_HandleNode *n = processes.first; n != 0; n = n->next) { - os_process_join(n->v, max_U64); + os_process_join(n->v, max_U64, 0); } } @@ -130,7 +130,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0) } for(OS_HandleNode *n = processes.first; n != 0; n = n->next) { - os_process_join(n->v, max_U64); + os_process_join(n->v, max_U64, 0); } } diff --git a/src/torture/torture.c b/src/torture/torture.c index 78951f77..ab845134 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -142,7 +142,9 @@ t_invoke_linker_with_time_out(U64 time_out, String8 cmdline) if (os_handle_match(linker_handle, os_handle_zero())) { fprintf(stderr, "unable to start process: %.*s\n", str8_varg(g_linker)); } else { - B32 was_joined = os_process_join_exit_code(linker_handle, time_out, &exit_code); + U64 exit_code_u64 = 0; + B32 was_joined = os_process_join(linker_handle, time_out, &exit_code_u64); + exit_code = (int)exit_code_u64; if (!was_joined) { os_process_kill(linker_handle); exit_code = T_LINKER_TIME_OUT_EXIT_CODE; @@ -4428,8 +4430,8 @@ t_import_kernel32(void) str8_list_pushf(scratch.arena, &launch_opts.cmd_line, "%S/a.exe", g_wdir); OS_Handle handle = os_process_launch(&launch_opts); AssertAlways(!os_handle_match(handle, os_handle_zero())); - int exit_code = -1; - os_process_join_exit_code(handle, max_U64, &exit_code); + U64 exit_code = max_U64; + os_process_join(handle, max_U64, &exit_code); os_process_detach(handle); if (exit_code != 0) { goto exit; } From 08904c9e2db64ef481d60066e04cecdfd3227a2d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 14:51:28 -0700 Subject: [PATCH 295/302] another checkpoint on new dbg info loading --- src/dbg_info/dbg_info2.c | 280 +++++++++++++++++++++++++++++++++++---- src/dbg_info/dbg_info2.h | 13 +- 2 files changed, 262 insertions(+), 31 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 604adb75..993bdb37 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -198,20 +198,120 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) internal void di2_open(DI2_Key key) { - DI2_RequestBatch *batch = &di2_shared->req_batches[1]; - MutexScope(batch->mutex) + //- rjf: unpack key + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di2_shared->slots_count; + DI2_Slot *slot = &di2_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); + + //- rjf: bump this key's node's refcount; create if needed + B32 node_is_new = 0; + RWMutexScope(stripe->rw_mutex, 1) { - DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); - SLLQueuePush(batch->first, batch->last, n); - n->v.key = key; - batch->count += 1; + DI2_Node *node = 0; + for(DI2_Node *n = slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) > 0) + { + node = n; + break; + } + } + if(node == 0) + { + node_is_new = 1; + node = stripe->free; + if(node) + { + stripe->free = node->next; + } + else + { + node = push_array_no_zero(stripe->arena, DI2_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->key = key; + node->batch_request_counts[1] = 1; + } + node->refcount += 1; + } + + //- rjf: if new, submit low-priority request to load this key + if(node_is_new) + { + DI2_RequestBatch *batch = &di2_shared->req_batches[1]; + MutexScope(batch->mutex) + { + DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.key = key; + batch->count += 1; + } + cond_var_broadcast(async_tick_start_cond_var); } } internal void di2_close(DI2_Key key) { - // TODO(rjf) + //- rjf: unpack key + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di2_shared->slots_count; + DI2_Slot *slot = &di2_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); + + //- rjf: decrement this key's node's refcount; remove if needed + B32 node_released = 0; + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + Arena *arena = 0; + RWMutexScope(stripe->rw_mutex, 1) + { + DI2_Node *node = 0; + for(DI2_Node *n = slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key) && ins_atomic_u64_eval(&n->completion_count) > 0) + { + node = n; + break; + } + } + if(node) + { + node->refcount -= 1; + if(node->refcount == 0) + { + for(;;) + { + if(access_pt_is_expired(&node->access_pt, .time = 0, .update_idxs = 0)) + { + node_released = 1; + DLLRemove(slot->first, slot->last, node); + node->next = stripe->free; + stripe->free = node; + file = node->file; + file_map = node->file_map; + file_props = node->file_props; + arena = node->arena; + break; + } + cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64); + } + } + } + } + + //- rjf: release node's resources if needed + if(node_released) + { + arena_release(arena); + os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); + os_file_map_close(file_map); + os_file_close(file); + } } //////////////////////////////// @@ -222,7 +322,58 @@ di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) { RDI_Parsed *rdi = &rdi_parsed_nil; { - // TODO(rjf) + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di2_shared->slots_count; + DI2_Slot *slot = &di2_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) for(;;) + { + // rjf: try to grab current results + B32 found = 0; + B32 need_hi_request = 0; + B32 grabbed = 0; + for(DI2_Node *n = slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key)) + { + found = 1; + if(high_priority && ins_atomic_u64_eval_cond_assign(&n->batch_request_counts[0], 1, 0) == 0) + { + need_hi_request = 1; + } + if(ins_atomic_u64_eval(&n->completion_count) > 0) + { + grabbed = 1; + rdi = &n->rdi; + access_touch(access, &n->access_pt, stripe->cv); + } + break; + } + } + + // rjf: push high-priority request if needed + if(need_hi_request) + { + DI2_RequestBatch *batch = &di2_shared->req_batches[0]; + MutexScope(batch->mutex) + { + DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1); + SLLQueuePush(batch->first, batch->last, n); + n->v.key = key; + batch->count += 1; + } + cond_var_broadcast(async_tick_start_cond_var); + } + + // rjf: found current results, or out-of-time? abort + if(grabbed || os_now_microseconds() >= endt_us) + { + break; + } + + // rjf: wait on stripe change + cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 0, endt_us); + } } return rdi; } @@ -258,8 +409,10 @@ di2_async_tick(void) ParseTaskNode *last_parse_task = 0; //////////////////////////// - //- rjf: pop requests, high priority first, and generate conversion tasks for them + //- rjf: pop all requests, high priority first // + DI2_RequestNode *first_req = 0; + DI2_RequestNode *last_req = 0; for EachElement(idx, di2_shared->req_batches) { DI2_RequestBatch *b = &di2_shared->req_batches[idx]; @@ -267,22 +420,59 @@ di2_async_tick(void) { for EachNode(n, DI2_RequestNode, b->first) { - DI2_LoadTask *t = di2_shared->free_load_task; - if(t) - { - SLLStackPop(di2_shared->free_load_task); - } - else - { - t = push_array_no_zero(di2_shared->arena, DI2_LoadTask, 1); - } - MemoryZeroStruct(t); - DLLPushBack(di2_shared->first_load_task, di2_shared->last_load_task, t); - t->key = n->v.key; + DI2_RequestNode *n_copy = push_array(scratch.arena, DI2_RequestNode, 1); + MemoryCopyStruct(&n_copy->v, &n->v); + SLLQueuePush(first_req, last_req, n_copy); } - arena_clear(b->arena); - b->first = b->last = 0; - b->count = 0; + } + arena_clear(b->arena); + b->first = b->last = 0; + b->count = 0; + } + + //////////////////////////// + //- rjf: generate load tasks for all unique requests + // + for EachNode(n, DI2_RequestNode, first_req) + { + // rjf: unpack request + DI2_Key key = n->v.key; + + // rjf: determine if this request is a duplicate + B32 request_is_duplicate = 1; + { + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di2_shared->slots_count; + DI2_Slot *slot = &di2_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) + { + for(DI2_Node *n = slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key)) + { + request_is_duplicate = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) != 0); + break; + } + } + } + } + + // rjf: if not a duplicate, create new task + if(!request_is_duplicate) + { + DI2_LoadTask *t = di2_shared->free_load_task; + if(t) + { + SLLStackPop(di2_shared->free_load_task); + } + else + { + t = push_array_no_zero(di2_shared->arena, DI2_LoadTask, 1); + } + MemoryZeroStruct(t); + DLLPushBack(di2_shared->first_load_task, di2_shared->last_load_task, t); + t->key = key; } } @@ -481,6 +671,7 @@ di2_async_tick(void) //- rjf: unpack task DI2_Key key = parse_tasks[parse_task_idx].key; String8 rdi_path = parse_tasks[parse_task_idx].rdi_path; + ProfBegin("parse %.*s", str8_varg(rdi_path)); //- rjf: open file OS_Handle file = {0}; @@ -518,8 +709,47 @@ di2_async_tick(void) //- rjf: commit parsed info to cache { - // TODO(rjf) + U64 hash = u64_hash_from_str8(str8_struct(&key)); + U64 slot_idx = hash%di2_shared->slots_count; + DI2_Slot *slot = &di2_shared->slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 1) + { + DI2_Node *node = 0; + for(DI2_Node *n = slot->first; n != 0; n = n->next) + { + if(di2_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node) + { + node->file = file; + node->file_map = file_map; + node->file_props = file_props; + node->file_base = file_base; + node->arena = rdi_parsed_arena; + MemoryCopyStruct(&node->rdi, &rdi_parsed); + node->completion_count += 1; + node->working_count -= 1; + } + else + { + if(rdi_parsed_arena != 0) + { + arena_release(rdi_parsed_arena); + } + os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); + os_file_map_close(file_map); + os_file_close(file); + } + } + cond_var_broadcast(stripe->cv); } + + ProfEnd(); } } lane_sync(); diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 01f5b0ab..287f2e66 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -43,12 +43,6 @@ struct DI2_Node DI2_Node *next; DI2_Node *prev; - // rjf: metadata - AccessPt access_pt; - U64 refcount; - U64 working_count; - U64 completion_count; - // rjf: key DI2_Key key; @@ -59,6 +53,13 @@ struct DI2_Node FileProperties file_props; Arena *arena; RDI_Parsed rdi; + + // rjf: metadata + AccessPt access_pt; + U64 refcount; + U64 batch_request_counts[2]; + U64 working_count; + U64 completion_count; }; typedef struct DI2_Slot DI2_Slot; From 92809ee6b6535a6851b1e12dfcea358b289d3068 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 15:07:08 -0700 Subject: [PATCH 296/302] new debug info loading layer debugging & fixes --- src/dbg_info/dbg_info2.c | 36 ++++++++++++++++++++---------------- src/dbg_info/dbg_info2.h | 14 +++++++------- src/scratch/ryan_scratch.c | 17 +++++++++++------ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 993bdb37..1d3c924a 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -27,12 +27,12 @@ di2_init(void) Arena *arena = arena_alloc(); di2_shared = push_array(arena, DI2_Shared, 1); di2_shared->arena = arena; - di2_shared->key_slots_count = 4096; - di2_shared->key_slots = push_array(arena, DI2_KeySlot, di2_shared->key_slots_count); - di2_shared->key_stripes = stripe_array_alloc(arena); - di2_shared->key_path_slots_count = 4096; - di2_shared->key_path_slots = push_array(arena, DI2_KeySlot, di2_shared->key_path_slots_count); - di2_shared->key_path_stripes = stripe_array_alloc(arena); + di2_shared->key2path_slots_count = 4096; + di2_shared->key2path_slots = push_array(arena, DI2_KeySlot, di2_shared->key2path_slots_count); + di2_shared->key2path_stripes = stripe_array_alloc(arena); + di2_shared->path2key_slots_count = 4096; + di2_shared->path2key_slots = push_array(arena, DI2_KeySlot, di2_shared->path2key_slots_count); + di2_shared->path2key_stripes = stripe_array_alloc(arena); di2_shared->slots_count = 4096; di2_shared->slots = push_array(arena, DI2_Slot, di2_shared->slots_count); di2_shared->stripes = stripe_array_alloc(arena); @@ -51,9 +51,9 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) { //- rjf: unpack key U64 hash = u64_hash_from_str8(path); - U64 slot_idx = hash%di2_shared->key_slots_count; - DI2_KeySlot *slot = &di2_shared->key_slots[slot_idx]; - Stripe *stripe = stripe_from_slot_idx(&di2_shared->key_stripes, slot_idx); + U64 slot_idx = hash%di2_shared->path2key_slots_count; + DI2_KeySlot *slot = &di2_shared->path2key_slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->path2key_stripes, slot_idx); //- rjf: look up key, create if needed DI2_Key key = {0}; @@ -117,6 +117,7 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) B32 is_pdb = 0; if(!is_pdb) { + read_only local_persist char msf_msf20_magic[] = "Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"; U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) @@ -126,6 +127,7 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) } if(!is_pdb) { + read_only local_persist char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) @@ -154,9 +156,9 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) if(made_key) { U64 key_hash = u64_hash_from_str8(str8_struct(&key)); - U64 key_slot_idx = key_hash%di2_shared->key_path_slots_count; - DI2_KeySlot *key_slot = &di2_shared->key_path_slots[key_slot_idx]; - Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_path_stripes, key_slot_idx); + U64 key_slot_idx = key_hash%di2_shared->key2path_slots_count; + DI2_KeySlot *key_slot = &di2_shared->key2path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key_slot_idx); RWMutexScope(key_stripe->rw_mutex, 1) { DI2_KeyNode *node = 0; @@ -486,9 +488,9 @@ di2_async_tick(void) //- rjf: unpack key DI2_Key key = t->key; U64 key_hash = u64_hash_from_str8(str8_struct(&key)); - U64 key_slot_idx = key_hash%di2_shared->key_slots_count; - DI2_KeySlot *key_slot = &di2_shared->key_slots[key_slot_idx]; - Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_stripes, key_slot_idx); + U64 key_slot_idx = key_hash%di2_shared->key2path_slots_count; + DI2_KeySlot *key_slot = &di2_shared->key2path_slots[key_slot_idx]; + Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key_slot_idx); //- rjf: get key's O.G. path String8 og_path = {0}; @@ -646,6 +648,8 @@ di2_async_tick(void) } } } + lane_sync_u64(&parse_tasks, 0); + lane_sync_u64(&parse_tasks_count, 0); lane_sync(); ////////////////////////////// @@ -662,7 +666,7 @@ di2_async_tick(void) for(;;) { //- rjf: take next task - U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr); + U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr) - 1; if(parse_task_idx >= parse_tasks_count) { break; diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 287f2e66..2e93cd70 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -135,14 +135,14 @@ struct DI2_Shared Arena *arena; // rjf: key -> path cache - U64 key_slots_count; - DI2_KeySlot *key_slots; - StripeArray key_stripes; + U64 key2path_slots_count; + DI2_KeySlot *key2path_slots; + StripeArray key2path_stripes; // rjf: path -> key cache - U64 key_path_slots_count; - DI2_KeySlot *key_path_slots; - StripeArray key_path_stripes; + U64 path2key_slots_count; + DI2_KeySlot *path2key_slots; + StripeArray path2key_stripes; // rjf: debug info cache U64 slots_count; @@ -179,7 +179,7 @@ internal void di2_init(void); //////////////////////////////// //~ rjf: Path * Timestamp Cache Submission & Lookup -internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 timestamp); +internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 min_timestamp); //////////////////////////////// //~ rjf: Debug Info Opening / Closing diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index adca33dd..692a9e04 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -16,6 +16,8 @@ #include "content/content.h" #include "artifact_cache/artifact_cache.h" #include "file_stream/file_stream.h" +#include "rdi/rdi_local.h" +#include "dbg_info/dbg_info2.h" //- rjf: [c] #include "base/base_inc.c" @@ -23,6 +25,8 @@ #include "content/content.c" #include "artifact_cache/artifact_cache.c" #include "file_stream/file_stream.c" +#include "rdi/rdi_local.c" +#include "dbg_info/dbg_info2.c" //////////////////////////////// //~ rjf: Entry Point @@ -30,15 +34,16 @@ internal void entry_point(CmdLine *cmdline) { + DI2_Key key = di2_key_from_path_timestamp(str8_lit("C:/devel/raddebugger/build/raddbg.pdb"), 0); + di2_open(key); for(;;) { - C_Key key = fs_key_from_path(str8_lit("C:/devel/raddebugger/build/x.dump"), os_now_microseconds() + 100000); - U128 hash = c_hash_from_key(key, 0); - printf("hash: 0x%I64x, 0x%I64x\n", hash.u64[0], hash.u64[1]); - fflush(stdout); - if(!u128_match(u128_zero(), hash)) + Access *access = access_open(); + RDI_Parsed *rdi = di2_rdi_from_key(access, key, 1, 0); + if(rdi != &rdi_parsed_nil) { - break; + int x = 0; } + access_close(access); } } From 3a409f5ab3d9bad33db7fb68aee690ed80798bfc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 16:07:16 -0700 Subject: [PATCH 297/302] throttle new conversion process launches based on available system-wide threads, with heuristic threshold of oversubscription; tweak size -> thread count heuristic --- src/dbg_info/dbg_info2.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 1d3c924a..70dafa8e 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -571,15 +571,25 @@ di2_async_tick(void) if(0){} else if(og_size <= MB(4)) {thread_count = 1;} else if(og_size <= MB(256)) {thread_count = max_thread_count/4;} - else if(og_size <= MB(512)) {thread_count = max_thread_count/2;} + else if(og_size <= MB(512)) {thread_count = max_thread_count/3;} + else if(og_size <= GB(1)) {thread_count = max_thread_count/2;} else {thread_count = max_thread_count;} } thread_count = Max(1, thread_count); t->thread_count = thread_count; } + //- rjf: determine if there are threads available + B32 threads_available = 0; + { + U64 max_threads = os_get_system_info()->logical_processor_count*8; + U64 current_threads = di2_shared->conversion_thread_count; + U64 needed_threads = (current_threads + t->thread_count); + threads_available = (max_threads >= needed_threads); + } + //- rjf: launch conversion processes - if(!og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI2_LoadTaskStatus_Active) + if(threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI2_LoadTaskStatus_Active) { B32 should_compress = 0; OS_ProcessLaunchParams params = {0}; @@ -610,6 +620,8 @@ di2_async_tick(void) if(t->status == DI2_LoadTaskStatus_Active && os_process_join(t->process, 0, &exit_code)) { t->status = DI2_LoadTaskStatus_Done; + di2_shared->conversion_process_count -= 1; + di2_shared->conversion_thread_count -= t->thread_count; } } @@ -625,8 +637,6 @@ di2_async_tick(void) { DLLRemove(di2_shared->first_load_task, di2_shared->last_load_task, t); SLLStackPush(di2_shared->free_load_task, t); - di2_shared->conversion_process_count -= 1; - di2_shared->conversion_thread_count -= t->thread_count; ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1); n->v.key = key; n->v.rdi_path = rdi_path; From 768755b0a4b17e26b12b50b4a4be9b156effc53a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 16:38:57 -0700 Subject: [PATCH 298/302] equip conversion subprocesses with info to signal parent on completion, + plug into a wakeup thread, which can re-trigger the async wavefront. also fix duplicate line counts in text parsing --- src/base/base_entry_point.c | 2 +- src/dbg_info/dbg_info2.c | 43 ++++++++++++++++++++++++++++++- src/dbg_info/dbg_info2.h | 13 +++++++++- src/os/core/win32/os_core_win32.c | 2 +- src/raddbg/raddbg_main.c | 9 ++++--- src/text/text.c | 6 +---- 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 5037dbde..7411e32c 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -72,7 +72,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments) di_init(); #endif #if defined(DBG_INFO2_H) && !defined(DI_INIT_MANUAL) - di2_init(); + di2_init(&cmdline); #endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 70dafa8e..5a66d242 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -22,7 +22,7 @@ di2_key_match(DI2_Key a, DI2_Key b) //~ rjf: Main Layer Initialization internal void -di2_init(void) +di2_init(CmdLine *cmdline) { Arena *arena = arena_alloc(); di2_shared = push_array(arena, DI2_Shared, 1); @@ -41,6 +41,24 @@ di2_init(void) di2_shared->req_batches[idx].mutex = mutex_alloc(); di2_shared->req_batches[idx].arena = arena_alloc(); } + U64 signal_pid = 0; + String8 signal_pid_string = cmd_line_string(cmdline, str8_lit("signal_pid")); + B32 has_parent = 1; + if(!try_u64_from_str8_c_rules(signal_pid_string, &signal_pid)) + { + has_parent = 0; + signal_pid = os_get_process_info()->pid; + } + di2_shared->conversion_completion_signal_semaphore_name = str8f(arena, "conversion_completion_signal_pid_%I64u", signal_pid); + if(has_parent) + { + di2_shared->conversion_completion_signal_semaphore = semaphore_open(di2_shared->conversion_completion_signal_semaphore_name); + } + else + { + di2_shared->conversion_completion_signal_semaphore = semaphore_alloc(0, 65536, di2_shared->conversion_completion_signal_semaphore_name); + di2_shared->conversion_completion_signal_receiver_thread = thread_launch(di2_conversion_completion_signal_receiver_thread_entry_point, 0); + } } //////////////////////////////// @@ -607,6 +625,7 @@ di2_async_tick(void) str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi"); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count); + str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--signal_pid:%I64u", (U64)os_get_process_info()->pid); str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path); t->process = os_process_launch(¶ms); t->status = DI2_LoadTaskStatus_Active; @@ -770,3 +789,25 @@ di2_async_tick(void) scratch_end(scratch); } + +//////////////////////////////// +//~ rjf: Conversion Completion Signal Receiver Thread + +internal void +di2_signal_completion(void) +{ + semaphore_drop(di2_shared->conversion_completion_signal_semaphore); +} + +internal void +di2_conversion_completion_signal_receiver_thread_entry_point(void *p) +{ + ThreadNameF("di2_conversion_completion_signal_receiver_thread"); + for(;;) + { + if(semaphore_take(di2_shared->conversion_completion_signal_semaphore, max_U64)) + { + cond_var_broadcast(async_tick_start_cond_var); + } + } +} diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 2e93cd70..6062a262 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -158,6 +158,11 @@ struct DI2_Shared DI2_LoadTask *free_load_task; U64 conversion_process_count; U64 conversion_thread_count; + + // rjf: conversion completion receiving thread + String8 conversion_completion_signal_semaphore_name; + Semaphore conversion_completion_signal_semaphore; + Thread conversion_completion_signal_receiver_thread; }; //////////////////////////////// @@ -174,7 +179,7 @@ internal B32 di2_key_match(DI2_Key a, DI2_Key b); //////////////////////////////// //~ rjf: Main Layer Initialization -internal void di2_init(void); +internal void di2_init(CmdLine *cmdline); //////////////////////////////// //~ rjf: Path * Timestamp Cache Submission & Lookup @@ -197,4 +202,10 @@ internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_prio internal void di2_async_tick(void); +//////////////////////////////// +//~ rjf: Conversion Completion Signal Receiver Thread + +internal void di2_signal_completion(void); +internal void di2_conversion_completion_signal_receiver_thread_entry_point(void *p); + #endif // DBG_INFO2_H diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index d91b8088..a2e8cd9f 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -1300,7 +1300,7 @@ os_semaphore_open(String8 name) { Temp scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); - HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS , 0, (WCHAR *)name16.str); + HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, 0, (WCHAR *)name16.str); Semaphore result = {(U64)handle}; scratch_end(scratch); return result; diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 14af7b95..4d7a2865 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -510,8 +510,8 @@ entry_point(CmdLine *cmd_line) String8 ipc_sender2main_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_lock_semaphore_%i_", instance_pid); OS_Handle ipc_sender2main_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_sender2main_shared_memory_name); ipc_sender2main_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_sender2main_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); - ipc_sender2main_signal_semaphore = os_semaphore_alloc(0, 1, ipc_sender2main_signal_semaphore_name); - ipc_sender2main_lock_semaphore = os_semaphore_alloc(1, 1, ipc_sender2main_lock_semaphore_name); + ipc_sender2main_signal_semaphore = semaphore_alloc(0, 1, ipc_sender2main_signal_semaphore_name); + ipc_sender2main_lock_semaphore = semaphore_alloc(1, 1, ipc_sender2main_lock_semaphore_name); // rjf: set up cross-process main -> sender ring buffer String8 ipc_main2sender_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_shared_memory_%i_", instance_pid); @@ -519,8 +519,8 @@ entry_point(CmdLine *cmd_line) String8 ipc_main2sender_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_lock_semaphore_%i_", instance_pid); OS_Handle ipc_main2sender_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_main2sender_shared_memory_name); ipc_main2sender_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_main2sender_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); - ipc_main2sender_signal_semaphore = os_semaphore_alloc(0, 1, ipc_main2sender_signal_semaphore_name); - ipc_main2sender_lock_semaphore = os_semaphore_alloc(1, 1, ipc_main2sender_lock_semaphore_name); + ipc_main2sender_signal_semaphore = semaphore_alloc(0, 1, ipc_main2sender_signal_semaphore_name); + ipc_main2sender_lock_semaphore = semaphore_alloc(1, 1, ipc_main2sender_lock_semaphore_name); // rjf: set up ipc-receiver -> main thread ring buffer; launch signaler thread ipc_s2m_ring_mutex = mutex_alloc(); @@ -751,6 +751,7 @@ entry_point(CmdLine *cmd_line) case ExecMode_BinaryUtility: { rb_entry_point(cmd_line); + di2_signal_completion(); }break; //- rjf: help message box diff --git a/src/text/text.c b/src/text/text.c index dd59b33a..3ee0c191 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -2044,13 +2044,9 @@ txt_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) Rng1U64 range = lane_range(data.size); for EachInRange(idx, range) { - if(data.str[idx] == '\n' || data.str[idx] == '\r') + if(data.str[idx] == '\n') { lane_line_count += 1; - if(data.str[idx] == '\r') - { - idx += 1; - } } if(idx && idx%1000 == 0) { From d2678db25f8959740d999a692e2f1b64be1432a9 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 17:09:44 -0700 Subject: [PATCH 299/302] first pass at new wide async all-debug-info fuzzy searching --- src/dbg_info/dbg_info2.c | 282 ++++++++++++++++++++++++++++++++++++++- src/dbg_info/dbg_info2.h | 80 ++++++++++- 2 files changed, 349 insertions(+), 13 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 5a66d242..9faede86 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -81,8 +81,8 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) B32 found = 0; RWMutexScope(stripe->rw_mutex, write_mode) { - DI2_KeyNode *node = 0; - for(DI2_KeyNode *n = slot->first; n != 0; n = n->next) + DI2_KeyPathNode *node = 0; + for(DI2_KeyPathNode *n = slot->first; n != 0; n = n->next) { if(str8_match(n->path, path, 0) && min_timestamp <= n->min_timestamp) { @@ -101,7 +101,7 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) } else { - node = push_array(stripe->arena, DI2_KeyNode, 1); + node = push_array(stripe->arena, DI2_KeyPathNode, 1); } node->path = str8_copy(stripe->arena, path); node->min_timestamp = min_timestamp; @@ -179,8 +179,8 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, key_slot_idx); RWMutexScope(key_stripe->rw_mutex, 1) { - DI2_KeyNode *node = 0; - for EachNode(n, DI2_KeyNode, key_slot->first) + DI2_KeyPathNode *node = 0; + for EachNode(n, DI2_KeyPathNode, key_slot->first) { if(di2_key_match(n->key, key)) { @@ -197,7 +197,7 @@ di2_key_from_path_timestamp(String8 path, U64 min_timestamp) } else { - node = push_array(key_stripe->arena, DI2_KeyNode, 1); + node = push_array(key_stripe->arena, DI2_KeyPathNode, 1); } DLLPushBack(key_slot->first, key_slot->last, node); node->path = str8_copy(key_stripe->arena, path); @@ -337,6 +337,43 @@ di2_close(DI2_Key key) //////////////////////////////// //~ rjf: Debug Info Lookups +internal DI2_KeyArray +di2_push_all_loaded_keys(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + DI2_KeyList list = {0}; + { + for EachIndex(slot_idx, di2_shared->key2path_slots_count) + { + DI2_KeySlot *slot = &di2_shared->key2path_slots[slot_idx]; + Stripe *stripe = stripe_from_slot_idx(&di2_shared->key2path_stripes, slot_idx); + RWMutexScope(stripe->rw_mutex, 0) + { + for(DI2_KeyPathNode *n = slot->first; n != 0; n = n->next) + { + DI2_KeyNode *dst_n = push_array(scratch.arena, DI2_KeyNode, 1); + SLLQueuePush(list.first, list.last, dst_n); + list.count += 1; + dst_n->v = n->key; + } + } + } + } + DI2_KeyArray array = {0}; + array.count = list.count; + array.v = push_array(arena, DI2_Key, array.count); + { + U64 idx = 0; + for EachNode(n, DI2_KeyNode, list.first) + { + array.v[idx] = n->v; + idx += 1; + } + } + scratch_end(scratch); + return array; +} + internal RDI_Parsed * di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us) { @@ -515,7 +552,7 @@ di2_async_tick(void) U64 og_min_timestamp = 0; RWMutexScope(key_stripe->rw_mutex, 0) { - for(DI2_KeyNode *n = key_slot->first; n != 0; n = n->next) + for(DI2_KeyPathNode *n = key_slot->first; n != 0; n = n->next) { if(di2_key_match(n->key, key)) { @@ -811,3 +848,234 @@ di2_conversion_completion_signal_receiver_thread_entry_point(void *p) } } } + +//////////////////////////////// +//~ rjf: Search Artifact Cache Hooks / Lookups + +internal AC_Artifact +di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) +{ + Access *access = access_open(); + Temp scratch = scratch_begin(0, 0); + AC_Artifact artifact = {0}; + { + //- rjf: unpack key + RDI_SectionKind section_kind = RDI_SectionKind_NULL; + String8 query = {0}; + { + U64 key_read_off = 0; + key_read_off += str8_deserial_read_struct(key, key_read_off, §ion_kind); + key_read_off += str8_deserial_read_struct(key, key_read_off, &query.size); + query.str = push_array(scratch.arena, U8, query.size); + key_read_off += str8_deserial_read(key, key_read_off, query.str, query.size, 1); + } + + //- rjf: gather all debug info keys we'll search on + DI2_KeyArray keys = {0}; + if(lane_idx() == 0) + { + keys = di2_push_all_loaded_keys(scratch.arena); + } + lane_sync_u64(&keys.v, 0); + lane_sync_u64(&keys.count, 0); + + //- rjf: map all debug info keys -> RDIs + RDI_Parsed **rdis = 0; + if(lane_idx() == 0) + { + rdis = push_array(scratch.arena, RDI_Parsed *, keys.count); + } + lane_sync_u64(&rdis, 0); + { + Rng1U64 range = lane_range(keys.count); + for EachInRange(idx, range) + { + rdis[idx] = di2_rdi_from_key(access, keys.v[idx], 0, 0); + } + } + lane_sync(); + + //- rjf: do wide search on all lanes + DI2_SearchItemChunkList *lanes_items = 0; + if(lane_idx() == 0) + { + lanes_items = push_array(scratch.arena, DI2_SearchItemChunkList, lane_count()); + } + lane_sync_u64(&lanes_items, 0); + Arena *arena = arena_alloc(); + DI2_SearchItemChunkList *lane_items = &lanes_items[lane_idx()]; + { + for EachIndex(rdi_idx, keys.count) + { + DI2_Key key = keys.v[rdi_idx]; + RDI_Parsed *rdi = rdis[rdi_idx]; + + // rjf: unpack table info + U64 element_count = 0; + void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); + U64 element_size = rdi_section_element_size_table[section_kind]; + + // rjf: determine name string index offset, depending on table kind + U64 element_name_idx_off = 0; + switch(section_kind) + { + default:{}break; + case RDI_SectionKind_Procedures: + { + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + }break; + case RDI_SectionKind_GlobalVariables: + { + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + }break; + case RDI_SectionKind_ThreadVariables: + { + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + }break; + case RDI_SectionKind_UDTs: + { + // NOTE(rjf): name must be determined from self_type_idx + }break; + case RDI_SectionKind_SourceFiles: + { + // NOTE(rjf): name must be determined from file path node chain + }break; + } + + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) + { + //- rjf: every so often, check if we need to cancel, and cancel + { + // TODO(rjf) + } + + //- rjf: get element, map to string; if empty, continue to next element + void *element = (U8 *)table_base + element_size*idx; + String8 name = {0}; + switch(section_kind) + { + case RDI_SectionKind_UDTs: + { + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); + name = str8_copy(arena, name); + }break; + case RDI_SectionKind_SourceFiles: + { + Temp scratch = scratch_begin(&arena, 1); + RDI_SourceFile *file = (RDI_SourceFile *)element; + String8List path_parts = {0}; + for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file->file_path_node_idx); + fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); + fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) + { + String8 path_part = {0}; + path_part.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &path_part.size); + str8_list_push_front(scratch.arena, &path_parts, path_part); + } + StringJoin join = {0}; + join.sep = str8_lit("/"); + name = str8_list_join(arena, &path_parts, &join); + scratch_end(scratch); + }break; + default: + { + U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); + name = str8(name_base, name_size); + }break; + } + if(name.size == 0) { continue; } + + //- rjf: fuzzy match against query + FuzzyMatchRangeList matches = fuzzy_match_find(arena, query, name); + + //- rjf: collect + if(matches.count == matches.needle_part_count) + { + DI2_SearchItemChunk *chunk = lane_items->last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, DI2_SearchItemChunk, 1); + chunk->base_idx = lane_items->total_count; + chunk->cap = 1024; + chunk->count = 0; + chunk->v = push_array_no_zero(scratch.arena, DI2_SearchItem, chunk->cap); + SLLQueuePush(lane_items->first, lane_items->last, chunk); + lane_items->chunk_count += 1; + } + chunk->v[chunk->count].idx = idx; + chunk->v[chunk->count].key = key; + chunk->v[chunk->count].match_ranges = matches; + chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; + chunk->count += 1; + lane_items->total_count += 1; + } + } + } + } + lane_sync(); + + //- rjf: join all lane chunk lists + DI2_SearchItemChunkList *all_items = &lanes_items[0]; + if(lane_idx() == 0) + { + for(U64 lidx = 1; lidx < lane_count(); lidx += 1) + { + DI2_SearchItemChunkList *dst = all_items; + DI2_SearchItemChunkList *to_push = &lanes_items[lidx]; + for EachNode(n, DI2_SearchItemChunk, to_push->first) + { + n->base_idx += dst->total_count; + } + if(dst->first && to_push->first) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + MemoryCopyStruct(dst, to_push); + } + MemoryZeroStruct(to_push); + } + } + lane_sync(); + + //- rjf: flatten into array + DI2_SearchItemArray items = {0}; + if(lane_idx() == 0) + { + items.count = all_items->total_count; + items.v = push_array(arena, DI2_SearchItem, items.count); + } + lane_sync_u64(&items.count, 0); + lane_sync_u64(&items.v, 0); + for EachNode(n, DI2_SearchItemChunk, all_items->first) + { + Rng1U64 range = lane_range(n->count); + U64 dst_idx = n->base_idx + range.min; + MemoryCopy(&items.v[dst_idx], n->v, sizeof(n->v[0]) * dim_1u64(range)); + } + } + scratch_end(scratch); + access_close(access); + return artifact; +} + +internal void +di2_search_artifact_destroy(AC_Artifact artifact) +{ + +} + +internal DI2_SearchItemArray +di2_search_item_array_from_target_query(RDI_SectionKind target, String8 query) +{ + +} diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 6062a262..227be869 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -13,14 +13,36 @@ struct DI2_Key U64 u64[2]; }; -//////////////////////////////// -//~ rjf: Debug Info Path / Timestamp => Key Cache Types - typedef struct DI2_KeyNode DI2_KeyNode; struct DI2_KeyNode { DI2_KeyNode *next; - DI2_KeyNode *prev; + DI2_Key v; +}; + +typedef struct DI2_KeyList DI2_KeyList; +struct DI2_KeyList +{ + DI2_KeyNode *first; + DI2_KeyNode *last; + U64 count; +}; + +typedef struct DI2_KeyArray DI2_KeyArray; +struct DI2_KeyArray +{ + DI2_Key *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Debug Info Path / Timestamp => Key Cache Types + +typedef struct DI2_KeyPathNode DI2_KeyPathNode; +struct DI2_KeyPathNode +{ + DI2_KeyPathNode *next; + DI2_KeyPathNode *prev; String8 path; U64 min_timestamp; DI2_Key key; @@ -29,8 +51,8 @@ struct DI2_KeyNode typedef struct DI2_KeySlot DI2_KeySlot; struct DI2_KeySlot { - DI2_KeyNode *first; - DI2_KeyNode *last; + DI2_KeyPathNode *first; + DI2_KeyPathNode *last; }; //////////////////////////////// @@ -126,6 +148,44 @@ struct DI2_LoadTask OS_Handle process; }; +//////////////////////////////// +//~ rjf: Search Types + +typedef struct DI2_SearchItem DI2_SearchItem; +struct DI2_SearchItem +{ + U64 idx; + DI2_Key key; + U64 missed_size; + FuzzyMatchRangeList match_ranges; +}; + +typedef struct DI2_SearchItemChunk DI2_SearchItemChunk; +struct DI2_SearchItemChunk +{ + DI2_SearchItemChunk *next; + U64 base_idx; + DI2_SearchItem *v; + U64 count; + U64 cap; +}; + +typedef struct DI2_SearchItemChunkList DI2_SearchItemChunkList; +struct DI2_SearchItemChunkList +{ + DI2_SearchItemChunk *first; + DI2_SearchItemChunk *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct DI2_SearchItemArray DI2_SearchItemArray; +struct DI2_SearchItemArray +{ + DI2_SearchItem *v; + U64 count; +}; + //////////////////////////////// //~ rjf: Shared State @@ -195,6 +255,7 @@ internal void di2_close(DI2_Key key); //////////////////////////////// //~ rjf: Debug Info Lookups +internal DI2_KeyArray di2_push_all_loaded_keys(Arena *arena); internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us); //////////////////////////////// @@ -208,4 +269,11 @@ internal void di2_async_tick(void); internal void di2_signal_completion(void); internal void di2_conversion_completion_signal_receiver_thread_entry_point(void *p); +//////////////////////////////// +//~ rjf: Search Artifact Cache Hooks / Lookups + +internal AC_Artifact di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); +internal void di2_search_artifact_destroy(AC_Artifact artifact); +internal DI2_SearchItemArray di2_search_item_array_from_target_query(RDI_SectionKind target, String8 query); + #endif // DBG_INFO2_H From 4d30933c44f9fb874878c1e9a796bc741b6131ee Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 17:15:03 -0700 Subject: [PATCH 300/302] debug info load gen, to easily key anything based on entire set of loaded debug info --- src/dbg_info/dbg_info2.c | 11 +++++++++++ src/dbg_info/dbg_info2.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 9faede86..641f98b0 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -337,6 +337,13 @@ di2_close(DI2_Key key) //////////////////////////////// //~ rjf: Debug Info Lookups +internal U64 +di2_load_gen(void) +{ + U64 result = ins_atomic_u64_eval(&di2_shared->load_gen); + return result; +} + internal DI2_KeyArray di2_push_all_loaded_keys(Arena *arena) { @@ -804,6 +811,7 @@ di2_async_tick(void) MemoryCopyStruct(&node->rdi, &rdi_parsed); node->completion_count += 1; node->working_count -= 1; + ins_atomic_u64_inc_eval(&di2_shared->load_gen); } else { @@ -1062,6 +1070,9 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ U64 dst_idx = n->base_idx + range.min; MemoryCopy(&items.v[dst_idx], n->v, sizeof(n->v[0]) * dim_1u64(range)); } + + //- rjf: sort items + } scratch_end(scratch); access_close(access); diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 227be869..01a73b43 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -193,6 +193,7 @@ typedef struct DI2_Shared DI2_Shared; struct DI2_Shared { Arena *arena; + U64 load_gen; // rjf: key -> path cache U64 key2path_slots_count; @@ -255,6 +256,7 @@ internal void di2_close(DI2_Key key); //////////////////////////////// //~ rjf: Debug Info Lookups +internal U64 di2_load_gen(void); internal DI2_KeyArray di2_push_all_loaded_keys(Arena *arena); internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us); From d842da0b2ed8a7c8efcdc4603ff6e5aa1b95600e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 29 Sep 2025 17:21:37 -0700 Subject: [PATCH 301/302] checkpoint on wide all-debug-info fuzzy searching cache --- src/dbg_info/dbg_info2.c | 298 ++++++++++++++++++++++----------------- src/dbg_info/dbg_info2.h | 2 +- 2 files changed, 173 insertions(+), 127 deletions(-) diff --git a/src/dbg_info/dbg_info2.c b/src/dbg_info/dbg_info2.c index 641f98b0..720ddce0 100644 --- a/src/dbg_info/dbg_info2.c +++ b/src/dbg_info/dbg_info2.c @@ -863,6 +863,7 @@ di2_conversion_completion_signal_receiver_thread_entry_point(void *p) internal AC_Artifact di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out) { + ProfBeginFunction(); Access *access = access_open(); Temp scratch = scratch_begin(0, 0); AC_Artifact artifact = {0}; @@ -880,147 +881,156 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ //- rjf: gather all debug info keys we'll search on DI2_KeyArray keys = {0}; - if(lane_idx() == 0) + ProfScope("gather all debug info keys we'll search on") { - keys = di2_push_all_loaded_keys(scratch.arena); + if(lane_idx() == 0) + { + keys = di2_push_all_loaded_keys(scratch.arena); + } + lane_sync_u64(&keys.v, 0); + lane_sync_u64(&keys.count, 0); } - lane_sync_u64(&keys.v, 0); - lane_sync_u64(&keys.count, 0); //- rjf: map all debug info keys -> RDIs RDI_Parsed **rdis = 0; - if(lane_idx() == 0) + ProfScope("map all debug info keys -> RDIs") { - rdis = push_array(scratch.arena, RDI_Parsed *, keys.count); - } - lane_sync_u64(&rdis, 0); - { - Rng1U64 range = lane_range(keys.count); - for EachInRange(idx, range) + if(lane_idx() == 0) { - rdis[idx] = di2_rdi_from_key(access, keys.v[idx], 0, 0); + rdis = push_array(scratch.arena, RDI_Parsed *, keys.count); + } + lane_sync_u64(&rdis, 0); + { + Rng1U64 range = lane_range(keys.count); + for EachInRange(idx, range) + { + rdis[idx] = di2_rdi_from_key(access, keys.v[idx], 0, 0); + } } } lane_sync(); //- rjf: do wide search on all lanes - DI2_SearchItemChunkList *lanes_items = 0; - if(lane_idx() == 0) - { - lanes_items = push_array(scratch.arena, DI2_SearchItemChunkList, lane_count()); - } - lane_sync_u64(&lanes_items, 0); Arena *arena = arena_alloc(); - DI2_SearchItemChunkList *lane_items = &lanes_items[lane_idx()]; + DI2_SearchItemChunkList *lanes_items = 0; + ProfScope("do wide search on all lanes") { - for EachIndex(rdi_idx, keys.count) + if(lane_idx() == 0) { - DI2_Key key = keys.v[rdi_idx]; - RDI_Parsed *rdi = rdis[rdi_idx]; - - // rjf: unpack table info - U64 element_count = 0; - void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); - U64 element_size = rdi_section_element_size_table[section_kind]; - - // rjf: determine name string index offset, depending on table kind - U64 element_name_idx_off = 0; - switch(section_kind) + lanes_items = push_array(scratch.arena, DI2_SearchItemChunkList, lane_count()); + } + lane_sync_u64(&lanes_items, 0); + { + DI2_SearchItemChunkList *lane_items = &lanes_items[lane_idx()]; + for EachIndex(rdi_idx, keys.count) { - default:{}break; - case RDI_SectionKind_Procedures: - { - element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); - }break; - case RDI_SectionKind_GlobalVariables: - { - element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); - }break; - case RDI_SectionKind_ThreadVariables: - { - element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); - }break; - case RDI_SectionKind_UDTs: - { - // NOTE(rjf): name must be determined from self_type_idx - }break; - case RDI_SectionKind_SourceFiles: - { - // NOTE(rjf): name must be determined from file path node chain - }break; - } - - Rng1U64 range = lane_range(element_count); - for EachInRange(idx, range) - { - //- rjf: every so often, check if we need to cancel, and cancel - { - // TODO(rjf) - } + DI2_Key key = keys.v[rdi_idx]; + RDI_Parsed *rdi = rdis[rdi_idx]; - //- rjf: get element, map to string; if empty, continue to next element - void *element = (U8 *)table_base + element_size*idx; - String8 name = {0}; + // rjf: unpack table info + U64 element_count = 0; + void *table_base = rdi_section_raw_table_from_kind(rdi, section_kind, &element_count); + U64 element_size = rdi_section_element_size_table[section_kind]; + + // rjf: determine name string index offset, depending on table kind + U64 element_name_idx_off = 0; switch(section_kind) { + default:{}break; + case RDI_SectionKind_Procedures: + { + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + }break; + case RDI_SectionKind_GlobalVariables: + { + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + }break; + case RDI_SectionKind_ThreadVariables: + { + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + }break; case RDI_SectionKind_UDTs: { - RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); - name = str8_copy(arena, name); + // NOTE(rjf): name must be determined from self_type_idx }break; case RDI_SectionKind_SourceFiles: { - Temp scratch = scratch_begin(&arena, 1); - RDI_SourceFile *file = (RDI_SourceFile *)element; - String8List path_parts = {0}; - for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file->file_path_node_idx); - fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); - fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) - { - String8 path_part = {0}; - path_part.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &path_part.size); - str8_list_push_front(scratch.arena, &path_parts, path_part); - } - StringJoin join = {0}; - join.sep = str8_lit("/"); - name = str8_list_join(arena, &path_parts, &join); - scratch_end(scratch); - }break; - default: - { - U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); - name = str8(name_base, name_size); + // NOTE(rjf): name must be determined from file path node chain }break; } - if(name.size == 0) { continue; } - //- rjf: fuzzy match against query - FuzzyMatchRangeList matches = fuzzy_match_find(arena, query, name); - - //- rjf: collect - if(matches.count == matches.needle_part_count) + Rng1U64 range = lane_range(element_count); + for EachInRange(idx, range) { - DI2_SearchItemChunk *chunk = lane_items->last; - if(chunk == 0 || chunk->count >= chunk->cap) + //- rjf: every so often, check if we need to cancel, and cancel { - chunk = push_array(scratch.arena, DI2_SearchItemChunk, 1); - chunk->base_idx = lane_items->total_count; - chunk->cap = 1024; - chunk->count = 0; - chunk->v = push_array_no_zero(scratch.arena, DI2_SearchItem, chunk->cap); - SLLQueuePush(lane_items->first, lane_items->last, chunk); - lane_items->chunk_count += 1; + // TODO(rjf) + } + + //- rjf: get element, map to string; if empty, continue to next element + void *element = (U8 *)table_base + element_size*idx; + String8 name = {0}; + switch(section_kind) + { + case RDI_SectionKind_UDTs: + { + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size); + name = str8_copy(arena, name); + }break; + case RDI_SectionKind_SourceFiles: + { + Temp scratch = scratch_begin(&arena, 1); + RDI_SourceFile *file = (RDI_SourceFile *)element; + String8List path_parts = {0}; + for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, file->file_path_node_idx); + fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0); + fpn = rdi_element_from_name_idx(rdi, FilePathNodes, fpn->parent_path_node)) + { + String8 path_part = {0}; + path_part.str = rdi_string_from_idx(rdi, fpn->name_string_idx, &path_part.size); + str8_list_push_front(scratch.arena, &path_parts, path_part); + } + StringJoin join = {0}; + join.sep = str8_lit("/"); + name = str8_list_join(arena, &path_parts, &join); + scratch_end(scratch); + }break; + default: + { + U32 name_idx = *(U32 *)((U8 *)element + element_name_idx_off); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); + name = str8(name_base, name_size); + }break; + } + if(name.size == 0) { continue; } + + //- rjf: fuzzy match against query + FuzzyMatchRangeList matches = fuzzy_match_find(arena, query, name); + + //- rjf: collect + if(matches.count == matches.needle_part_count) + { + DI2_SearchItemChunk *chunk = lane_items->last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, DI2_SearchItemChunk, 1); + chunk->base_idx = lane_items->total_count; + chunk->cap = 1024; + chunk->count = 0; + chunk->v = push_array_no_zero(scratch.arena, DI2_SearchItem, chunk->cap); + SLLQueuePush(lane_items->first, lane_items->last, chunk); + lane_items->chunk_count += 1; + } + chunk->v[chunk->count].idx = idx; + chunk->v[chunk->count].key = key; + chunk->v[chunk->count].match_ranges = matches; + chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; + chunk->count += 1; + lane_items->total_count += 1; } - chunk->v[chunk->count].idx = idx; - chunk->v[chunk->count].key = key; - chunk->v[chunk->count].match_ranges = matches; - chunk->v[chunk->count].missed_size = (name.size > matches.total_dim) ? (name.size-matches.total_dim) : 0; - chunk->count += 1; - lane_items->total_count += 1; } } } @@ -1029,7 +1039,7 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ //- rjf: join all lane chunk lists DI2_SearchItemChunkList *all_items = &lanes_items[0]; - if(lane_idx() == 0) + if(lane_idx() == 0) ProfScope("join all lane chunk lists") { for(U64 lidx = 1; lidx < lane_count(); lidx += 1) { @@ -1057,36 +1067,72 @@ di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_ //- rjf: flatten into array DI2_SearchItemArray items = {0}; - if(lane_idx() == 0) + ProfScope("flatten into array") { - items.count = all_items->total_count; - items.v = push_array(arena, DI2_SearchItem, items.count); - } - lane_sync_u64(&items.count, 0); - lane_sync_u64(&items.v, 0); - for EachNode(n, DI2_SearchItemChunk, all_items->first) - { - Rng1U64 range = lane_range(n->count); - U64 dst_idx = n->base_idx + range.min; - MemoryCopy(&items.v[dst_idx], n->v, sizeof(n->v[0]) * dim_1u64(range)); + if(lane_idx() == 0) + { + items.count = all_items->total_count; + items.v = push_array(arena, DI2_SearchItem, items.count); + } + lane_sync_u64(&items.count, 0); + lane_sync_u64(&items.v, 0); + for EachNode(n, DI2_SearchItemChunk, all_items->first) + { + Rng1U64 range = lane_range(n->count); + U64 dst_idx = n->base_idx + range.min; + MemoryCopy(&items.v[dst_idx], n->v, sizeof(n->v[0]) * dim_1u64(range)); + } } //- rjf: sort items + ProfScope("sort items") + { + + } + //- rjf: bundle as artifact + artifact.u64[0] = (U64)arena; + artifact.u64[1] = (U64)items.v; + artifact.u64[2] = items.count; } scratch_end(scratch); access_close(access); + ProfEnd(); return artifact; } internal void di2_search_artifact_destroy(AC_Artifact artifact) { - + Arena *arena = (Arena *)artifact.u64[0]; + if(arena != 0) + { + arena_release(arena); + } } internal DI2_SearchItemArray -di2_search_item_array_from_target_query(RDI_SectionKind target, String8 query) +di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us) { - + DI2_SearchItemArray result = {0}; + { + Temp scratch = scratch_begin(0, 0); + + // rjf: form key + String8List key_parts = {0}; + str8_list_push(scratch.arena, &key_parts, str8_struct(&target)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&query.size)); + str8_list_push(scratch.arena, &key_parts, query); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + + // rjf: get artifact + AC_Artifact artifact = ac_artifact_from_key(access, key, di2_search_artifact_create, di2_search_artifact_destroy, endt_us, .gen = di2_load_gen(), .flags = AC_Flag_Wide); + + // rjf: unpack artifact + result.v = (DI2_SearchItem *)artifact.u64[1]; + result.count = artifact.u64[2]; + + scratch_end(scratch); + } + return result; } diff --git a/src/dbg_info/dbg_info2.h b/src/dbg_info/dbg_info2.h index 01a73b43..d1129d3c 100644 --- a/src/dbg_info/dbg_info2.h +++ b/src/dbg_info/dbg_info2.h @@ -276,6 +276,6 @@ internal void di2_conversion_completion_signal_receiver_thread_entry_point(void internal AC_Artifact di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out); internal void di2_search_artifact_destroy(AC_Artifact artifact); -internal DI2_SearchItemArray di2_search_item_array_from_target_query(RDI_SectionKind target, String8 query); +internal DI2_SearchItemArray di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us); #endif // DBG_INFO2_H From 81d747b8d7d27c496fadd23d2b622d094daf1122 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 29 Sep 2025 18:05:11 -0700 Subject: [PATCH 302/302] fix process join --- src/linker/lnk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index be4779d6..aa13ab29 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -402,7 +402,7 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest if (os_handle_match(mt_handle, os_handle_zero())) { lnk_error(LNK_Error_Mt, "unable to start process: %S", mt_path); } else { - os_process_join(mt_handle, max_U64); + os_process_join(mt_handle, max_U64, 0); os_process_detach(mt_handle); }