diff --git a/project.4coder b/project.4coder index a3fc4681..a83c192c 100644 --- a/project.4coder +++ b/project.4coder @@ -48,7 +48,7 @@ commands = //- rjf: [raddbg] // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg 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", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .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/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index a558e5f8..6a17d6f2 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -314,7 +314,7 @@ di_open(DI_Key key) internal void di_close(DI_Key key, B32 force_closed) -{ +{ //- rjf: unpack key U64 hash = u64_hash_from_str8(str8_struct(&key)); U64 slot_idx = hash%di_shared->slots_count; @@ -340,15 +340,15 @@ di_close(DI_Key key, B32 force_closed) } } if(node) - { - if(force_closed) - { - node->refcount = 0; - } - else - { - node->refcount -= 1; - } + { + if(force_closed) + { + node->refcount = 0; + } + else + { + node->refcount -= 1; + } if(node->refcount == 0) { for(;;) @@ -374,9 +374,9 @@ di_close(DI_Key key, B32 force_closed) //- rjf: release node's resources if needed if(node_released) - { - ins_atomic_u64_dec_eval(&di_shared->load_count); - ins_atomic_u64_inc_eval(&di_shared->load_gen); + { + ins_atomic_u64_dec_eval(&di_shared->load_count); + ins_atomic_u64_inc_eval(&di_shared->load_gen); os_file_map_view_close(file_map, file_base, r1u64(0, file_props.size)); os_file_map_close(file_map); os_file_close(file); @@ -384,7 +384,7 @@ di_close(DI_Key key, B32 force_closed) { arena_release(arena); } - } + } } //////////////////////////////// @@ -396,13 +396,13 @@ di_load_gen(void) U64 result = ins_atomic_u64_eval(&di_shared->load_gen); return result; } - -internal U64 -di_load_count(void) -{ + +internal U64 +di_load_count(void) +{ U64 result = ins_atomic_u64_eval(&di_shared->load_count); - return result; -} + return result; +} internal DI_KeyArray di_push_all_loaded_keys(Arena *arena) @@ -598,14 +598,14 @@ di_async_tick(void) //////////////////////////// //- rjf: generate load tasks for all unique requests - // - for EachElement(priority_idx, first_req) - { + // + for EachElement(priority_idx, first_req) + { for EachNode(n, DI_RequestNode, first_req[priority_idx]) { // rjf: unpack request DI_Key key = n->v.key; - + // rjf: determine if this request is a duplicate B32 request_is_duplicate = 1; { @@ -625,7 +625,7 @@ di_async_tick(void) } } } - + // rjf: if not a duplicate, create new task if(!request_is_duplicate) { @@ -642,25 +642,25 @@ di_async_tick(void) DLLPushBack(di_shared->first_load_task[priority_idx], di_shared->last_load_task[priority_idx], t); t->key = key; } - } - } + } + } //////////////////////////// //- rjf: update tasks: configure, launch if we can, & retire if we can - // - for EachElement(priority_idx, di_shared->first_load_task) - { + // + for EachElement(priority_idx, di_shared->first_load_task) + { for(DI_LoadTask *t = di_shared->first_load_task[priority_idx], *next = 0; t != 0; t = next) { next = t->next; - + //- rjf: unpack key DI_Key key = t->key; U64 key_hash = u64_hash_from_str8(str8_struct(&key)); U64 key_slot_idx = key_hash%di_shared->key2path_slots_count; DI_KeySlot *key_slot = &di_shared->key2path_slots[key_slot_idx]; Stripe *key_stripe = stripe_from_slot_idx(&di_shared->key2path_stripes, key_slot_idx); - + //- rjf: get key's O.G. path String8 og_path = {0}; U64 og_min_timestamp = 0; @@ -676,13 +676,13 @@ di_async_tick(void) } } } - - //- rjf: analyze O.G. debug info + + //- 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); + 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 && @@ -692,12 +692,12 @@ di_async_tick(void) } os_file_close(file); } - U64 og_size = t->og_size; + U64 og_size = t->og_size; B32 og_is_rdi = t->og_is_rdi; - B32 og_is_good = (og_size > 0); - + B32 og_is_good = (og_size > 0); + //- rjf: compute key's RDI path - String8 rdi_path = {0}; + String8 rdi_path = {0}; { if(og_is_rdi) { @@ -708,7 +708,7 @@ di_async_tick(void) rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); } } - + //- rjf: determine if RDI is stale if(!t->rdi_analyzed) { @@ -731,16 +731,16 @@ di_async_tick(void) 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/2; - if(priority_idx > 0) - { - max_thread_count = Max(1, max_thread_count/2); - } + U64 max_thread_count = os_get_system_info()->logical_processor_count/2; + if(priority_idx > 0) + { + max_thread_count = Max(1, max_thread_count/2); + } { if(0){} else if(og_size <= MB(4)) {thread_count = 1;} @@ -752,7 +752,7 @@ di_async_tick(void) thread_count = Max(1, thread_count); t->thread_count = thread_count; } - + //- rjf: determine if there are threads available B32 threads_available = 0; { @@ -761,30 +761,30 @@ di_async_tick(void) U64 needed_threads = (current_threads + t->thread_count); threads_available = (max_threads >= needed_threads); } - - //- rjf: if this conversion will overwrite an RDI we already have in cache, - // then we need to evict the old one from the cache. - B32 ready_to_launch_conversion = (threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active); - if(ready_to_launch_conversion) - { + + //- rjf: if this conversion will overwrite an RDI we already have in cache, + // then we need to evict the old one from the cache. + B32 ready_to_launch_conversion = (threads_available && !og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI_LoadTaskStatus_Active); + if(ready_to_launch_conversion) + { U64 path2key_hash = u64_hash_from_str8(og_path); U64 path2key_slot_idx = path2key_hash%di_shared->path2key_slots_count; DI_KeySlot *path2key_slot = &di_shared->path2key_slots[path2key_slot_idx]; - Stripe *path2key_stripe = stripe_from_slot_idx(&di_shared->path2key_stripes, path2key_slot_idx); - RWMutexScope(path2key_stripe->rw_mutex, 0) - { - // NOTE(rjf): we need to iterate from last -> first, since we want to evict the - // most recent key. - for(DI_KeyPathNode *n = path2key_slot->last; n != 0; n = n->prev) - { - if(str8_match(n->path, og_path, 0) && !di_key_match(key, n->key)) - { - di_close(n->key, 1); - } - } - } - } - + Stripe *path2key_stripe = stripe_from_slot_idx(&di_shared->path2key_stripes, path2key_slot_idx); + RWMutexScope(path2key_stripe->rw_mutex, 0) + { + // NOTE(rjf): we need to iterate from last -> first, since we want to evict the + // most recent key. + for(DI_KeyPathNode *n = path2key_slot->last; n != 0; n = n->prev) + { + if(str8_match(n->path, og_path, 0) && !di_key_match(key, n->key)) + { + di_close(n->key, 1); + } + } + } + } + //- rjf: launch conversion processes if(og_is_good && ready_to_launch_conversion) { @@ -812,7 +812,7 @@ di_async_tick(void) t->status = DI_LoadTaskStatus_Active; di_shared->conversion_process_count += 1; di_shared->conversion_thread_count += t->thread_count; - + // rjf: send event MutexScope(di_shared->event_mutex) { @@ -823,7 +823,7 @@ di_async_tick(void) n->v.string = str8_copy(di_shared->event_arena, rdi_path); } } - + //- rjf: if active & process has completed, mark as done { U64 exit_code = 0; @@ -849,21 +849,21 @@ di_async_tick(void) di_shared->conversion_thread_count -= t->thread_count; } } - } - - //- rjf: ready to launch, but bad O.G. file -> just immediately mark as done - if(!og_is_good && ready_to_launch_conversion) - { - t->status = DI_LoadTaskStatus_Done; - } - + } + + //- rjf: ready to launch, but bad O.G. file -> just immediately mark as done + if(!og_is_good && ready_to_launch_conversion) + { + t->status = DI_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 = DI_LoadTaskStatus_Done; } - + //- rjf: if the RDI for this task *is* stale, but the O.G. path is actually RDI, // then we can't actually re-convert to produce a non-stale RDI. in this case, just // mark as done. @@ -871,7 +871,7 @@ di_async_tick(void) { t->status = DI_LoadTaskStatus_Done; } - + //- rjf: if task is done, retire & recycle task; gather path to load if(t->status == DI_LoadTaskStatus_Done) { @@ -891,8 +891,8 @@ di_async_tick(void) SLLQueuePush(first_parse_task, last_parse_task, n); parse_tasks_count += 1; } - } - } + } + } //////////////////////////// //- rjf: join all parse tasks @@ -997,12 +997,12 @@ di_async_tick(void) node->arena = rdi_parsed_arena; MemoryCopyStruct(&node->rdi, &rdi_parsed); node->completion_count += 1; - node->working_count -= 1; - if(node->rdi.raw_data_size != 0) - { - ins_atomic_u64_inc_eval(&di_shared->load_gen); - } - ins_atomic_u64_inc_eval(&di_shared->load_count); + node->working_count -= 1; + if(node->rdi.raw_data_size != 0) + { + ins_atomic_u64_inc_eval(&di_shared->load_gen); + } + ins_atomic_u64_inc_eval(&di_shared->load_count); } else { @@ -1122,16 +1122,16 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * } lane_sync(); - //- rjf: do wide search on all lanes - Arena *arena = arena_alloc(); - Arena **arenas = 0; - U64 arenas_count = lane_count(); - if(lane_idx() == 0) - { - arenas = push_array(arena, Arena *, arenas_count); - } - lane_sync_u64(&arenas, 0); - arenas[lane_idx()] = arena; + //- rjf: do wide search on all lanes + Arena *arena = arena_alloc(); + Arena **arenas = 0; + U64 arenas_count = lane_count(); + if(lane_idx() == 0) + { + arenas = push_array(arena, Arena *, arenas_count); + } + lane_sync_u64(&arenas, 0); + arenas[lane_idx()] = arena; DI_SearchItemChunkList *lanes_items = 0; ProfScope("do wide search on all lanes") { @@ -1176,10 +1176,10 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * Rng1U64 range = lane_range(element_count); for EachInRange(idx, range) { - //- rjf: every so often, check if we need to cancel, and cancel - if(idx%10000 == 0 && !!ins_atomic_u32_eval(cancel_signal)) + //- rjf: every so often, check if we need to cancel, and cancel + if(idx%10000 == 0 && !!ins_atomic_u32_eval(cancel_signal)) { - break; + break; } //- rjf: get element, map to string; if empty, continue to next element @@ -1279,15 +1279,15 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * } } lane_sync(); - - //- rjf: decide if we cancelled - B32 cancelled = 0; - if(lane_idx() == 0 && !!ins_atomic_u32_eval(cancel_signal)) - { - cancelled = 1; - } - lane_sync_u64(&cancelled, 0); - + + //- rjf: decide if we cancelled + B32 cancelled = 0; + if(lane_idx() == 0 && !!ins_atomic_u32_eval(cancel_signal)) + { + cancelled = 1; + } + lane_sync_u64(&cancelled, 0); + //- rjf: produce sort records typedef struct SortRecord SortRecord; struct SortRecord @@ -1444,20 +1444,20 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * } lane_sync(); - //- rjf: bundle as artifact - if(!cancelled) - { - artifact.u64[0] = (U64)arenas; - artifact.u64[1] = arenas_count; + //- rjf: bundle as artifact + if(!cancelled) + { + artifact.u64[0] = (U64)arenas; + artifact.u64[1] = arenas_count; artifact.u64[2] = (U64)items.v; - artifact.u64[3] = items.count; - } - - //- rjf: release results on cancel - else - { - arena_release(arena); - } + artifact.u64[3] = items.count; + } + + //- rjf: release results on cancel + else + { + arena_release(arena); + } } scratch_end(scratch); access_close(access); @@ -1467,20 +1467,20 @@ di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 * internal void di_search_artifact_destroy(AC_Artifact artifact) -{ - Temp scratch = scratch_begin(0, 0); - Arena **arenas = (Arena **)artifact.u64[0]; - U64 arenas_count = artifact.u64[1]; - Arena **arenas_copy = push_array(scratch.arena, Arena *, arenas_count); - MemoryCopy(arenas_copy, arenas, sizeof(Arena *) * arenas_count); - for EachIndex(idx, arenas_count) - { - if(arenas_copy[idx]) - { - arena_release(arenas_copy[idx]); - } - } - scratch_end(scratch); +{ + Temp scratch = scratch_begin(0, 0); + Arena **arenas = (Arena **)artifact.u64[0]; + U64 arenas_count = artifact.u64[1]; + Arena **arenas_copy = push_array(scratch.arena, Arena *, arenas_count); + MemoryCopy(arenas_copy, arenas, sizeof(Arena *) * arenas_count); + for EachIndex(idx, arenas_count) + { + if(arenas_copy[idx]) + { + arena_release(arenas_copy[idx]); + } + } + scratch_end(scratch); } internal DI_SearchItemArray @@ -1520,32 +1520,103 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g //- rjf: unpack key U64 index = 0; - String8 name = {0}; - DI_Key preferred_key = {0}; + String8 name = {0}; + DI_Key preferred_key = {0}; { U64 key_read_off = 0; - key_read_off += str8_deserial_read_struct(key, key_read_off, &index); - key_read_off += str8_deserial_read_struct(key, key_read_off, &preferred_key); - key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); + key_read_off += str8_deserial_read_struct(key, key_read_off, &index); + key_read_off += str8_deserial_read_struct(key, key_read_off, &preferred_key); + key_read_off += str8_deserial_read_struct(key, key_read_off, &name.size); name.str = push_array_no_zero(scratch.arena, U8, name.size); key_read_off += str8_deserial_read(key, key_read_off, name.str, name.size, 1); } + //- rjf: find split point between container part of name & "leaf" + U64 container_part_opl = 0; + U64 leaf_part_first = 0; + for(U64 off = 0; off+1 < name.size; off += 1) + { + if(name.str[off] == '.') + { + container_part_opl = off; + leaf_part_first = off+1; + } + else if(name.str[off] == ':' && name.str[off+1] == ':') + { + container_part_opl = off; + leaf_part_first = off+2; + } + } + + //- rjf: unpack container/leaf + String8 container_part_of_name = str8_prefix(name, container_part_opl); + String8 leaf_part_of_name = str8_skip(name, leaf_part_first); + + //- rjf: produce the fully qualified name, sanitize the container part (convert all `.`s to `::`s) + String8 fully_qualified_name = name; + if(container_part_of_name.size != 0) + { + // rjf: gather parts of container + String8List parts = {0}; + for(U64 off = 0, next_off = 0; off < container_part_of_name.size; off = next_off) + { + // rjf: find the next separator + U64 next_separator_pos = container_part_of_name.size; + U64 next_separator_size = 0; + { + S64 template_nest_depth = 0; + for(U64 off2 = off; off2+1 < container_part_of_name.size; off2 += 1) + { + if(template_nest_depth == 0 && container_part_of_name.str[off2] == '.') + { + next_separator_pos = off2; + next_separator_size = 1; + break; + } + else if(template_nest_depth == 0 && container_part_of_name.str[off2] == ':' && container_part_of_name.str[off2+1] == ':') + { + next_separator_pos = off2; + next_separator_size = 2; + break; + } + else if(container_part_of_name.str[off2] == '<') + { + template_nest_depth += 1; + } + else if(container_part_of_name.str[off2] == '>') + { + template_nest_depth -= 1; + template_nest_depth = ClampBot(0, template_nest_depth); + } + } + } + + // rjf: gather portions of container + str8_list_push(scratch.arena, &parts, str8_substr(container_part_of_name, r1u64(off, next_separator_pos))); + next_off = next_separator_pos + next_separator_size; + } + + // rjf: add leaf & join + str8_list_push(scratch.arena, &parts, leaf_part_of_name); + StringJoin join = {.sep = str8_lit("::")}; + fully_qualified_name = str8_list_join(scratch.arena, &parts, &join); + } + //- rjf: get all loaded keys DI_KeyArray dbgi_keys = di_push_all_loaded_keys(scratch.arena); - - //- rjf: take cancellation signal - B32 cancelled = 0; - if(lane_idx() == 0) - { - cancelled = ins_atomic_u32_eval(cancel_signal); - } - lane_sync_u64(&cancelled, 0); - + + //- rjf: take cancellation signal + B32 cancelled = 0; + if(lane_idx() == 0) + { + cancelled = ins_atomic_u32_eval(cancel_signal); + } + lane_sync_u64(&cancelled, 0); + //- rjf: wide search across all debug infos - DI_Match *lane_matches = 0; - if(!cancelled) - { + DI_Match *lane_matches = 0; + if(!cancelled) + { if(lane_idx() == 0) { lane_matches = push_array(scratch.arena, DI_Match, lane_count()); @@ -1577,44 +1648,94 @@ di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); for EachElement(name_map_kind_idx, name_map_kinds) { + // rjf: unpack name map RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kinds[name_map_kind_idx]); RDI_ParsedNameMap parsed_name_map = {0}; rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *map_node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); - U32 num = 0; - U32 *run = rdi_matches_from_map_node(rdi, map_node, &num); - if(num != 0) - { - U64 run_idx = (num-1) - Min(index, num-1); + + // rjf: find matches for (possibly leaf) name + RDI_NameMapNode *map_node = rdi_name_map_lookup(rdi, &parsed_name_map, leaf_part_of_name.str, leaf_part_of_name.size); + U32 matches_count = 0; + U32 *matches = rdi_matches_from_map_node(rdi, map_node, &matches_count); + + // rjf: do we have a container? -> filter matches according to container string also + if(container_part_of_name.size != 0) + { + U32 *filtered_matches = push_array(scratch.arena, U32, matches_count); + U32 filtered_matches_count = 0; + for EachIndex(match_idx, matches_count) + { + Temp scratch = scratch_begin(0, 0); + String8 match_fully_qualified_name = {0}; + switch(name_map_section_kinds[name_map_kind_idx]) + { + default:{}break; + case RDI_SectionKind_GlobalVariables: + case RDI_SectionKind_ThreadVariables: + case RDI_SectionKind_Constants: + case RDI_SectionKind_Procedures: + { + RDI_Symbol *symbol = (RDI_Symbol *)rdi_section_raw_element_from_kind_idx(rdi, name_map_section_kinds[name_map_kind_idx], matches[match_idx]); + String8 match_fully_qualified_name = fully_qualified_str8_from_rdi_symbol(scratch.arena, rdi, symbol); + if(str8_match(match_fully_qualified_name, fully_qualified_name, 0)) + { + filtered_matches[filtered_matches_count] = matches[match_idx]; + filtered_matches_count += 1; + } + }break; + case RDI_SectionKind_TypeNodes: + { + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, match_idx); + if(RDI_TypeKind_FirstUserDefined <= type_node->kind && type_node->kind <= RDI_TypeKind_LastUserDefined) + { + String8 match_fully_qualified_name = fully_qualified_str8_from_rdi_type(scratch.arena, rdi, type_node); + if(str8_match(match_fully_qualified_name, fully_qualified_name, 0)) + { + filtered_matches[filtered_matches_count] = matches[match_idx]; + filtered_matches_count += 1; + } + } + }break; + } + scratch_end(scratch); + } + matches = filtered_matches; + matches_count = filtered_matches_count; + } + + // rjf: given matches, pick selected & return as result + if(matches_count != 0) + { + U64 selected_match_idx = (matches_count-1) - Min(index, matches_count-1); lane_matches[lane_idx()].key = dbgi_key; lane_matches[lane_idx()].section_kind = name_map_section_kinds[name_map_kind_idx]; - lane_matches[lane_idx()].idx = run[run_idx]; + lane_matches[lane_idx()].idx = matches[selected_match_idx]; } } } access_close(access); } - } - } - lane_sync(); - + } + } + lane_sync(); + //- rjf: pick match - DI_Match match = {0}; - if(lane_matches != 0) - { + DI_Match match = {0}; + if(lane_matches != 0) + { for EachIndex(idx, lane_count()) { if(lane_matches[idx].idx != 0) { - match = lane_matches[idx]; - if(di_key_match(di_key_zero(), preferred_key) || di_key_match(match.key, preferred_key)) - { - break; - } + match = lane_matches[idx]; + if(di_key_match(di_key_zero(), preferred_key) || di_key_match(match.key, preferred_key)) + { + break; + } } } - } - + } + //- rjf: package as artifact AC_Artifact artifact = {0}; { @@ -1640,12 +1761,12 @@ di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 e { String8List key_parts = {0}; str8_list_push(scratch.arena, &key_parts, str8_struct(&index)); - str8_list_push(scratch.arena, &key_parts, str8_struct(&preferred_dbgi_key)); - str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&preferred_dbgi_key)); + str8_list_push(scratch.arena, &key_parts, str8_struct(&string.size)); str8_list_push(scratch.arena, &key_parts, string); - String8 key = str8_list_join(scratch.arena, &key_parts, 0); - U64 dbgi_count = di_load_count(); - B32 wide = (dbgi_count > 256); + String8 key = str8_list_join(scratch.arena, &key_parts, 0); + U64 dbgi_count = di_load_count(); + B32 wide = (dbgi_count > 256); AC_Artifact artifact = ac_artifact_from_key(access, key, di_match_artifact_create, 0, endt_us, .flags = wide ? AC_Flag_Wide : 0, .gen = di_load_gen(), .evict_threshold_us = wide ? 20000000 : 10000000); result.key.u64[0] = artifact.u64[0]; result.key.u64[1] = artifact.u64[1]; diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index d7563cb3..b8f671b7 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1887,6 +1887,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I // rjf: find match DI_Match match = di_match_from_string(string, match_disambiguating_idx, e_base_ctx->primary_dbg_info->dbgi_key, 0); + +#if 0 + //~ TODO(rjf): vvvvv this used to be used for namespaceifying partially-qualified strings. + // now, the debugger just stores partially-qualified strings, so we instead need to do the + // reverse: given a fully-qualified name, try to parse out the leaf, and look up the partial + // qualified name. if(match.idx == 0) { String8List namespaceified_strings = {0}; @@ -1923,6 +1929,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I } } } +#endif // rjf: match -> RDI RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0); diff --git a/src/rdi/rdi_local.c b/src/rdi/rdi_local.c index 3e09527d..948c1c75 100644 --- a/src/rdi/rdi_local.c +++ b/src/rdi/rdi_local.c @@ -48,6 +48,59 @@ str8_from_rdi_path_node_idx(Arena *arena, RDI_Parsed *rdi, PathStyle path_style, return path; } +internal String8 +fully_qualified_from_rdi_string_and_container(Arena *arena, RDI_Parsed *rdi, U32 name_string_idx, U32 start_container_idx, RDI_ContainerFlags start_container_flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List parts = {0}; + { + str8_list_push(scratch.arena, &parts, str8_from_rdi_string_idx(rdi, name_string_idx)); + RDI_ContainerFlags container_flags = start_container_flags; + RDI_ContainerFlags next_container_flags = 0; + for(U32 container_idx = start_container_idx, next_container_idx = 0; + container_idx != 0; + container_idx = next_container_idx, container_flags = next_container_flags) + { + next_container_idx = 0; + next_container_flags = 0; + switch(container_flags & RDI_ContainerFlag_KindMask) + { + default:{}break; + case RDI_ContainerKind_Type: + { + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, container_idx); + RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + String8 type_name = str8_from_rdi_string_idx(rdi, type->user_defined.name_string_idx); + str8_list_push_front(scratch.arena, &parts, type_name); + next_container_idx = udt->container_idx; + next_container_flags = udt->container_flags; + }break; + case RDI_ContainerKind_Scope: + { + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, container_idx); + RDI_Symbol *symbol = rdi_procedure_from_scope(rdi, scope); + String8 name = str8_from_rdi_string_idx(rdi, symbol->name_string_idx); + str8_list_push_front(scratch.arena, &parts, name); + next_container_idx = symbol->container_idx; + next_container_flags = symbol->container_flags; + }break; + case RDI_ContainerKind_Namespace: + { + RDI_Namespace *ns = rdi_element_from_name_idx(rdi, Namespaces, container_idx); + String8 name = str8_from_rdi_string_idx(rdi, ns->name_string_idx); + str8_list_push_front(scratch.arena, &parts, name); + next_container_idx = ns->container_idx; + next_container_flags = ns->container_flags; + }break; + } + } + } + StringJoin join = {.sep = str8_lit("::")}; + String8 result = str8_list_join(arena, &parts, &join); + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: String <=> Enum @@ -795,7 +848,8 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse } else if(RDI_TypeKind_FirstUserDefined <= type->kind && type->kind <= RDI_TypeKind_LastUserDefined) { - dumpf(" name: '%S'\n", str8_from_rdi_string_idx(rdi, type->user_defined.name_string_idx)); + String8 fully_qualified_name = fully_qualified_str8_from_rdi_type(scratch.arena, rdi, type); + dumpf(" name: '%S'\n", fully_qualified_name); dumpf(" user_defined__direct_type: %u\n", type->user_defined.direct_type_idx); dumpf(" user_defined__udt: %u\n", type->user_defined.udt_idx); } @@ -825,7 +879,8 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse { RDI_UDT *udt = &v[idx]; Temp scratch = scratch_begin(&arena, 1); - dumpf("\n // udt[%I64u]\n {\n", idx); + String8 fully_qualified_name = fully_qualified_str8_from_rdi_udt(scratch.arena, rdi, udt); + dumpf("\n // udt[%I64u]\n '%S':\n {\n", idx, fully_qualified_name); dumpf(" self_type: %u\n", udt->self_type_idx); dumpf(" flags: `%S`\n", rdi_string_from_udt_flags(scratch.arena, udt->flags)); if(udt->container_idx != 0 && (udt->container_flags & RDI_ContainerFlag_KindMask) == RDI_ContainerKind_Type) @@ -929,7 +984,8 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse { RDI_Symbol *symbol = &v[idx]; Temp scratch = scratch_begin(&arena, 1); - dumpf("\n '%S': // %S[%I64u]\n {\n", str8_from_rdi_string_idx(rdi, symbol->name_string_idx), table_name, idx); + String8 fully_qualified_name = fully_qualified_str8_from_rdi_symbol(scratch.arena, rdi, symbol); + dumpf("\n '%S': // %S[%I64u]\n {\n", fully_qualified_name, table_name, idx); dumpf(" type_idx: %u\n", symbol->type_idx); if(symbol->link_name_string_idx != 0) { @@ -1258,6 +1314,7 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse Rng1U64 range = lane_range(count); for EachInRange(idx, range) { + Temp scratch = scratch_begin(&arena, 1); RDI_Namespace *ns = &v[idx]; String8 container_kind_name = str8_lit("container_idx"); switch(ns->container_flags & RDI_ContainerFlag_KindMask) @@ -1276,7 +1333,9 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse container_kind_name = str8_lit("container_scope_idx"); }break; } - dumpf("\n '%S': {%S: %u} // namespaces[%I64u]", str8_from_rdi_string_idx(rdi, ns->name_string_idx), container_kind_name, ns->container_idx, idx); + String8 fully_qualified_name = fully_qualified_str8_from_rdi_namespace(scratch.arena, rdi, ns); + dumpf("\n '%S': {%S: %u} // namespaces[%I64u]", fully_qualified_name, container_kind_name, ns->container_idx, idx); + scratch_end(scratch); } if(lane_idx() == lane_count()-1) { dumpf("\n"); } } diff --git a/src/rdi/rdi_local.h b/src/rdi/rdi_local.h index c3aec22c..adc5f180 100644 --- a/src/rdi/rdi_local.h +++ b/src/rdi/rdi_local.h @@ -75,7 +75,12 @@ internal Arch arch_from_rdi_arch(RDI_Arch arch); //~ rjf: Lookup Helpers internal String8 str8_from_rdi_string_idx(RDI_Parsed *rdi, U32 idx); -internal String8 str8_from_rdi_path_node_idx(Arena *arean, RDI_Parsed *rdi, PathStyle path_style, U32 path_node_idx); +internal String8 str8_from_rdi_path_node_idx(Arena *arena, RDI_Parsed *rdi, PathStyle path_style, U32 path_node_idx); +internal String8 fully_qualified_from_rdi_string_and_container(Arena *arena, RDI_Parsed *rdi, U32 name_string_idx, U32 start_container_idx, RDI_ContainerFlags start_container_flags); +#define fully_qualified_str8_from_rdi_symbol(arena, rdi, symbol) fully_qualified_from_rdi_string_and_container((arena), (rdi), (symbol)->name_string_idx, (symbol)->container_idx, (symbol)->container_flags) +#define fully_qualified_str8_from_rdi_udt(arena, rdi, udt) fully_qualified_from_rdi_string_and_container((arena), (rdi), rdi_element_from_name_idx((rdi), TypeNodes, (udt)->self_type_idx)->user_defined.name_string_idx, (udt)->container_idx, (udt)->container_flags) +#define fully_qualified_str8_from_rdi_type(arena, rdi, type) fully_qualified_from_rdi_string_and_container((arena), (rdi), (type)->user_defined.name_string_idx, rdi_element_from_name_idx((rdi), UDTs, (type)->user_defined.udt_idx)->container_idx, rdi_element_from_name_idx((rdi), UDTs, (type)->user_defined.udt_idx)->container_flags) +#define fully_qualified_str8_from_rdi_namespace(arena, rdi, ns) fully_qualified_from_rdi_string_and_container((arena), (rdi), (ns)->name_string_idx, (ns)->container_idx, (ns)->container_flags) //////////////////////////////// //~ rjf: String <=> Enum diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 73a4b1e2..d28ac7bf 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -19,14 +19,23 @@ p2r_end_of_cplusplus_container_name(String8 str) U64 result = 0; if(str.size >= 2) { - String8 str_before_templates = str8_prefix(str, str8_find_needle(str, 0, str8_lit("<"), 0)); - for(U64 i = str_before_templates.size; i >= 2; i -= 1) + S64 template_nest_depth = 0; + for(U64 i = str.size; i >= 2; i -= 1) { - if(str_before_templates.str[i - 2] == ':' && str_before_templates.str[i - 1] == ':') + if(template_nest_depth == 0 && str.str[i - 2] == ':' && str.str[i - 1] == ':') { result = i; break; } + if(str.str[i-1] == '>') + { + template_nest_depth += 1; + } + else if(str.str[i-1] == '<') + { + template_nest_depth -= 1; + template_nest_depth = ClampBot(template_nest_depth, 0); + } } } return result; @@ -2873,44 +2882,49 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) // rjf: symbol name -> container name String8 container_name = str8_chop(str8_prefix(symbol_name, p2r_end_of_cplusplus_container_name(symbol_name)), 2); - U64 container_name_hash = u64_hash_from_str8(container_name); - // rjf: first, check if this container already showed up from type info - B32 already_exists = 0; - if(!already_exists) + // rjf: non-empty container name -> gather + if(container_name.size != 0) { - U64 slot_idx = container_name_hash%all_namespace_slots_count; - for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) + U64 container_name_hash = u64_hash_from_str8(container_name); + + // rjf: first, check if this container already showed up from type info + B32 already_exists = 0; + if(!already_exists) { - if(str8_match(n->string, container_name, 0)) + U64 slot_idx = container_name_hash%all_namespace_slots_count; + for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) { - already_exists = 1; - break; + if(str8_match(n->string, container_name, 0)) + { + already_exists = 1; + break; + } } } - } - - // rjf: next, check if we've already gathered this namespace for this lane - if(!already_exists) - { - U64 slot_idx = container_name_hash%lane_namespace_slots_count; - for(String8Node *n = lane_namespace_slots[slot_idx]; n != 0; n = n->next) + + // rjf: next, check if we've already gathered this namespace for this lane + if(!already_exists) { - if(str8_match(n->string, container_name, 0)) + U64 slot_idx = container_name_hash%lane_namespace_slots_count; + for(String8Node *n = lane_namespace_slots[slot_idx]; n != 0; n = n->next) { - already_exists = 1; - break; + if(str8_match(n->string, container_name, 0)) + { + already_exists = 1; + break; + } } } - } - - // rjf: if we didn't find this namespace in either those from types, or already found in this lane, then gather - if(!already_exists) - { - U64 slot_idx = container_name_hash%lane_namespace_slots_count; - String8Node *n = push_array(scratch2.arena, String8Node, 1); - SLLStackPush(lane_namespace_slots[slot_idx], n); - n->string = container_name; + + // rjf: if we didn't find this namespace in either those from types, or already found in this lane, then gather + if(!already_exists) + { + U64 slot_idx = container_name_hash%lane_namespace_slots_count; + String8Node *n = push_array(scratch2.arena, String8Node, 1); + SLLStackPush(lane_namespace_slots[slot_idx], n); + n->string = container_name; + } } } } @@ -3023,7 +3037,6 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for EachIndex(node_in_slot_idx, node_count) { P2R_NamespaceNode *n = nodes[node_in_slot_idx]; - raddbg_log("%S%s\n", n->string, n->corresponds_to_scope ? " (is scope)" : n->type != 0 ? " (is type)" : ""); if(n->corresponds_to_scope || n->scope != 0 || n->type != 0) { continue; } String8 string = n->string; RDIM_Namespace *ns = rdim_namespace_chunk_list_push(arena, &lane_namespaces, 32); @@ -3316,10 +3329,17 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } + // rjf: un-namespaceify the symbol name + String8 name__maybe_partially_qualified = name; + if(got_container) + { + name__maybe_partially_qualified = str8_skip(name, container_name_opl); + } + // rjf: build symbol RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_global_variables, sym_global_variables_chunk_cap); symbol->is_extern = (iter.kind == CV_SymKind_GDATA32); - symbol->name = name; + symbol->name = name__maybe_partially_qualified; symbol->type = type; symbol->container_scope = container_scope; symbol->container_type = container_type; @@ -3435,12 +3455,19 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } + // rjf: un-namespaceify the symbol name + String8 name__maybe_partially_qualified = name; + if(got_container) + { + name__maybe_partially_qualified = str8_skip(name, container_name_opl); + } + // rjf: build procedure symbol if(params->subset_flags & (RDIM_SubsetFlag_Procedures|RDIM_SubsetFlag_ProcedureNameMap)) { curr_proc_symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap); curr_proc_symbol->is_extern = (iter.kind == CV_SymKind_GPROC32); - curr_proc_symbol->name = name; + curr_proc_symbol->name = name__maybe_partially_qualified; curr_proc_symbol->link_name = link_name; curr_proc_symbol->type = type; curr_proc_symbol->container_scope = container_scope; @@ -3564,6 +3591,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { RDIM_Scope *scope = top_scope_node->scope; RDIM_Symbol *local = rdim_symbol_chunk_list_push(arena, &scope->locals, 8); + local->container_scope = scope; local->is_param = is_param; local->name = name; local->type = type; @@ -3599,29 +3627,57 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); // rjf: unpack thread variable's container type + B32 got_container = 0; 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_chop(str8_prefix(name, container_name_opl), 2); + if(!got_container && container_name.size != 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); + got_container = (container_type != 0); } // rjf: unpack thread variable's container symbol RDIM_Scope *container_scope = 0; - if(container_type == 0 && top_scope_node != 0) + if(!got_container && top_scope_node != 0) { + got_container = 1; container_scope = top_scope_node->scope; } + // rjf: unpack proc's container namespace + RDIM_Namespace *container_namespace = 0; + if(!got_container && container_name.size != 0) + { + U64 hash = u64_hash_from_str8(container_name); + U64 slot_idx = hash%all_namespace_slots_count; + for(P2R_NamespaceNode *n = all_namespace_slots[slot_idx]; n != 0; n = n->next) + { + if(str8_match(container_name, n->string, 0) && + n->ns != 0) + { + container_namespace = n->ns; + break; + } + } + } + + // rjf: un-namespaceify the symbol name + String8 name__maybe_partially_qualified = name; + if(got_container) + { + name__maybe_partially_qualified = str8_skip(name, container_name_opl); + } + // 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 = (iter.kind == CV_SymKind_GTHREAD32); - tvar->container_type = container_type; - tvar->container_scope = container_scope; + tvar->name = name__maybe_partially_qualified; + tvar->type = type; + tvar->is_extern = (iter.kind == CV_SymKind_GTHREAD32); + tvar->container_type = container_type; + tvar->container_scope = container_scope; + tvar->container_namespace = container_namespace; RDIM_Location loc = {.kind = RDI_LocationKind_TLSOff, .offset = tls_off}; RDIM_Rng1U64 range = {0, 0xffffffffffffffffull}; rdim_location_case_list_push(arena, &tvar->location_cases, loc, range); @@ -3665,6 +3721,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) RDIM_Scope *scope = top_scope_node->scope; RDIM_Symbol *local = rdim_symbol_chunk_list_push(arena, &scope->locals, 8); { + local->container_scope = scope; local->is_param = !!(slocal->flags & CV_LocalFlag_Param); local->name = name; local->type = type; @@ -4061,7 +4118,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) lane_sync(); ////////////////////////////////////////////////////////////// - //- rjf: upgrade namespaces with container info + //- rjf: upgrade namespaces with container info; trim off container names // for EachNode(n, RDIM_NamespaceChunkNode, all_namespaces.first) { @@ -4069,18 +4126,24 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) for EachInRange(n_idx, range) { RDIM_Namespace *ns = &n->v[n_idx]; - String8 container_name = str8_chop(str8_prefix(ns->name, p2r_end_of_cplusplus_container_name(ns->name)), 2); - U64 hash = u64_hash_from_str8(container_name); - U64 slot_idx = hash%all_namespace_slots_count; - for(P2R_NamespaceNode *ns_n = all_namespace_slots[slot_idx]; ns_n != 0; ns_n = ns_n->next) + U64 container_name_opl = p2r_end_of_cplusplus_container_name(ns->name); + String8 container_name = str8_chop(str8_prefix(ns->name, container_name_opl), 2); + if(container_name.size != 0) { - if(str8_match(ns_n->string, container_name, 0)) + String8 leaf_name = str8_skip(ns->name, container_name_opl); + U64 hash = u64_hash_from_str8(container_name); + U64 slot_idx = hash%all_namespace_slots_count; + for(P2R_NamespaceNode *ns_n = all_namespace_slots[slot_idx]; ns_n != 0; ns_n = ns_n->next) { - ns->parent_scope = ns_n->scope; - ns->parent_type = ns_n->type; - ns->parent_namespace = ns_n->ns; - break; + if(str8_match(ns_n->string, container_name, 0)) + { + ns->parent_scope = ns_n->scope; + ns->parent_type = ns_n->type; + ns->parent_namespace = ns_n->ns; + break; + } } + ns->name = leaf_name; } } } @@ -4762,7 +4825,9 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) if(dst_type != 0 && dst_type->udt != 0 && udt_name.size != 0) { // rjf: unpack fully qualified namespace from udt name - String8 container_name = str8_chop(str8_prefix(udt_name, p2r_end_of_cplusplus_container_name(udt_name)), 2); + U64 container_name_opl = p2r_end_of_cplusplus_container_name(udt_name); + String8 container_name = str8_chop(str8_prefix(udt_name, container_name_opl), 2); + String8 leaf_name = str8_skip(udt_name, container_name_opl); // rjf: look up namespace node associated with namespace P2R_NamespaceNode *ns_node = 0; @@ -4779,7 +4844,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) } } - // rjf: equip container info to udt + // rjf: equip container info to udt, equip partial name to type if(ns_node != 0) { RDIM_UDT *udt = dst_type->udt; @@ -4795,6 +4860,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params) { udt->container_type = ns_node->type; } + dst_type->name = leaf_name; } } }