Files
raddebugger/src/raddbgi_cons/raddbgi_cons.c
T
2024-02-12 15:03:13 -08:00

3464 lines
109 KiB
C

// 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("<NIL>");
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>");
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();
}