// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// //~ rjf: API Implementation Helper Macros #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 //- rjf: memory set #if !defined(RDIM_MEMSET_OVERRIDE) RDI_PROC void * rdim_memset_fallback(void *dst, RDI_U8 c, RDI_U64 size) { for(RDI_U64 idx = 0; idx < size; idx += 1) { ((RDI_U8 *)dst)[idx] = c; } return dst; } #endif #if !defined(RDIM_MEMCPY_OVERRIDE) RDI_PROC void * rdim_memcpy_fallback(void *dst, void *src, RDI_U64 size) { for(RDI_U64 idx = 0; idx < size; idx += 1) { ((RDI_U8 *)dst)[idx] = ((RDI_U8 *)src)[idx]; } return dst; } #endif //- rjf: arenas #if !defined (RDIM_ARENA_OVERRIDE) RDI_PROC RDIM_Arena * rdim_arena_alloc_fallback(void) { RDIM_Arena *arena = 0; // TODO(rjf) return arena; } RDI_PROC void rdim_arena_release_fallback(RDIM_Arena *arena) { // TODO(rjf) } RDI_PROC RDI_U64 rdim_arena_pos_fallback(RDIM_Arena *arena) { // TODO(rjf) return 0; } RDI_PROC void * rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size, RDI_U64 align, RDI_U32 zero) { // TODO(rjf) return 0; } RDI_PROC void rdim_arena_pop_to_fallback(RDIM_Arena *arena, RDI_U64 pos) { // TODO(rjf) } #endif //- rjf: thread-local scratch arenas #if !defined (RDIM_SCRATCH_OVERRIDE) static RDIM_THREAD_LOCAL RDIM_Arena *rdim_thread_scratches[2]; RDI_PROC RDIM_Temp rdim_scratch_begin_fallback(RDIM_Arena **conflicts, RDI_U64 conflicts_count) { if(rdim_thread_scratches[0] == 0) { rdim_thread_scratches[0] = rdim_arena_alloc(); rdim_thread_scratches[1] = rdim_arena_alloc(); } RDIM_Arena *arena = 0; for(RDI_U64 scratch_idx = 0; scratch_idx < sizeof(rdim_thread_scratches)/sizeof(rdim_thread_scratches[0]); scratch_idx += 1) { RDI_S32 scratch_conflicts = 0; for(RDI_U64 conflict_idx = 0; conflict_idx < conflicts_count; conflict_idx += 1) { if(conflicts[conflict_idx] == rdim_thread_scratches[scratch_idx]) { scratch_conflicts = 1; break; } } if(!scratch_conflicts) { arena = rdim_thread_scratches[scratch_idx]; } } RDIM_Temp temp; temp.arena = arena; temp.pos = rdim_arena_pos(arena); return temp; } RDI_PROC void rdim_scratch_end_fallback(RDIM_Temp temp) { rdim_arena_pop_to(temp.arena, temp.pos); } #endif //- rjf: strings RDI_PROC RDIM_String8 rdim_str8(RDI_U8 *str, RDI_U64 size) { RDIM_String8 result; result.RDIM_String8_BaseMember = str; result.RDIM_String8_SizeMember = size; return result; } RDI_PROC RDIM_String8 rdim_str8_copy(RDIM_Arena *arena, RDIM_String8 src) { RDIM_String8 dst; dst.RDIM_String8_SizeMember = src.RDIM_String8_SizeMember; dst.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, dst.RDIM_String8_SizeMember+1); rdim_memcpy(dst.RDIM_String8_BaseMember, src.RDIM_String8_BaseMember, src.RDIM_String8_SizeMember); dst.RDIM_String8_BaseMember[dst.RDIM_String8_SizeMember] = 0; return dst; } RDI_PROC RDIM_String8 rdim_str8f(RDIM_Arena *arena, char *fmt, ...) { va_list args; va_start(args, fmt); RDIM_String8 result = rdim_str8fv(arena, fmt, args); va_end(args); return(result); } RDI_PROC RDIM_String8 rdim_str8fv(RDIM_Arena *arena, char *fmt, va_list args) { va_list args2; va_copy(args2, args); RDI_U32 needed_bytes = rdim_vsnprintf(0, 0, fmt, args) + 1; RDIM_String8 result = {0}; result.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, needed_bytes); result.RDIM_String8_SizeMember = rdim_vsnprintf((char*)result.str, needed_bytes, fmt, args2); result.RDIM_String8_BaseMember[result.RDIM_String8_SizeMember] = 0; va_end(args2); return(result); } RDI_PROC RDI_S32 rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatchFlags flags) { RDI_S32 result = 0; if(a.RDIM_String8_SizeMember == b.RDIM_String8_SizeMember) { RDI_S32 case_insensitive = (flags & RDIM_StringMatchFlag_CaseInsensitive); RDI_U64 size = a.RDIM_String8_SizeMember; result = 1; for(RDI_U64 idx = 0; idx < size; idx += 1) { RDI_U8 at = a.RDIM_String8_BaseMember[idx]; RDI_U8 bt = b.RDIM_String8_BaseMember[idx]; if(case_insensitive) { at = ('a' <= at && at <= 'z') ? at-('a'-'A') : at; bt = ('a' <= bt && bt <= 'z') ? bt-('a'-'A') : bt; } if(at != bt) { result = 0; break; } } } return result; } RDI_PROC RDIM_String8 rdim_lower_from_str8(RDIM_Arena *arena, RDIM_String8 string) { RDIM_String8 result = rdim_str8_copy(arena, string); for(RDI_U64 idx = 0; idx < result.RDIM_String8_SizeMember; idx += 1) { RDI_U8 byte = result.RDIM_String8_BaseMember[idx]; if('A' <= byte && byte <= 'Z') { result.RDIM_String8_BaseMember[idx] += ('a' - 'A'); } } return result; } //- rjf: string lists RDI_PROC void rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string) { RDIM_String8Node *n = rdim_push_array(arena, RDIM_String8Node, 1); n->RDIM_String8Node_StringMember = string; RDIM_SLLQueuePush_N(list->RDIM_String8List_FirstMember, list->RDIM_String8List_LastMember, n, RDIM_String8Node_NextPtrMember); list->RDIM_String8List_NodeCountMember += 1; list->RDIM_String8List_TotalSizeMember += string.RDIM_String8_SizeMember; } RDI_PROC void rdim_str8_list_push_front(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string) { RDIM_String8Node *n = rdim_push_array(arena, RDIM_String8Node, 1); n->RDIM_String8Node_StringMember = string; RDIM_SLLQueuePushFront_N(list->RDIM_String8List_FirstMember, list->RDIM_String8List_LastMember, n, RDIM_String8Node_NextPtrMember); list->RDIM_String8List_NodeCountMember += 1; list->RDIM_String8List_TotalSizeMember += string.RDIM_String8_SizeMember; } RDI_PROC void rdim_str8_list_push_align(RDIM_Arena *arena, RDIM_String8List *list, RDI_U64 align) { RDI_U64 total_size_pre_align = list->total_size; RDI_U64 total_size_post_align = (total_size_pre_align + (align-1))&(~(align-1)); RDI_U64 needed_size = total_size_post_align - total_size_pre_align; if(needed_size != 0) { RDI_U8 *padding = rdim_push_array(arena, RDI_U8, needed_size); rdim_str8_list_push(arena, list, rdim_str8(padding, needed_size)); } } RDI_PROC RDIM_String8 rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) { RDIM_String8 result; rdim_memzero_struct(&result); RDI_U64 sep_count = (list->RDIM_String8List_NodeCountMember > 1) ? (list->RDIM_String8List_NodeCountMember-1) : 0; result.RDIM_String8_SizeMember = list->RDIM_String8List_TotalSizeMember+sep_count*sep.RDIM_String8_SizeMember; result.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, result.RDIM_String8_SizeMember+1); RDI_U64 off = 0; for(RDIM_String8Node *node = list->RDIM_String8List_FirstMember; node != 0; node = node->RDIM_String8Node_NextPtrMember) { rdim_memcpy((RDI_U8*)result.RDIM_String8_BaseMember+off, node->RDIM_String8Node_StringMember.RDIM_String8_BaseMember, node->RDIM_String8Node_StringMember.RDIM_String8_SizeMember); off += node->RDIM_String8Node_StringMember.RDIM_String8_SizeMember; if(sep.RDIM_String8_SizeMember != 0 && node->RDIM_String8Node_NextPtrMember != 0) { rdim_memcpy((RDI_U8*)result.RDIM_String8_BaseMember+off, sep.RDIM_String8_BaseMember, sep.RDIM_String8_SizeMember); off += sep.RDIM_String8_SizeMember; } } result.RDIM_String8_BaseMember[off] = 0; return result; } //- 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) { // This sort is designed to take advantage of lots of pre-existing sorted ranges. // Most line info is already sorted or close to already sorted. // Similarly most vmap data has lots of pre-sorted ranges. etc. etc. // 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_Temp scratch = rdim_scratch_begin(&arena, 1); RDIM_SortKey *result = 0; if(count <= 1) { result = keys; } else { RDIM_OrderedRange *ranges_first = 0; RDIM_OrderedRange *ranges_last = 0; RDI_U64 range_count = 0; { RDI_U64 pos = 0; for(;pos < count;) { // identify ordered range RDI_U64 first = pos; RDI_U64 opl = pos + 1; for(; opl < count && keys[opl - 1].key <= keys[opl].key; opl += 1); // generate an ordered range node RDIM_OrderedRange *new_range = rdim_push_array(rdim_temp_arena(scratch), RDIM_OrderedRange, 1); RDIM_SLLQueuePush(ranges_first, ranges_last, new_range); range_count += 1; new_range->first = first; new_range->opl = opl; // update pos pos = opl; } } if(range_count == 1) { result = keys; } else { RDIM_SortKey *keys_swap = rdim_push_array_no_zero(arena, RDIM_SortKey, count); RDIM_SortKey *src = keys; RDIM_SortKey *dst = keys_swap; RDIM_OrderedRange *src_ranges = ranges_first; RDIM_OrderedRange *dst_ranges = 0; RDIM_OrderedRange *dst_ranges_last = 0; for(;;) { // begin a pass for(;;) { // end pass when out of ranges if(src_ranges == 0) { break; } // get first range RDIM_OrderedRange *range1 = src_ranges; RDIM_SLLStackPop(src_ranges); // if this range is the whole array, we are done if(range1->first == 0 && range1->opl == count) { result = src; goto sort_done; } // if there is not a second range, save this range for next time and end this pass if(src_ranges == 0) { RDI_U64 first = range1->first; rdim_memcpy(dst + first, src + first, sizeof(*src)*(range1->opl - first)); RDIM_SLLQueuePush(dst_ranges, dst_ranges_last, range1); break; } // get second range RDIM_OrderedRange *range2 = src_ranges; RDIM_SLLStackPop(src_ranges); #if 0 rdim_assert(range1->opl == range2->first); #endif // merge these ranges RDI_U64 jd = range1->first; RDI_U64 j1 = range1->first; RDI_U64 j1_opl = range1->opl; RDI_U64 j2 = range2->first; RDI_U64 j2_opl = range2->opl; for(;;) { if(src[j1].key <= src[j2].key) { rdim_memcpy(dst + jd, src + j1, sizeof(*src)); j1 += 1; jd += 1; if(j1 >= j1_opl) { break; } } else { rdim_memcpy(dst + jd, src + j2, sizeof(*src)); j2 += 1; jd += 1; if(j2 >= j2_opl) { break; } } } if(j1 < j1_opl) { rdim_memcpy(dst + jd, src + j1, sizeof(*src)*(j1_opl - j1)); } else { rdim_memcpy(dst + jd, src + j2, sizeof(*src)*(j2_opl - j2)); } // save this as one range range1->opl = range2->opl; SLLQueuePush(dst_ranges, dst_ranges_last, range1); } // end pass by swapping buffers and range nodes { RDIM_SortKey *temp = src; src = dst; dst = temp; } src_ranges = dst_ranges; dst_ranges = 0; dst_ranges_last = 0; } } } sort_done:; #if 0 // assert sortedness for(RDI_U64 i = 1; i < count; i += 1) { rdim_assert(result[i - 1].key <= result[i].key); } #endif rdim_scratch_end(scratch); return result; } //- rjf: rng1u64 list RDI_PROC void rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r) { RDIM_Rng1U64Node *n = rdim_push_array(arena, RDIM_Rng1U64Node, 1); n->v = r; RDIM_SLLQueuePush(list->first, list->last, n); list->count += 1; if(list->count == 1 || r.min < list->min) { list->min = r.min; } } RDI_PROC void rdim_rng1u64_chunk_list_push(RDIM_Arena *arena, RDIM_Rng1U64ChunkList *list, RDI_U64 chunk_cap, RDIM_Rng1U64 r) { RDIM_Rng1U64ChunkNode *n = list->last; if(n == 0 || n->count >= n->cap) { n = rdim_push_array(arena, RDIM_Rng1U64ChunkNode, 1); RDIM_SLLQueuePush(list->first, list->last, n); n->cap = chunk_cap; n->v = rdim_push_array_no_zero(arena, RDIM_Rng1U64, n->cap); list->chunk_count += 1; } n->v[n->count] = r; n->count += 1; list->total_count += 1; if(list->total_count == 1 || r.min < list->min) { list->min = r.min; } } //////////////////////////////// //~ Data Model RDI_PROC RDI_TypeKind rdim_short_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_unsigned_short_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_int_type_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_long_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_unsigned_long_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_long_long_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_unsigned_long_long_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } RDI_PROC RDI_TypeKind rdim_pointer_size_t_type_kind_from_data_model(RDIM_DataModel data_model) { switch(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; } return RDI_TypeKind_NULL; } //////////////////////////////// //~ rjf: [Building] Binary Section List Building RDI_PROC RDIM_BinarySection * rdim_binary_section_list_push(RDIM_Arena *arena, RDIM_BinarySectionList *list) { RDIM_BinarySectionNode *n = rdim_push_array(arena, RDIM_BinarySectionNode, 1); RDIM_SLLQueuePush(list->first, list->last, n); list->count += 1; RDIM_BinarySection *result = &n->v; return result; } //////////////////////////////// //~ rjf: [Building] Source File Info Building RDI_PROC RDIM_SrcFile * rdim_src_file_chunk_list_push(RDIM_Arena *arena, RDIM_SrcFileChunkList *list, RDI_U64 cap) { 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) { 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) { 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 rdim_src_file_push_line_sequence(RDIM_Arena *arena, RDIM_SrcFileChunkList *src_files, RDIM_SrcFile *src_file, RDIM_LineSequence *seq) { if(src_file->first_line_map_fragment == 0) { src_files->source_line_map_count += 1; } 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_files->total_line_count += seq->line_count; } //////////////////////////////// //~ rjf: [Building] Line Info Building RDI_PROC RDIM_LineTable * rdim_line_table_chunk_list_push(RDIM_Arena *arena, RDIM_LineTableChunkList *list, RDI_U64 cap) { 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) { 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) { 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 * rdim_line_table_push_sequence(RDIM_Arena *arena, RDIM_LineTableChunkList *line_tables, RDIM_LineTable *line_table, RDIM_SrcFile *src_file, RDI_U64 *voffs, RDI_U32 *line_nums, RDI_U16 *col_nums, RDI_U64 line_count) { RDIM_LineSequenceNode *n = push_array(arena, RDIM_LineSequenceNode, 1); n->v.src_file = src_file; n->v.voffs = voffs; n->v.line_nums = line_nums; n->v.col_nums = col_nums; n->v.line_count = line_count; SLLQueuePush(line_table->first_seq, line_table->last_seq, n); line_table->seq_count += 1; line_table->line_count += line_count; line_table->col_count += line_count*2*(col_nums != 0); line_tables->total_seq_count += 1; line_tables->total_line_count += line_count; line_tables->total_col_count += line_count*2*(col_nums != 0); return &n->v; } //////////////////////////////// //~ rjf: [Building] Unit List Building RDI_PROC RDIM_Unit * rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDI_U64 cap) { RDIM_IdxedChunkListPush(arena, list, RDIM_UnitChunkNode, RDIM_Unit, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_unit(RDIM_Unit *unit) { RDIM_IdxedChunkListElementGetIdx(unit, idx); return idx; } RDI_PROC void rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push) { RDIM_IdxedChunkListConcatInPlace(RDIM_UnitChunkNode, dst, to_push); } //////////////////////////////// //~ rjf: [Building] Type Info Building //- rjf: type nodes RDI_PROC RDIM_Type ** rdim_array_from_type_list(RDIM_Arena *arena, RDIM_TypeList list) { RDIM_Type **arr = push_array(arena, RDIM_Type *, list.count); U64 i = 0; for(RDIM_TypeNode *n = list.first; n != 0; n = n->next, ++i) { arr[i] = n->v; } return arr; } RDI_PROC RDIM_TypeNode * rdim_type_list_push(RDIM_Arena *arena, RDIM_TypeList *list, RDIM_Type *v) { RDIM_TypeNode *n = push_array(arena, RDIM_TypeNode, 1); n->v = v; SLLQueuePush(list->first, list->last, n); list->count += 1; return n; } RDI_PROC RDIM_Type * rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap) { RDIM_IdxedChunkListPush(arena, list, RDIM_TypeChunkNode, RDIM_Type, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_type(RDIM_Type *type) { RDIM_IdxedChunkListElementGetIdx(type, idx); return idx; } RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push) { RDIM_IdxedChunkListConcatInPlace(RDIM_TypeChunkNode, dst, to_push); } //- rjf: UDTs RDI_PROC RDIM_UDT * rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap) { RDIM_IdxedChunkListPush(arena, list, RDIM_UDTChunkNode, RDIM_UDT, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt) { RDIM_IdxedChunkListElementGetIdx(udt, idx); return idx; } RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *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 * rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt) { RDIM_UDTMember *mem = rdim_push_array(arena, RDIM_UDTMember, 1); RDIM_SLLQueuePush(udt->first_member, udt->last_member, mem); udt->member_count += 1; list->total_member_count += 1; return mem; } RDI_PROC RDIM_UDTEnumVal * rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt) { RDIM_UDTEnumVal *mem = rdim_push_array(arena, RDIM_UDTEnumVal, 1); RDIM_SLLQueuePush(udt->first_enum_val, udt->last_enum_val, mem); udt->enum_val_count += 1; list->total_enum_val_count += 1; return mem; } //////////////////////////////// //~ rjf: [Building] Symbol Info Building RDI_PROC RDIM_Symbol * rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U64 cap) { RDIM_IdxedChunkListPush(arena, list, RDIM_SymbolChunkNode, RDIM_Symbol, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_symbol(RDIM_Symbol *symbol) { RDIM_IdxedChunkListElementGetIdx(symbol, idx); return idx; } RDI_PROC void rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push) { RDIM_IdxedChunkListConcatInPlace(RDIM_SymbolChunkNode, dst, to_push, dst->total_value_data_size += to_push->total_value_data_size); } internal void rdim_symbol_push_value_data(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDIM_Symbol *symbol, RDIM_String8 data) { symbol->value_data = rdim_str8_copy(arena, data); list->total_value_data_size += data.size; } //////////////////////////////// //~ rjf: [Building] Inline Site Info Building RDI_PROC RDIM_InlineSite * rdim_inline_site_chunk_list_push(RDIM_Arena *arena, RDIM_InlineSiteChunkList *list, RDI_U64 cap) { 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) { 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) { RDIM_IdxedChunkListConcatInPlace(RDIM_InlineSiteChunkNode, dst, to_push); } //////////////////////////////// //~ rjf: [Building] Location Info Building 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); } //////////////////////////////// //~ 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) { RDIM_IdxedChunkListPush(arena, list, RDIM_ScopeChunkNode, RDIM_Scope, cap, result); return result; } RDI_PROC RDI_U64 rdim_idx_from_scope(RDIM_Scope *scope) { RDIM_IdxedChunkListElementGetIdx(scope, idx); return idx; } 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); } RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDIM_Scope *scope, RDIM_Rng1U64 range) { rdim_rng1u64_list_push(arena, &scope->voff_ranges, range); list->scope_voff_count += 2; } RDI_PROC RDIM_Local * rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope) { RDIM_Local *local = rdim_push_array(arena, RDIM_Local, 1); RDIM_SLLQueuePush(scope->first_local, scope->last_local, local); scope->local_count += 1; scopes->local_count += 1; return local; } //- 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: 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_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 //- rjf: chunk lists RDI_PROC RDIM_BakeString * rdim_bake_string_chunk_list_push(RDIM_Arena *arena, RDIM_BakeStringChunkList *list, RDI_U64 cap) { RDIM_BakeStringChunkNode *n = list->last; if(n == 0 || n->count >= n->cap) { n = rdim_push_array(arena, RDIM_BakeStringChunkNode, 1); n->cap = cap; n->v = rdim_push_array(arena, RDIM_BakeString, n->cap); RDIM_SLLQueuePush(list->first, list->last, n); list->chunk_count += 1; } RDIM_BakeString *s = &n->v[n->count]; n->count += 1; list->total_count += 1; return s; } RDI_PROC void rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_BakeStringChunkList *to_push) { for(RDIM_BakeStringChunkNode *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_string_is_before(void *l, void *r) { return str8_is_before(((RDIM_BakeString *)l)->string, ((RDIM_BakeString *)r)->string); } RDI_PROC RDIM_BakeStringChunkList rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStringChunkList *src) { //- rjf: produce unsorted destination list with single chunk node RDIM_BakeStringChunkList dst = {0}; for(RDIM_BakeStringChunkNode *n = src->first; n != 0; n = n->next) { for(RDI_U64 idx = 0; idx < n->count; idx += 1) { RDIM_BakeString *src_str = &n->v[idx]; RDIM_BakeString *dst_str = rdim_bake_string_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_string_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: loose map RDI_PROC RDIM_BakeStringMapLoose * rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top) { RDIM_BakeStringMapLoose *map = rdim_push_array(arena, RDIM_BakeStringMapLoose, 1); map->slots = rdim_push_array(arena, RDIM_BakeStringChunkList *, top->slots_count); return map; } 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) { 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_BakeStringChunkList *slot = map->slots[slot_idx]; if(slot == 0) { slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeStringChunkList, 1); } RDI_S32 is_duplicate = 0; for(RDIM_BakeStringChunkNode *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_BakeString *bstr = rdim_bake_string_chunk_list_push(arena, slot, chunk_cap); bstr->string = string; bstr->hash = hash; } } } 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) { RDIM_BakeStringMapBaseIndices 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_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) { RDI_U32 idx = 0; 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->slots_count; for(RDIM_BakeStringChunkNode *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 && rdim_str8_match(n->v[chunk_idx].string, string, 0)) { idx = map->slots_base_idxs[slot_idx] + n->base_idx + chunk_idx + 1; break; } } } } return idx; } //////////////////////////////// //~ 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) { 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) { 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; } 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); } } } return is_less_than; } 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].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; } 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); map->slots_idx_counts = rdim_push_array(arena, RDI_U64, 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 && n->v[idx].count == count && MemoryMatch(n->v[idx].idxes, idxes, sizeof(idxes[0])*count)) { 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; map->slots_idx_counts[slot_idx] += 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_U32 idx = 0; if(count != 0) { 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 && n->v[chunk_idx].count == count && MemoryMatch(n->v[chunk_idx].idxes, idxes, sizeof(idxes[0])*count)) { 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; } //////////////////////////////// //~ 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) { 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) { 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 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) && dst.first->v[last_idx].idx == dst.first->v[idx].idx) { 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) && n->v[idx].idx == idx) { 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: [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 RDI_PROC RDIM_BakePathNode * rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) { RDIM_BakePathNode *node = &tree->root; RDI_U8 *ptr = string.str; RDI_U8 *opl = string.str + string.size; for(;ptr < opl && node != 0;) { // rjf: skip past slashes for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); // rjf: save beginning of non-slash range RDI_U8 *range_first = ptr; // rjf: skip past non-slashes for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); // rjf: empty range -> continue if(range_first >= ptr) { continue; } // rjf: range -> sub-directory string RDIM_String8 sub_dir = rdim_str8(range_first, (RDI_U64)(ptr-range_first)); // rjf: sub-directory string -> find child of node RDIM_BakePathNode *sub_dir_node = 0; for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling) { if(rdim_str8_match(child->name, sub_dir, 0)) { sub_dir_node = child; } } // rjf: .. -> go up if(sub_dir.RDIM_String8_SizeMember == 2 && sub_dir.RDIM_String8_BaseMember[0] == '.' && sub_dir.RDIM_String8_BaseMember[1] == '.') { sub_dir_node = node->parent; if(sub_dir_node == 0) { sub_dir_node = &tree->root; } } // rjf: . -> stay here else if(sub_dir.RDIM_String8_SizeMember == 1 && sub_dir.RDIM_String8_BaseMember[0] == '.') { sub_dir_node = node; } // rjf: descend to child node = sub_dir_node; } return node; } RDI_PROC RDI_U32 rdim_bake_path_node_idx_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) { RDIM_BakePathNode *path_node = rdim_bake_path_node_from_string(tree, string); RDI_U32 result = 0; if(path_node != 0) { result = path_node->idx; } return result; } RDI_PROC RDIM_BakePathNode * rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string) { RDIM_BakePathNode *node = &tree->root; RDI_U8 *ptr = string.str; RDI_U8 *opl = string.str + string.size; for(;ptr < opl;) { // rjf: skip past slashes for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); // rjf: save beginning of non-slash range RDI_U8 *range_first = ptr; // rjf: skip past non-slashes for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); // rjf: empty range -> continue if(range_first >= ptr) { continue; } // rjf: range -> sub-directory string RDIM_String8 sub_dir = rdim_str8(range_first, (RDI_U64)(ptr-range_first)); // rjf: sub-directory string -> find child of node RDIM_BakePathNode *sub_dir_node = 0; for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling) { if(rdim_str8_match(child->name, sub_dir, 0)) { sub_dir_node = child; } } // rjf: .. -> go up if(sub_dir.RDIM_String8_SizeMember == 2 && sub_dir.RDIM_String8_BaseMember[0] == '.' && sub_dir.RDIM_String8_BaseMember[1] == '.') { sub_dir_node = node->parent; if(sub_dir_node == 0) { sub_dir_node = &tree->root; } } // rjf: . -> stay here else if(sub_dir.RDIM_String8_SizeMember == 1 && sub_dir.RDIM_String8_BaseMember[0] == '.') { sub_dir_node = node; } // rjf: no child -> make one else if(sub_dir_node == 0) { sub_dir_node = rdim_push_array(arena, RDIM_BakePathNode, 1); RDIM_SLLQueuePush_N(tree->first, tree->last, sub_dir_node, next_order); sub_dir_node->parent = node; RDIM_SLLQueuePush_N(node->first_child, node->last_child, sub_dir_node, next_sibling); sub_dir_node->name = rdim_str8_copy(arena, sub_dir); sub_dir_node->idx = tree->count; tree->count += 1; } // rjf: descend to child node = sub_dir_node; } 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 RDI_PROC RDIM_BakeSection * rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_BakeSectionList *list) { RDIM_BakeSectionNode *n = rdim_push_array(arena, RDIM_BakeSectionNode, 1); RDIM_SLLQueuePush(list->first, list->last, n); list->count += 1; RDIM_BakeSection *result = &n->v; return result; } 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) { RDIM_BakeSection *section = rdim_bake_section_list_push(arena, list); section->data = data; section->encoding = RDI_SectionEncoding_Unpacked; section->encoded_size = size; section->unpacked_size = size; section->tag = tag; section->tag_idx = tag_idx; return section; } RDI_PROC void rdim_bake_section_list_concat_in_place(RDIM_BakeSectionList *dst, RDIM_BakeSectionList *to_push) { if(dst->last != 0 && to_push->first != 0) { dst->last->next = to_push->first; dst->last = to_push->last; dst->count += to_push->count; } else if(to_push->first != 0) { rdim_memcpy_struct(dst, to_push); } 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 RDI_PROC RDIM_SerializedSection rdim_serialized_section_make_unpacked(void *data, RDI_U64 size) { RDIM_SerializedSection s; rdim_memzero_struct(&s); s.data = data; s.encoded_size = s.unpacked_size = size; s.encoding = RDI_SectionEncoding_Unpacked; return s; } RDI_PROC RDIM_SerializedSectionBundle 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_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); bundle.sections[RDI_SectionKind_BinarySections] = rdim_serialized_section_make_unpacked_array(results->binary_sections.binary_sections, results->binary_sections.binary_sections_count); bundle.sections[RDI_SectionKind_FilePathNodes] = rdim_serialized_section_make_unpacked_array(results->file_paths.nodes, results->file_paths.nodes_count); bundle.sections[RDI_SectionKind_SourceFiles] = rdim_serialized_section_make_unpacked_array(results->src_files.source_files, results->src_files.source_files_count); bundle.sections[RDI_SectionKind_LineTables] = rdim_serialized_section_make_unpacked_array(results->line_tables.line_tables, results->line_tables.line_tables_count); bundle.sections[RDI_SectionKind_LineInfoVOffs] = rdim_serialized_section_make_unpacked_array(results->line_tables.line_table_voffs, results->line_tables.line_table_voffs_count); bundle.sections[RDI_SectionKind_LineInfoLines] = rdim_serialized_section_make_unpacked_array(results->line_tables.line_table_lines, results->line_tables.line_table_lines_count); bundle.sections[RDI_SectionKind_LineInfoColumns] = rdim_serialized_section_make_unpacked_array(results->line_tables.line_table_columns, results->line_tables.line_table_columns_count); bundle.sections[RDI_SectionKind_SourceLineMaps] = rdim_serialized_section_make_unpacked_array(results->src_files.source_line_maps, results->src_files.source_line_maps_count); bundle.sections[RDI_SectionKind_SourceLineMapNumbers] = rdim_serialized_section_make_unpacked_array(results->src_files.source_line_map_nums, results->src_files.source_line_map_nums_count); 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); 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); 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); 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); bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->location_data.str, results->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); bundle.sections[RDI_SectionKind_NameMapBuckets] = rdim_serialized_section_make_unpacked_array(results->name_maps.buckets, results->name_maps.buckets_count); bundle.sections[RDI_SectionKind_NameMapNodes] = rdim_serialized_section_make_unpacked_array(results->name_maps.nodes, results->name_maps.nodes_count); return bundle; } RDI_PROC RDIM_String8List rdim_file_blobs_from_section_bundle(RDIM_Arena *arena, RDIM_SerializedSectionBundle *bundle) { RDIM_String8List strings; rdim_memzero_struct(&strings); { RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); // rjf: push empty header & data section table RDI_Header *rdi_header = rdim_push_array(arena, RDI_Header, 1); RDI_Section *rdi_sections = rdim_push_array(arena, RDI_Section, RDI_SectionKind_COUNT); rdim_str8_list_push(arena, &strings, rdim_str8_struct(rdi_header)); rdim_str8_list_push_align(arena, &strings, 8); U32 data_section_off = (U32)strings.total_size; rdim_str8_list_push(arena, &strings, rdim_str8((RDI_U8 *)rdi_sections, sizeof(RDI_Section)*RDI_SectionKind_COUNT)); // rjf: fill baked header { rdi_header->magic = RDI_MAGIC_CONSTANT; rdi_header->encoding_version = RDI_ENCODING_VERSION; rdi_header->data_section_off = data_section_off; rdi_header->data_section_count = RDI_SectionKind_COUNT; } // rjf: fill baked data section table for(RDI_SectionKind k = RDI_SectionKind_NULL; k < RDI_SectionKind_COUNT; k += 1) { RDI_Section *dst = rdi_sections+k; U64 data_section_off = 0; if(bundle->sections[k].encoded_size != 0) { rdim_str8_list_push_align(arena, &strings, 8); data_section_off = strings.total_size; rdim_str8_list_push(arena, &strings, rdim_str8((RDI_U8 *)bundle->sections[k].data, bundle->sections[k].encoded_size)); } dst->encoding = bundle->sections[k].encoding; dst->off = data_section_off; dst->encoded_size = bundle->sections[k].encoded_size; dst->unpacked_size = bundle->sections[k].unpacked_size; } rdim_scratch_end(scratch); } return strings; }