// Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// //~ rjf: API Implementation Helper Macros #define cons_require(root, b32, else_code, error_msg) do { if(!(b32)) {cons_error((root), (error_msg)); else_code;} }while(0) #define cons_requiref(root, b32, else_code, fmt, ...) do { if(!(b32)) {cons_errorf((root), (fmt), __VA_ARGS__); else_code;} }while(0) //////////////////////////////// //~ rjf: Basic Type Helpers //- rjf: type lists static void cons_type_list_push(Arena *arena, CONS_TypeList *list, CONS_Type *type) { CONS_TypeNode *node = push_array(arena, CONS_TypeNode, 1); SLLQueuePush(list->first, list->last, node); list->count += 1; node->type = type; } //- rjf: bytecode lists static void cons_bytecode_push_op(Arena *arena, CONS_EvalBytecode *bytecode, RADDBGI_EvalOp op, U64 p) { U8 ctrlbits = raddbgi_eval_opcode_ctrlbits[op]; U32 p_size = RADDBGI_DECODEN_FROM_CTRLBITS(ctrlbits); CONS_EvalBytecodeOp *node = push_array(arena, CONS_EvalBytecodeOp, 1); node->op = op; node->p_size = p_size; node->p = p; SLLQueuePush(bytecode->first_op, bytecode->last_op, node); bytecode->op_count += 1; bytecode->encoded_size += 1 + p_size; } static void cons_bytecode_push_uconst(Arena *arena, CONS_EvalBytecode *bytecode, U64 x) { if(x <= 0xFF) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU8, x); } else if(x <= 0xFFFF) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU16, x); } else if(x <= 0xFFFFFFFF) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU32, x); } else { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU64, x); } } static void cons_bytecode_push_sconst(Arena *arena, CONS_EvalBytecode *bytecode, S64 x) { if(-0x80 <= x && x <= 0x7F) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU8, (U64)x); cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_TruncSigned, 8); } else if(-0x8000 <= x && x <= 0x7FFF) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU16, (U64)x); cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_TruncSigned, 16); } else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll) { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU32, (U64)x); cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_TruncSigned, 32); } else { cons_bytecode_push_op(arena, bytecode, RADDBGI_EvalOp_ConstU64, (U64)x); } } static void cons_bytecode_concat_in_place(CONS_EvalBytecode *left_dst, CONS_EvalBytecode *right_destroyed) { if(right_destroyed->first_op != 0) { if(left_dst->first_op == 0) { MemoryCopyStruct(left_dst, right_destroyed); } else { left_dst->last_op = right_destroyed->last_op; left_dst->op_count += right_destroyed->op_count; left_dst->encoded_size += right_destroyed->encoded_size; } MemoryZeroStruct(right_destroyed); } } //- rjf: sortable range sorting static CONS__SortKey* cons__sort_key_array(Arena *arena, CONS__SortKey *keys, 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. ProfBegin("cons__sort_key_array"); Temp scratch = scratch_begin(&arena, 1); CONS__SortKey *result = 0; if(count <= 1) { result = keys; } else { CONS__OrderedRange *ranges_first = 0; CONS__OrderedRange *ranges_last = 0; U64 range_count = 0; { U64 pos = 0; for(;pos < count;) { // identify ordered range U64 first = pos; U64 opl = pos + 1; for(; opl < count && keys[opl - 1].key <= keys[opl].key; opl += 1); // generate an ordered range node CONS__OrderedRange *new_range = push_array(scratch.arena, CONS__OrderedRange, 1); 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 { CONS__SortKey *keys_swap = push_array_no_zero(arena, CONS__SortKey, count); CONS__SortKey *src = keys; CONS__SortKey *dst = keys_swap; CONS__OrderedRange *src_ranges = ranges_first; CONS__OrderedRange *dst_ranges = 0; CONS__OrderedRange *dst_ranges_last = 0; for(;;) { // begin a pass for(;;) { // end pass when out of ranges if(src_ranges == 0) { break; } // get first range CONS__OrderedRange *range1 = src_ranges; 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) { U64 first = range1->first; MemoryCopy(dst + first, src + first, sizeof(*src)*(range1->opl - first)); SLLQueuePush(dst_ranges, dst_ranges_last, range1); break; } // get second range CONS__OrderedRange *range2 = src_ranges; SLLStackPop(src_ranges); Assert(range1->opl == range2->first); // merge these ranges U64 jd = range1->first; U64 j1 = range1->first; U64 j1_opl = range1->opl; U64 j2 = range2->first; U64 j2_opl = range2->opl; for(;;) { if(src[j1].key <= src[j2].key) { MemoryCopy(dst + jd, src + j1, sizeof(*src)); j1 += 1; jd += 1; if(j1 >= j1_opl) { break; } } else { MemoryCopy(dst + jd, src + j2, sizeof(*src)); j2 += 1; jd += 1; if(j2 >= j2_opl) { break; } } } if(j1 < j1_opl) { MemoryCopy(dst + jd, src + j1, sizeof(*src)*(j1_opl - j1)); } else { MemoryCopy(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 Swap(CONS__SortKey*, src, dst); src_ranges = dst_ranges; dst_ranges = 0; dst_ranges_last = 0; } } } sort_done:; #if 0 // assert sortedness for(U64 i = 1; i < count; i += 1){ Assert(result[i - 1].key <= result[i].key); } #endif scratch_end(scratch); ProfEnd(); return result; } //////////////////////////////// //~ rjf: Auxiliary Data Structure Functions //- rjf: u64 -> ptr map static void cons__u64toptr_init(Arena *arena, CONS__U64ToPtrMap *map, U64 bucket_count) { Assert(IsPow2OrZero(bucket_count) && bucket_count > 0); map->buckets = push_array(arena, CONS__U64ToPtrNode*, bucket_count); map->buckets_count = bucket_count; } static void cons__u64toptr_lookup(CONS__U64ToPtrMap *map, U64 key, U64 hash, CONS__U64ToPtrLookup *lookup_out) { U64 bucket_idx = hash&(map->buckets_count - 1); CONS__U64ToPtrNode *check_node = map->buckets[bucket_idx]; for(;check_node != 0; check_node = check_node->next){ for(U32 k = 0; k < ArrayCount(check_node->key); k += 1){ if(check_node->ptr[k] == 0){ lookup_out->fill_node = check_node; lookup_out->fill_k = k; break; } else if(check_node->key[k] == key){ lookup_out->match = check_node->ptr[k]; break; } } } } static void cons__u64toptr_insert(Arena *arena, CONS__U64ToPtrMap *map, U64 key, U64 hash, CONS__U64ToPtrLookup *lookup, void *ptr) { if(lookup->fill_node != 0) { CONS__U64ToPtrNode *node = lookup->fill_node; U32 k = lookup->fill_k; node->key[k] = key; node->ptr[k] = ptr; } else { U64 bucket_idx = hash&(map->buckets_count - 1); CONS__U64ToPtrNode *node = push_array(arena, CONS__U64ToPtrNode, 1); SLLStackPush(map->buckets[bucket_idx], node); node->key[0] = key; node->ptr[0] = ptr; lookup->fill_node = node; lookup->fill_k = 0; map->pair_count += 1; map->bucket_collision_count += (node->next != 0); } } //- rjf: string8 -> ptr map static void cons__str8toptr_init(Arena *arena, CONS__Str8ToPtrMap *map, U64 bucket_count) { map->buckets_count = bucket_count; map->buckets = push_array(arena, CONS__Str8ToPtrNode*, map->buckets_count); } static void* cons__str8toptr_lookup(CONS__Str8ToPtrMap *map, String8 key, U64 hash) { void *result = 0; U64 bucket_idx = hash%map->buckets_count; for(CONS__Str8ToPtrNode *node = map->buckets[bucket_idx]; node != 0; node = node->next) { if(node->hash == hash && str8_match(node->key, key, 0)) { result = node->ptr; break; } } return result; } static void cons__str8toptr_insert(Arena *arena, CONS__Str8ToPtrMap *map, String8 key, U64 hash, void *ptr) { U64 bucket_idx = hash%map->buckets_count; CONS__Str8ToPtrNode *node = push_array(arena, CONS__Str8ToPtrNode, 1); SLLStackPush(map->buckets[bucket_idx], node); node->key = push_str8_copy(arena, key); node->hash = hash; node->ptr = ptr; map->bucket_collision_count += (node->next != 0); map->pair_count += 1; } //////////////////////////////// //~ rjf: Loose Debug Info Construction (Anything -> Loose) Functions //- rjf: root creation static CONS_Root* cons_root_new(CONS_RootParams *params) { Arena *arena = arena_alloc__sized(GB(64), MB(64)); CONS_Root *result = push_array(arena, CONS_Root, 1); result->arena = arena; // fill in root parameters { result->addr_size = params->addr_size; } // setup singular types { result->nil_type = cons__type_new(result); result->variadic_type = cons__type_new(result); result->variadic_type->kind = RADDBGI_TypeKind_Variadic; // references to "handled nil type" should be emitted as // references to nil - but should not generate error // messages when they are detected - they are expected! Assert(result->nil_type->idx == result->handled_nil_type.idx); } // setup a null scope { CONS_Scope *scope = push_array(result->arena, CONS_Scope, 1); SLLQueuePush_N(result->first_scope, result->last_scope, scope, next_order); result->scope_count += 1; } // rjf: setup null UDT { cons__type_udt_from_any_type(result, result->nil_type); } // initialize maps { #define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(128)) cons__u64toptr_init(arena, &result->unit_map, BKTCOUNT(params->bucket_count_units)); cons__u64toptr_init(arena, &result->symbol_map, BKTCOUNT(params->bucket_count_symbols)); cons__u64toptr_init(arena, &result->scope_map, BKTCOUNT(params->bucket_count_scopes)); cons__u64toptr_init(arena, &result->local_map, BKTCOUNT(params->bucket_count_locals)); cons__u64toptr_init(arena, &result->type_from_id_map, BKTCOUNT(params->bucket_count_types)); cons__str8toptr_init(arena, &result->construct_map, BKTCOUNT(params->bucket_count_type_constructs)); #undef BKTCOUNT } return result; } static void cons_root_release(CONS_Root *root) { arena_release(root->arena); } //- rjf: error accumulation static void cons_error(CONS_Root *root, String8 string) { CONS_Error *error = push_array(root->arena, CONS_Error, 1); SLLQueuePush(root->errors.first, root->errors.last, error); root->errors.count += 1; error->msg = string; } static void cons_errorf(CONS_Root *root, char *fmt, ...) { va_list args; va_start(args, fmt); String8 str = push_str8fv(root->arena, fmt, args); cons_error(root, str); va_end(args); } static CONS_Error* cons_get_first_error(CONS_Root *root) { return root->errors.first; } //- rjf: top-level info specification static void cons_set_top_level_info(CONS_Root *root, CONS_TopLevelInfo *tli) { cons_requiref(root, !root->top_level_info_is_set, return, "Top level information set multiple times."); MemoryCopyStruct(&root->top_level_info, tli); root->top_level_info_is_set = 1; } //- rjf: binary section building static void cons_add_binary_section(CONS_Root *root, String8 name, RADDBGI_BinarySectionFlags flags, U64 voff_first, U64 voff_opl, U64 foff_first, U64 foff_opl) { CONS_BinarySection *sec = push_array(root->arena, CONS_BinarySection, 1); SLLQueuePush(root->binary_section_first, root->binary_section_last, sec); root->binary_section_count += 1; sec->name = name; sec->flags = flags; sec->voff_first = voff_first; sec->voff_opl = voff_opl; sec->foff_first = foff_first; sec->foff_opl = foff_opl; } //- rjf: unit info building static CONS_Unit* cons_unit_handle_from_user_id(CONS_Root *root, U64 unit_user_id, U64 unit_user_id_hash) { CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->unit_map, unit_user_id, unit_user_id_hash, &lookup); CONS_Unit *result = 0; if(lookup.match != 0) { result = (CONS_Unit*)lookup.match; } else { result = push_array(root->arena, CONS_Unit, 1); result->idx = root->unit_count; SLLQueuePush_N(root->unit_first, root->unit_last, result, next_order); root->unit_count += 1; cons__u64toptr_insert(root->arena, &root->unit_map, unit_user_id, unit_user_id, &lookup, result); } return result; } static void cons_unit_set_info(CONS_Root *root, CONS_Unit *unit, CONS_UnitInfo *info) { cons_requiref(root, !unit->info_is_set, return, "Unit information set multiple times."); unit->info_is_set = 1; unit->unit_name = push_str8_copy(root->arena, info->unit_name); unit->compiler_name = push_str8_copy(root->arena, info->compiler_name); unit->source_file = push_str8_copy(root->arena, info->source_file); unit->object_file = push_str8_copy(root->arena, info->object_file); unit->archive_file = push_str8_copy(root->arena, info->archive_file); unit->build_path = push_str8_copy(root->arena, info->build_path); unit->language = info->language; } static void cons_unit_add_line_sequence(CONS_Root *root, CONS_Unit *unit, CONS_LineSequence *line_sequence) { CONS_LineSequenceNode *node = push_array(root->arena, CONS_LineSequenceNode, 1); SLLQueuePush(unit->line_seq_first, unit->line_seq_last, node); unit->line_seq_count += 1; node->line_seq.file_name = push_str8_copy(root->arena, line_sequence->file_name); node->line_seq.voffs = push_array(root->arena, U64, line_sequence->line_count + 1); MemoryCopy(node->line_seq.voffs, line_sequence->voffs, sizeof(U64)*(line_sequence->line_count + 1)); node->line_seq.line_nums = push_array(root->arena, U32, line_sequence->line_count); MemoryCopy(node->line_seq.line_nums, line_sequence->line_nums, sizeof(U32)*line_sequence->line_count); if(line_sequence->col_nums != 0) { node->line_seq.col_nums = push_array(root->arena, U16, line_sequence->line_count); MemoryCopy(node->line_seq.col_nums, line_sequence->col_nums, sizeof(U16)*line_sequence->line_count); } node->line_seq.line_count = line_sequence->line_count; } static void cons_unit_vmap_add_range(CONS_Root *root, CONS_Unit *unit, U64 first, U64 opl) { CONS_UnitVMapRange *node = push_array(root->arena, CONS_UnitVMapRange, 1); SLLQueuePush(root->unit_vmap_range_first, root->unit_vmap_range_last, node); root->unit_vmap_range_count += 1; node->unit = unit; node->first = first; node->opl = opl; } //- rjf: type info lookups/reservations static CONS_Type* cons_type_from_id(CONS_Root *root, U64 type_user_id, U64 type_user_id_hash) { CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, type_user_id_hash, &lookup); CONS_Type *result = (CONS_Type*)lookup.match; return result; } static CONS_Reservation* cons_type_reserve_id(CONS_Root *root, U64 type_user_id, U64 type_user_id_hash) { CONS_Reservation *result = 0; CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, type_user_id_hash, &lookup); if(lookup.match == 0) { cons__u64toptr_insert(root->arena, &root->type_from_id_map, type_user_id, type_user_id_hash, &lookup, root->nil_type); void **slot = &lookup.fill_node->ptr[lookup.fill_k]; result = (CONS_Reservation*)slot; } return result; } static void cons_type_fill_id(CONS_Root *root, CONS_Reservation *res, CONS_Type *type) { if(res != 0 && type != 0) { *(void**)res = type; } } //- rjf: nil/singleton types static B32 cons_type_is_unhandled_nil(CONS_Root *root, CONS_Type *type) { B32 result = (type->kind == RADDBGI_TypeKind_NULL && type != &root->handled_nil_type); return result; } static CONS_Type* cons_type_handled_nil(CONS_Root *root) { return &root->handled_nil_type; } static CONS_Type* cons_type_nil(CONS_Root *root) { return root->nil_type; } static CONS_Type* cons_type_variadic(CONS_Root *root) { return root->variadic_type; } //- rjf: base type info constructors static CONS_Type* cons__type_new(CONS_Root *root) { CONS_Type *result = push_array(root->arena, CONS_Type, 1); result->idx = root->type_count; SLLQueuePush_N(root->first_type, root->last_type, result, next_order); root->type_count += 1; return result; } static CONS_TypeUDT* cons__type_udt_from_any_type(CONS_Root *root, CONS_Type *type) { if(type->udt == 0) { CONS_TypeUDT *new_udt = push_array(root->arena, CONS_TypeUDT, 1); new_udt->idx = root->type_udt_count; SLLQueuePush_N(root->first_udt, root->last_udt, new_udt, next_order); root->type_udt_count += 1; new_udt->self_type = type; type->udt = new_udt; } CONS_TypeUDT *result = type->udt; return result; } static CONS_TypeUDT* cons__type_udt_from_record_type(CONS_Root *root, CONS_Type *type) { cons_requiref(root, (type->kind == RADDBGI_TypeKind_Struct || type->kind == RADDBGI_TypeKind_Class || type->kind == RADDBGI_TypeKind_Union), return 0, "Tried to use non-user-defined-type-kind to create user-defined-type."); CONS_TypeUDT *result = 0; result = cons__type_udt_from_any_type(root, type); return result; } //- rjf: basic/operator type construction helpers static CONS_Type* cons_type_basic(CONS_Root *root, RADDBGI_TypeKind type_kind, String8 name) { cons_requiref(root, (RADDBGI_TypeKind_FirstBuiltIn <= type_kind && type_kind <= RADDBGI_TypeKind_LastBuiltIn), return root->nil_type, "Non-basic type kind passed to construct basic type."); CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(type_kind) + name.size; U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "basic" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Basic; ptr += sizeof(CONS_TypeConstructKind); // type_kind MemoryCopy(ptr, &type_kind, sizeof(type_kind)); ptr += sizeof(type_kind); // name MemoryCopy(ptr, name.str, name.size); ptr += name.size; } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // calculate size U32 byte_size = raddbgi_size_from_basic_type_kind(type_kind); if(byte_size == 0xFFFFFFFF) { byte_size = root->addr_size; } // setup new node result = cons__type_new(root); result->kind = type_kind; result->name = push_str8_copy(root->arena, name); result->byte_size = byte_size; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); // save in name map { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Types); cons__name_map_add_pair(root, map, result->name, result->idx); } } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_modifier(CONS_Root *root, CONS_Type *direct_type, RADDBGI_TypeModifierFlags flags) { CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(flags) + sizeof(direct_type->idx); U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "modifier" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Modifier; ptr += sizeof(CONS_TypeConstructKind); // flags MemoryCopy(ptr, &flags, sizeof(flags)); ptr += sizeof(flags); // direct_type->idx MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); ptr += sizeof(direct_type->idx); } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0){ // setup new node result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Modifier; result->flags = flags; result->byte_size = direct_type->byte_size; result->direct_type = direct_type; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_bitfield(CONS_Root *root, CONS_Type *direct_type, U32 bit_off, U32 bit_count) { CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(U32)*2; U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "bitfield" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Bitfield; ptr += sizeof(CONS_TypeConstructKind); // direct_type->idx MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); ptr += sizeof(direct_type->idx); // bit_off MemoryCopy(ptr, &bit_off, sizeof(bit_off)); ptr += sizeof(bit_off); // bit_count MemoryCopy(ptr, &bit_count, sizeof(bit_count)); ptr += sizeof(bit_count); } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // setup new node result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Bitfield; result->byte_size = direct_type->byte_size; result->off = bit_off; result->count = bit_count; result->direct_type = direct_type; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_pointer(CONS_Root *root, CONS_Type *direct_type, RADDBGI_TypeKind ptr_type_kind) { cons_requiref(root, (ptr_type_kind == RADDBGI_TypeKind_Ptr || ptr_type_kind == RADDBGI_TypeKind_LRef || ptr_type_kind == RADDBGI_TypeKind_RRef), return root->nil_type, "Non-pointer type kind used to construct pointer type."); CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(ptr_type_kind) + sizeof(direct_type->idx); U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "pointer" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Pointer; ptr += sizeof(CONS_TypeConstructKind); // type_kind MemoryCopy(ptr, &ptr_type_kind, sizeof(ptr_type_kind)); ptr += sizeof(ptr_type_kind); // direct_type->idx MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); ptr += sizeof(direct_type->idx); } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // setup new node result = cons__type_new(root); result->kind = ptr_type_kind; result->byte_size = root->addr_size; result->direct_type = direct_type; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_array(CONS_Root *root, CONS_Type *direct_type, U64 count) { CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(count); U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "array" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Array; ptr += sizeof(CONS_TypeConstructKind); // direct_type->idx MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); ptr += sizeof(direct_type->idx); // count MemoryCopy(ptr, &count, sizeof(count)); ptr += sizeof(count); } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // setup new node result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Array; result->count = count; result->direct_type = direct_type; result->byte_size = direct_type->byte_size*count; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_proc(CONS_Root *root, CONS_Type *return_type, struct CONS_TypeList *params) { CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(1 + params->count); U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "procedure" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Procedure; ptr += sizeof(CONS_TypeConstructKind); // ret_type->idx MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); ptr += sizeof(return_type->idx); // (params ...)->idx for(CONS_TypeNode *node = params->first; node != 0; node = node->next) { MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); ptr += sizeof(node->type->idx); } } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // setup param buffer CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count); { CONS_Type **ptr = param_types; for(CONS_TypeNode *node = params->first; node != 0; node = node->next) { *ptr = node->type; ptr += 1; } } // setup new node result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Function; result->byte_size = root->addr_size; result->count = params->count; result->direct_type = return_type; result->param_types = param_types; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } static CONS_Type* cons_type_method(CONS_Root *root, CONS_Type *this_type, CONS_Type *return_type, struct CONS_TypeList *params) { CONS_Type *result = root->nil_type; Temp scratch = scratch_begin(0, 0); // setup construct buffer U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(2 + params->count); U8 *buf = push_array(scratch.arena, U8, buf_size); { U8 *ptr = buf; // "method" *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Method; ptr += sizeof(CONS_TypeConstructKind); // ret_type->idx MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); ptr += sizeof(return_type->idx); // this_type->idx MemoryCopy(ptr, &this_type->idx, sizeof(this_type->idx)); ptr += sizeof(this_type->idx); // (params ...)->idx for(CONS_TypeNode *node = params->first; node != 0; node = node->next) { MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); ptr += sizeof(node->type->idx); } } // check for duplicate construct String8 blob = str8(buf, buf_size); U64 blob_hash = raddbgi_hash(buf, buf_size); void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); result = (CONS_Type*)lookup_ptr; if(result == 0) { // setup param buffer CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count + 1); { CONS_Type **ptr = param_types; { *ptr = this_type; ptr += 1; } for(CONS_TypeNode *node = params->first; node != 0; node = node->next) { *ptr = node->type; ptr += 1; } } // setup new node result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Method; result->byte_size = root->addr_size; result->count = params->count; result->direct_type = return_type; result->param_types = param_types; // save in construct map cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); } scratch_end(scratch); Assert(result != 0); return result; } //- rjf: udt type constructors static CONS_Type* cons_type_udt(CONS_Root *root, RADDBGI_TypeKind record_type_kind, String8 name, U64 size) { cons_requiref(root, (record_type_kind == RADDBGI_TypeKind_Struct || record_type_kind == RADDBGI_TypeKind_Class || record_type_kind == RADDBGI_TypeKind_Union), return root->nil_type, "Non-user-defined-type-kind used to create user-defined type."); // rjf: make type CONS_Type *result = cons__type_new(root); result->kind = record_type_kind; result->byte_size = size; result->name = push_str8_copy(root->arena, name); // rjf: save in name map { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Types); cons__name_map_add_pair(root, map, result->name, result->idx); } return result; } static CONS_Type* cons_type_enum(CONS_Root *root, CONS_Type *direct_type, String8 name) { // rjf: make type CONS_Type *result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Enum; result->byte_size = direct_type->byte_size; result->name = push_str8_copy(root->arena, name); result->direct_type = direct_type; // rjf: save in name map { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Types); cons__name_map_add_pair(root, map, result->name, result->idx); } return result; } static CONS_Type* cons_type_alias(CONS_Root *root, CONS_Type *direct_type, String8 name) { // rjf: make type CONS_Type *result = cons__type_new(root); result->kind = RADDBGI_TypeKind_Alias; result->byte_size = direct_type->byte_size; result->name = push_str8_copy(root->arena, name); result->direct_type = direct_type; // rjf: save in name map { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Types); cons__name_map_add_pair(root, map, result->name, result->idx); } return result; } static CONS_Type* cons_type_incomplete(CONS_Root *root, RADDBGI_TypeKind type_kind, String8 name) { cons_requiref(root, (type_kind == RADDBGI_TypeKind_IncompleteStruct || type_kind == RADDBGI_TypeKind_IncompleteClass || type_kind == RADDBGI_TypeKind_IncompleteUnion || type_kind == RADDBGI_TypeKind_IncompleteEnum), return root->nil_type, "Non-incomplete-type-kind used to create incomplete type."); // rjf: make type CONS_Type *result = cons__type_new(root); result->kind = type_kind; result->name = push_str8_copy(root->arena, name); // save in name map { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Types); cons__name_map_add_pair(root, map, result->name, result->idx); } return result; } //- rjf: type member building static void cons_type_add_member_data_field(CONS_Root *root, CONS_Type *record_type, String8 name, CONS_Type *mem_type, U32 off) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_DataField; member->name = push_str8_copy(root->arena, name); member->type = mem_type; member->off = off; } } static void cons_type_add_member_static_data(CONS_Root *root, CONS_Type *record_type, String8 name, CONS_Type *mem_type) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_StaticData; member->name = push_str8_copy(root->arena, name); member->type = mem_type; } } static void cons_type_add_member_method(CONS_Root *root, CONS_Type *record_type, String8 name, CONS_Type *mem_type) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_Method; member->name = push_str8_copy(root->arena, name); member->type = mem_type; } } static void cons_type_add_member_static_method(CONS_Root *root, CONS_Type *record_type, String8 name, CONS_Type *mem_type) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_StaticMethod; member->name = push_str8_copy(root->arena, name); member->type = mem_type; } } static void cons_type_add_member_virtual_method(CONS_Root *root, CONS_Type *record_type, String8 name, CONS_Type *mem_type) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_VirtualMethod; member->name = push_str8_copy(root->arena, name); member->type = mem_type; } } static void cons_type_add_member_base(CONS_Root *root, CONS_Type *record_type, CONS_Type *base_type, U32 off) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_Base; member->type = base_type; member->off = off; } } static void cons_type_add_member_virtual_base(CONS_Root *root, CONS_Type *record_type, CONS_Type *base_type, U32 vptr_off, U32 vtable_off) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_VirtualBase; member->type = base_type; // TODO(allen): what to do with the two offsets in this case? } } static void cons_type_add_member_nested_type(CONS_Root *root, CONS_Type *record_type, CONS_Type *nested_type) { CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); if(udt != 0) { CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); SLLQueuePush(udt->first_member, udt->last_member, member); udt->member_count += 1; root->total_member_count += 1; member->kind = RADDBGI_MemberKind_NestedType; member->type = nested_type; } } static void cons_type_add_enum_val(CONS_Root *root, CONS_Type *enum_type, String8 name, U64 val) { cons_requiref(root, (enum_type->kind == RADDBGI_TypeKind_Enum), return, "Tried to add enum value to non-enum type."); CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, enum_type); if(udt != 0) { CONS_TypeEnumVal *enum_val = push_array(root->arena, CONS_TypeEnumVal, 1); SLLQueuePush(udt->first_enum_val, udt->last_enum_val, enum_val); udt->enum_val_count += 1; root->total_enum_val_count += 1; enum_val->name = push_str8_copy(root->arena, name); enum_val->val = val; } } //- rjf: type source coordinate specifications static void cons_type_set_source_coordinates(CONS_Root *root, CONS_Type *defined_type, String8 source_path, U32 line, U32 col) { cons_requiref(root, (RADDBGI_TypeKind_FirstUserDefined <= defined_type->kind && defined_type->kind <= RADDBGI_TypeKind_LastUserDefined), return, "Tried to add source coordinates to non-user-defined type."); CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, defined_type); if(udt != 0) { udt->source_path = push_str8_copy(root->arena, source_path); udt->line = line; udt->col = col; } } //- rjf: symbol info building static CONS_Symbol* cons_symbol_handle_from_user_id(CONS_Root *root, U64 symbol_user_id, U64 symbol_user_id_hash) { CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->symbol_map, symbol_user_id, symbol_user_id_hash, &lookup); CONS_Symbol *result = 0; if(lookup.match != 0) { result = (CONS_Symbol*)lookup.match; } else { result = push_array(root->arena, CONS_Symbol, 1); SLLQueuePush_N(root->first_symbol, root->last_symbol, result, next_order); root->symbol_count += 1; cons__u64toptr_insert(root->arena, &root->symbol_map, symbol_user_id, symbol_user_id_hash, &lookup, result); } return result; } static void cons_symbol_set_info(CONS_Root *root, CONS_Symbol *symbol, CONS_SymbolInfo *info) { // rjf: unpack CONS_SymbolKind kind = info->kind; CONS_Symbol *container_symbol = info->container_symbol; CONS_Type *container_type = info->container_type; // rjf: requirements cons_requiref(root, CONS_SymbolKind_NULL == symbol->kind, return, "Symbol information set multiple times."); cons_requiref(root, CONS_SymbolKind_NULL < info->kind && info->kind < CONS_SymbolKind_COUNT, return, "Invalid symbol kind used to initialize symbol."); cons_requiref(root, info->type != 0, return, "Invalid type used to initialize symbol."); cons_requiref(root, info->container_symbol == 0 || info->container_type == 0, container_type = 0, "Symbol initialized with both a containing symbol and containing type, when only one is allowed."); // rjf: fill root->symbol_kind_counts[kind] += 1; symbol->idx = root->symbol_kind_counts[kind]; symbol->kind = kind; symbol->name = push_str8_copy(root->arena, info->name); symbol->link_name = push_str8_copy(root->arena, info->link_name); symbol->type = info->type; symbol->is_extern = info->is_extern; symbol->offset = info->offset; symbol->container_symbol = container_symbol; symbol->container_type = container_type; // rjf: set root scope switch(kind) { default:{}break; case CONS_SymbolKind_GlobalVariable: case CONS_SymbolKind_ThreadVariable: { cons_requiref(root, info->root_scope == 0, NoOp, "Global or thread variable initialized with root scope."); }break; case CONS_SymbolKind_Procedure: { cons_requiref(root, info->root_scope != 0, NoOp, "Procedure symbol initialized without root scope."); symbol->root_scope = info->root_scope; cons__scope_recursive_set_symbol(info->root_scope, symbol); }break; } // save name map { CONS__NameMap *map = 0; switch(kind) { default:{}break; case CONS_SymbolKind_GlobalVariable: { map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_GlobalVariables); }break; case CONS_SymbolKind_ThreadVariable: { map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_ThreadVariables); }break; case CONS_SymbolKind_Procedure: { map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_Procedures); }break; } if(map != 0) { cons__name_map_add_pair(root, map, symbol->name, symbol->idx); } } // save link name map if(kind == CONS_SymbolKind_Procedure && symbol->link_name.size > 0) { CONS__NameMap *map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_LinkNameProcedures); cons__name_map_add_pair(root, map, symbol->link_name, symbol->idx); } } //- rjf: scope info building static CONS_Scope * cons_scope_handle_from_user_id(CONS_Root *root, U64 scope_user_id, U64 scope_user_id_hash) { CONS_Scope *result = 0; CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->scope_map, scope_user_id, scope_user_id_hash, &lookup); if(lookup.match != 0) { result = (CONS_Scope*)lookup.match; } else { result = push_array(root->arena, CONS_Scope, 1); result->idx = root->scope_count; SLLQueuePush_N(root->first_scope, root->last_scope, result, next_order); root->scope_count += 1; cons__u64toptr_insert(root->arena, &root->scope_map, scope_user_id, scope_user_id_hash, &lookup, result); } return result; } static void cons_scope_set_parent(CONS_Root *root, CONS_Scope *scope, CONS_Scope *parent) { cons_requiref(root, scope->parent_scope == 0, return, "Scope parent set multiple times."); cons_requiref(root, parent != 0, return, "Tried to set invalid parent as scope parent."); scope->symbol = parent->symbol; scope->parent_scope = parent; SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); } static void cons_scope_add_voff_range(CONS_Root *root, CONS_Scope *scope, U64 voff_first, U64 voff_opl) { CONS__VOffRange *range = push_array(root->arena, CONS__VOffRange, 1); SLLQueuePush(scope->first_range, scope->last_range, range); scope->range_count += 1; range->voff_first = voff_first; range->voff_opl = voff_opl; scope->voff_base = Min(scope->voff_base, voff_first); root->scope_voff_count += 2; } static void cons__scope_recursive_set_symbol(CONS_Scope *scope, CONS_Symbol *symbol) { scope->symbol = symbol; for(CONS_Scope *node = scope->first_child; node != 0; node = node->next_sibling) { cons__scope_recursive_set_symbol(node, symbol); } } //- rjf: local info building static CONS_Local* cons_local_handle_from_user_id(CONS_Root *root, U64 local_user_id, U64 local_user_id_hash) { CONS_Local *result = 0; CONS__U64ToPtrLookup lookup = {0}; cons__u64toptr_lookup(&root->local_map, local_user_id, local_user_id_hash, &lookup); if(lookup.match != 0) { result = (CONS_Local*)lookup.match; } else { result = push_array(root->arena, CONS_Local, 1); cons__u64toptr_insert(root->arena, &root->local_map, local_user_id, local_user_id_hash, &lookup, result); } return result; } static void cons_local_set_basic_info(CONS_Root *root, CONS_Local *local, CONS_LocalInfo *info) { cons_requiref(root, local->kind == RADDBGI_LocalKind_NULL, return, "Local information set multiple times."); cons_requiref(root, info->scope != 0, return, "Tried to set invalid scope as local's containing scope."); cons_requiref(root, RADDBGI_LocalKind_NULL < info->kind && info->kind < RADDBGI_LocalKind_COUNT, return, "Invalid local kind."); cons_requiref(root, info->type != 0, return, "Tried to set invalid type as local's type."); CONS_Scope *scope = info->scope; SLLQueuePush(scope->first_local, scope->last_local, local); scope->local_count += 1; root->local_count += 1; local->kind = info->kind; local->name = push_str8_copy(root->arena, info->name); local->type = info->type; } static CONS_LocationSet* cons_location_set_from_local(CONS_Root *root, CONS_Local *local) { CONS_LocationSet *result = local->locset; if(result == 0) { local->locset = push_array(root->arena, CONS_LocationSet, 1); result = local->locset; } return result; } //- rjf: location info building static void cons_location_set_add_case(CONS_Root *root, CONS_LocationSet *locset, U64 voff_first, U64 voff_opl, CONS_Location *location) { CONS__LocationCase *location_case = push_array(root->arena, CONS__LocationCase, 1); SLLQueuePush(locset->first_location_case, locset->last_location_case, location_case); locset->location_case_count += 1; root->location_count += 1; location_case->voff_first = voff_first; location_case->voff_opl = voff_opl; location_case->location = location; } static CONS_Location* cons_location_addr_bytecode_stream(CONS_Root *root, struct CONS_EvalBytecode *bytecode) { CONS_Location *result = push_array(root->arena, CONS_Location, 1); result->kind = RADDBGI_LocationKind_AddrBytecodeStream; result->bytecode = *bytecode; return result; } static CONS_Location* cons_location_val_bytecode_stream(CONS_Root *root, struct CONS_EvalBytecode *bytecode) { CONS_Location *result = push_array(root->arena, CONS_Location, 1); result->kind = RADDBGI_LocationKind_ValBytecodeStream; result->bytecode = *bytecode; return result; } static CONS_Location* cons_location_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset) { CONS_Location *result = push_array(root->arena, CONS_Location, 1); result->kind = RADDBGI_LocationKind_AddrRegisterPlusU16; result->register_code = reg_code; result->offset = offset; return result; } static CONS_Location* cons_location_addr_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset) { CONS_Location *result = push_array(root->arena, CONS_Location, 1); result->kind = RADDBGI_LocationKind_AddrAddrRegisterPlusU16; result->register_code = reg_code; result->offset = offset; return result; } static CONS_Location* cons_location_val_reg(CONS_Root *root, U8 reg_code) { CONS_Location *result = push_array(root->arena, CONS_Location, 1); result->kind = RADDBGI_LocationKind_ValRegister; result->register_code = reg_code; return result; } //- rjf: name map building static CONS__NameMap* cons__name_map_for_kind(CONS_Root *root, RADDBGI_NameMapKind kind) { CONS__NameMap *result = 0; if(kind < RADDBGI_NameMapKind_COUNT) { if(root->name_maps[kind] == 0) { root->name_maps[kind] = push_array(root->arena, CONS__NameMap, 1); root->name_maps[kind]->buckets_count = 16384; root->name_maps[kind]->buckets = push_array(root->arena, CONS__NameMapNode *, root->name_maps[kind]->buckets_count); } result = root->name_maps[kind]; } return result; } static void cons__name_map_add_pair(CONS_Root *root, CONS__NameMap *map, String8 string, U32 idx) { // hash U64 hash = raddbgi_hash(string.str, string.size); U64 bucket_idx = hash%map->buckets_count; // find existing name node CONS__NameMapNode *match = 0; for(CONS__NameMapNode *node = map->buckets[bucket_idx]; node != 0; node = node->bucket_next) { if(str8_match(string, node->string, 0)) { match = node; break; } } // make name node if necessary if(match == 0) { match = push_array(root->arena, CONS__NameMapNode, 1); match->string = push_str8_copy(root->arena, string); SLLStackPush_N(map->buckets[bucket_idx], match, bucket_next); SLLQueuePush_N(map->first, map->last, match, order_next); map->name_count += 1; map->bucket_collision_count += (match->bucket_next != 0); } // find existing idx B32 existing_idx = 0; for(CONS__NameMapIdxNode *node = match->idx_first; node != 0; node = node->next) { for(U32 i = 0; i < ArrayCount(node->idx); i += 1) { if(node->idx[i] == 0) { break; } if(node->idx[i] == idx) { existing_idx = 1; break; } } } // insert new idx if necessary if(!existing_idx) { CONS__NameMapIdxNode *idx_node = match->idx_last; U32 insert_i = match->idx_count%ArrayCount(idx_node->idx); if(insert_i == 0) { idx_node = push_array(root->arena, CONS__NameMapIdxNode, 1); SLLQueuePush(match->idx_first, match->idx_last, idx_node); } idx_node->idx[insert_i] = idx; match->idx_count += 1; } } //////////////////////////////// //~ rjf: Debug Info Baking (Loose -> Tight) Functions //- rjf: bake context construction static CONS__BakeCtx* cons__bake_ctx_begin(CONS__BakeParams *params) { Arena *arena = arena_alloc(); CONS__BakeCtx *result = push_array(arena, CONS__BakeCtx, 1); result->arena = arena; #define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(16384)) result->strs.buckets_count = BKTCOUNT(params->strings_bucket_count); result->idxs.buckets_count = BKTCOUNT(params->idx_runs_bucket_count); #undef BKTCOUNT result->strs.buckets = push_array(arena, CONS__StringNode *, result->strs.buckets_count); result->idxs.buckets = push_array(arena, CONS__IdxRunNode *, result->idxs.buckets_count); cons__string(result, str8_lit("")); cons__idx_run(result, 0, 0); result->tree = push_array(arena, CONS__PathTree, 1); { CONS__PathNode *nil_path_node = cons__paths_new_node(result); nil_path_node->name = str8_lit(""); CONS__SrcNode *nil_src_node = cons__paths_new_src_node(result); nil_src_node->path_node = nil_path_node; nil_src_node->normal_full_path = str8_lit(""); nil_path_node->src_file = nil_src_node; } return result; } static void cons__bake_ctx_release(CONS__BakeCtx *bake_ctx) { arena_release(bake_ctx->arena); } //- rjf: string baking static U32 cons__string(CONS__BakeCtx *bctx, String8 str) { Arena *arena = bctx->arena; CONS__Strings *strs = &bctx->strs; U64 hash = raddbgi_hash(str.str, str.size); U64 bucket_idx = hash%strs->buckets_count; // look for a match CONS__StringNode *match = 0; for(CONS__StringNode *node = strs->buckets[bucket_idx]; node != 0; node = node->bucket_next) { if(node->hash == hash && str8_match(node->str, str, 0)) { match = node; break; } } // insert new node if no match if(match == 0) { CONS__StringNode *node = push_array_no_zero(arena, CONS__StringNode, 1); node->str = push_str8_copy(arena, str); node->hash = hash; node->idx = strs->count; strs->count += 1; SLLQueuePush_N(strs->order_first, strs->order_last, node, order_next); SLLStackPush_N(strs->buckets[bucket_idx], node, bucket_next); match = node; strs->bucket_collision_count += (node->bucket_next != 0); } // extract idx to return Assert(match != 0); U32 result = match->idx; return result; } //- rjf: idx run baking static U64 cons__idx_run_hash(U32 *idx_run, U32 count) { U64 hash = 5381; U32 *ptr = idx_run; U32 *opl = idx_run + count; for(;ptr < opl; ptr += 1) { hash = ((hash << 5) + hash) + (*ptr); } return(hash); } static U32 cons__idx_run(CONS__BakeCtx *bctx, U32 *idx_run, U32 count) { Arena *arena = bctx->arena; CONS__IdxRuns *idxs = &bctx->idxs; U64 hash = cons__idx_run_hash(idx_run, count); U64 bucket_idx = hash%idxs->buckets_count; // look for a match CONS__IdxRunNode *match = 0; for(CONS__IdxRunNode *node = idxs->buckets[bucket_idx]; node != 0; node = node->bucket_next) { if(node->hash == hash) { S32 is_match = 1; U32 *node_idx = node->idx_run; for(U32 i = 0; i < count; i += 1) { if(node_idx[i] != idx_run[i]) { is_match = 0; break; } } if(is_match) { match = node; break; } } } // insert new node if no match if(match == 0) { CONS__IdxRunNode *node = push_array_no_zero(arena, CONS__IdxRunNode, 1); U32 *idx_run_copy = push_array_no_zero(arena, U32, count); for(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 = idxs->idx_count; idxs->count += 1; idxs->idx_count += count; SLLQueuePush_N(idxs->order_first, idxs->order_last, node, order_next); SLLStackPush_N(idxs->buckets[bucket_idx], node, bucket_next); match = node; idxs->bucket_collision_count += (node->bucket_next != 0); } // extract idx to return Assert(match != 0); U32 result = match->first_idx; return result; } //- rjf: data section baking static U32 cons__dsection(Arena *arena, CONS__DSections *dss, void *data, U64 size, RADDBGI_DataSectionTag tag) { U32 result = dss->count; CONS__DSectionNode *node = push_array(arena, CONS__DSectionNode, 1); SLLQueuePush(dss->first, dss->last, node); node->data = data; node->size = size; node->tag = tag; dss->count += 1; return result; } //- rjf: paths baking static String8 cons__normal_string_from_path_node(Arena *arena, CONS__PathNode *node) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; if(node != 0) { cons__normal_string_from_path_node_build(scratch.arena, node, &list); } StringJoin join = {0}; join.sep = str8_lit("/"); String8 result = str8_list_join(arena, &list, &join); { U8 *ptr = result.str; U8 *opl = result.str + result.size; for(; ptr < opl; ptr += 1) { U8 c = *ptr; if('A' <= c && c <= 'Z') { c += 'a' - 'A'; } *ptr = c; } } scratch_end(scratch); return result; } static void cons__normal_string_from_path_node_build(Arena *arena, CONS__PathNode *node, String8List *out) { // TODO(rjf): why is this recursive... if(node->parent != 0) { cons__normal_string_from_path_node_build(arena, node->parent, out); } if(node->name.size > 0) { str8_list_push(arena, out, node->name); } } static CONS__PathNode* cons__paths_new_node(CONS__BakeCtx *bctx) { CONS__PathTree *tree = bctx->tree; CONS__PathNode *result = push_array(bctx->arena, CONS__PathNode, 1); SLLQueuePush_N(tree->first, tree->last, result, next_order); result->idx = tree->count; tree->count += 1; return result; } static CONS__PathNode* cons__paths_sub_path(CONS__BakeCtx *bctx, CONS__PathNode *dir, String8 sub_dir) { // look for existing match CONS__PathNode *match = 0; for(CONS__PathNode *node = dir->first_child; node != 0; node = node->next_sibling){ if(str8_match(node->name, sub_dir, StringMatchFlag_CaseInsensitive)){ match = node; break; } } // construct new node if no match CONS__PathNode *new_node = 0; if(match == 0){ new_node = cons__paths_new_node(bctx); new_node->parent = dir; SLLQueuePush_N(dir->first_child, dir->last_child, new_node, next_sibling); new_node->name = push_str8_copy(bctx->arena, sub_dir); } // select result from the two paths CONS__PathNode *result = match; if(match == 0){ result = new_node; } return result; } static CONS__PathNode* cons__paths_node_from_path(CONS__BakeCtx *bctx, String8 path) { CONS__PathNode *node_cursor = &bctx->tree->root; U8 *ptr = path.str; U8 *opl = path.str + path.size; for(;ptr < opl;){ // skip past slashes for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); // save beginning of non-slash range U8 *range_first = ptr; // skip past non-slashes for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); // if range is non-empty advance the node cursor if(range_first < ptr){ String8 sub_dir = str8_range(range_first, ptr); node_cursor = cons__paths_sub_path(bctx, node_cursor, sub_dir); } } CONS__PathNode *result = node_cursor; return result; } static U32 cons__paths_idx_from_path(CONS__BakeCtx *bctx, String8 path) { CONS__PathNode *node = cons__paths_node_from_path(bctx, path); U32 result = node->idx; return result; } static CONS__SrcNode* cons__paths_new_src_node(CONS__BakeCtx *bctx) { CONS__PathTree *tree = bctx->tree; CONS__SrcNode *result = push_array(bctx->arena, CONS__SrcNode, 1); SLLQueuePush(tree->src_first, tree->src_last, result); result->idx = tree->src_count; tree->src_count += 1; return result; } static CONS__SrcNode* cons__paths_src_node_from_path_node(CONS__BakeCtx *bctx, CONS__PathNode *path_node) { CONS__SrcNode *result = path_node->src_file; if(result == 0) { CONS__SrcNode *new_node = cons__paths_new_src_node(bctx); new_node->path_node = path_node; new_node->normal_full_path = cons__normal_string_from_path_node(bctx->arena, path_node); result = path_node->src_file = new_node; } return result; } //- rjf: per-unit line info baking static CONS__UnitLinesCombined* cons__unit_combine_lines(Arena *arena, CONS__BakeCtx *bctx, CONS_LineSequenceNode *first_seq) { ProfBegin("cons__unit_combine_lines"); Temp scratch = scratch_begin(&arena, 1); // gather up all line info into two arrays // keys: sortable array; pairs voffs with line info records; null records are sequence enders // recs: contains all the source coordinates for a range of voffs U64 line_count = 0; U64 seq_count = 0; for(CONS_LineSequenceNode *node = first_seq; node != 0; node = node->next){ seq_count += 1; line_count += node->line_seq.line_count; } U64 key_count = line_count + seq_count; CONS__SortKey *line_keys = push_array_no_zero(scratch.arena, CONS__SortKey, key_count); CONS__LineRec *line_recs = push_array_no_zero(scratch.arena, CONS__LineRec, line_count); { CONS__SortKey *key_ptr = line_keys; CONS__LineRec *rec_ptr = line_recs; for(CONS_LineSequenceNode *node = first_seq; node != 0; node = node->next){ CONS__PathNode *src_path = cons__paths_node_from_path(bctx, node->line_seq.file_name); CONS__SrcNode *src_file = cons__paths_src_node_from_path_node(bctx, src_path); U32 file_id = src_file->idx; U64 node_line_count = node->line_seq.line_count; for(U64 i = 0; i < node_line_count; i += 1){ key_ptr->key = node->line_seq.voffs[i]; key_ptr->val = rec_ptr; key_ptr += 1; rec_ptr->file_id = file_id; rec_ptr->line_num = node->line_seq.line_nums[i]; if(node->line_seq.col_nums != 0){ rec_ptr->col_first = node->line_seq.col_nums[i*2]; rec_ptr->col_opl = node->line_seq.col_nums[i*2 + 1]; } rec_ptr += 1; } key_ptr->key = node->line_seq.voffs[node_line_count]; key_ptr->val = 0; key_ptr += 1; CONS__LineMapFragment *fragment = push_array(arena, CONS__LineMapFragment, 1); SLLQueuePush(src_file->first_fragment, src_file->last_fragment, fragment); fragment->sequence = node; } } // sort CONS__SortKey *sorted_line_keys = cons__sort_key_array(scratch.arena, line_keys, key_count); // TODO(allen): 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 // arrange output U64 *arranged_voffs = push_array_no_zero(arena, U64, key_count + 1); RADDBGI_Line *arranged_lines = push_array_no_zero(arena, RADDBGI_Line, key_count); for(U64 i = 0; i < key_count; i += 1){ arranged_voffs[i] = sorted_line_keys[i].key; } arranged_voffs[key_count] = ~0ull; for(U64 i = 0; i < key_count; i += 1){ CONS__LineRec *rec = (CONS__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; } } CONS__UnitLinesCombined *result = push_array(arena, CONS__UnitLinesCombined, 1); result->voffs = arranged_voffs; result->lines = arranged_lines; result->cols = 0; result->line_count = key_count; scratch_end(scratch); ProfEnd(); return result; } //- rjf: per-src line info baking static CONS__SrcLinesCombined* cons__source_combine_lines(Arena *arena, CONS__LineMapFragment *first) { ProfBegin("cons__source_combine_lines"); Temp scratch = scratch_begin(&arena, 1); // gather line number map CONS__SrcLineMapBucket *first_bucket = 0; CONS__SrcLineMapBucket *last_bucket = 0; U64 line_hash_slots_count = 1024; CONS__SrcLineMapBucket **line_hash_slots = push_array(scratch.arena, CONS__SrcLineMapBucket *, line_hash_slots_count); U64 line_count = 0; U64 voff_count = 0; U64 max_line_num = 0; ProfScope("gather line number map") { for(CONS__LineMapFragment *map_fragment = first; map_fragment != 0; map_fragment = map_fragment->next) { CONS_LineSequence *sequence = &map_fragment->sequence->line_seq; U64 *seq_voffs = sequence->voffs; U32 *seq_line_nums = sequence->line_nums; U64 seq_line_count = sequence->line_count; for(U64 i = 0; i < seq_line_count; i += 1){ U32 line_num = seq_line_nums[i]; U64 voff = seq_voffs[i]; U64 line_hash_slot_idx = line_num%line_hash_slots_count; // update unique voff counter & max line number voff_count += 1; max_line_num = Max(max_line_num, line_num); // find match CONS__SrcLineMapBucket *match = 0; { for(CONS__SrcLineMapBucket *node = line_hash_slots[line_hash_slot_idx]; node != 0; node = node->hash_next){ if(node->line_num == line_num){ match = node; break; } } } // introduce new line if no match if(match == 0){ match = push_array(scratch.arena, CONS__SrcLineMapBucket, 1); SLLQueuePush_N(first_bucket, last_bucket, match, order_next); SLLStackPush_N(line_hash_slots[line_hash_slot_idx], match, hash_next); match->line_num = line_num; line_count += 1; } // insert new voff { CONS__SrcLineMapVoffBlock *block = push_array(scratch.arena, CONS__SrcLineMapVoffBlock, 1); SLLQueuePush(match->first_voff_block, match->last_voff_block, block); match->voff_count += 1; block->voff = voff; } } } } // bake sortable keys array CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, line_count); ProfScope("bake sortable keys array") { CONS__SortKey *key_ptr = keys; for(CONS__SrcLineMapBucket *node = first_bucket; node != 0; node = node->order_next, key_ptr += 1){ key_ptr->key = node->line_num; key_ptr->val = node; } } // sort CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, line_count); // bake result U32 *line_nums = push_array_no_zero(arena, U32, line_count); U32 *line_ranges = push_array_no_zero(arena, U32, line_count + 1); U64 *voffs = push_array_no_zero(arena, U64, voff_count); ProfScope("bake result") { U64 *voff_ptr = voffs; for(U32 i = 0; i < line_count; i += 1){ line_nums[i] = sorted_keys[i].key; line_ranges[i] = (U32)(voff_ptr - voffs); CONS__SrcLineMapBucket *bucket = (CONS__SrcLineMapBucket*)sorted_keys[i].val; for(CONS__SrcLineMapVoffBlock *node = bucket->first_voff_block; node != 0; node = node->next){ *voff_ptr = node->voff; voff_ptr += 1; } } line_ranges[line_count] = voff_count; } CONS__SrcLinesCombined *result = push_array(arena, CONS__SrcLinesCombined, 1); result->line_nums = line_nums; result->line_ranges = line_ranges; result->line_count = line_count; result->voffs = voffs; result->voff_count = voff_count; scratch_end(scratch); ProfEnd(); return result; } //- rjf: vmap baking static CONS__VMap* cons__vmap_from_markers(Arena *arena, CONS__VMapMarker *markers, CONS__SortKey *keys, U64 marker_count) { Temp scratch = scratch_begin(&arena, 1); // sort markers CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, marker_count); // determine if an extra vmap entry for zero is needed U32 extra_vmap_entry = 0; if(marker_count > 0 && sorted_keys[0].key != 0){ extra_vmap_entry = 1; } // fill output vmap entries U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; RADDBGI_VMapEntry *vmap = push_array_no_zero(arena, RADDBGI_VMapEntry, vmap_count_raw + 1); U32 vmap_entry_count_pass_1 = 0; { RADDBGI_VMapEntry *vmap_ptr = vmap; if(extra_vmap_entry){ vmap_ptr->voff = 0; vmap_ptr->idx = 0; vmap_ptr += 1; } CONS__VMapRangeTracker *tracker_stack = 0; CONS__VMapRangeTracker *tracker_free = 0; CONS__SortKey *key_ptr = sorted_keys; CONS__SortKey *key_opl = sorted_keys + marker_count; for(;key_ptr < key_opl;){ // get initial map state from tracker stack U32 initial_idx = max_U32; if(tracker_stack != 0){ initial_idx = tracker_stack->idx; } // update tracker stack // * we must process _all_ of the changes that apply at this voff before moving on U64 voff = key_ptr->key; for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1){ CONS__VMapMarker *marker = (CONS__VMapMarker*)key_ptr->val; U32 idx = marker->idx; // push to stack if(marker->begin_range){ CONS__VMapRangeTracker *new_tracker = tracker_free; if(new_tracker != 0){ SLLStackPop(tracker_free); } else{ new_tracker = push_array(scratch.arena, CONS__VMapRangeTracker, 1); } SLLStackPush(tracker_stack, new_tracker); new_tracker->idx = idx; } // pop matching node from stack (not always the top) else{ CONS__VMapRangeTracker **ptr_in = &tracker_stack; CONS__VMapRangeTracker *match = 0; for(CONS__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; SLLStackPush(tracker_free, match); } } } // get final map state from tracker stack U32 final_idx = 0; if(tracker_stack != 0){ final_idx = tracker_stack->idx; } // 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 = (U32)(vmap_ptr - vmap); } // replace zero unit indexes that follow a non-zero // TODO(rjf): 0 *is* a real unit index right now if(0) { // (the last entry is not replaced because it acts as a terminator) U32 last = vmap_entry_count_pass_1 - 1; RADDBGI_VMapEntry *vmap_ptr = vmap; U64 real_idx = 0; for(U32 i = 0; i < last; i += 1, vmap_ptr += 1){ // is this a zero after a real index? if(vmap_ptr->idx == 0){ vmap_ptr->idx = real_idx; } // remember a real index else{ real_idx = vmap_ptr->idx; } } } // combine duplicate neighbors U32 vmap_entry_count = 0; { RADDBGI_VMapEntry *vmap_ptr = vmap; RADDBGI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; RADDBGI_VMapEntry *vmap_out = vmap; for(;vmap_ptr < vmap_opl;){ RADDBGI_VMapEntry *vmap_range_first = vmap_ptr; U64 idx = vmap_ptr->idx; vmap_ptr += 1; for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; MemoryCopyStruct(vmap_out, vmap_range_first); vmap_out += 1; } vmap_entry_count = (U32)(vmap_out - vmap); } // fill result CONS__VMap *result = push_array(arena, CONS__VMap, 1); result->vmap = vmap; result->count = vmap_entry_count - 1; scratch_end(scratch); return result; } static CONS__VMap* cons__vmap_from_unit_ranges(Arena *arena, CONS_UnitVMapRange *first, U64 count) { Temp scratch = scratch_begin(&arena, 1); // count necessary markers U64 marker_count = count*2; // fill markers CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); { CONS__SortKey *key_ptr = keys; CONS__VMapMarker *marker_ptr = markers; for(CONS_UnitVMapRange *range = first; range != 0; range = range->next){ if(range->first < range->opl){ U32 unit_idx = range->unit->idx; key_ptr->key = range->first; 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->opl; key_ptr->val = marker_ptr; marker_ptr->idx = unit_idx; marker_ptr->begin_range = 0; key_ptr += 1; marker_ptr += 1; } } } // construct vmap CONS__VMap *result = cons__vmap_from_markers(arena, markers, keys, marker_count); scratch_end(scratch); return result; } //- rjf: type info baking static U32* cons__idx_run_from_types(Arena *arena, CONS_Type **types, U32 count) { U32 *result = push_array(arena, U32, count); for(U32 i = 0; i < count; i += 1){ result[i] = types[i]->idx; } return result; } static CONS__TypeData* cons__type_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx) { ProfBegin("cons__type_data_combine"); Temp scratch = scratch_begin(&arena, 1); // fill type nodes U32 type_count = root->type_count; RADDBGI_TypeNode *type_nodes = push_array_no_zero(arena, RADDBGI_TypeNode, type_count); { RADDBGI_TypeNode *ptr = type_nodes; RADDBGI_TypeNode *opl = ptr + type_count; CONS_Type *loose_type = root->first_type; for(;loose_type != 0 && ptr < opl; loose_type = loose_type->next_order, ptr += 1){ RADDBGI_TypeKind kind = loose_type->kind; // shared ptr->kind = kind; ptr->flags = loose_type->flags; ptr->byte_size = loose_type->byte_size; // built-in if(RADDBGI_TypeKind_FirstBuiltIn <= kind && kind <= RADDBGI_TypeKind_LastBuiltIn){ ptr->built_in.name_string_idx = cons__string(bctx, loose_type->name); } // constructed else if(RADDBGI_TypeKind_FirstConstructed <= kind && kind <= RADDBGI_TypeKind_LastConstructed){ ptr->constructed.direct_type_idx = loose_type->direct_type->idx; switch (kind){ case RADDBGI_TypeKind_Array: { ptr->constructed.count = loose_type->count; }break; case RADDBGI_TypeKind_Function: { // parameters U32 count = loose_type->count; U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); ptr->constructed.count = count; }break; case RADDBGI_TypeKind_Method: { // parameters U32 count = loose_type->count; U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); ptr->constructed.count = count; }break; } } // user-defined else if(RADDBGI_TypeKind_FirstUserDefined <= kind && kind <= RADDBGI_TypeKind_LastUserDefined){ ptr->user_defined.name_string_idx = cons__string(bctx, loose_type->name); if(loose_type->udt != 0){ ptr->user_defined.udt_idx = loose_type->udt->idx; } if(loose_type->direct_type != 0){ ptr->user_defined.direct_type_idx = loose_type->direct_type->idx; } } // bitfield else if(kind == RADDBGI_TypeKind_Bitfield){ ptr->bitfield.off = loose_type->off; ptr->bitfield.size = loose_type->count; } temp_end(scratch); } // both iterators should end at the same time Assert(loose_type == 0); Assert(ptr == opl); } // fill udts U32 udt_count = root->type_udt_count; RADDBGI_UDT *udts = push_array_no_zero(arena, RADDBGI_UDT, udt_count); U32 member_count = root->total_member_count; RADDBGI_Member *members = push_array_no_zero(arena, RADDBGI_Member, member_count); U32 enum_member_count = root->total_enum_val_count; RADDBGI_EnumMember *enum_members = push_array_no_zero(arena, RADDBGI_EnumMember, enum_member_count); { RADDBGI_UDT *ptr = udts; RADDBGI_UDT *opl = ptr + udt_count; RADDBGI_Member *member_ptr = members; RADDBGI_Member *member_opl = members + member_count; RADDBGI_EnumMember *enum_member_ptr = enum_members; RADDBGI_EnumMember *enum_member_opl = enum_members + enum_member_count; CONS_TypeUDT *loose_udt = root->first_udt; for(;loose_udt != 0 && ptr < opl; loose_udt = loose_udt->next_order, ptr += 1){ ptr->self_type_idx = loose_udt->self_type->idx; Assert(loose_udt->member_count == 0 || loose_udt->enum_val_count == 0); // enum members if(loose_udt->enum_val_count != 0){ ptr->flags |= RADDBGI_UserDefinedTypeFlag_EnumMembers; ptr->member_first = (U32)(enum_member_ptr - enum_members); ptr->member_count = loose_udt->enum_val_count; U32 local_enum_val_count = loose_udt->enum_val_count; CONS_TypeEnumVal *loose_enum_val = loose_udt->first_enum_val; for(U32 i = 0; i < local_enum_val_count; i += 1, enum_member_ptr += 1, loose_enum_val = loose_enum_val->next){ enum_member_ptr->name_string_idx = cons__string(bctx, loose_enum_val->name); enum_member_ptr->val = loose_enum_val->val; } } // struct/class/union members else{ ptr->member_first = (U32)(member_ptr - members); ptr->member_count = loose_udt->member_count; U32 local_member_count = loose_udt->member_count; CONS_TypeMember *loose_member = loose_udt->first_member; for(U32 i = 0; i < local_member_count; i += 1, member_ptr += 1, loose_member = loose_member->next){ member_ptr->kind = loose_member->kind; // TODO(allen): member_ptr->visibility = ; member_ptr->name_string_idx = cons__string(bctx, loose_member->name); member_ptr->off = loose_member->off; member_ptr->type_idx = loose_member->type->idx; // TODO(allen): if(loose_member->kind == RADDBGI_MemberKind_Method){ //loose_member_ptr->unit_idx = ; //loose_member_ptr->proc_symbol_idx = ; } } } U32 file_idx = 0; if(loose_udt->source_path.size > 0){ CONS__PathNode *path_node = cons__paths_node_from_path(bctx, loose_udt->source_path); CONS__SrcNode *src_node = cons__paths_src_node_from_path_node(bctx, path_node); file_idx = src_node->idx; } ptr->file_idx = file_idx; ptr->line = loose_udt->line; ptr->col = loose_udt->col; } // all iterators should end at the same time Assert(loose_udt == 0); Assert(ptr == opl); Assert(member_ptr == member_opl); Assert(enum_member_ptr == enum_member_opl); } // fill result CONS__TypeData *result = push_array(arena, CONS__TypeData, 1); result->type_nodes = type_nodes; result->type_node_count = type_count; result->udts = udts; result->udt_count = udt_count; result->members = members; result->member_count = member_count; result->enum_members = enum_members; result->enum_member_count = enum_member_count; scratch_end(scratch); ProfEnd(); return result; } //- rjf: symbol data baking static CONS__SymbolData* cons__symbol_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx) { ProfBegin("cons__symbol_data_combine"); Temp scratch = scratch_begin(&arena, 1); // count symbol kinds U32 globalvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_GlobalVariable]; U32 threadvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_ThreadVariable]; U32 procedure_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_Procedure]; // allocate symbol arrays RADDBGI_GlobalVariable *global_variables = push_array(arena, RADDBGI_GlobalVariable, globalvar_count); RADDBGI_ThreadVariable *thread_variables = push_array(arena, RADDBGI_ThreadVariable, threadvar_count); RADDBGI_Procedure *procedures = push_array(arena, RADDBGI_Procedure, procedure_count); // fill symbol arrays { RADDBGI_GlobalVariable *global_ptr = global_variables; RADDBGI_ThreadVariable *thread_local_ptr = thread_variables; RADDBGI_Procedure *procedure_ptr = procedures; // nils global_ptr += 1; thread_local_ptr += 1; procedure_ptr += 1; // symbol nodes for(CONS_Symbol *node = root->first_symbol; node != 0; node = node->next_order){ U32 name_string_idx = cons__string(bctx, node->name); U32 link_name_string_idx = cons__string(bctx, node->link_name); U32 type_idx = node->type->idx; RADDBGI_LinkFlags link_flags = 0; U32 container_idx = 0; { if(node->is_extern){ link_flags |= RADDBGI_LinkFlag_External; } if(node->container_symbol != 0){ container_idx = node->container_symbol->idx; link_flags |= RADDBGI_LinkFlag_ProcScoped; } else if(node->container_type != 0 && node->container_type->udt != 0){ container_idx = node->container_type->udt->idx; link_flags |= RADDBGI_LinkFlag_TypeScoped; } } switch (node->kind){ default:{}break; case CONS_SymbolKind_GlobalVariable: { global_ptr->name_string_idx = name_string_idx; global_ptr->link_flags = link_flags; global_ptr->voff = node->offset; global_ptr->type_idx = type_idx; global_ptr->container_idx = container_idx; global_ptr += 1; }break; case CONS_SymbolKind_ThreadVariable: { thread_local_ptr->name_string_idx = name_string_idx; thread_local_ptr->link_flags = link_flags; thread_local_ptr->tls_off = (U32)node->offset; thread_local_ptr->type_idx = type_idx; thread_local_ptr->container_idx = container_idx; thread_local_ptr += 1; }break; case CONS_SymbolKind_Procedure: { procedure_ptr->name_string_idx = name_string_idx; procedure_ptr->link_name_string_idx = link_name_string_idx; procedure_ptr->link_flags = link_flags; procedure_ptr->type_idx = type_idx; procedure_ptr->root_scope_idx = node->root_scope->idx; procedure_ptr->container_idx = container_idx; procedure_ptr += 1; }break; } } Assert(global_ptr - global_variables == globalvar_count); Assert(thread_local_ptr - thread_variables == threadvar_count); Assert(procedure_ptr - procedures == procedure_count); } // global vmap CONS__VMap *global_vmap = 0; { // count necessary markers U32 marker_count = globalvar_count*2; // fill markers CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); CONS__SortKey *key_ptr = keys; CONS__VMapMarker *marker_ptr = markers; // real globals for(CONS_Symbol *node = root->first_symbol; node != 0; node = node->next_order){ if(node->kind == CONS_SymbolKind_GlobalVariable){ U32 global_idx = node->idx; U64 first = node->offset; U64 opl = first + node->type->byte_size; 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; } } // nil global { U32 global_idx = 0; U64 first = 0; U64 opl = max_U64; 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; } // assert we filled all the markers Assert(key_ptr - keys == marker_count && marker_ptr - markers == marker_count); // construct vmap global_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); } // allocate scope array // (assert there is a nil scope) Assert(root->first_scope != 0 && root->first_scope->symbol == 0 && root->first_scope->first_child == 0 && root->first_scope->next_sibling == 0 && root->first_scope->range_count == 0); U32 scope_count = root->scope_count; RADDBGI_Scope *scopes = push_array(arena, RADDBGI_Scope, scope_count); U32 scope_voff_count = root->scope_voff_count; U64 *scope_voffs = push_array(arena, U64, scope_voff_count); U32 local_count = root->local_count; RADDBGI_Local *locals = push_array(arena, RADDBGI_Local, local_count); U32 location_block_count = root->location_count; RADDBGI_LocationBlock *location_blocks = push_array(arena, RADDBGI_LocationBlock, location_block_count); String8List location_data = {0}; // iterate scopes, locals, and locations // fill scope voffs, locals, and location information { RADDBGI_Scope *scope_ptr = scopes; U64 *scope_voff_ptr = scope_voffs; RADDBGI_Local *local_ptr = locals; RADDBGI_LocationBlock *location_block_ptr = location_blocks; for(CONS_Scope *node = root->first_scope; node != 0; node = node->next_order, scope_ptr += 1){ // emit voffs U32 voff_first = (U32)(scope_voff_ptr - scope_voffs); for(CONS__VOffRange *range = node->first_range; range != 0; range = range->next){ *scope_voff_ptr = range->voff_first; scope_voff_ptr += 1; *scope_voff_ptr = range->voff_opl; scope_voff_ptr += 1; } U32 voff_opl = (U32)(scope_voff_ptr - scope_voffs); // emit locals U32 scope_local_count = node->local_count; U32 scope_local_first = (U32)(local_ptr - locals); for(CONS_Local *slocal = node->first_local; slocal != 0; slocal = slocal->next, local_ptr += 1){ local_ptr->kind = slocal->kind; local_ptr->name_string_idx = cons__string(bctx, slocal->name); local_ptr->type_idx = slocal->type->idx; CONS_LocationSet *locset = slocal->locset; if(locset != 0){ U32 location_first = (U32)(location_block_ptr - location_blocks); U32 location_opl = location_first + locset->location_case_count; local_ptr->location_first = location_first; local_ptr->location_opl = location_opl; for(CONS__LocationCase *location_case = locset->first_location_case; location_case != 0; location_case = location_case->next){ location_block_ptr->scope_off_first = location_case->voff_first; location_block_ptr->scope_off_opl = location_case->voff_opl; location_block_ptr->location_data_off = location_data.total_size; location_block_ptr += 1; CONS_Location *location = location_case->location; if(location == 0){ U64 data = 0; str8_serial_push_align(scratch.arena, &location_data, 8); str8_serial_push_data(scratch.arena, &location_data, &data, 1); } else{ switch (location->kind){ default: { U64 data = 0; str8_serial_push_align(scratch.arena, &location_data, 8); str8_serial_push_data(scratch.arena, &location_data, &data, 1); }break; case RADDBGI_LocationKind_AddrBytecodeStream: case RADDBGI_LocationKind_ValBytecodeStream: { str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&location->kind))); for(CONS_EvalBytecodeOp *op_node = location->bytecode.first_op; op_node != 0; op_node = op_node->next){ U8 op_data[9]; op_data[0] = op_node->op; MemoryCopy(op_data + 1, &op_node->p, op_node->p_size); String8 op_data_str = str8(op_data, 1 + op_node->p_size); str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, op_data_str)); } { U64 data = 0; String8 data_str = str8((U8 *)&data, 1); str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, data_str)); } }break; case RADDBGI_LocationKind_AddrRegisterPlusU16: case RADDBGI_LocationKind_AddrAddrRegisterPlusU16: { RADDBGI_LocationRegisterPlusU16 loc = {0}; loc.kind = location->kind; loc.register_code = location->register_code; loc.offset = location->offset; str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); }break; case RADDBGI_LocationKind_ValRegister: { RADDBGI_LocationRegister loc = {0}; loc.kind = location->kind; loc.register_code = location->register_code; str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); }break; } } } Assert(location_block_ptr - location_blocks == location_opl); } } Assert(local_ptr - locals == scope_local_first + scope_local_count); // emit scope scope_ptr->proc_idx = (node->symbol == 0)?0:node->symbol->idx; scope_ptr->parent_scope_idx = (node->parent_scope == 0)?0:node->parent_scope->idx; scope_ptr->first_child_scope_idx = (node->first_child == 0)?0:node->first_child->idx; scope_ptr->next_sibling_scope_idx = (node->next_sibling == 0)?0:node->next_sibling->idx; scope_ptr->voff_range_first = voff_first; scope_ptr->voff_range_opl = voff_opl; scope_ptr->local_first = scope_local_first; scope_ptr->local_count = scope_local_count; // TODO(allen): //scope_ptr->static_local_idx_run_first = ; //scope_ptr->static_local_count = ; } Assert(scope_ptr - scopes == scope_count); Assert(local_ptr - locals == local_count); } // flatten location data String8 location_data_str = str8_list_join(arena, &location_data, 0); // scope vmap CONS__VMap *scope_vmap = 0; { // count necessary markers U32 marker_count = scope_voff_count; // fill markers CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); CONS__SortKey *key_ptr = keys; CONS__VMapMarker *marker_ptr = markers; for(CONS_Scope *node = root->first_scope; node != 0; node = node->next_order){ U32 scope_idx = node->idx; for(CONS__VOffRange *range = node->first_range; range != 0; range = range->next){ key_ptr->key = range->voff_first; key_ptr->val = marker_ptr; marker_ptr->idx = scope_idx; marker_ptr->begin_range = 1; key_ptr += 1; marker_ptr += 1; key_ptr->key = range->voff_opl; key_ptr->val = marker_ptr; marker_ptr->idx = scope_idx; marker_ptr->begin_range = 0; key_ptr += 1; marker_ptr += 1; } } scope_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); } // fill result CONS__SymbolData *result = push_array(arena, CONS__SymbolData, 1); result->global_variables = global_variables; result->global_variable_count = globalvar_count; result->global_vmap = global_vmap; result->thread_variables = thread_variables; result->thread_variable_count = threadvar_count; result->procedures = procedures; result->procedure_count = procedure_count; result->scopes = scopes; result->scope_count = scope_count; result->scope_voffs = scope_voffs; result->scope_voff_count = scope_voff_count; result->scope_vmap = scope_vmap; result->locals = locals; result->local_count = local_count; result->location_blocks = location_blocks; result->location_block_count = location_block_count; result->location_data = location_data_str.str; result->location_data_size = location_data_str.size; scratch_end(scratch); ProfEnd(); return result; } //- rjf: name map baking static CONS__NameMapBaked* cons__name_map_bake(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx, CONS__NameMap *map) { Temp scratch = scratch_begin(&arena, 1); U32 bucket_count = map->name_count; U32 node_count = map->name_count; // setup the final bucket layouts CONS__NameMapSemiBucket *sbuckets = push_array(scratch.arena, CONS__NameMapSemiBucket, bucket_count); for(CONS__NameMapNode *node = map->first; node != 0; node = node->order_next){ U64 hash = raddbgi_hash(node->string.str, node->string.size); U64 bi = hash%bucket_count; CONS__NameMapSemiNode *snode = push_array(scratch.arena, CONS__NameMapSemiNode, 1); SLLQueuePush(sbuckets[bi].first, sbuckets[bi].last, snode); snode->node = node; sbuckets[bi].count += 1; } // allocate tables RADDBGI_NameMapBucket *buckets = push_array(arena, RADDBGI_NameMapBucket, bucket_count); RADDBGI_NameMapNode *nodes = push_array_no_zero(arena, RADDBGI_NameMapNode, node_count); // convert to serialized buckets & nodes { RADDBGI_NameMapBucket *bucket_ptr = buckets; RADDBGI_NameMapNode *node_ptr = nodes; for(U32 i = 0; i < bucket_count; i += 1, bucket_ptr += 1){ bucket_ptr->first_node = (U32)(node_ptr - nodes); bucket_ptr->node_count = sbuckets[i].count; for(CONS__NameMapSemiNode *snode = sbuckets[i].first; snode != 0; snode = snode->next){ CONS__NameMapNode *node = snode->node; // cons name and index(es) U32 string_idx = cons__string(bctx, node->string); U32 match_count = node->idx_count; U32 idx = 0; if(match_count == 1){ idx = node->idx_first->idx[0]; } else{ Temp temp = temp_begin(scratch.arena); U32 *idx_run = push_array_no_zero(temp.arena, U32, match_count); U32 *idx_ptr = idx_run; for(CONS__NameMapIdxNode *idxnode = node->idx_first; idxnode != 0; idxnode = idxnode->next){ for(U32 i = 0; i < ArrayCount(idxnode->idx); i += 1){ if(idxnode->idx[i] == 0){ goto dblbreak; } *idx_ptr = idxnode->idx[i]; idx_ptr += 1; } } dblbreak:; Assert(idx_ptr == idx_run + match_count); idx = cons__idx_run(bctx, idx_run, match_count); temp_end(temp); } // 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; } } Assert(node_ptr - nodes == node_count); } scratch_end(scratch); CONS__NameMapBaked *result = push_array(arena, CONS__NameMapBaked, 1); result->buckets = buckets; result->nodes = nodes; result->bucket_count = bucket_count; result->node_count = node_count; return result; } //- rjf: top-level baking entry point static void cons_bake_file(Arena *arena, CONS_Root *root, String8List *out) { ProfBeginFunction(); str8_serial_begin(arena, out); // setup cons helpers CONS__DSections dss = {0}; cons__dsection(arena, &dss, 0, 0, RADDBGI_DataSectionTag_NULL); CONS__BakeParams bctx_params = {0}; { bctx_params.strings_bucket_count = u64_up_to_pow2(root->symbol_map.pair_count*8); bctx_params.idx_runs_bucket_count = u64_up_to_pow2(root->symbol_map.pair_count*8); } CONS__BakeCtx *bctx = cons__bake_ctx_begin(&bctx_params); //////////////////////////////// // MAIN PART: allocating and filling out sections of the file // top level info RADDBGI_TopLevelInfo *tli = push_array(arena, RADDBGI_TopLevelInfo, 1); { CONS_TopLevelInfo *cons_tli = &root->top_level_info; tli->architecture = cons_tli->architecture; tli->exe_name_string_idx = cons__string(bctx, cons_tli->exe_name); tli->exe_hash = cons_tli->exe_hash; tli->voff_max = cons_tli->voff_max; } cons__dsection(arena, &dss, tli, sizeof(*tli), RADDBGI_DataSectionTag_TopLevelInfo); // binary sections array { U32 count = root->binary_section_count; RADDBGI_BinarySection *sections = push_array(arena, RADDBGI_BinarySection, count); RADDBGI_BinarySection *dsec = sections; for(CONS_BinarySection *ssec = root->binary_section_first; ssec != 0; ssec = ssec->next, dsec += 1){ dsec->name_string_idx = cons__string(bctx, ssec->name); dsec->flags = ssec->flags; dsec->voff_first = ssec->voff_first; dsec->voff_opl = ssec->voff_opl; dsec->foff_first = ssec->foff_first; dsec->foff_opl = ssec->foff_opl; } cons__dsection(arena, &dss, sections, sizeof(*sections)*count, RADDBGI_DataSectionTag_BinarySections); } // units array // * pass for per-unit information including: // * top-level unit information // * combining line info for whole unit { U32 count = root->unit_count; RADDBGI_Unit *units = push_array(arena, RADDBGI_Unit, count); RADDBGI_Unit *dunit = units; for(CONS_Unit *sunit = root->unit_first; sunit != 0; sunit = sunit->next_order, dunit += 1){ // strings & paths U32 unit_name = cons__string(bctx, sunit->unit_name); U32 cmp_name = cons__string(bctx, sunit->compiler_name); U32 src_path = cons__paths_idx_from_path(bctx, sunit->source_file); U32 obj_path = cons__paths_idx_from_path(bctx, sunit->object_file); U32 archive_path = cons__paths_idx_from_path(bctx, sunit->archive_file); U32 build_path = cons__paths_idx_from_path(bctx, sunit->build_path); dunit->unit_name_string_idx = unit_name; dunit->compiler_name_string_idx = cmp_name; dunit->source_file_path_node = src_path; dunit->object_file_path_node = obj_path; dunit->archive_file_path_node = archive_path; dunit->build_path_node = build_path; dunit->language = sunit->language; // line info (voff -> file*line*col) CONS_LineSequenceNode *first_seq = sunit->line_seq_first; CONS__UnitLinesCombined *lines = cons__unit_combine_lines(arena, bctx, first_seq); U32 line_count = lines->line_count; if(line_count > 0){ dunit->line_info_voffs_data_idx = cons__dsection(arena, &dss, lines->voffs, sizeof(U64)*(line_count + 1), RADDBGI_DataSectionTag_LineInfoVoffs); dunit->line_info_data_idx = cons__dsection(arena, &dss, lines->lines, sizeof(RADDBGI_Line)*line_count, RADDBGI_DataSectionTag_LineInfoData); if(lines->cols != 0){ dunit->line_info_col_data_idx = cons__dsection(arena, &dss, lines->cols, sizeof(RADDBGI_Column)*line_count, RADDBGI_DataSectionTag_LineInfoColumns); } dunit->line_info_count = line_count; } } cons__dsection(arena, &dss, units, sizeof(*units)*count, RADDBGI_DataSectionTag_Units); } // source file line info baking // * pass for "source_combine_line" for each source file - // * can only be run after a pass that does "unit_combine_lines" for each unit. for(CONS__SrcNode *src_node = bctx->tree->src_first; src_node != 0; src_node = src_node->next){ CONS__LineMapFragment *first_fragment = src_node->first_fragment; CONS__SrcLinesCombined *lines = cons__source_combine_lines(arena, first_fragment); U32 line_count = lines->line_count; if(line_count > 0){ src_node->line_map_count = line_count; src_node->line_map_nums_data_idx = cons__dsection(arena, &dss, lines->line_nums, sizeof(*lines->line_nums)*line_count, RADDBGI_DataSectionTag_LineMapNumbers); src_node->line_map_range_data_idx = cons__dsection(arena, &dss, lines->line_ranges, sizeof(*lines->line_ranges)*(line_count + 1), RADDBGI_DataSectionTag_LineMapRanges); src_node->line_map_voff_data_idx = cons__dsection(arena, &dss, lines->voffs, sizeof(*lines->voffs)*lines->voff_count, RADDBGI_DataSectionTag_LineMapVoffs); } } // source file name mapping { CONS__NameMap* map = cons__name_map_for_kind(root, RADDBGI_NameMapKind_NormalSourcePaths); for(CONS__SrcNode *src_node = bctx->tree->src_first; src_node != 0; src_node = src_node->next){ if(src_node->idx != 0){ cons__name_map_add_pair(root, map, src_node->normal_full_path, src_node->idx); } } } // unit vmap baking { CONS__VMap *vmap = cons__vmap_from_unit_ranges(arena, root->unit_vmap_range_first, root->unit_vmap_range_count); U64 vmap_size = sizeof(*vmap->vmap)*(vmap->count + 1); cons__dsection(arena, &dss, vmap->vmap, vmap_size, RADDBGI_DataSectionTag_UnitVmap); } // type info baking { CONS__TypeData *types = cons__type_data_combine(arena, root, bctx); U64 type_nodes_size = sizeof(*types->type_nodes)*types->type_node_count; cons__dsection(arena, &dss, types->type_nodes, type_nodes_size, RADDBGI_DataSectionTag_TypeNodes); U64 udt_size = sizeof(*types->udts)*types->udt_count; cons__dsection(arena, &dss, types->udts, udt_size, RADDBGI_DataSectionTag_UDTs); U64 member_size = sizeof(*types->members)*types->member_count; cons__dsection(arena, &dss, types->members, member_size, RADDBGI_DataSectionTag_Members); U64 enum_member_size = sizeof(*types->enum_members)*types->enum_member_count; cons__dsection(arena, &dss, types->enum_members, enum_member_size, RADDBGI_DataSectionTag_EnumMembers); } // symbol info baking { CONS__SymbolData *symbol_data = cons__symbol_data_combine(arena, root, bctx); U64 global_variables_size = sizeof(*symbol_data->global_variables)*symbol_data->global_variable_count; cons__dsection(arena, &dss, symbol_data->global_variables, global_variables_size, RADDBGI_DataSectionTag_GlobalVariables); CONS__VMap *global_vmap = symbol_data->global_vmap; U64 global_vmap_size = sizeof(*global_vmap->vmap)*(global_vmap->count + 1); cons__dsection(arena, &dss, global_vmap->vmap, global_vmap_size, RADDBGI_DataSectionTag_GlobalVmap); U64 thread_variables_size = sizeof(*symbol_data->thread_variables)*symbol_data->thread_variable_count; cons__dsection(arena, &dss, symbol_data->thread_variables, thread_variables_size, RADDBGI_DataSectionTag_ThreadVariables); U64 procedures_size = sizeof(*symbol_data->procedures)*symbol_data->procedure_count; cons__dsection(arena, &dss, symbol_data->procedures, procedures_size, RADDBGI_DataSectionTag_Procedures); U64 scopes_size = sizeof(*symbol_data->scopes)*symbol_data->scope_count; cons__dsection(arena, &dss, symbol_data->scopes, scopes_size, RADDBGI_DataSectionTag_Scopes); U64 scope_voffs_size = sizeof(*symbol_data->scope_voffs)*symbol_data->scope_voff_count; cons__dsection(arena, &dss, symbol_data->scope_voffs, scope_voffs_size, RADDBGI_DataSectionTag_ScopeVoffData); CONS__VMap *scope_vmap = symbol_data->scope_vmap; U64 scope_vmap_size = sizeof(*scope_vmap->vmap)*(scope_vmap->count + 1); cons__dsection(arena, &dss, scope_vmap->vmap, scope_vmap_size, RADDBGI_DataSectionTag_ScopeVmap); U64 local_size = sizeof(*symbol_data->locals)*symbol_data->local_count; cons__dsection(arena, &dss, symbol_data->locals, local_size, RADDBGI_DataSectionTag_Locals); U64 location_blocks_size = sizeof(*symbol_data->location_blocks)*symbol_data->location_block_count; cons__dsection(arena, &dss, symbol_data->location_blocks, location_blocks_size, RADDBGI_DataSectionTag_LocationBlocks); U64 location_data_size = symbol_data->location_data_size; cons__dsection(arena, &dss, symbol_data->location_data, location_data_size, RADDBGI_DataSectionTag_LocationData); } // name map baking { U32 name_map_count = 0; for(U32 i = 0; i < RADDBGI_NameMapKind_COUNT; i += 1){ if(root->name_maps[i] != 0){ name_map_count += 1; } } RADDBGI_NameMap *name_maps = push_array(arena, RADDBGI_NameMap, name_map_count); RADDBGI_NameMap *name_map_ptr = name_maps; for(U32 i = 0; i < RADDBGI_NameMapKind_COUNT; i += 1){ CONS__NameMap *map = root->name_maps[i]; if(map != 0){ CONS__NameMapBaked *baked = cons__name_map_bake(arena, root, bctx, map); name_map_ptr->kind = i; name_map_ptr->bucket_data_idx = cons__dsection(arena, &dss, baked->buckets, sizeof(*baked->buckets)*baked->bucket_count, RADDBGI_DataSectionTag_NameMapBuckets); name_map_ptr->node_data_idx = cons__dsection(arena, &dss, baked->nodes, sizeof(*baked->nodes)*baked->node_count, RADDBGI_DataSectionTag_NameMapNodes); name_map_ptr += 1; } } cons__dsection(arena, &dss, name_maps, sizeof(*name_maps)*name_map_count, RADDBGI_DataSectionTag_NameMaps); } //////////////////////////////// // LATE PART: baking loose structures and creating final layout // generate data sections for file paths { U32 count = bctx->tree->count; RADDBGI_FilePathNode *nodes = push_array(arena, RADDBGI_FilePathNode, count); RADDBGI_FilePathNode *out_node = nodes; for(CONS__PathNode *node = bctx->tree->first; node != 0; node = node->next_order, out_node += 1){ out_node->name_string_idx = cons__string(bctx, node->name); if(node->parent != 0){ out_node->parent_path_node = node->parent->idx; } if(node->first_child != 0){ out_node->first_child = node->first_child->idx; } if(node->next_sibling != 0){ out_node->next_sibling = node->next_sibling->idx; } if(node->src_file != 0){ out_node->source_file_idx = node->src_file->idx; } } cons__dsection(arena, &dss, nodes, sizeof(*nodes)*count, RADDBGI_DataSectionTag_FilePathNodes); } // generate data sections for files { U32 count = bctx->tree->src_count; RADDBGI_SourceFile *src_files = push_array(arena, RADDBGI_SourceFile, count); RADDBGI_SourceFile *out_src_file = src_files; for(CONS__SrcNode *node = bctx->tree->src_first; node != 0; node = node->next, out_src_file += 1){ out_src_file->file_path_node_idx = node->path_node->idx; out_src_file->normal_full_path_string_idx = cons__string(bctx, node->normal_full_path); out_src_file->line_map_nums_data_idx = node->line_map_nums_data_idx; out_src_file->line_map_range_data_idx = node->line_map_range_data_idx; out_src_file->line_map_count = node->line_map_count; out_src_file->line_map_voff_data_idx = node->line_map_voff_data_idx; } cons__dsection(arena, &dss, src_files, sizeof(*src_files)*count, RADDBGI_DataSectionTag_SourceFiles); } // generate data sections for strings { U32 *str_offs = push_array_no_zero(arena, U32, bctx->strs.count + 1); U32 off_cursor = 0; { U32 *off_ptr = str_offs; *off_ptr = 0; off_ptr += 1; for(CONS__StringNode *node = bctx->strs.order_first; node != 0; node = node->order_next){ off_cursor += node->str.size; *off_ptr = off_cursor; off_ptr += 1; } } U8 *buf = push_array(arena, U8, off_cursor); { U8 *ptr = buf; for(CONS__StringNode *node = bctx->strs.order_first; node != 0; node = node->order_next){ MemoryCopy(ptr, node->str.str, node->str.size); ptr += node->str.size; } } cons__dsection(arena, &dss, str_offs, sizeof(*str_offs)*(bctx->strs.count + 1), RADDBGI_DataSectionTag_StringTable); cons__dsection(arena, &dss, buf, off_cursor, RADDBGI_DataSectionTag_StringData); } // generate data sections for index runs { U32 *idx_data = push_array_no_zero(arena, U32, bctx->idxs.idx_count); { U32 *out_ptr = idx_data; U32 *opl = out_ptr + bctx->idxs.idx_count; CONS__IdxRunNode *node = bctx->idxs.order_first; for(;node != 0 && out_ptr < opl; node = node->order_next){ MemoryCopy(out_ptr, node->idx_run, sizeof(*node->idx_run)*node->count); out_ptr += node->count; } Assert(out_ptr == opl); } cons__dsection(arena, &dss, idx_data, sizeof(*idx_data)*bctx->idxs.idx_count, RADDBGI_DataSectionTag_IndexRuns); } // layout // * the header and data section table have to be initialized "out of order" // * so that the rest of the system can avoid this tricky order-layout interdependence stuff RADDBGI_Header *header = push_array(arena, RADDBGI_Header, 1); RADDBGI_DataSection *dstable = push_array(arena, RADDBGI_DataSection, dss.count); str8_serial_push_align(arena, out, 8); U64 header_off = out->total_size; str8_list_push(arena, out, str8_struct(header)); str8_serial_push_align(arena, out, 8); U64 data_section_off = out->total_size; str8_list_push(arena, out, str8((U8 *)dstable, sizeof(*dstable)*dss.count)); { header->magic = RADDBGI_MAGIC_CONSTANT; header->encoding_version = RADDBGI_ENCODING_VERSION; header->data_section_off = data_section_off; header->data_section_count = dss.count; } { U64 test_dss_count = 0; for(CONS__DSectionNode *node = dss.first; node != 0; node = node->next){ test_dss_count += 1; } Assert(test_dss_count == dss.count); RADDBGI_DataSection *ptr = dstable; for(CONS__DSectionNode *node = dss.first; node != 0; node = node->next, ptr += 1){ U64 data_section_offset = 0; if(node->size != 0) { str8_serial_push_align(arena, out, 8); data_section_offset = out->total_size; str8_list_push(arena, out, str8((U8 *)node->data, node->size)); } ptr->tag = node->tag; ptr->encoding = RADDBGI_DataSectionEncoding_Unpacked; ptr->off = data_section_offset; ptr->encoded_size = node->size; ptr->unpacked_size = node->size; } Assert(ptr == dstable + dss.count); } cons__bake_ctx_release(bctx); ProfEnd(); }