d2r2 type deduplication: further work on type content hashing; correct .debug_str_offsets handling; sketch out type dependency chain build

This commit is contained in:
Ryan Fleury
2026-04-24 20:34:20 -07:00
parent 35e00de05c
commit ad0d023c93
9 changed files with 674 additions and 326 deletions
+14 -16
View File
@@ -758,34 +758,32 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
} }
internal U64 internal U64
rng_1u64_array_bsearch(Rng1U64Array arr, U64 value) rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value)
{ {
if(arr.count > 0 && arr.v[0].min < value && value < arr.v[arr.count-1].max) U64 result = 0;
if(array->count > 0 && array->v[0].min <= value && value < array->v[array->count-1].max)
{ {
U64 l = 0; U64 min_idx = 0;
U64 r = arr.count - 1; U64 max_idx = array->count - 1;
for(; l <= r; ) for(;min_idx <= max_idx;)
{ {
U64 m = l + (r - l) / 2; U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
if(contains_1u64(arr.v[m], value)) if(contains_1u64(array->v[mid_idx], value))
{ {
return m; result = mid_idx+1;
break;
} }
else if(arr.v[m].min < value) else if(array->v[mid_idx].min < value)
{ {
l = m + 1; min_idx = mid_idx + 1;
} }
else else
{ {
r = m - 1; max_idx = mid_idx - 1;
} }
} }
} }
else if(arr.count == 1 && contains_1u64(arr.v[0], value)) return result;
{
return 0;
}
return max_U64;
} }
internal void internal void
+1 -1
View File
@@ -682,7 +682,7 @@ internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); internal U64 rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value);
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
+139 -139
View File
@@ -245,9 +245,9 @@ internal U64
dw_reg_count_from_arch(Arch arch) dw_reg_count_from_arch(Arch arch)
{ {
switch (arch) { switch (arch) {
default: { NotImplemented; } // fall-through default: { NotImplemented; } // fall-through
case Arch_Null: return 0; case Arch_Null: return 0;
case Arch_x64: return DW_RegX64_Last; case Arch_x64: return DW_RegX64_Last;
} }
} }
@@ -269,9 +269,9 @@ internal U64
dw_sp_from_arch(Arch arch) dw_sp_from_arch(Arch arch)
{ {
switch (arch) { switch (arch) {
default: NotImplemented; default: NotImplemented;
case Arch_Null: return 0; case Arch_Null: return 0;
case Arch_x64: return DW_RegX64_Rsp; case Arch_x64: return DW_RegX64_Rsp;
} }
} }
@@ -280,11 +280,11 @@ internal U64
dw_size_from_format(DW_Format format) dw_size_from_format(DW_Format format)
{ {
U64 result = 0; U64 result = 0;
switch (format) { switch(format)
case DW_Format_Null: break; {
case DW_Format_32Bit: result = 4; break; case DW_Format_Null:{}break;
case DW_Format_64Bit: result = 8; break; case DW_Format_32Bit:{result = 4;}break;
default: InvalidPath; break; case DW_Format_64Bit:{result = 8;}break;
} }
return result; return result;
} }
@@ -389,11 +389,11 @@ dw_operand_count_from_expr_op(DW_ExprOp op)
switch (op) { switch (op) {
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _OPER_COUNT; #define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _OPER_COUNT;
DW_Expr_V3_XList DW_Expr_V3_XList
DW_Expr_V4_XList DW_Expr_V4_XList
DW_Expr_V5_XList DW_Expr_V5_XList
DW_Expr_GNU_XList DW_Expr_GNU_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -404,11 +404,11 @@ dw_pop_count_from_expr_op(DW_ExprOp op)
switch (op) { switch (op) {
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _POP_COUNT; #define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _POP_COUNT;
DW_Expr_V3_XList DW_Expr_V3_XList
DW_Expr_V4_XList DW_Expr_V4_XList
DW_Expr_V5_XList DW_Expr_V5_XList
DW_Expr_GNU_XList DW_Expr_GNU_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -419,11 +419,11 @@ dw_push_count_from_expr_op(DW_ExprOp op)
switch (op) { switch (op) {
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _PUSH_COUNT; #define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, ...) case _ID: return _PUSH_COUNT;
DW_Expr_V3_XList DW_Expr_V3_XList
DW_Expr_V4_XList DW_Expr_V4_XList
DW_Expr_V5_XList DW_Expr_V5_XList
DW_Expr_GNU_XList DW_Expr_GNU_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -433,12 +433,12 @@ dw_operand_types_from_expr_opcode(DW_ExprOp op)
{ {
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, _OPER_TYPE0, _OPER_TYPE1) case _ID: { local_persist DW_ExprOperandType t[] = { DW_ExprOperandType_##_OPER_TYPE0, DW_ExprOperandType_##_OPER_TYPE1 }; return t; } #define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT, _OPER_TYPE0, _OPER_TYPE1) case _ID: { local_persist DW_ExprOperandType t[] = { DW_ExprOperandType_##_OPER_TYPE0, DW_ExprOperandType_##_OPER_TYPE1 }; return t; }
switch (op) { switch (op) {
DW_Expr_V3_XList DW_Expr_V3_XList
DW_Expr_V4_XList DW_Expr_V4_XList
DW_Expr_V5_XList DW_Expr_V5_XList
DW_Expr_GNU_XList DW_Expr_GNU_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -450,7 +450,7 @@ dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode)
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return ArrayCount(t)-1; } #define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return ArrayCount(t)-1; }
DW_CFA_Kind_XList DW_CFA_Kind_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -460,21 +460,21 @@ dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode)
{ {
B32 is_invalid = 0; B32 is_invalid = 0;
switch (opcode) { switch (opcode) {
case DW_ExprOp_Addrx: case DW_ExprOp_Addrx:
case DW_ExprOp_Call2: case DW_ExprOp_Call2:
case DW_ExprOp_Call4: case DW_ExprOp_Call4:
case DW_ExprOp_CallRef: case DW_ExprOp_CallRef:
case DW_ExprOp_ConstType: case DW_ExprOp_ConstType:
case DW_ExprOp_Constx: case DW_ExprOp_Constx:
case DW_ExprOp_Convert: case DW_ExprOp_Convert:
case DW_ExprOp_DerefType: case DW_ExprOp_DerefType:
case DW_ExprOp_RegvalType: case DW_ExprOp_RegvalType:
case DW_ExprOp_Reinterpret: case DW_ExprOp_Reinterpret:
case DW_ExprOp_PushObjectAddress: case DW_ExprOp_PushObjectAddress:
case DW_ExprOp_CallFrameCfa: { case DW_ExprOp_CallFrameCfa: {
is_invalid = 1; is_invalid = 1;
} break; } break;
default: break; default: break;
} }
return is_invalid; return is_invalid;
} }
@@ -484,14 +484,14 @@ dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode)
{ {
B32 is_new_row_op = 0; B32 is_new_row_op = 0;
switch (opcode) { switch (opcode) {
case DW_CFA_SetLoc: case DW_CFA_SetLoc:
case DW_CFA_AdvanceLoc: case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1: case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2: case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: { case DW_CFA_AdvanceLoc4: {
is_new_row_op = 1; is_new_row_op = 1;
} break; } break;
default: break; default: break;
} }
return is_new_row_op; return is_new_row_op;
} }
@@ -503,7 +503,7 @@ dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode)
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return &t[0] + 1; } #define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return &t[0] + 1; }
DW_CFA_Kind_XList DW_CFA_Kind_XList
#undef X #undef X
default: { NotImplemented; } break; default: { NotImplemented; } break;
} }
return 0; return 0;
} }
@@ -512,9 +512,9 @@ internal String8
dw_string_from_format(DW_Format format) dw_string_from_format(DW_Format format)
{ {
switch (format) { switch (format) {
case DW_Format_Null: return str8_lit("NULL"); case DW_Format_Null: return str8_lit("NULL");
case DW_Format_32Bit: return str8_lit("DWARF32"); case DW_Format_32Bit: return str8_lit("DWARF32");
case DW_Format_64Bit: return str8_lit("DWARF64"); case DW_Format_64Bit: return str8_lit("DWARF64");
} }
return str8_zero(); return str8_zero();
} }
@@ -810,7 +810,7 @@ dw_string_from_cfa_opcode(DW_CFA_Opcode opcode)
#define X(_NAME, _ID, ...) case _ID: return str8_lit(Stringify(_NAME)); #define X(_NAME, _ID, ...) case _ID: return str8_lit(Stringify(_NAME));
DW_CFA_Kind_XList DW_CFA_Kind_XList
#undef X #undef X
default: InvalidPath; break; default: InvalidPath; break;
} }
return str8_zero(); return str8_zero();
} }
@@ -965,78 +965,78 @@ internal B32
dw_form_match(DW_Form a, DW_Form b) dw_form_match(DW_Form a, DW_Form b)
{ {
B32 is_match = 0; B32 is_match = 0;
if (a.kind == b.kind) { if (a.kind == b.kind) {
switch (a.kind) { switch (a.kind) {
case DW_Form_Null: {} break; case DW_Form_Null: {} break;
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break; case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break;
case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break; case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break;
case DW_Form_ExprLoc: { is_match = str8_match(a.exprloc, b.exprloc, 0); } break; case DW_Form_ExprLoc: { is_match = str8_match(a.exprloc, b.exprloc, 0); } break;
case DW_Form_Block: case DW_Form_Block:
case DW_Form_Block1: case DW_Form_Block1:
case DW_Form_Block2: case DW_Form_Block2:
case DW_Form_Block4: { case DW_Form_Block4: {
is_match = str8_match(a.block, b.block, 0); is_match = str8_match(a.block, b.block, 0);
} break; } break;
case DW_Form_Data1: case DW_Form_Data1:
case DW_Form_Data2: case DW_Form_Data2:
case DW_Form_Data4: case DW_Form_Data4:
case DW_Form_Data8: case DW_Form_Data8:
case DW_Form_Data16: { case DW_Form_Data16: {
is_match = str8_match(a.data, b.data, 0); is_match = str8_match(a.data, b.data, 0);
} break; } break;
case DW_Form_Flag: { is_match = a.flag == b.flag; } break; case DW_Form_Flag: { is_match = a.flag == b.flag; } break;
case DW_Form_SData: { is_match = a.sdata == b.sdata; } break; case DW_Form_SData: { is_match = a.sdata == b.sdata; } break;
case DW_Form_UData: { is_match = a.udata == b.udata; } break; case DW_Form_UData: { is_match = a.udata == b.udata; } break;
case DW_Form_RefAddr: case DW_Form_RefAddr:
case DW_Form_Ref1: case DW_Form_Ref1:
case DW_Form_Ref2: case DW_Form_Ref2:
case DW_Form_Ref4: case DW_Form_Ref4:
case DW_Form_Ref8: case DW_Form_Ref8:
case DW_Form_RefUData: case DW_Form_RefUData:
case DW_Form_GNU_RefAlt: { case DW_Form_GNU_RefAlt: {
is_match = a.ref == b.ref; is_match = a.ref == b.ref;
} break; } break;
case DW_Form_Indirect: { NotImplemented; } break; case DW_Form_Indirect: { NotImplemented; } break;
case DW_Form_SecOffset: case DW_Form_SecOffset:
case DW_Form_LineStrp: case DW_Form_LineStrp:
case DW_Form_GNU_StrpAlt: { case DW_Form_GNU_StrpAlt: {
is_match = a.sec_offset == b.sec_offset; is_match = a.sec_offset == b.sec_offset;
} break; } break;
case DW_Form_ImplicitConst: { is_match = a.implicit_const, b.implicit_const; } break; case DW_Form_ImplicitConst: { is_match = a.implicit_const, b.implicit_const; } break;
case DW_Form_Strx: case DW_Form_Strx:
case DW_Form_Strx1: case DW_Form_Strx1:
case DW_Form_Strx2: case DW_Form_Strx2:
case DW_Form_Strx3: case DW_Form_Strx3:
case DW_Form_Strx4: case DW_Form_Strx4:
case DW_Form_Addrx: case DW_Form_Addrx:
case DW_Form_Addrx1: case DW_Form_Addrx1:
case DW_Form_Addrx2: case DW_Form_Addrx2:
case DW_Form_Addrx3: case DW_Form_Addrx3:
case DW_Form_Addrx4: case DW_Form_Addrx4:
case DW_Form_RngListx: case DW_Form_RngListx:
case DW_Form_LocListx: { case DW_Form_LocListx: {
is_match = a.xval == b.xval; is_match = a.xval == b.xval;
} break; } break;
case DW_Form_StrpSup: { is_match = a.strp_sup == b.strp_sup; } break; case DW_Form_StrpSup: { is_match = a.strp_sup == b.strp_sup; } break;
case DW_Form_RefSup4: { NotImplemented; } break; case DW_Form_RefSup4: { NotImplemented; } break;
case DW_Form_RefSup8: { NotImplemented; } break; case DW_Form_RefSup8: { NotImplemented; } break;
default: { InvalidPath; } break; default: { InvalidPath; } break;
} }
} }
return is_match; return is_match;
} }
@@ -1044,20 +1044,20 @@ internal U64
dw_length_from_std_opcode(DW_StdOpcode opcode) dw_length_from_std_opcode(DW_StdOpcode opcode)
{ {
switch (opcode) { switch (opcode) {
case DW_StdOpcode_ExtendedOpcode: return 0; case DW_StdOpcode_ExtendedOpcode: return 0;
case DW_StdOpcode_Copy: return 0; case DW_StdOpcode_Copy: return 0;
case DW_StdOpcode_AdvancePc: return 1; case DW_StdOpcode_AdvancePc: return 1;
case DW_StdOpcode_AdvanceLine: return 1; case DW_StdOpcode_AdvanceLine: return 1;
case DW_StdOpcode_SetFile: return 1; case DW_StdOpcode_SetFile: return 1;
case DW_StdOpcode_SetColumn: return 1; case DW_StdOpcode_SetColumn: return 1;
case DW_StdOpcode_NegateStmt: return 0; case DW_StdOpcode_NegateStmt: return 0;
case DW_StdOpcode_SetBasicBlock: return 0; case DW_StdOpcode_SetBasicBlock: return 0;
case DW_StdOpcode_ConstAddPc: return 0; case DW_StdOpcode_ConstAddPc: return 0;
case DW_StdOpcode_FixedAdvancePc: return 1; case DW_StdOpcode_FixedAdvancePc: return 1;
case DW_StdOpcode_SetPrologueEnd: return 0; case DW_StdOpcode_SetPrologueEnd: return 0;
case DW_StdOpcode_SetEpilogueBegin: return 0; case DW_StdOpcode_SetEpilogueBegin: return 0;
case DW_StdOpcode_SetIsa: return 1; case DW_StdOpcode_SetIsa: return 1;
default: InvalidPath; break; default: InvalidPath; break;
} }
return 0; return 0;
} }
+8 -8
View File
@@ -2072,16 +2072,16 @@ dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64
U64 loclists_sec_off = dw_interp_sec_offset(loclists_base_attrib->form ); U64 loclists_sec_off = dw_interp_sec_offset(loclists_base_attrib->form );
// map section offset to unit index // map section offset to unit index
U64 addr_lu_idx = rng_1u64_array_bsearch(lu_input.addr_ranges, addr_sec_off ); U64 addr_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.addr_ranges, addr_sec_off );
U64 str_offsets_lu_idx = rng_1u64_array_bsearch(lu_input.str_offset_ranges, str_offsets_sec_off); U64 str_offsets_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.str_offset_ranges, str_offsets_sec_off);
U64 rnglists_lu_idx = rng_1u64_array_bsearch(lu_input.rnglist_ranges, rnglists_sec_off ); U64 rnglists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.rnglist_ranges, rnglists_sec_off );
U64 loclists_lu_idx = rng_1u64_array_bsearch(lu_input.loclist_ranges, loclists_sec_off ); U64 loclists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.loclist_ranges, loclists_sec_off );
// map index to unit // map index to unit
DW_ListUnit *addr_lu = addr_lu_idx < lu_input.addr_count ? &lu_input.addrs[addr_lu_idx] : 0; DW_ListUnit *addr_lu = 0 < (addr_lu_num && addr_lu_num <= lu_input.addr_count) ? &lu_input.addrs[addr_lu_num-1] : 0;
DW_ListUnit *str_offsets_lu = str_offsets_lu_idx < lu_input.str_offset_count ? &lu_input.str_offsets[str_offsets_lu_idx] : 0; DW_ListUnit *str_offsets_lu = 0 < (str_offsets_lu_num && str_offsets_lu_num <= lu_input.str_offset_count) ? &lu_input.str_offsets[str_offsets_lu_num-1] : 0;
DW_ListUnit *rnglists_lu = rnglists_lu_idx < lu_input.rnglist_count ? &lu_input.rnglists[rnglists_lu_idx] : 0; DW_ListUnit *rnglists_lu = 0 < (rnglists_lu_num && rnglists_lu_num <= lu_input.rnglist_count) ? &lu_input.rnglists[rnglists_lu_num-1] : 0;
DW_ListUnit *loclists_lu = loclists_lu_idx < lu_input.loclist_count ? &lu_input.loclists[loclists_lu_idx] : 0; DW_ListUnit *loclists_lu = 0 < (loclists_lu_num && loclists_lu_num <= lu_input.loclist_count) ? &lu_input.loclists[loclists_lu_num-1] : 0;
// find compile unit base address // find compile unit base address
DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LowPc); DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LowPc);
+70 -1
View File
@@ -399,8 +399,19 @@ dw2_read_form_val(DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kin
case DW_Form_Strx3: case DW_Form_Strx3:
case DW_Form_Strx4: case DW_Form_Strx4:
case DW_Form_Strx: case DW_Form_Strx:
if(ctx->str_offsets_table != 0)
{ {
// TODO(rjf) U64 entry_idx = val.u128.u64[0];
if(entry_idx < ctx->str_offsets_table->entries_count)
{
U64 entry_size = ctx->str_offsets_table->entry_size;
U64 entry_off = entry_idx * entry_size;
U64 string_data_off = 0;
MemoryCopy(&string_data_off, (U8 *)ctx->str_offsets_table->entries + entry_off, entry_size);
String8 string_section_data = ctx->raw->sec[DW_Section_Str].data;
val.string = str8_cstring_capped(string_section_data.str + string_data_off,
string_section_data.str + string_section_data.size);
}
}break; }break;
case DW_Form_LineStrp: case DW_Form_LineStrp:
{ {
@@ -545,6 +556,25 @@ dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind)
return result; return result;
} }
internal U64
dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v)
{
U64 result = 0;
switch(v->kind)
{
default:{}break;
case DW_Form_Ref1:
case DW_Form_Ref2:
case DW_Form_Ref4:
case DW_Form_Ref8:
{
result = v->u128.u64[0];
}break;
// TODO(rjf): DW_Form_RefAddr, DW_Form_RefUData, DW_Form_RefSig8, DW_Form_RefSup8, etc.
}
return result;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Line Table Parsing //~ rjf: Line Table Parsing
@@ -831,3 +861,42 @@ dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 of
scratch_end(scratch); scratch_end(scratch);
return bytes_read; return bytes_read;
} }
////////////////////////////////
//~ rjf: String Offset Table Parsing (.debug_str_offsets)
internal U64
dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out)
{
U64 start_off = off;
{
// rjf: read data length / format
U64 unit_data_length = 0;
DW_Format format = DW_Format_Null;
off += dw2_read_initial_length(data, off, &unit_data_length, &format);
U64 unit_data_off_opl = off + unit_data_length;
// rjf: read version
DW_Version version = DW_Version_Null;
off += str8_deserial_read_struct(data, off, &version);
// rjf: version 5: read rest (this section only exists in 5+)
if(version == DW_Version_5)
{
// rjf: skip padding
off += sizeof(U16);
// rjf: fill table info
out->format = format;
out->version = version;
out->entry_size = dw_size_from_format(format);
out->entries_count = (unit_data_off_opl - off) / out->entry_size;
out->entries = data.str + off;
// rjf: skip table
off = unit_data_off_opl;
}
}
U64 bytes_read = (off - start_off);
return bytes_read;
}
+20
View File
@@ -36,6 +36,19 @@ struct DW2_AbbrevMap
U64 slots_count; U64 slots_count;
}; };
////////////////////////////////
//~ rjf: String Offset Table (.debug_str_offsets)
typedef struct DW2_StrOffsetsTable DW2_StrOffsetsTable;
struct DW2_StrOffsetsTable
{
DW_Format format;
DW_Version version;
U64 entry_size;
U64 entries_count;
void *entries;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Parsing Context Bundle //~ rjf: Parsing Context Bundle
@@ -49,6 +62,7 @@ struct DW2_ParseCtx
DW_Format format; DW_Format format;
U64 addr_size; U64 addr_size;
DW2_AbbrevMap *abbrev_map; DW2_AbbrevMap *abbrev_map;
DW2_StrOffsetsTable *str_offsets_table;
String8 unit_dir; String8 unit_dir;
String8 unit_file; String8 unit_file;
}; };
@@ -210,10 +224,16 @@ internal U64 dw2_read_form_val(DW2_ParseCtx *ctx, String8 data, U64 off, DW_Form
internal U64 dw2_read_tag(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out); internal U64 dw2_read_tag(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
internal DW2_Attrib *dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind); internal DW2_Attrib *dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind);
internal U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v);
//////////////////////////////// ////////////////////////////////
//~ rjf: Line Table Parsing //~ rjf: Line Table Parsing
internal U64 dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out); internal U64 dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
////////////////////////////////
//~ rjf: String Offset Table Parsing (.debug_str_offsets)
internal U64 dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out);
#endif // DWARF_PARSE_2_H #endif // DWARF_PARSE_2_H
+4 -2
View File
@@ -2415,7 +2415,8 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
if (obj_sect_header->vsize == 0) { if (obj_sect_header->vsize == 0) {
continue; continue;
} }
sect_number = rng_1u64_array_bsearch(task->image_section_virt_ranges, obj_sect_header->voff); U64 sect_num = rng1u64_array_num_from_value__binary_search(&task->image_section_virt_ranges, obj_sect_header->voff);
sect_number = sect_num-1;
Assert(sect_number < task->image_section_virt_ranges.count); Assert(sect_number < task->image_section_virt_ranges.count);
sect_data = str8_zero(); sect_data = str8_zero();
sect_off = obj_sect_header->voff - task->image_section_virt_ranges.v[sect_number].min; sect_off = obj_sect_header->voff - task->image_section_virt_ranges.v[sect_number].min;
@@ -2424,7 +2425,8 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
if (obj_sect_header->fsize == 0) { if (obj_sect_header->fsize == 0) {
continue; continue;
} }
sect_number = rng_1u64_array_bsearch(task->image_section_file_ranges, obj_sect_header->foff); U64 sect_num = rng1u64_array_num_from_value__binary_search(&task->image_section_file_ranges, obj_sect_header->foff);
sect_number = sect_num-1;
Assert(sect_number < task->image_section_file_ranges.count); Assert(sect_number < task->image_section_file_ranges.count);
sect_data = str8_substr(task->image_data, rng_1u64(obj_sect_header->foff, obj_sect_header->foff + obj_sect_header->fsize)); sect_data = str8_substr(task->image_data, rng_1u64(obj_sect_header->foff, obj_sect_header->foff + obj_sect_header->fsize));
sect_off = obj_sect_header->foff - task->image_section_file_ranges.v[sect_number].min; sect_off = obj_sect_header->foff - task->image_section_file_ranges.v[sect_number].min;
+418 -154
View File
@@ -1,25 +1,6 @@
// Copyright (c) Epic Games Tools // Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal U64
d2r2_hash_from_seed_tag(U64 seed, DW2_Tag *tag)
{
U64 result = seed;
result = u64_hash_from_seed_str8(result, str8_struct(&tag->kind));
for EachNode(n, DW2_AttribNode, tag->attribs.first)
{
DW2_Attrib *attrib = &n->v;
result = u64_hash_from_seed_str8(result, str8_struct(&attrib->attrib_kind));
result = u64_hash_from_seed_str8(result, str8_struct(&attrib->val.kind));
result = u64_hash_from_seed_str8(result, attrib->val.string);
result = u64_hash_from_seed_str8(result, str8_struct(&attrib->val.u128));
}
return result;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Conversion Entry Point (New) //~ rjf: Main Conversion Entry Point (New)
@@ -276,6 +257,86 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
} }
lane_sync(); lane_sync();
////////////////////////////
//- rjf: parse all string offsets tables
//
// in an incredible twist of fate, DWARF decided to decouple these from
// compilation units. compilation units *do* contain a
// DW_AttribKind_StrOffsetsBase attribute. but this base offset does *not*
// point to the beginning of a table in .debug_str_offsets! it instead points
// PAST THE INITIAL VARIABLE-WIDTH LENGTH AND FORMAT ENCODING! this means
// you can't actually use the StrOffsetsBase attribute for ANYTHING other
// than correllating a unit to its associated string offset table - but you
// *necessarily needed to have parsed that table beforehand*, completely
// independently from units.
//
// so, we have to parse all the string offset tables up-front, then
// *binary search* their ranges to determine which unit has which table.
//
// of course, in practice, it's perhaps likely/expected that these match
// one-to-one with units, and in the same order, because that is what is
// most natural for generators. but, the format does not *guarantee this*,
// and instead specced something far more arbitrary.
//
// thank you, again, DWARF.
//
U64 str_offsets_tables_count = 0;
DW2_StrOffsetsTable *str_offsets_tables = 0;
Rng1U64 *str_offsets_tables_ranges = 0;
ProfScope("parse all string offsets tables") if(lane_idx() == 0)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
//- rjf: gather all tables (loose)
typedef struct TableNode TableNode;
struct TableNode
{
TableNode *next;
DW2_StrOffsetsTable v;
Rng1U64 range;
};
TableNode *first_table = 0;
TableNode *last_table = 0;
U64 table_count = 0;
for(U64 off = 0; off < raw->sec[DW_Section_StrOffsets].data.size;)
{
U64 start_off = off;
DW2_StrOffsetsTable table = {0};
off += dw2_read_str_offsets_table(raw->sec[DW_Section_StrOffsets].data, off, &table);
if(table.entries != 0)
{
TableNode *n = push_array(scratch2.arena, TableNode, 1);
SLLQueuePush(first_table, last_table, n);
n->v = table;
n->range = r1u64(start_off, off);
table_count += 1;
}
if(off == start_off)
{
break;
}
}
//- rjf: tighten
str_offsets_tables_count = table_count;
str_offsets_tables = push_array(scratch.arena, DW2_StrOffsetsTable, str_offsets_tables_count);
str_offsets_tables_ranges = push_array(scratch.arena, Rng1U64, str_offsets_tables_count);
{
U64 idx = 0;
for EachNode(n, TableNode, first_table)
{
str_offsets_tables[idx] = n->v;
str_offsets_tables_ranges[idx] = n->range;
idx += 1;
}
}
scratch_end(scratch2);
}
lane_sync_u64(&str_offsets_tables_count, 0);
lane_sync_u64(&str_offsets_tables, 0);
lane_sync_u64(&str_offsets_tables_ranges, 0);
//////////////////////////// ////////////////////////////
//- rjf: build per-unit parsing contexts //- rjf: build per-unit parsing contexts
// //
@@ -301,7 +362,58 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
lane_sync(); lane_sync();
//////////////////////////// ////////////////////////////
//- rjf: parse each unit's root-level tag //- rjf: do initial parse of each unit's root-level tag
//
// an incredible NOTE: this is actually not sufficient. because this tag parse
// is what informs us which .debug_str_offsets table each unit should be associated
// with (via the StrOffsetsBase attribute), we actually don't have the right string
// offset table *before* we parse this, which means we can't resolve some of the
// string attribute values.
//
// so, in another incredible twist of fate, we actually must do this *twice*. first,
// to find *just the StrOffsetsBase*, and then, to actually fully resolve everything.
//
DW2_Tag *unit_root_tags__pre_str_offsets = 0;
{
if(lane_idx() == 0)
{
unit_root_tags__pre_str_offsets = push_array(scratch.arena, DW2_Tag, unit_count);
}
lane_sync_u64(&unit_root_tags__pre_str_offsets, 0);
Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range)
{
dw2_read_tag(scratch.arena, &unit_parse_ctxs[unit_idx], raw->sec[DW_Section_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags__pre_str_offsets[unit_idx]);
}
}
lane_sync();
////////////////////////////
//- rjf: look up string offset tables for each unit (.debug_str_offsets);
// equip to per-unit parsing contexts
//
{
Rng1U64Array str_offsets_tables_ranges_array = {str_offsets_tables_ranges, str_offsets_tables_count};
Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range)
{
DW2_Tag *unit_root_tag = &unit_root_tags__pre_str_offsets[unit_idx];
DW2_Attrib *str_offsets_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StrOffsetsBase);
U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0];
U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off);
if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count)
{
DW2_StrOffsetsTable *table = &str_offsets_tables[str_offsets_table_num-1];
unit_parse_ctxs[unit_idx].str_offsets_table = table;
}
}
}
lane_sync();
////////////////////////////
//- rjf: do parse of each unit's root tag AFTER finding the right .debug_str_offsets table
//
// (excellent work everyone - thank you for reminding me why RDI is necessary)
// //
DW2_Tag *unit_root_tags = 0; DW2_Tag *unit_root_tags = 0;
{ {
@@ -888,9 +1000,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
U64 total_tag_count_estimate = 1; U64 total_tag_count_estimate = 1;
{ {
U64 tag_size_estimate = 32; U64 tag_size_estimate = 32;
for EachIndex(unit_idx, unit_info_ranges->count) for EachIndex(unit_idx, unit_count)
{ {
total_tag_count_estimate += dim_1u64(unit_info_ranges->v[unit_idx]) / tag_size_estimate; total_tag_count_estimate += dim_1u64(unit_info_tag_ranges[unit_idx]) / tag_size_estimate;
} }
} }
@@ -921,6 +1033,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
UniqueTypeTagNode **unique_type_tag_slots = 0; UniqueTypeTagNode **unique_type_tag_slots = 0;
U64 unique_type_tag_slots_count = total_tag_count_estimate/8 + 1; U64 unique_type_tag_slots_count = total_tag_count_estimate/8 + 1;
UnitTypeMap *unit_type_maps = 0; UnitTypeMap *unit_type_maps = 0;
ProfScope("gather all unique type tags across all units")
{ {
if(lane_idx() == 0) if(lane_idx() == 0)
{ {
@@ -935,167 +1048,231 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
for(;;) for(;;)
{ {
//- rjf: take next unit //- rjf: take next unit
U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr) - 1; U64 origin_unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr) - 1;
if(unit_idx >= unit_count) if(origin_unit_idx >= unit_count)
{ {
break; break;
} }
//- rjf: unpack unit //- rjf: unpack unit info
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx]; Rng1U64 origin_unit_info_tag_range = unit_info_tag_ranges[origin_unit_idx];
Rng1U64 unit_info_range = unit_info_ranges->v[unit_idx];
//- rjf: set up type map for this unit //- rjf: set up type map for this unit
unit_type_maps[unit_idx].slots_count = dim_1u64(unit_info_range) / 256 + 1; unit_type_maps[origin_unit_idx].slots_count = dim_1u64(origin_unit_info_tag_range) / 256 + 1;
unit_type_maps[unit_idx].slots = push_array(scratch.arena, UnitTypeNode *, unit_type_maps[unit_idx].slots_count); unit_type_maps[origin_unit_idx].slots = push_array(scratch.arena, UnitTypeNode *, unit_type_maps[origin_unit_idx].slots_count);
//- rjf: find all type tags in this unit //- rjf: hash all type content from tags in this unit; record if unique
for(U64 off = unit_info_range.min; off < unit_info_range.max;) for(U64 off = origin_unit_info_tag_range.min; off < origin_unit_info_tag_range.max;)
{ {
Temp scratch2 = scratch_begin(&scratch.arena, 1); Temp scratch2 = scratch_begin(&scratch.arena, 1);
U64 start_off = off; U64 start_off = off;
// rjf: read next tag //- rjf: hash type tags - this requires a hash of not only type tags'
DW2_Tag tag = {0}; // attributes, but also a walk of all other type tags this tag references,
off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag); // and a hash of them too. so we produce a list of tasks for
// parsing/hashing tags, in order to find the full comprehensive hash
// for each type tag.
//
B32 is_type_tag_tree = 0;
U64 hash = 0;
{
typedef struct TypeTagTask TypeTagTask;
struct TypeTagTask
{
TypeTagTask *next;
U64 unit_idx;
U64 off;
};
TypeTagTask start_task = {0, origin_unit_idx, off};
TypeTagTask *first_task = &start_task;
TypeTagTask *last_task = first_task;
TypeTagTask *free_task = 0;
for(TypeTagTask *t = first_task; t != 0; t = t->next)
{
U64 t_off = t->off;
// rjf: unpack unit
Rng1U64 unit_info_range = unit_info_ranges->v[t->unit_idx];
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[t->unit_idx];
// rjf: read/hash the full tag tree at `t_off`; kick off additional
// tasks for referenced dependency types
U64 depth = 0;
for(;unit_info_range.min <= t_off && t_off < unit_info_range.max;)
{
U64 t_start_off = t_off;
// rjf: read tag
DW2_Tag tag = {0};
t_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, t_off, &tag);
// rjf: record top-level info about this tag tree
if(t_start_off == t->off && t == &start_task)
{
is_type_tag_tree = (tag.kind == DW_TagKind_ArrayType || tag.kind == DW_TagKind_ClassType ||
tag.kind == DW_TagKind_EnumerationType || tag.kind == DW_TagKind_PointerType ||
tag.kind == DW_TagKind_ReferenceType || tag.kind == DW_TagKind_StringType ||
tag.kind == DW_TagKind_StructureType || tag.kind == DW_TagKind_SubroutineType ||
tag.kind == DW_TagKind_Typedef || tag.kind == DW_TagKind_UnionType ||
tag.kind == DW_TagKind_PtrToMemberType || tag.kind == DW_TagKind_SetType ||
tag.kind == DW_TagKind_SubrangeType || tag.kind == DW_TagKind_BaseType ||
tag.kind == DW_TagKind_ConstType || tag.kind == DW_TagKind_FileType ||
tag.kind == DW_TagKind_PackedType || tag.kind == DW_TagKind_VolatileType ||
tag.kind == DW_TagKind_RestrictType || tag.kind == DW_TagKind_InterfaceType ||
tag.kind == DW_TagKind_UnspecifiedType || tag.kind == DW_TagKind_SharedType ||
tag.kind == DW_TagKind_RValueReferenceType || tag.kind == DW_TagKind_CoarrayType ||
tag.kind == DW_TagKind_DynamicType || tag.kind == DW_TagKind_AtomicType ||
tag.kind == DW_TagKind_ImmutableType);
}
// rjf: is type -> combine tag's content into hash
if(is_type_tag_tree)
{
// rjf: combine tag's kind
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag.kind));
// rjf: combine non-reference attributes (references could be different,
// because of deduping, but they could match ultimately). for any
// referenced dependency types, kick them off
for(DW2_AttribNode *n = tag.attribs.first; n != 0; n = n->next)
{
if(n->v.val.kind != DW_Form_RefAddr &&
n->v.val.kind != DW_Form_Ref1 &&
n->v.val.kind != DW_Form_Ref2 &&
n->v.val.kind != DW_Form_Ref4 &&
n->v.val.kind != DW_Form_Ref8 &&
n->v.val.kind != DW_Form_RefUData &&
n->v.val.kind != DW_Form_RefSup4 &&
n->v.val.kind != DW_Form_RefSig8)
{
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.kind));
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.u128));
hash = u64_hash_from_seed_str8(hash, n->v.val.string);
}
if(n->v.attrib_kind == DW_AttribKind_Type)
{
TypeTagTask *dependency_task = free_task;
if(dependency_task != 0)
{
SLLStackPop(free_task);
}
else
{
dependency_task = push_array(scratch2.arena, TypeTagTask, 1);
}
dependency_task->off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &n->v.val);
dependency_task->unit_idx = t->unit_idx;
if(!contains_1u64(unit_info_range, dependency_task->off))
{
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(unit_info_ranges, dependency_task->off);
if(0 < new_unit_num && new_unit_num <= unit_count)
{
dependency_task->unit_idx = new_unit_num-1;
}
}
}
}
}
// rjf: is type tag tree, has children -> descend
if(is_type_tag_tree && tag.has_children)
{
depth += 1;
}
// rjf: zero tag kind -> ascend
if(is_type_tag_tree && tag.kind == DW_TagKind_Null && depth > 0)
{
depth -= 1;
}
// rjf: no advancing? -> +1
if(t_off == t_start_off)
{
t_off += 1;
}
// rjf: depth == 0? -> done
if(depth == 0)
{
break;
}
}
// rjf: is this the starter task? -> advance base reading offset
if(t == &start_task)
{
off = t_off;
}
}
}
// rjf: if offset not advanced -> increment //- rjf: if offset not advanced -> increment
if(off == start_off) if(off == start_off)
{ {
off += 1; off += 1;
} }
// rjf: if type tag -> read full tree, hash, gather //- rjf: atomically gather this hash if not already gathered
switch(tag.kind) if(is_type_tag_tree)
{ {
default:{}break; B32 gathered = 0;
case DW_TagKind_ArrayType: U64 slot_idx = hash%unique_type_tag_slots_count;
case DW_TagKind_ClassType: for(;!gathered;)
case DW_TagKind_EnumerationType:
case DW_TagKind_PointerType:
case DW_TagKind_ReferenceType:
case DW_TagKind_StringType:
case DW_TagKind_StructureType:
case DW_TagKind_SubroutineType:
case DW_TagKind_Typedef:
case DW_TagKind_UnionType:
case DW_TagKind_PtrToMemberType:
case DW_TagKind_SetType:
case DW_TagKind_SubrangeType:
case DW_TagKind_BaseType:
case DW_TagKind_ConstType:
case DW_TagKind_FileType:
case DW_TagKind_PackedType:
case DW_TagKind_VolatileType:
case DW_TagKind_RestrictType:
case DW_TagKind_InterfaceType:
case DW_TagKind_UnspecifiedType:
case DW_TagKind_SharedType:
case DW_TagKind_RValueReferenceType:
case DW_TagKind_CoarrayType:
case DW_TagKind_DynamicType:
case DW_TagKind_AtomicType:
case DW_TagKind_ImmutableType:
{ {
// rjf: form hash from top-level tag // rjf: read existing slot head pointer *before* we lookup / insert
U64 hash = d2r2_hash_from_seed_tag(5381, &tag); U64 slot_head_val = ins_atomic_u64_eval(&unique_type_tag_slots[slot_idx]);
// rjf: if this tag has children -> hash all children, combine into `hash` // rjf: determine if this hash has been gathered
if(tag.has_children) for(UniqueTypeTagNode *n = (UniqueTypeTagNode *)slot_head_val; n != 0; n = n->next)
{ {
U64 depth = 1; if(n->hash == hash)
for(;off < unit_info_range.max && depth > 0;)
{ {
Temp temp = temp_begin(scratch2.arena); gathered = 1;
U64 start_off_2 = off; break;
// rjf: read descendant tag
DW2_Tag descendant_tag = {0};
off += dw2_read_tag(temp.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &descendant_tag);
// rjf: if offset not advanced -> increment
if(off == start_off_2)
{
off += 1;
}
// rjf: combine hash of descendant tag to main hash
hash = d2r2_hash_from_seed_tag(hash, &descendant_tag);
// rjf: navigate the tree
if(descendant_tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
else if(descendant_tag.has_children)
{
depth += 1;
}
temp_end(temp);
} }
} }
// rjf: atomically gather this hash if not already gathered // rjf: if this hash has *not* been gathered, try an insert. we:
//
// 1. allocate/fill a node
// 2. set it up to point to the old head
// 3. compare/exchange the old head with the new head - IFF the head matches what we expect from above
// 4. if we fail, another thread has touched this slot, we pop the allocated node & try again
// (we may find that another thread has filled this hash, so we'll just be done)
//
if(!gathered)
{ {
B32 gathered = 0; Temp insert_temp = temp_begin(scratch.arena);
U64 slot_idx = hash%unique_type_tag_slots_count; UniqueTypeTagNode *n = push_array(scratch.arena, UniqueTypeTagNode, 1);
for(;!gathered;) n->next = (UniqueTypeTagNode *)slot_head_val;
n->hash = hash;
n->unit_idx = origin_unit_idx;
n->info_off = start_off;
U64 new_head_val = (U64)n;
if(slot_head_val == ins_atomic_u64_eval_cond_assign(&unique_type_tag_slots[slot_idx], new_head_val, slot_head_val))
{ {
// rjf: read existing slot head pointer *before* we lookup / insert gathered = 1;
U64 slot_head_val = ins_atomic_u64_eval(&unique_type_tag_slots[slot_idx]); }
else
// rjf: determine if this hash has been gathered {
for(UniqueTypeTagNode *n = (UniqueTypeTagNode *)slot_head_val; n != 0; n = n->next) temp_end(insert_temp);
{
if(n->hash == hash)
{
gathered = 1;
break;
}
}
// rjf: if this hash has *not* been gathered, try an insert. we:
//
// 1. allocate/fill a node
// 2. set it up to point to the old head
// 3. compare/exchange the old head with the new head - IFF the head matches what we expect from above
// 4. if we fail, another thread has touched this slot, we pop the allocated node & try again
// (we may find that another thread has filled this hash, so we'll just be done)
//
if(!gathered)
{
Temp insert_temp = temp_begin(scratch.arena);
UniqueTypeTagNode *n = push_array(scratch.arena, UniqueTypeTagNode, 1);
n->next = (UniqueTypeTagNode *)slot_head_val;
n->hash = hash;
n->unit_idx = unit_idx;
n->info_off = start_off;
U64 new_head_val = (U64)n;
if(slot_head_val == ins_atomic_u64_eval_cond_assign(&unique_type_tag_slots[slot_idx], slot_head_val, new_head_val))
{
gathered = 1;
}
else
{
temp_end(insert_temp);
}
}
} }
} }
}
// rjf: record this (info_off -> hash) mapping, so that when we have }
// later references to this type, we can redirect to the deduplicated
// type with the right hash later. //- rjf: record this (info_off -> hash) mapping, so that when we have
{ // later references to this type, we can redirect to the deduplicated
U64 info_off_hash = u64_hash_from_str8(str8_struct(&start_off)); // type with the right hash later.
U64 info_off_slot_idx = info_off_hash%unit_type_maps[unit_idx].slots_count; if(is_type_tag_tree)
UnitTypeNode *n = push_array(scratch.arena, UnitTypeNode, 1); {
n->src_info_off = start_off; U64 info_off_hash = u64_hash_from_str8(str8_struct(&start_off));
n->dst_hash = hash; U64 info_off_slot_idx = info_off_hash%unit_type_maps[origin_unit_idx].slots_count;
SLLStackPush(unit_type_maps[unit_idx].slots[info_off_slot_idx], n); UnitTypeNode *n = push_array(scratch.arena, UnitTypeNode, 1);
} n->src_info_off = start_off;
}break; n->dst_hash = hash;
SLLStackPush(unit_type_maps[origin_unit_idx].slots[info_off_slot_idx], n);
} }
scratch_end(scratch2); scratch_end(scratch2);
@@ -1104,6 +1281,93 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
lane_sync(); lane_sync();
} }
////////////////////////////
//- rjf: produce [0...n) -> unique-tag-node mapping for all types
//
U64 type_count = 0;
UniqueTypeTagNode **type_tag_nodes = 0;
ProfScope("produce [0...n) -> hash mapping for all types") if(lane_idx() == 0)
{
for EachIndex(slot_idx, unique_type_tag_slots_count)
{
for EachNode(n, UniqueTypeTagNode, unique_type_tag_slots[slot_idx])
{
type_count += 1;
}
}
type_tag_nodes = push_array(scratch.arena, UniqueTypeTagNode *, type_count);
U64 idx = 0;
for EachIndex(slot_idx, unique_type_tag_slots_count)
{
for EachNode(n, UniqueTypeTagNode, unique_type_tag_slots[slot_idx])
{
type_tag_nodes[idx] = n;
idx += 1;
}
}
}
lane_sync_u64(&type_count, 0);
lane_sync_u64(&type_tag_nodes, 0);
////////////////////////////
//- rjf: gather per-type dependency chains
//
typedef struct TypeDepChain TypeDepChain;
struct TypeDepChain
{
TypeDepChain *next;
U64 hash;
};
TypeDepChain **type_dep_chains = 0;
ProfScope("gather per-type dependency chains")
{
if(lane_idx() == 0)
{
type_dep_chains = push_array(scratch.arena, TypeDepChain *, type_count);
}
lane_sync_u64(&type_dep_chains, 0);
Rng1U64 range = lane_range(type_count);
for EachInRange(type_idx, range)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
// rjf: unpack type's tag node
UniqueTypeTagNode *type_tag_node = type_tag_nodes[type_idx];
U64 info_off = type_tag_node->info_off;
U64 unit_idx = type_tag_node->unit_idx;
// rjf: unpack unit
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx];
Rng1U64 unit_info_range = unit_info_ranges->v[unit_idx];
// rjf: parse this type's tag
DW2_Tag tag = {0};
dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, info_off, &tag);
// rjf: find direct type, if one exists
switch(tag.kind)
{
default:{}break;
case DW_TagKind_PointerType:
case DW_TagKind_ReferenceType:
case DW_TagKind_RValueReferenceType:
case DW_TagKind_RestrictType:
case DW_TagKind_VolatileType:
case DW_TagKind_ConstType:
case DW_TagKind_ArrayType:
case DW_TagKind_SubrangeType:
case DW_TagKind_Typedef:
{
DW2_Attrib *direct_type_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Type);
U64 direct_type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &direct_type_attrib->val);
}break;
}
scratch_end(scratch2);
}
}
//////////////////////////// ////////////////////////////
//- rjf: fill result //- rjf: fill result
// //
-5
View File
@@ -21,11 +21,6 @@ struct D2R2_ConvertParams
B32 deterministic; B32 deterministic;
}; };
////////////////////////////////
//~ rjf: Helpers
internal U64 d2r2_hash_from_seed_tag(U64 seed, DW2_Tag *tag);
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Conversion Entry Point (New) //~ rjf: Main Conversion Entry Point (New)