From 76213ec5cde699fef9f1fa1d6f6d1c990d2231f2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 15 Feb 2026 23:11:51 -0800 Subject: [PATCH] switch to using 32-bit offsets for leaf records over the pointers --- src/base/base_core.c | 6 + src/base/base_core.h | 1 + src/codeview/codeview.h | 2 + src/linker/codeview_ext/codeview.c | 151 +++++-------- src/linker/codeview_ext/codeview.h | 17 +- src/linker/lnk.c | 18 +- src/linker/lnk_debug_info.c | 342 ++++++++++++++++------------- src/linker/lnk_debug_info.h | 65 +++--- src/linker/pdb_ext/pdb_builder.c | 61 +++-- src/linker/pdb_ext/pdb_builder.h | 5 +- 10 files changed, 347 insertions(+), 321 deletions(-) diff --git a/src/base/base_core.c b/src/base/base_core.c index 8988f41e..4dbcffcd 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -288,6 +288,12 @@ memory_is_zero(void *ptr, U64 size) return result; } +internal void UBSAN_NO_ALIGN +memory_write16(void *ptr, U16 v) +{ + MemoryCopy(ptr, &v, sizeof(v)); +} + internal void UBSAN_NO_ALIGN memory_write32(void *ptr, U32 v) { diff --git a/src/base/base_core.h b/src/base/base_core.h index ba7d20cc..2c43fcb7 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -1009,6 +1009,7 @@ internal F32 sign_from_side_F32(Side side); internal B32 memory_is_zero(void *ptr, U64 size); +internal void memory_write16(void *ptr, U16 v); internal void memory_write32(void *ptr, U32 v); internal U8 memory_read8(void *ptr); diff --git a/src/codeview/codeview.h b/src/codeview/codeview.h index 635acfe8..a3f5ee19 100644 --- a/src/codeview/codeview.h +++ b/src/codeview/codeview.h @@ -1161,6 +1161,8 @@ struct CV_SymPub32 //- (SymKind: LPROC32, GPROC32) +#define CV_IsProc32(x) (x == CV_SymKind_LPROC32_ID || x == CV_SymKind_GPROC32_ID || x == CV_SymKind_LPROC32_DPC) + typedef struct CV_SymProc32 CV_SymProc32; struct CV_SymProc32 { diff --git a/src/linker/codeview_ext/codeview.c b/src/linker/codeview_ext/codeview.c index ba22e2e8..c6989dd2 100644 --- a/src/linker/codeview_ext/codeview.c +++ b/src/linker/codeview_ext/codeview.c @@ -170,8 +170,10 @@ cv_deserial_leaf(String8 raw_data, U64 off, U64 align, CV_Leaf *leaf_out) // do we have enough bytes to read header? Assert(raw_data.size >= sizeof(CV_LeafHeader)); + U8 *leaf_ptr = raw_data.str + off; + StaticAssert(sizeof(CV_LeafHeader) == 4, g_leaf_header_size_check); - CV_LeafHeader header = { .v = memory_read32(raw_data.str + off) }; + CV_LeafHeader header = { .v = memory_read32(leaf_ptr) }; // leaf size must have enough bytes for the kind enum Assert(header.size >= sizeof(CV_LeafKind)); @@ -181,7 +183,7 @@ cv_deserial_leaf(String8 raw_data, U64 off, U64 align, CV_Leaf *leaf_out) // fill out leaf leaf_out->kind = header.kind; - leaf_out->data = str8(raw_data.str + sizeof(CV_LeafHeader), header.size - sizeof(CV_LeafKind)); + leaf_out->data = str8(leaf_ptr + sizeof(CV_LeafHeader), header.size - sizeof(CV_LeafKind)); U64 leaf_size = AlignPow2(sizeof(CV_LeafHeader) + leaf_out->data.size, align); Assert(leaf_size <= raw_data.size); @@ -1070,68 +1072,36 @@ cv_dedup_symbol_ptr_array(TP_Context *tp, CV_SymbolPtrArray *symbols) //~ .debug$T helpers internal CV_DebugT -cv_debug_t_from_data_arr(Arena *arena, String8Array data_arr, U64 align) +cv_debug_t_from_data(Arena *arena, String8 data, U64 align) { ProfBegin("Upfront parse"); - U64 max_leaf_count = 0; - for (U64 data_idx = 0; data_idx < data_arr.count; data_idx += 1) { - String8 data = data_arr.v[data_idx]; - for (U64 cursor = 0; cursor < data.size; ) { - CV_Leaf leaf; - cursor += cv_deserial_leaf(data, cursor, align, &leaf); - max_leaf_count += 1; - } + U64 count = 0; + for (U64 cursor = 0; cursor < data.size; count += 1) { + CV_Leaf leaf; + cursor += cv_deserial_leaf(data, cursor, align, &leaf); } ProfEnd(); - U8 **leaf_arr = push_array_no_zero(arena, U8 *, max_leaf_count); - U64 leaf_count = 0; - for (U64 data_idx = 0; data_idx < data_arr.count; data_idx += 1) { - String8 data = data_arr.v[data_idx]; + U32 *offsets = push_array_no_zero(arena, U32, count); + for (U64 cursor = 0, idx = 0; cursor < data.size;) { + offsets[idx++] = cursor; - U64 cursor = 0; - while (cursor < data.size) { - CV_Leaf leaf; - U64 read_size = cv_deserial_leaf(data, cursor, align, &leaf); - - Assert(leaf_count < max_leaf_count); - leaf_arr[leaf_count] = str8_deserial_get_raw_ptr(data, cursor, read_size); - leaf_count += 1; - - // advance cursor - cursor += read_size; - } + CV_Leaf leaf; + cursor += cv_deserial_leaf(data, cursor, align, &leaf); } - CV_DebugT debug_t = {0}; - debug_t.count = leaf_count; - debug_t.v = leaf_arr; - return debug_t; -} - -internal CV_DebugT -cv_debug_t_from_data(Arena *arena, String8 data, U64 align) -{ - String8Array arr = {0}; - arr.count = 1; - arr.v = &data; - return cv_debug_t_from_data_arr(arena, arr, align); + return (CV_DebugT){ .count = count, .data = data, .offsets = offsets }; } internal CV_Leaf cv_debug_t_get_leaf(CV_DebugT debug_t, U64 leaf_idx) { - Assert(leaf_idx < debug_t.count); - - U8 *ptr = debug_t.v[leaf_idx]; - String8 data = str8(ptr, max_U64); - - CV_Leaf leaf; - cv_deserial_leaf(data, 0, 1, &leaf); - - U64 size = cv_header_struct_size_from_leaf_kind(leaf.kind); - Assert(size <= leaf.data.size); - + CV_Leaf leaf = {0}; + if (debug_t.count > 0) { + Assert(leaf_idx < debug_t.count); + cv_deserial_leaf(debug_t.data, debug_t.offsets[leaf_idx], 1, &leaf); + Assert(cv_header_struct_size_from_leaf_kind(leaf.kind) <= leaf.data.size); + } return leaf; } @@ -1139,83 +1109,60 @@ internal String8 cv_debug_t_get_raw_leaf(CV_DebugT debug_t, U64 leaf_idx) { Assert(leaf_idx < debug_t.count); - U8 *leaf_ptr = debug_t.v[leaf_idx]; - CV_LeafSize size = memory_read16(debug_t.v[leaf_idx]); - return str8(leaf_ptr, sizeof(size) + size); + U8 *leaf_ptr = debug_t.data.str + debug_t.offsets[leaf_idx]; + CV_LeafSize leaf_size = memory_read16(leaf_ptr); + return str8(leaf_ptr, leaf_size + sizeof(leaf_size)); } internal CV_LeafHeader * cv_debug_t_get_leaf_header(CV_DebugT debug_t, U64 leaf_idx) { - Assert(leaf_idx < debug_t.count); - CV_LeafHeader *leaf_header = (CV_LeafHeader *) debug_t.v[leaf_idx]; - return leaf_header; + CV_LeafHeader *header = 0; + if (leaf_idx < debug_t.count) { + header = (CV_LeafHeader *)(debug_t.data.str + debug_t.offsets[leaf_idx]); + } + return header; } internal B32 cv_debug_t_is_pch(CV_DebugT debug_t) { - if (debug_t.count > 0) { - CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, 0); - return cv_is_leaf_pch(leaf.kind); - } - return 0; + return cv_is_leaf_pch(cv_debug_t_get_leaf(debug_t, 0).kind); } internal B32 cv_debug_t_is_type_server(CV_DebugT debug_t) { - if (debug_t.count > 0) { - CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, 0); - return cv_is_leaf_type_server(leaf.kind); - } - return 0; + return cv_is_leaf_type_server(cv_debug_t_get_leaf(debug_t, 0).kind); } internal U64 -cv_debug_t_array_count_leaves(U64 count, CV_DebugT *arr) +cv_debug_t_array_count_leaves(U64 count, CV_DebugT *debug_t) { - U64 total_leaf_count = 0; - for (U64 i = 0; i < count; i += 1) { - total_leaf_count += arr[i].count; - } - return total_leaf_count; + U64 total = 0; + for EachIndex(i, count) { total += debug_t[i].count; } + return total; } -internal -THREAD_POOL_TASK_FUNC(cv_str8_list_from_debug_t_task) +internal CV_Leaf +cv_leaf_from_ptr(U8 *ptr) { - CV_Str8ListFromDebugT *task = raw_task; - for (U64 leaf_idx = task->ranges[task_id].min; leaf_idx < task->ranges[task_id].max; ++leaf_idx) { - String8Node *node = &task->nodes[leaf_idx]; - node->string = cv_debug_t_get_raw_leaf(task->debug_t, leaf_idx); - str8_list_push_node(&task->lists[task_id], node); - } + CV_Leaf leaf = {0}; + cv_deserial_leaf(str8(ptr, max_U64), 0, 1, &leaf); + return leaf; } -internal String8List -cv_str8_list_from_debug_t_parallel(TP_Context *tp, Arena *arena, CV_DebugT debug_t) +internal U16 +cv_leaf_size_from_ptr(U8 *ptr) { - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); + CV_LeafSize size = memory_read16(ptr); + return size + sizeof(size); +} - // build lists in parallel - CV_Str8ListFromDebugT task = {0}; - task.debug_t = debug_t; - task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count); - task.lists = push_array(scratch.arena, String8List, tp->worker_count); - task.nodes = push_array_no_zero(arena, String8Node, debug_t.count); - tp_for_parallel(tp, 0, tp->worker_count, cv_str8_list_from_debug_t_task, &task); - - // concat output lists - String8List list = {0}; - for (U64 task_id = 0; task_id < tp->worker_count; ++task_id) { - str8_list_concat_in_place(&list, &task.lists[task_id]); - } - - scratch_end(scratch); - ProfEnd(); - return list; +internal String8 +cv_raw_leaf_from_ptr(U8 *ptr) +{ + return str8(ptr, cv_leaf_size_from_ptr(ptr)); } // $$Symbols diff --git a/src/linker/codeview_ext/codeview.h b/src/linker/codeview_ext/codeview.h index db8ad632..354a0e14 100644 --- a/src/linker/codeview_ext/codeview.h +++ b/src/linker/codeview_ext/codeview.h @@ -255,9 +255,9 @@ typedef struct CV_DebugS typedef struct CV_DebugT { - U64 size; - U64 count; - U8 **v; + U64 count; + String8 data; + U32 *offsets; } CV_DebugT; //////////////////////////////// @@ -358,14 +358,6 @@ typedef struct CV_StringBucket **buckets; } CV_PackStringHashTableTask; -typedef struct -{ - CV_DebugT debug_t; - Rng1U64 *ranges; - String8List *lists; - String8Node *nodes; -} CV_Str8ListFromDebugT; - //////////////////////////////// internal CV_ObjInfo cv_obj_info_from_symbol(CV_Symbol symbol); @@ -421,7 +413,6 @@ internal String8 cv_file_chksms_from_debug_s(CV_DebugS debug_s); //////////////////////////////// //~ .debug$T helpers -internal CV_DebugT cv_debug_t_from_data_arr(Arena *arena, String8Array data_arr, U64 align); internal CV_DebugT cv_debug_t_from_data(Arena *arena, String8 data, U64 align); internal CV_Leaf cv_debug_t_get_leaf(CV_DebugT debug_t, U64 leaf_idx); internal String8 cv_debug_t_get_raw_leaf(CV_DebugT debug_t, U64 leaf_idx); @@ -430,8 +421,6 @@ internal B32 cv_debug_t_is_pch(CV_DebugT debug_t); internal B32 cv_debug_t_is_type_server(CV_DebugT debug_t); internal U64 cv_debug_t_array_count_leaves(U64 count, CV_DebugT *arr); -internal String8List cv_str8_list_from_debug_t_parallel(TP_Context *tp, Arena *arena, CV_DebugT types); - //////////////////////////////// //~ Sub Section helpers diff --git a/src/linker/lnk.c b/src/linker/lnk.c index cac11a07..4de0462c 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -5150,8 +5150,8 @@ 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, config->alt_pch_dirs, debug_info_objs_count, debug_info_objs); - CV_DebugT *types = lnk_import_types(tp, arena, &input); + 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); + LNK_MergedTypes merged_types = lnk_merge_types(tp, arena, &input); // // RDI @@ -5171,7 +5171,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) input.total_symbol_input_count, input.symbol_inputs, input.parsed_symbols, - types); + merged_types.count, + merged_types.v); lnk_write_data_list_to_file_path(config->rad_debug_name, config->temp_rad_debug_name, rdi_data); @@ -5187,7 +5188,13 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) lnk_timer_begin(LNK_Timer_Pdb); if (config->pdb_hash_type_names != LNK_TypeNameHashMode_Null && config->pdb_hash_type_names != LNK_TypeNameHashMode_None) { - lnk_replace_type_names_with_hashes(tp, arena, types[CV_TypeIndexSource_TPI], config->pdb_hash_type_names, config->pdb_hash_type_name_length, config->pdb_hash_type_name_map); + lnk_replace_type_names_with_hashes(tp, + arena, + merged_types.count[CV_TypeIndexSource_TPI], + merged_types.v [CV_TypeIndexSource_TPI], + config->pdb_hash_type_names, + config->pdb_hash_type_name_length, + config->pdb_hash_type_name_map); } String8List pdb_data = lnk_build_pdb(tp, @@ -5201,7 +5208,8 @@ lnk_run(TP_Context *tp, TP_Arena *arena, LNK_Config *config) input.total_symbol_input_count, input.symbol_inputs, input.parsed_symbols, - types); + merged_types.count, + merged_types.v); lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data); lnk_timer_end(LNK_Timer_Pdb); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index fd10a371..bec8e05c 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -113,8 +113,11 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_t_task) U64 obj_idx = task_id; LNK_ParseDebugTTaskData *task = raw_task; String8Array data_arr = task->data_arr_arr[obj_idx]; - CV_DebugT *debug_t = &task->debug_t_arr[obj_idx]; - *debug_t = cv_debug_t_from_data_arr(arena, data_arr, CV_LeafAlign); + if (data_arr.count > 0) { + task->debug_t_arr[obj_idx] = cv_debug_t_from_data(arena, data_arr.v[0], CV_LeafAlign); + } else { + MemoryZeroStruct(&task->debug_t_arr[obj_idx]); + } ProfEnd(); } @@ -253,8 +256,8 @@ lnk_setup_pch(Arena *arena, U64 obj_count, LNK_Obj **obj_arr, CV_DebugT *debug_t pch->debug_p_obj_idx = debug_p_obj_idx; // [start_index, start_index+type_index_count) - debug_t_arr[obj_idx].count -= 1; - debug_t_arr[obj_idx].v += 1; + debug_t_arr[obj_idx].count -= 1; + debug_t_arr[obj_idx].offsets += 1; endprecomp_arr[debug_p_obj_idx] = cv_debug_t_get_leaf_header(debug_p, precomp.leaf_count); } else { @@ -2112,69 +2115,74 @@ THREAD_POOL_TASK_FUNC(lnk_unbucket_raw_leaves_task) { LNK_CvImportTypes *task = raw_task; for EachInRange(i, task->ranges[task_id]) { - task->types[task->ti_source].v[i] = lnk_data_from_leaf_ref(task->input, *task->unique_leaf_refs_arr[task->ti_source].v[i]).str; + LNK_LeafRef *leaf_ref_ptr = task->unique_leaf_refs_arr[task->ti_source].v[i]; + task->merged_types.v[task->ti_source][i] = lnk_data_from_leaf_ref(task->input, *leaf_ref_ptr).str; } } internal -THREAD_POOL_TASK_FUNC(lnk_post_process_cv_symbols_task) +THREAD_POOL_TASK_FUNC(lnk_fixup_symbols_task) { LNK_CvImportTypes *task = raw_task; - CV_DebugT ipi_types = task->types[CV_TypeIndexSource_IPI]; - CV_TypeIndex ipi_min_type_index = task->min_type_indices[CV_TypeIndexSource_IPI]; + U64 leaf_count_ipi = task->merged_types.count[CV_TypeIndexSource_IPI]; + U8 **leaf_arr_ipi = task->merged_types.v [CV_TypeIndexSource_IPI]; + CV_TypeIndex min_ti_ipi = task->min_type_indices [CV_TypeIndexSource_IPI]; for EachNode(symnode, CV_SymbolNode, task->input->symbol_inputs[task_id].symbol_list->first) { CV_Symbol *symbol = &symnode->data; - if (symbol->kind == CV_SymKind_LPROC32_ID || symbol->kind == CV_SymKind_GPROC32_ID || symbol->kind == CV_SymKind_LPROC32_DPC) { - CV_SymProc32 *proc32 = (CV_SymProc32 *) symbol->data.str; - if (proc32->itype >= ipi_min_type_index) { - if ((proc32->itype - ipi_min_type_index) < ipi_types.count) { - U64 leaf_idx = proc32->itype - ipi_min_type_index; - CV_Leaf leaf = cv_debug_t_get_leaf(ipi_types, leaf_idx); - - if (leaf.kind == CV_LeafKind_FUNC_ID) { - if (leaf.data.size >= sizeof(CV_LeafFuncId)) { - proc32->itype = ((CV_LeafFuncId *) leaf.data.str)->itype; - } else { - Assert(!"TODO: error handle corrupt leaf"); - } - } else if (leaf.kind == CV_LeafKind_MFUNC_ID) { - if (leaf.data.size >= sizeof(CV_LeafMFuncId)) { - proc32->itype = ((CV_LeafMFuncId *) leaf.data.str)->itype; - } else { - Assert(!"TODO: error handle corrupt leaf"); - } - } else { - Assert(!"TODO: erorr handle unexpected leaf type"); - } - } else { - Assert("TODO: error handle corrupted type index"); - } - } else { - // TODO: in some cases destructors don't have a type, need a repro - } - } - // convert symbol to final type switch (symbol->kind) { - case CV_SymKind_LPROC32_ID: symbol->kind = CV_SymKind_LPROC32; break; - case CV_SymKind_GPROC32_ID: symbol->kind = CV_SymKind_GPROC32; break; - case CV_SymKind_LPROC32_DPC_ID: symbol->kind = CV_SymKind_LPROC32_DPC; break; - case CV_SymKind_LPROCMIPS_ID: symbol->kind = CV_SymKind_LPROCMIPS; break; - case CV_SymKind_GPROCMIPS_ID: symbol->kind = CV_SymKind_GPROCMIPS; break; - case CV_SymKind_LPROCIA64_ID: symbol->kind = CV_SymKind_LPROCIA64; break; - case CV_SymKind_GPROCIA64_ID: symbol->kind = CV_SymKind_GPROCIA64; break; - case CV_SymKind_PROC_ID_END: symbol->kind = CV_SymKind_END; break; + case CV_SymKind_LPROC32_ID: symbol->kind = CV_SymKind_LPROC32; goto fixup_id; + case CV_SymKind_GPROC32_ID: symbol->kind = CV_SymKind_GPROC32; goto fixup_id; + case CV_SymKind_LPROC32_DPC_ID: symbol->kind = CV_SymKind_LPROC32_DPC; goto fixup_id; + case CV_SymKind_LPROCMIPS_ID: symbol->kind = CV_SymKind_LPROCMIPS; goto fixup_id; + case CV_SymKind_GPROCMIPS_ID: symbol->kind = CV_SymKind_GPROCMIPS; goto fixup_id; + case CV_SymKind_LPROCIA64_ID: symbol->kind = CV_SymKind_LPROCIA64; goto fixup_id; + case CV_SymKind_GPROCIA64_ID: symbol->kind = CV_SymKind_GPROCIA64; goto fixup_id; + fixup_id:; { + CV_SymProc32 *proc32 = (CV_SymProc32 *) symbol->data.str; + if (proc32->itype < min_ti_ipi) { + // TODO: in some cases destructors don't have a type, need a repro + break; + } + + if ((proc32->itype - min_ti_ipi) > leaf_count_ipi) { + Assert("TODO: error handle corrupted type index"); + break; + } + + U64 leaf_idx = proc32->itype - min_ti_ipi; + String8 leaf_data = str8(leaf_arr_ipi[leaf_idx], max_U64); + + CV_Leaf leaf; + cv_deserial_leaf(leaf_data, 0, 1, &leaf); + + U64 min_leaf_size = cv_header_struct_size_from_leaf_kind(leaf.kind); + if (min_leaf_size > leaf.data.size) { + Assert(!"TODO: error handle corrupt leaf"); + break; + } + + if (leaf.kind == CV_LeafKind_FUNC_ID) { + proc32->itype = ((CV_LeafFuncId *) leaf.data.str)->itype; + } else if (leaf.kind == CV_LeafKind_MFUNC_ID) { + proc32->itype = ((CV_LeafMFuncId *) leaf.data.str)->itype; + } else { + Assert(!"TODO: erorr handle unexpected leaf type"); + break; + } + } break; + case CV_SymKind_PROC_ID_END: symbol->kind = CV_SymKind_END; break; } } } -internal CV_DebugT * -lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) +internal LNK_MergedTypes +lnk_merge_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) { - ProfBegin("Import Types"); + ProfBeginFunction(); Temp scratch = temp_begin(lnk_get_huge_arena()); U64 max_ti_list_size = sizeof(CV_TypeIndexInfo) * (max_U16 / sizeof(CV_TypeIndex)); @@ -2216,8 +2224,8 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) for EachIndex(ts_idx, input->type_server_count) { task.hashes->external_hashes[ts_idx] = push_array_no_zero(scratch.arena, U64 *, CV_TypeIndexSource_COUNT); for EachIndex(ti_source, CV_TypeIndexSource_COUNT) { - U64 leaf_count = dim_1u64(input->external_ti_ranges[ts_idx][ti_source]); - task.hashes->external_hashes[ts_idx][ti_source] = push_array(scratch.arena, U64, leaf_count); // :zero_hash_check + U64 type_count = dim_1u64(input->external_ti_ranges[ts_idx][ti_source]); + task.hashes->external_hashes[ts_idx][ti_source] = push_array(scratch.arena, U64, type_count); // :zero_hash_check } } ProfEnd(); @@ -2246,12 +2254,12 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) Temp temp = temp_begin(scratch.arena); ProfBegin("Compute Per Task Ranges"); - U64 per_task_leaf_count = 10000; + U64 per_task_type_count = 10000; LNK_LeafRangeList *leaf_ranges_per_task = push_array(temp.arena, LNK_LeafRangeList, tp->worker_count); for (U64 i = 0, task_weight = 0, task_id = 0; i < input->internal_count; i += 1) { CV_DebugT *debug_t = &input->merged_debug_t_p_arr[i]; - for (U64 k = 0; k < debug_t->count; k += per_task_leaf_count) { - U64 cap = per_task_leaf_count - task_weight; + for (U64 k = 0; k < debug_t->count; k += per_task_type_count) { + U64 cap = per_task_type_count - task_weight; LNK_LeafRange *leaf_range = push_array(temp.arena, LNK_LeafRange, 1); leaf_range->range = rng_1u64(k, Min(k + cap, debug_t->count)); @@ -2262,7 +2270,7 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) list->count += 1; task_weight += dim_1u64(leaf_range->range); - if (task_weight >= per_task_leaf_count) { + if (task_weight >= per_task_type_count) { task_id = (task_id + 1) % tp->worker_count; task_weight = 0; } @@ -2371,21 +2379,20 @@ lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) } ProfEnd(); - task.types = push_array(tp_temp->v[0], CV_DebugT, CV_TypeIndexSource_COUNT); for EachIndex(ti_source, CV_TypeIndexSource_COUNT) { LNK_LeafRefArray unique_leaf_refs = task.unique_leaf_refs_arr[ti_source]; - task.ti_source = ti_source; - task.types[ti_source].count = unique_leaf_refs.count; - task.types[ti_source].v = push_array(tp_temp->v[0], U8 *, unique_leaf_refs.count); - task.ranges = tp_divide_work(scratch.arena, unique_leaf_refs.count, tp->worker_count); + task.ti_source = ti_source; + task.merged_types.count[ti_source] = unique_leaf_refs.count; + task.merged_types.v [ti_source] = push_array(tp_temp->v[0], U8 *, unique_leaf_refs.count); + task.ranges = tp_divide_work(scratch.arena, unique_leaf_refs.count, tp->worker_count); tp_for_parallel(tp, 0, tp->worker_count, lnk_unbucket_raw_leaves_task, &task); } - tp_for_parallel_prof(tp, 0, input->total_symbol_input_count, lnk_post_process_cv_symbols_task, &task, "Post Process CV Symbols"); + tp_for_parallel_prof(tp, 0, input->total_symbol_input_count, lnk_fixup_symbols_task, &task, "fixup type indices in symbols"); temp_end(scratch); ProfEnd(); - return task.types; + return task.merged_types; } internal @@ -2395,7 +2402,8 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) LNK_TypeNameReplacer *task = raw_task; Rng1U64 range = task->ranges[task_id]; - CV_DebugT debug_t = task->debug_t; + U64 leaf_count = task->leaf_count; + U8 **leaf_arr = task->leaf_arr; U64 hash_length = task->hash_length; B32 make_map = task->make_map; @@ -2409,8 +2417,8 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) U64 hash_max_chars = hash_length*2; char temp[128]; - for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) { - CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx); + for EachInRange(leaf_idx, range) { + CV_Leaf leaf = cv_leaf_from_ptr(leaf_arr[leaf_idx]); if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); @@ -2446,24 +2454,28 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_lenient_task) udt_info.unique_name.size = size; // update leaf header - CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx); - header->size = sizeof(CV_LeafKind) + - sizeof(CV_LeafStruct) + - numeric_size + - udt_info.name.size + 1 + - udt_info.unique_name.size + 1; + U64 new_size = sizeof(CV_LeafKind) + + sizeof(CV_LeafStruct) + + numeric_size + + udt_info.name.size + 1 + + udt_info.unique_name.size + 1; + CV_LeafHeader *header = (CV_LeafHeader *)leaf_arr[leaf_idx]; + Assert(new_size <= max_U16); + memory_write16(MemberFromPtr(CV_LeafHeader, header, size), (U16)new_size); } else { // replace uniuqe type name with hash udt_info.unique_name.str = udt_info.name.str + udt_info.name.size + 1; udt_info.unique_name.size = raddbg_snprintf(udt_info.unique_name.cstr, udt_info.unique_name.size, "%llx", name_hash); // update leaf header - CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx); - header->size = sizeof(CV_LeafKind) + - sizeof(CV_LeafStruct) + - numeric_size + - udt_info.name.size + 1 + - udt_info.unique_name.size + 1; + U64 new_size = sizeof(CV_LeafKind) + + sizeof(CV_LeafStruct) + + numeric_size + + udt_info.name.size + 1 + + udt_info.unique_name.size + 1; + CV_LeafHeader *header = (CV_LeafHeader *)leaf_arr[leaf_idx]; + Assert(new_size <= max_U16); + memory_write16(MemberFromPtr(CV_LeafHeader, header, size), (U16)new_size); } } } @@ -2479,7 +2491,8 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task) LNK_TypeNameReplacer *task = raw_task; Rng1U64 range = task->ranges[task_id]; - CV_DebugT debug_t = task->debug_t; + U64 leaf_count = task->leaf_count; + U8 **leaf_arr = task->leaf_arr; U64 hash_length = task->hash_length; B32 make_map = task->make_map; @@ -2492,8 +2505,8 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task) U64 hash_max_chars = hash_length*2; - for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) { - CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx); + for EachInRange(leaf_idx, range) { + CV_Leaf leaf = cv_leaf_from_ptr(leaf_arr[leaf_idx]); if (leaf.kind == CV_LeafKind_STRUCTURE || leaf.kind == CV_LeafKind_CLASS) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); @@ -2508,7 +2521,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task) // hash name U64 name_hash; - blake3_hasher hasher; blake3_hasher_init(&hasher); + blake3_hasher hasher = {0}; blake3_hasher_init(&hasher); blake3_hasher_update(&hasher, udt_info.name.str, udt_info.name.size); blake3_hasher_finalize(&hasher, (U8*)&name_hash, sizeof(name_hash)); @@ -2525,8 +2538,10 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task) U64 numeric_size = cv_read_numeric(leaf.data, sizeof(CV_LeafStruct), &dummy); // update header - CV_LeafHeader *header = cv_debug_t_get_leaf_header(debug_t, leaf_idx); - header->size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1; + U64 new_size = sizeof(CV_LeafKind) + sizeof(CV_LeafStruct) + numeric_size + udt_info.name.size + 1; + CV_LeafHeader *header = (CV_LeafHeader *)leaf_arr[leaf_idx]; + Assert(new_size <= max_U16); + memory_write16(MemberFromPtr(CV_LeafHeader, header, size), (U16)new_size); // discard unique name CV_LeafStruct *lf = (CV_LeafStruct *)(header + 1); @@ -2539,15 +2554,16 @@ THREAD_POOL_TASK_FUNC(lnk_replace_type_names_with_hashes_full_task) } internal void -lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name) +lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name) { ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); // init task context LNK_TypeNameReplacer task = {0}; - task.debug_t = debug_t; - task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count); + task.leaf_count = leaf_count; + task.leaf_arr = leaf_arr; + task.ranges = tp_divide_work(scratch.arena, leaf_count, tp->worker_count); task.hash_length = Clamp(1, hash_length, 16); if (map_name.size > 0) { @@ -3026,7 +3042,8 @@ lnk_build_pdb(TP_Context *tp, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, CV_SymbolListArray *parsed_symbols, - CV_DebugT types[CV_TypeIndexSource_COUNT]) + U64 leaf_count[CV_TypeIndexSource_COUNT], + U8 **leaf_arr [CV_TypeIndexSource_COUNT]) { ProfBegin("PDB"); Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); @@ -3044,8 +3061,8 @@ lnk_build_pdb(TP_Context *tp, // // leaf data is stored in g_file_arena which has linker's life-time // and this way we skip redundant leaf copy to the type server to make things faster - pdb_type_server_push_parallel(tp, pdb->type_servers[CV_TypeIndexSource_IPI], types[CV_TypeIndexSource_IPI]); - pdb_type_server_push_parallel(tp, pdb->type_servers[CV_TypeIndexSource_TPI], types[CV_TypeIndexSource_TPI]); + pdb_type_server_push_parallel(tp, pdb->type_servers[CV_TypeIndexSource_IPI], leaf_count[CV_TypeIndexSource_IPI], leaf_arr[CV_TypeIndexSource_IPI]); + pdb_type_server_push_parallel(tp, pdb->type_servers[CV_TypeIndexSource_TPI], leaf_count[CV_TypeIndexSource_TPI], leaf_arr[CV_TypeIndexSource_TPI]); ProfBegin("Collect Symbols for GSI"); CV_SymbolList *gsi_list_arr = push_array(scratch.arena, CV_SymbolList, obj_count); @@ -3279,84 +3296,92 @@ THREAD_POOL_TASK_FUNC(lnk_build_udt_name_hash_table_task) LNK_BuildUDTNameHashTableTask *task = raw_task; LNK_UDTNameBucket *new_bucket = 0; + for EachInRange(leaf_idx, task->ranges[task_id]) { + String8 leaf_data = str8(task->leaf_arr[leaf_idx], max_U64); - for (U64 leaf_idx = task->ranges[task_id].min; leaf_idx < task->ranges[task_id].max; ++leaf_idx) { - CV_Leaf leaf = cv_debug_t_get_leaf(task->debug_t, leaf_idx); - if (cv_is_udt(leaf.kind)) { - CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); - if (~udt_info.props & CV_TypeProp_FwdRef) { - if (!cv_is_udt_name_anon(udt_info.name)) { - String8 name = cv_name_from_udt_info(udt_info); - U64 hash = lnk_udt_name_hash_table_hash(name); - U64 best_idx = hash % task->buckets_cap; - U64 bucket_idx = best_idx; + CV_Leaf leaf; + cv_deserial_leaf(leaf_data, 0, 1, &leaf); - if (new_bucket == 0) { - new_bucket = push_array(arena, LNK_UDTNameBucket, 1); - } - new_bucket->name = name; - new_bucket->leaf_idx = leaf_idx; - - B32 is_inserted_or_updated = 0; - do { - retry:; - LNK_UDTNameBucket *curr_bucket = task->buckets[bucket_idx]; + // is this UDT? + if ( ! cv_is_udt(leaf.kind)) { continue; } - if (curr_bucket == 0) { - LNK_UDTNameBucket *compare_bucket = ins_atomic_ptr_eval_cond_assign(&task->buckets[bucket_idx], new_bucket, curr_bucket); + // skip forward references + CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); + if (udt_info.props & CV_TypeProp_FwdRef) { continue; } - if (compare_bucket == curr_bucket) { - // success, bucket was inserted - is_inserted_or_updated = 1; - break; - } + // skip anon UDT + if (cv_is_udt_name_anon(udt_info.name)) { continue; } - // another thread took the bucket... - goto retry; - } else if (str8_match(curr_bucket->name, name, 0)) { - // there is more than one UDT with identical name, pick most recent and ignore others - - if (leaf_idx < curr_bucket->leaf_idx) { - LNK_UDTNameBucket *compare_bucket = ins_atomic_ptr_eval_cond_assign(&task->buckets[bucket_idx], new_bucket, curr_bucket); - if (compare_bucket == curr_bucket) { - is_inserted_or_updated = 1; - break; - } - } else { - // don't need to update, more recent leaf is in the bucket - break; - } + // UDT name -> bucket index + String8 name = cv_name_from_udt_info(udt_info); + U64 hash = lnk_udt_name_hash_table_hash(name); + U64 best_idx = hash % task->buckets_cap; + U64 bucket_idx = best_idx; - // another thread took the bucket... - goto retry; - } + // push and fill bucket + if (new_bucket == 0) { new_bucket = push_array(arena, LNK_UDTNameBucket, 1); } + new_bucket->name = name; + new_bucket->leaf_idx = leaf_idx; - // advance - bucket_idx = (bucket_idx + 1) % task->buckets_cap; - } while (bucket_idx != best_idx); + B32 is_inserted_or_updated = 0; + do { + retry:; + LNK_UDTNameBucket *curr_bucket = task->buckets[bucket_idx]; - if (is_inserted_or_updated) { - new_bucket = 0; - } + if (curr_bucket == 0) { + LNK_UDTNameBucket *compare_bucket = ins_atomic_ptr_eval_cond_assign(&task->buckets[bucket_idx], new_bucket, curr_bucket); + + if (compare_bucket == curr_bucket) { + // success, bucket was inserted + is_inserted_or_updated = 1; + break; } + + // another thread took the bucket... + goto retry; + } else if (str8_match(curr_bucket->name, name, 0)) { + // there is more than one UDT with identical name, pick most recent and ignore others + + if (leaf_idx < curr_bucket->leaf_idx) { + LNK_UDTNameBucket *compare_bucket = ins_atomic_ptr_eval_cond_assign(&task->buckets[bucket_idx], new_bucket, curr_bucket); + if (compare_bucket == curr_bucket) { + is_inserted_or_updated = 1; + break; + } + } else { + // don't need to update, more recent leaf is in the bucket + break; + } + + // another thread took the bucket... + goto retry; } + + // advance + bucket_idx = (bucket_idx + 1) % task->buckets_cap; + } while (bucket_idx != best_idx); + + if (is_inserted_or_updated) { + new_bucket = 0; } } } internal LNK_UDTNameBucket ** -lnk_udt_name_hash_table_from_debug_t(TP_Context *tp, +lnk_udt_name_hash_table_from_leaf_arr(TP_Context *tp, TP_Arena *arena, - CV_DebugT debug_t, + U64 leaf_count, + U8 **leaf_arr, U64 *buckets_cap_out) { Temp scratch = scratch_begin(&arena->v[0], 1); LNK_BuildUDTNameHashTableTask task = {0}; - task.debug_t = debug_t; - task.buckets_cap = (U64)((F64)debug_t.count * 1.3); + task.leaf_count = leaf_count; + task.leaf_arr = leaf_arr; + task.buckets_cap = (leaf_count * 13) / 10; task.buckets = push_array(arena->v[0], LNK_UDTNameBucket *, task.buckets_cap); - task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count); + task.ranges = tp_divide_work(scratch.arena, leaf_count, tp->worker_count); tp_for_parallel(tp, arena, tp->worker_count, lnk_build_udt_name_hash_table_task, &task); *buckets_cap_out = task.buckets_cap; scratch_end(scratch); @@ -3543,8 +3568,8 @@ lnk_rdib_type_from_itype(LNK_ConvertTypesToRDI *task, CV_TypeIndex itype) // try to resovle forward reference (defn might be missing) if (itype >= tpi_range.min) { - U64 leaf_idx = itype - tpi_range.min; - CV_Leaf leaf = cv_debug_t_get_leaf(task->types[CV_TypeIndexSource_TPI], leaf_idx); + CV_Leaf leaf; + cv_deserial_leaf(str8(task->leaf_arr[CV_TypeIndexSource_TPI][itype - tpi_range.min], max_U64), 0, 1, &leaf); if (cv_is_udt(leaf.kind)) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); if (udt_info.props & CV_TypeProp_FwdRef) { @@ -3590,7 +3615,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) for(U64 leaf_idx = task->ranges[task_id].min; leaf_idx < task->ranges[task_id].max; ++leaf_idx) { U64 itype = task->itype_ranges[CV_TypeIndexSource_TPI].min + leaf_idx; - CV_Leaf src = cv_debug_t_get_leaf(task->types[CV_TypeIndexSource_TPI], leaf_idx); + CV_Leaf src = cv_leaf_from_ptr(task->leaf_arr[CV_TypeIndexSource_TPI][leaf_idx]); switch (src.kind) { case CV_LeafKind_MODIFIER: { @@ -3613,7 +3638,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) CV_TypeIndex next_itype; for (next_itype = ptr->itype; task->itype_ranges[CV_TypeIndexSource_TPI].min <= next_itype && next_itype < task->itype_ranges[CV_TypeIndexSource_TPI].max;) { U64 next_leaf_idx = next_itype - task->itype_ranges[CV_TypeIndexSource_TPI].min; - CV_Leaf next_leaf = cv_debug_t_get_leaf(task->types[CV_TypeIndexSource_TPI], next_leaf_idx); + CV_Leaf next_leaf = cv_leaf_from_ptr(task->leaf_arr[CV_TypeIndexSource_TPI][next_leaf_idx]); if (next_leaf.kind != CV_LeafKind_MODIFIER) { break; } @@ -3909,7 +3934,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_types_to_rdi_task) if (contains_1u64(task->itype_ranges[CV_TypeIndexSource_TPI], method->list_itype)) { U64 method_list_leaf_idx = method->list_itype - task->itype_ranges[CV_TypeIndexSource_TPI].min; - CV_Leaf method_list_leaf = cv_debug_t_get_leaf(task->types[CV_TypeIndexSource_TPI], method_list_leaf_idx); + CV_Leaf method_list_leaf = cv_leaf_from_ptr(task->leaf_arr[CV_TypeIndexSource_TPI][method_list_leaf_idx]); if (method_list_leaf.kind == CV_LeafKind_METHODLIST) { for (U64 cursor = 0; cursor + sizeof(CV_LeafMethodListMember) <= method_list_leaf.data.size; ) { // parse CodeView method overload info @@ -5075,7 +5100,7 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) RDIB_Type *owner = 0; if (task->ipi_itype_range.min <= sym_inline_site->inlinee && sym_inline_site->inlinee < task->ipi_itype_range.max) { U64 leaf_idx = sym_inline_site->inlinee - task->tpi_itype_range.min; - CV_Leaf leaf = cv_debug_t_get_leaf(task->ipi, leaf_idx); + CV_Leaf leaf = cv_leaf_from_ptr(task->leaf_arr_ipi[leaf_idx]); if (leaf.kind == CV_LeafKind_MFUNC_ID) { if (sizeof(CV_LeafMFuncId) <= leaf.data.size) { CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId *) leaf.data.str; @@ -5260,7 +5285,8 @@ lnk_build_rad_debug_info(TP_Context *tp, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, CV_SymbolListArray *parsed_symbols, - CV_DebugT types[CV_TypeIndexSource_COUNT]) + U64 leaf_count[CV_TypeIndexSource_COUNT], + U8 **leaf_arr [CV_TypeIndexSource_COUNT]) { ProfBegin("RDI"); Temp scratch = scratch_begin(tp_arena->v,tp_arena->count); @@ -5314,7 +5340,7 @@ lnk_build_rad_debug_info(TP_Context *tp, // assing low and high type indices per source Rng1U64 itype_ranges[CV_TypeIndexSource_COUNT]; for (U64 i = 0; i < ArrayCount(itype_ranges); ++i) { - itype_ranges[i] = rng_1u64(CV_MinComplexTypeIndex, CV_MinComplexTypeIndex + types[i].count); + itype_ranges[i] = rng_1u64(CV_MinComplexTypeIndex, CV_MinComplexTypeIndex + leaf_count[i]); } ProfBegin("Convert Types"); @@ -5337,13 +5363,14 @@ lnk_build_rad_debug_info(TP_Context *tp, ProfBegin("Build UDT Name Hash Table"); // TODO: fix memory life-time udt_name_buckets_cap = 0; - udt_name_buckets = lnk_udt_name_hash_table_from_debug_t(tp, tp_arena, types[CV_TypeIndexSource_TPI], &udt_name_buckets_cap); + udt_name_buckets = lnk_udt_name_hash_table_from_leaf_arr(tp, tp_arena, leaf_count[CV_TypeIndexSource_TPI], leaf_arr[CV_TypeIndexSource_TPI], &udt_name_buckets_cap); ProfEnd(); ProfBegin("Convert CodeView types to RDIB Types"); LNK_ConvertTypesToRDI task = {0}; - task.types = types; + MemoryCopyTyped(&task.leaf_count[0], &leaf_count[0], CV_TypeIndexSource_COUNT); + MemoryCopyTyped(&task.leaf_arr[0], &leaf_arr[0], CV_TypeIndexSource_COUNT); task.type_cap = input.type_cap; task.udt_cap = input.udt_cap; task.variadic_type_ref = rdib_make_type_ref(scratch.arena, input.variadic_type); @@ -5360,7 +5387,7 @@ lnk_build_rad_debug_info(TP_Context *tp, task.rdib_types_params_lists = push_array(scratch.arena, RDIB_TypeChunkList, tp->worker_count); task.rdib_udt_members_lists = push_array(scratch.arena, RDIB_UDTMemberChunkList, tp->worker_count); task.rdib_enum_members_lists = push_array(scratch.arena, RDIB_UDTMemberChunkList, tp->worker_count); - task.ranges = tp_divide_work(scratch.arena, types[CV_TypeIndexSource_TPI].count, tp->worker_count); + task.ranges = tp_divide_work(scratch.arena, leaf_count[CV_TypeIndexSource_TPI], tp->worker_count); tp_for_parallel(tp, tp_arena, tp->worker_count, lnk_convert_types_to_rdi_task, &task); ProfEnd(); @@ -5443,7 +5470,8 @@ lnk_build_rad_debug_info(TP_Context *tp, task.image_sects = image_sects; task.obj_arr = obj_arr; task.debug_s_arr = debug_s_arr; - task.ipi = types[CV_TypeIndexSource_IPI]; + task.leaf_arr_count_ipi = leaf_count[CV_TypeIndexSource_IPI]; + task.leaf_arr_ipi = leaf_arr[CV_TypeIndexSource_IPI]; task.symbol_inputs = symbol_inputs; task.parsed_symbols = parsed_symbols; task.ipi_itype_range = itype_ranges[CV_TypeIndexSource_IPI]; diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index 61f34cfa..a70435bb 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -60,6 +60,12 @@ typedef struct LNK_CodeViewInput Rng1U64 external_obj_range; } LNK_CodeViewInput; +typedef struct LNK_MergedTypes +{ + U64 count[CV_TypeIndexSource_COUNT]; + U8 **v [CV_TypeIndexSource_COUNT]; +} LNK_MergedTypes; + // --- Leaf Ref ---------------------------------------------------------------- typedef enum @@ -202,7 +208,7 @@ typedef struct CV_SymbolList *symbol_list_arr; CV_DebugS *debug_s_arr; - CV_DebugT *types; + LNK_MergedTypes merged_types; } LNK_CvImportTypes; // --- Code View Processing Trasks --------------------------------------------- @@ -314,7 +320,8 @@ typedef struct typedef struct { - CV_DebugT debug_t; + U64 leaf_count; + U8 **leaf_arr; Rng1U64 *ranges; U64 hash_length; B32 make_map; @@ -332,7 +339,8 @@ typedef struct typedef struct { - CV_DebugT debug_t; + U64 leaf_count; + U8 **leaf_arr; Rng1U64 *ranges; U64 buckets_cap; LNK_UDTNameBucket **buckets; @@ -352,7 +360,8 @@ typedef struct typedef struct { - CV_DebugT *types; + U64 leaf_count[CV_TypeIndexSource_COUNT]; + U8 **leaf_arr[CV_TypeIndexSource_COUNT]; U64 type_cap; U64 udt_cap; RDIB_TypeRef variadic_type_ref; @@ -399,7 +408,8 @@ typedef struct COFF_SectionHeaderArray image_sects; LNK_Obj **obj_arr; CV_DebugS *debug_s_arr; - CV_DebugT ipi; + U64 leaf_arr_count_ipi; + U8 **leaf_arr_ipi; LNK_CodeViewSymbolsInput *symbol_inputs; CV_SymbolListArray *parsed_symbols; Rng1U64 ipi_itype_range; @@ -466,34 +476,36 @@ internal U64 lnk_hash_from_leaf_ref(LNK_LeafHashes *hashes, LNK_LeafRef leaf_re internal LNK_LeafRef * lnk_leaf_hash_table_insert_or_update(LNK_LeafHashTable *leaf_ht, LNK_CodeViewInput *input, LNK_LeafHashes *hashes, U64 hash, LNK_LeafRef *new_bucket); internal LNK_LeafRef * lnk_leaf_hash_table_search(LNK_LeafHashTable *ht, LNK_CodeViewInput *input, LNK_LeafHashes *hashes, LNK_LeafRef leaf_ref); -internal CV_DebugT * lnk_import_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input); -internal void lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name); +internal LNK_MergedTypes lnk_merge_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input); +internal void lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name); // --- RAD Debug info ---------------------------------------------------------- -internal U64 lnk_udt_name_hash_table_hash (String8 string); -internal LNK_UDTNameBucket ** lnk_udt_name_hash_table_from_debug_t(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, U64 *buckets_cap_out); -internal LNK_UDTNameBucket * lnk_udt_name_hash_table_lookup (LNK_UDTNameBucket **buckets, U64 cap, String8 name); -internal CV_TypeIndex * lnk_build_udt_fwdmap (TP_Context *tp, Arena *arena, CV_DebugT debug_t, CV_TypeIndex ti_lo, LNK_UDTNameBucket **udt_name_buckets, U64 udt_name_buckets_cap); +internal U64 lnk_udt_name_hash_table_hash (String8 string); +internal LNK_UDTNameBucket ** lnk_udt_name_hash_table_from_leaf_arr(TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, U64 *buckets_cap_out); +internal LNK_UDTNameBucket * lnk_udt_name_hash_table_lookup (LNK_UDTNameBucket **buckets, U64 cap, String8 name); +internal CV_TypeIndex * lnk_build_udt_fwdmap (TP_Context *tp, Arena *arena, CV_DebugT debug_t, CV_TypeIndex ti_lo, LNK_UDTNameBucket **udt_name_buckets, U64 udt_name_buckets_cap); internal RDIB_TypeRef lnk_rdib_type_from_itype (LNK_ConvertTypesToRDI *task, CV_TypeIndex itype); internal RDI_MemberKind lnk_rdib_method_kind_from_cv_prop (CV_MethodProp prop); internal LNK_SourceFileBucket * lnk_src_file_hash_table_hash (String8 file_path, CV_C13ChecksumKind checksum_kind, String8 checksum_bytes); internal LNK_SourceFileBucket * lnk_src_file_hash_table_lookup_slot(LNK_SourceFileBucket **src_file_buckets, U64 src_file_buckets_cap, U64 hash, String8 file_path, CV_C13ChecksumKind checksum_kind, String8 checksum_bytes); -internal String8List lnk_build_rad_debug_info(TP_Context *tp, - TP_Arena *tp_arena, - OperatingSystem os, - RDI_Arch arch, - String8 image_name, - String8 image_data, - U64 obj_count, - LNK_Obj **obj_arr, - CV_DebugS *debug_s_arr, - U64 total_symbol_input_count, - LNK_CodeViewSymbolsInput *symbol_inputs, - CV_SymbolListArray *parsed_symbols, - CV_DebugT types[CV_TypeIndexSource_COUNT]); +internal String8List +lnk_build_rad_debug_info(TP_Context *tp, + TP_Arena *tp_arena, + OperatingSystem os, + RDI_Arch arch, + String8 image_name, + String8 image_data, + U64 obj_count, + LNK_Obj **obj_arr, + CV_DebugS *debug_s_arr, + U64 total_symbol_input_count, + LNK_CodeViewSymbolsInput *symbol_inputs, + CV_SymbolListArray *parsed_symbols, + U64 leaf_count[CV_TypeIndexSource_COUNT], + U8 **leaf_arr [CV_TypeIndexSource_COUNT]); // --- PDB --------------------------------------------------------------------- @@ -515,12 +527,13 @@ internal String8List lnk_build_pdb(TP_Context *tp, U64 total_symbol_input_count, LNK_CodeViewSymbolsInput *symbol_inputs, CV_SymbolListArray *parsed_symbols, - CV_DebugT types[CV_TypeIndexSource_COUNT]); + U64 leaf_count[CV_TypeIndexSource_COUNT], + U8 **leaf_arr [CV_TypeIndexSource_COUNT]); // --- RAD Debug Info ---------------------------------------------------------- internal U64 lnk_udt_name_hash_table_hash (String8 string); -internal LNK_UDTNameBucket ** lnk_udt_name_hash_table_from_debug_t(TP_Context *tp, TP_Arena *arena, CV_DebugT debug_t, U64 *buckets_cap_out); +internal LNK_UDTNameBucket ** lnk_udt_name_hash_table_from_leaf_arr(TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, U64 *buckets_cap_out); internal LNK_UDTNameBucket * lnk_udt_name_hash_table_lookup (LNK_UDTNameBucket **buckets, U64 cap, String8 name); internal CV_TypeIndex * lnk_build_udt_fwdmap(TP_Context *tp, diff --git a/src/linker/pdb_ext/pdb_builder.c b/src/linker/pdb_ext/pdb_builder.c index b20901e6..76b0c0bc 100644 --- a/src/linker/pdb_ext/pdb_builder.c +++ b/src/linker/pdb_ext/pdb_builder.c @@ -1445,13 +1445,14 @@ internal THREAD_POOL_TASK_FUNC(pdb_count_udt_task) { PDB_PushLeafTask *task = raw_task; - Rng1U64 range = task->ranges[task_id]; - for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) { - CV_Leaf leaf = cv_debug_t_get_leaf(task->debug_t, leaf_idx); + for EachInRange(leaf_idx, task->ranges[task_id]) { + CV_Leaf leaf; + cv_deserial_leaf(str8(task->leaf_arr[leaf_idx], max_U64), 0, 1, &leaf); + if (cv_is_udt(leaf.kind)) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); if (~udt_info.props & CV_TypeProp_FwdRef) { - ++task->udt_counts[task_id]; + task->udt_counts[task_id] += 1; } } } @@ -1462,27 +1463,27 @@ THREAD_POOL_TASK_FUNC(pdb_push_udt_leaf_task) { PDB_PushLeafTask *task = raw_task; PDB_TypeServer *type_server = task->type_server; - Rng1U64 range = task->ranges[task_id]; U64 bucket_cursor = task->udt_offsets[task_id]; - CV_DebugT debug_t = task->debug_t; PDB_TypeBucket *new_buckets = task->udt_buckets; U64 type_ht_cap = type_server->bucket_cap; PDB_TypeBucket **type_ht_buckets = type_server->buckets; U64 base_type_index = type_server->ti_lo + type_server->leaf_list.node_count; - for (U64 leaf_idx = range.min; leaf_idx < range.max; ++leaf_idx) { - CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx); + for EachInRange(leaf_idx, task->ranges[task_id]) { + CV_Leaf leaf; + cv_deserial_leaf(str8(task->leaf_arr[leaf_idx], max_U64), 0, 1, &leaf); + if (cv_is_udt(leaf.kind)) { CV_UDTInfo udt_info = cv_get_udt_info(leaf.kind, leaf.data); if (~udt_info.props & CV_TypeProp_FwdRef) { // hash udt and compute bucket index - U32 hash = pdb_hash_udt(udt_info, leaf.data); + U32 hash = pdb_hash_udt(udt_info, leaf.data); U32 bucket_idx = hash % type_ht_cap; // fill out & insert bucket PDB_TypeBucket *bucket = &new_buckets[bucket_cursor++]; - bucket->raw_leaf = cv_debug_t_get_raw_leaf(debug_t, leaf_idx); + bucket->raw_leaf = leaf.data; bucket->type_index = base_type_index + leaf_idx; bucket->next = ins_atomic_ptr_eval_assign(&type_ht_buckets[bucket_idx], bucket); } @@ -1490,16 +1491,36 @@ THREAD_POOL_TASK_FUNC(pdb_push_udt_leaf_task) } } +typedef struct +{ + Rng1U64 *ranges; + U8 **leaf_arr; + String8List *lists; + String8Node *nodes; +} PDB_String8ListFromLeafArray; + +internal +THREAD_POOL_TASK_FUNC(pdb_str8_list_from_leaf_array_task) +{ + PDB_String8ListFromLeafArray *task = raw_task; + for EachInRange(leaf_idx, task->ranges[task_id]) { + String8Node *node = &task->nodes[leaf_idx]; + node->string = cv_raw_leaf_from_ptr(task->leaf_arr[leaf_idx]); + str8_list_push_node(&task->lists[task_id], node); + } +} + internal void -pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *type_server, CV_DebugT debug_t) +pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *type_server, U64 leaf_count, U8 **leaf_arr) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); PDB_PushLeafTask task = {0}; - task.debug_t = debug_t; + task.leaf_count = leaf_count; + task.leaf_arr = leaf_arr; task.type_server = type_server; - task.ranges = tp_divide_work(scratch.arena, debug_t.count, tp->worker_count); + task.ranges = tp_divide_work(scratch.arena, leaf_count, tp->worker_count); ProfBegin("Count UDT"); task.udt_counts = push_array(scratch.arena, U64, tp->worker_count); @@ -1514,8 +1535,18 @@ pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *type_server, CV_De ProfEnd(); ProfBegin("Append New Leaves"); - String8List new_leaves = cv_str8_list_from_debug_t_parallel(tp, type_server->arena, debug_t); - str8_list_concat_in_place(&type_server->leaf_list, &new_leaves); + { + PDB_String8ListFromLeafArray task = {0}; + task.leaf_arr = leaf_arr; + task.ranges = tp_divide_work(scratch.arena, leaf_count, tp->worker_count); + task.lists = push_array(scratch.arena, String8List, tp->worker_count); + task.nodes = push_array_no_zero(type_server->arena, String8Node, leaf_count); + tp_for_parallel(tp, 0, tp->worker_count, pdb_str8_list_from_leaf_array_task, &task); + + // concat output lists + String8List list = {0}; + for EachIndex(task_id, tp->worker_count) { str8_list_concat_in_place(&type_server->leaf_list, &task.lists[task_id]); } + } ProfEnd(); scratch_end(scratch); diff --git a/src/linker/pdb_ext/pdb_builder.h b/src/linker/pdb_ext/pdb_builder.h index f682e31e..529e75ab 100644 --- a/src/linker/pdb_ext/pdb_builder.h +++ b/src/linker/pdb_ext/pdb_builder.h @@ -119,7 +119,8 @@ typedef struct PDB_TypeServerParse typedef struct { - CV_DebugT debug_t; + U64 leaf_count; + U8 **leaf_arr; U64 *udt_counts; U64 *udt_offsets; Rng1U64 *ranges; @@ -474,7 +475,7 @@ internal PDB_TypeServer * pdb_type_server_open(MSF_Context *msf, MSF_Stre internal void pdb_type_server_build(TP_Context *tp, PDB_TypeServer *ts, PDB_StringTable *strtab, MSF_Context *msf, MSF_StreamNumber sn); internal void pdb_type_server_release(PDB_TypeServer **serv_ptr); internal void pdb_type_server_push(PDB_TypeServer *ts, String8 raw_leaf); -internal void pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *ts, CV_DebugT types); +internal void pdb_type_server_push_parallel(TP_Context *tp, PDB_TypeServer *ts, U64 leaf_count, U8 **leaf_arr); //internal CV_LeafNode * pdb_type_server_leaf_from_string(PDB_TypeServer *ts, String8 string); internal String8Node * pdb_type_server_reserve(PDB_TypeServer *ts, U64 count); internal String8Node * pdb_type_server_make_leaf(PDB_TypeServer *ts, CV_LeafKind kind, String8 data);