mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
raddbgi_from_pdb: complete initial parallelization pass over string map building, joining, & sorting
This commit is contained in:
+2
-2
@@ -47,7 +47,7 @@ commands =
|
||||
{
|
||||
.rjf_f1 =
|
||||
{
|
||||
.win = "build raddbgi_from_pdb telemetry release",
|
||||
.win = "build raddbgi_from_pdb telemetry debug",
|
||||
.linux = "",
|
||||
.out = "*compilation*",
|
||||
.footer_panel = true,
|
||||
@@ -74,7 +74,7 @@ commands =
|
||||
},
|
||||
.rjf_f4 =
|
||||
{
|
||||
.win = "build raddbgi_from_pdb release telemetry && pushd build && raddbgi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.raddbgi --capture && popd",
|
||||
.win = "build raddbgi_from_pdb release telemetry && pushd build && raddbgi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.raddbgi --capture && popd",
|
||||
.linux = "",
|
||||
.out = "*compilation*",
|
||||
.footer_panel = true,
|
||||
|
||||
@@ -1888,7 +1888,7 @@ rdim_bake_string_chunk_list_map_push_type_slice(RDIM_Arena *arena, RDIM_BakeStri
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < count; idx += 1)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 64, v[idx].name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, v[idx].name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1899,11 +1899,11 @@ rdim_bake_string_chunk_list_map_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStrin
|
||||
{
|
||||
for(RDIM_UDTMember *mem = v[idx].first_member; mem != 0; mem = mem->next)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 64, mem->name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, mem->name);
|
||||
}
|
||||
for(RDIM_UDTEnumVal *mem = v[idx].first_enum_val; mem != 0; mem = mem->next)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 64, mem->name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, mem->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1913,8 +1913,8 @@ rdim_bake_string_chunk_list_map_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeSt
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < count; idx += 1)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 1, v[idx].name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 1, v[idx].link_name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, v[idx].name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, v[idx].link_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1925,7 +1925,7 @@ rdim_bake_string_chunk_list_map_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStr
|
||||
{
|
||||
for(RDIM_Local *local = v[idx].first_local; local != 0; local = local->next)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 1, local->name);
|
||||
rdim_bake_string_chunk_list_map_insert(arena, top, map, 4, local->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -49,7 +49,11 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy)
|
||||
//
|
||||
// [ ] DBGI layer is case-sensitive even on case-insensitive systems
|
||||
// [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly
|
||||
// [ ] PDB files distributed with the build are not found by DbgHelp!!!
|
||||
// [ ] Jai compiler debugging crash
|
||||
// [ ] raddbgi file regeneration too strict
|
||||
//
|
||||
// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
//
|
||||
// [ ] ** Thread/process control bullet-proofing, including solo-step mode
|
||||
@@ -73,6 +77,8 @@
|
||||
// [ ] disasm animation & go-to-address
|
||||
//
|
||||
// [ ] visualize remapped files (via path map)
|
||||
//
|
||||
// [x] DBGI layer is case-sensitive even on case-insensitive systems
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
|
||||
|
||||
@@ -3516,14 +3516,51 @@ internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_strings_task__entry_point)
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_symbols_strings_task__entry_point)
|
||||
{
|
||||
P2R_BakeSymbolsStringsIn *in = (P2R_BakeSymbolsStringsIn *)p;
|
||||
ProfScope("bake symbol strings") rdim_bake_string_chunk_list_map_push_symbols(arena, in->top, in->maps[thread_idx], in->list);
|
||||
ProfScope("bake symbol strings")
|
||||
{
|
||||
for(P2R_BakeSymbolsStringsInNode *n = in->first; n != 0; n = n->next)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_push_symbol_slice(arena, in->top, in->maps[thread_idx], n->v, n->count);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_strings_task__entry_point)
|
||||
{
|
||||
P2R_BakeScopesStringsIn *in = (P2R_BakeScopesStringsIn *)p;
|
||||
ProfScope("bake scope strings") rdim_bake_string_chunk_list_map_push_scopes(arena, in->top, in->maps[thread_idx], in->list);
|
||||
ProfScope("bake scope strings")
|
||||
{
|
||||
for(P2R_BakeScopesStringsInNode *n = in->first; n != 0; n = n->next)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_push_scope_slice(arena, in->top, in->maps[thread_idx], n->v, n->count);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//- rjf: bake string map joining
|
||||
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_join_task__entry_point)
|
||||
{
|
||||
P2R_JoinBakeStringMapSlotsIn *in = (P2R_JoinBakeStringMapSlotsIn *)p;
|
||||
ProfScope("join bake string maps")
|
||||
{
|
||||
for(U64 src_map_idx = 0; src_map_idx < in->src_maps_count; src_map_idx += 1)
|
||||
{
|
||||
for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1)
|
||||
{
|
||||
if(in->dst_map->slots[slot_idx] == 0)
|
||||
{
|
||||
in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx];
|
||||
}
|
||||
else if(in->src_maps[src_map_idx]->slots[slot_idx] != 0)
|
||||
{
|
||||
rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3738,10 +3775,10 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
}
|
||||
|
||||
//- rjf: kick off string map building tasks
|
||||
RDIM_BakeStringChunkListMapTopology bake_string_chunk_list_map_topology = {(params->procedures.total_count*2 +
|
||||
params->global_variables.total_count*2 +
|
||||
params->thread_variables.total_count*2 +
|
||||
params->types.total_count*2)};
|
||||
RDIM_BakeStringChunkListMapTopology bake_string_chunk_list_map_topology = {(params->procedures.total_count*1 +
|
||||
params->global_variables.total_count*1 +
|
||||
params->thread_variables.total_count*1 +
|
||||
params->types.total_count/2)};
|
||||
RDIM_BakeStringChunkListMap **bake_string_chunk_list_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringChunkListMap *, ts_thread_count());
|
||||
for(U64 idx = 0; idx < ts_thread_count(); idx += 1)
|
||||
{
|
||||
@@ -3750,6 +3787,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
TS_TicketList bake_string_map_build_tickets = {0};
|
||||
{
|
||||
// rjf: src files
|
||||
ProfScope("kick off src files string map build task")
|
||||
{
|
||||
P2R_BakeSrcFilesStringsIn *in = push_array(scratch.arena, P2R_BakeSrcFilesStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
@@ -3759,6 +3797,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
}
|
||||
|
||||
// rjf: units
|
||||
ProfScope("kick off units string map build task")
|
||||
{
|
||||
P2R_BakeUnitsStringsIn *in = push_array(scratch.arena, P2R_BakeUnitsStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
@@ -3768,11 +3807,12 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
}
|
||||
|
||||
// rjf: types
|
||||
ProfScope("kick off types string map build tasks")
|
||||
{
|
||||
for(RDIM_TypeChunkNode *chunk = params->types.first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
U64 types_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+types_per_task-1)/types_per_task;
|
||||
U64 items_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task;
|
||||
for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; task_idx += 1)
|
||||
{
|
||||
P2R_BakeTypesStringsIn *in = push_array(scratch.arena, P2R_BakeTypesStringsIn, 1);
|
||||
@@ -3780,19 +3820,20 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
P2R_BakeTypesStringsInNode *n = push_array(scratch.arena, P2R_BakeTypesStringsInNode, 1);
|
||||
SLLQueuePush(in->first, in->last, n);
|
||||
n->v = chunk->v + task_idx*types_per_task;
|
||||
n->count = types_per_task;
|
||||
n->v = chunk->v + task_idx*items_per_task;
|
||||
n->count = Min(items_per_task, chunk->count - task_idx*items_per_task);
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_types_strings_task__entry_point, 0, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: UDTs
|
||||
ProfScope("kick off udts string map build tasks")
|
||||
{
|
||||
for(RDIM_UDTChunkNode *chunk = params->udts.first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
U64 udts_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+udts_per_task-1)/udts_per_task;
|
||||
U64 items_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task;
|
||||
for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; task_idx += 1)
|
||||
{
|
||||
P2R_BakeUDTsStringsIn *in = push_array(scratch.arena, P2R_BakeUDTsStringsIn, 1);
|
||||
@@ -3800,47 +3841,62 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
P2R_BakeUDTsStringsInNode *n = push_array(scratch.arena, P2R_BakeUDTsStringsInNode, 1);
|
||||
SLLQueuePush(in->first, in->last, n);
|
||||
n->v = chunk->v + task_idx*udts_per_task;
|
||||
n->count = udts_per_task;
|
||||
n->v = chunk->v + task_idx*items_per_task;
|
||||
n->count = Min(items_per_task, chunk->count - task_idx*items_per_task);
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_udts_strings_task__entry_point, 0, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: global variables
|
||||
// rjf: symbols
|
||||
ProfScope("kick off symbols string map build tasks")
|
||||
{
|
||||
P2R_BakeSymbolsStringsIn *in = push_array(scratch.arena, P2R_BakeSymbolsStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
in->list = ¶ms->global_variables;
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in));
|
||||
}
|
||||
|
||||
// rjf: thread variables
|
||||
{
|
||||
P2R_BakeSymbolsStringsIn *in = push_array(scratch.arena, P2R_BakeSymbolsStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
in->list = ¶ms->thread_variables;
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in));
|
||||
}
|
||||
|
||||
// rjf: procedures
|
||||
{
|
||||
P2R_BakeSymbolsStringsIn *in = push_array(scratch.arena, P2R_BakeSymbolsStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
in->list = ¶ms->procedures;
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in));
|
||||
RDIM_SymbolChunkList *symbol_lists[] =
|
||||
{
|
||||
¶ms->global_variables,
|
||||
¶ms->thread_variables,
|
||||
¶ms->procedures,
|
||||
};
|
||||
for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1)
|
||||
{
|
||||
for(RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
U64 items_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task;
|
||||
for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; task_idx += 1)
|
||||
{
|
||||
P2R_BakeSymbolsStringsIn *in = push_array(scratch.arena, P2R_BakeSymbolsStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
P2R_BakeSymbolsStringsInNode *n = push_array(scratch.arena, P2R_BakeSymbolsStringsInNode, 1);
|
||||
SLLQueuePush(in->first, in->last, n);
|
||||
n->v = chunk->v + task_idx*items_per_task;
|
||||
n->count = Min(items_per_task, chunk->count - task_idx*items_per_task);
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: scope chunks
|
||||
ProfScope("kick off scope chunks string map build tasks")
|
||||
{
|
||||
P2R_BakeScopesStringsIn *in = push_array(scratch.arena, P2R_BakeScopesStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
in->list = ¶ms->scopes;
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_scopes_strings_task__entry_point, 0, in));
|
||||
for(RDIM_ScopeChunkNode *chunk = params->scopes.first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
U64 items_per_task = Min(4096, chunk->count);
|
||||
U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task;
|
||||
for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; task_idx += 1)
|
||||
{
|
||||
P2R_BakeScopesStringsIn *in = push_array(scratch.arena, P2R_BakeScopesStringsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->maps = bake_string_chunk_list_maps__in_progress;
|
||||
P2R_BakeScopesStringsInNode *n = push_array(scratch.arena, P2R_BakeScopesStringsInNode, 1);
|
||||
SLLQueuePush(in->first, in->last, n);
|
||||
n->v = chunk->v + task_idx*items_per_task;
|
||||
n->count = Min(items_per_task, chunk->count - task_idx*items_per_task);
|
||||
ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_scopes_strings_task__entry_point, 0, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3869,9 +3925,27 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in)
|
||||
RDIM_BakeStringChunkListMap *unsorted_bake_string_chunk_list_map = rdim_bake_string_chunk_list_map_make(arena, &bake_string_chunk_list_map_topology);
|
||||
ProfScope("produce joined string map")
|
||||
{
|
||||
for(U64 idx = 0; idx < ts_thread_count(); idx += 1)
|
||||
U64 slots_per_task = 16384;
|
||||
U64 num_tasks = (bake_string_chunk_list_map_topology.slots_count+slots_per_task-1)/slots_per_task;
|
||||
TS_Ticket *task_tickets = push_array(scratch.arena, TS_Ticket, num_tasks);
|
||||
|
||||
// rjf: kickoff tasks
|
||||
for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1)
|
||||
{
|
||||
rdim_bake_string_chunk_list_map_join_in_place(&bake_string_chunk_list_map_topology, unsorted_bake_string_chunk_list_map, bake_string_chunk_list_maps__in_progress[idx]);
|
||||
P2R_JoinBakeStringMapSlotsIn *in = push_array(scratch.arena, P2R_JoinBakeStringMapSlotsIn, 1);
|
||||
in->top = &bake_string_chunk_list_map_topology;
|
||||
in->src_maps = bake_string_chunk_list_maps__in_progress;
|
||||
in->src_maps_count = ts_thread_count();
|
||||
in->dst_map = unsorted_bake_string_chunk_list_map;
|
||||
in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task);
|
||||
in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count);
|
||||
task_tickets[task_idx] = ts_kickoff(p2r_bake_string_map_join_task__entry_point, 0, in);
|
||||
}
|
||||
|
||||
// rjf: join tasks
|
||||
for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1)
|
||||
{
|
||||
ts_join(task_tickets[task_idx], max_U64);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,12 +295,29 @@ struct P2R_BakeUDTsStringsIn
|
||||
P2R_BakeUDTsStringsInNode *last;
|
||||
};
|
||||
|
||||
typedef struct P2R_BakeSymbolsStringsInNode P2R_BakeSymbolsStringsInNode;
|
||||
struct P2R_BakeSymbolsStringsInNode
|
||||
{
|
||||
P2R_BakeSymbolsStringsInNode *next;
|
||||
RDIM_Symbol *v;
|
||||
RDI_U64 count;
|
||||
};
|
||||
|
||||
typedef struct P2R_BakeSymbolsStringsIn P2R_BakeSymbolsStringsIn;
|
||||
struct P2R_BakeSymbolsStringsIn
|
||||
{
|
||||
RDIM_BakeStringChunkListMapTopology *top;
|
||||
RDIM_BakeStringChunkListMap **maps;
|
||||
RDIM_SymbolChunkList *list;
|
||||
P2R_BakeSymbolsStringsInNode *first;
|
||||
P2R_BakeSymbolsStringsInNode *last;
|
||||
};
|
||||
|
||||
typedef struct P2R_BakeScopesStringsInNode P2R_BakeScopesStringsInNode;
|
||||
struct P2R_BakeScopesStringsInNode
|
||||
{
|
||||
P2R_BakeScopesStringsInNode *next;
|
||||
RDIM_Scope *v;
|
||||
RDI_U64 count;
|
||||
};
|
||||
|
||||
typedef struct P2R_BakeScopesStringsIn P2R_BakeScopesStringsIn;
|
||||
@@ -308,7 +325,20 @@ struct P2R_BakeScopesStringsIn
|
||||
{
|
||||
RDIM_BakeStringChunkListMapTopology *top;
|
||||
RDIM_BakeStringChunkListMap **maps;
|
||||
RDIM_ScopeChunkList *list;
|
||||
P2R_BakeScopesStringsInNode *first;
|
||||
P2R_BakeScopesStringsInNode *last;
|
||||
};
|
||||
|
||||
//- rjf: string map joining task types
|
||||
|
||||
typedef struct P2R_JoinBakeStringMapSlotsIn P2R_JoinBakeStringMapSlotsIn;
|
||||
struct P2R_JoinBakeStringMapSlotsIn
|
||||
{
|
||||
RDIM_BakeStringChunkListMapTopology *top;
|
||||
RDIM_BakeStringChunkListMap **src_maps;
|
||||
U64 src_maps_count;
|
||||
RDIM_BakeStringChunkListMap *dst_map;
|
||||
Rng1U64 slot_idx_range;
|
||||
};
|
||||
|
||||
//- rjf: string map sorting task types
|
||||
@@ -538,6 +568,9 @@ internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_strings_task__entry_point);
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_symbols_strings_task__entry_point);
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_strings_task__entry_point);
|
||||
|
||||
//- rjf: bake string map joining
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_join_task__entry_point);
|
||||
|
||||
//- rjf: bake string map sorting
|
||||
internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_sort_task__entry_point);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user