Merge remote-tracking branch 'EpicGamesExt/master'

This commit is contained in:
ed
2026-08-07 00:46:42 -04:00
110 changed files with 12503 additions and 3255 deletions
+17
View File
@@ -1,3 +1,20 @@
# v0.9.28-alpha
## Linker Changes
- Implemented `/OPT:ICF` identical COMDAT folding.
- Added DEF, and SECTION configuration support.
- Improved COMDAT handling for weak symbols, ICF, and zero-sized COMDAT
anchors, and stopped emitting empty marker sections that could produce invalid
PE images.
- Fixed import/export edge cases, including import data-directory bounds and
archive member handling for `__imp_*` symbols.
- Accepted duplicate identical weak search aliases without reporting multiply
defined symbols.
- Add support for UTF-16 encoded response files.
- Fixed DBI section-contribution image-section range mapping.
- Improved debug logging for `/OPT:REF` liveness stats and unresolved symbols
referenced by `.llvm_addrsig`.
# v0.9.27-alpha # v0.9.27-alpha
## Debugger Changes ## Debugger Changes
+2 -2
View File
@@ -5,7 +5,7 @@ debugger itself, and is intended as a technical overview of the project. The
debugger's README, which includes usage instructions and tips, can be found debugger's README, which includes usage instructions and tips, can be found
packaged along with debugger releases, or within the `build` folder after a packaged along with debugger releases, or within the `build` folder after a
local copy has been built. You can find pre-built release binaries local copy has been built. You can find pre-built release binaries
[here](https://github.com/EpicGamesExt/raddebugger/releases)._ [here](https://github.com/EpicGames/raddebugger/releases)._
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
currently only supports local-machine Windows x64 debugging with PDBs, with currently only supports local-machine Windows x64 debugging with PDBs, with
@@ -14,7 +14,7 @@ support native Linux debugging and DWARF debug info.
The debugger is currently in *ALPHA*. In order to get the debugger The debugger is currently in *ALPHA*. In order to get the debugger
bullet-proof, it'd greatly help out if you submitted the issues you find bullet-proof, it'd greatly help out if you submitted the issues you find
[here](https://github.com/EpicGamesExt/raddebugger/issues), along with any [here](https://github.com/EpicGames/raddebugger/issues), along with any
information you can gather, like dump files (along with the build you used), information you can gather, like dump files (along with the build you used),
instructions to reproduce, test executables, and so on. instructions to reproduce, test executables, and so on.
+1 -1
View File
@@ -49,7 +49,7 @@ commands =
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build radbin no_meta debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, .f1 = { .win = "raddbg_stable --ipc kill_all && build torture && build ryan_scratch && pushd build && torture eval2/* && ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl] //- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+19 -3
View File
@@ -25,7 +25,7 @@ target:
{ {
executable: "build/torture.exe" executable: "build/torture.exe"
working_directory: build working_directory: build
arguments: "raddbg/*" arguments: "eval2/*"
} }
target: target:
{ {
@@ -47,13 +47,29 @@ target:
{ {
executable: "build/radbin.exe" executable: "build/radbin.exe"
working_directory: build working_directory: build
arguments: "--breakpad fat.so --capture" arguments: "--rdi fat.so --capture"
}
target:
{
executable: "build/radbin.exe"
working_directory: build
arguments: "--rdi fat.debug --capture"
} }
target: target:
{ {
executable: "build/radbin.exe" executable: "build/radbin.exe"
working_directory: build working_directory: build
arguments: "--rdi raddbg" arguments: "--rdi raddbg"
enabled: 1
} }
watch_pin: expression: tag_hash_slots watch_pin: expression: tag_hash_slots
target:
{
executable: "build/ryan_scratch.exe"
working_directory: build
enabled: 1
}
target:
{
executable: "../../Program Files/SuperTux/bin/supertux2.exe"
working_directory: "../../Program Files/SuperTux/bin"
}
+24 -14
View File
@@ -391,12 +391,12 @@ ac_async_tick(void)
} }
// rjf: compute val // rjf: compute val
B32 retry = 0; AC_Status status = AC_Status_Good;
U64 gen = r->gen; U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen); AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
// rjf: retry? -> resubmit request // rjf: retry? -> resubmit request
if(retry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal)) if(status == AC_Status_NeedRetry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal))
{ {
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex) MutexScope(batch->mutex)
@@ -412,7 +412,7 @@ ac_async_tick(void)
// rjf: create function -> cache // rjf: create function -> cache
AC_Cache *cache = 0; AC_Cache *cache = 0;
if(!retry && lane_idx() == 0) if(status != AC_Status_NeedRetry && lane_idx() == 0)
{ {
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create)); U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
@@ -431,7 +431,7 @@ ac_async_tick(void)
} }
// rjf: write value into cache // rjf: write value into cache
if(!retry && lane_idx() == 0) if(status != AC_Status_NeedRetry && lane_idx() == 0)
{ {
U64 hash = u64_hash_from_str8(r->key); U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count; U64 slot_idx = hash%cache->slots_count;
@@ -443,8 +443,10 @@ ac_async_tick(void)
{ {
if(str8_match(n->key, r->key, 0)) if(str8_match(n->key, r->key, 0))
{ {
B32 got_new_value = (status == AC_Status_Good);
// rjf: eliminate existing values, if any, if they do not match the current // rjf: eliminate existing values, if any, if they do not match the current
if(cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{ {
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0)) if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{ {
@@ -456,8 +458,11 @@ ac_async_tick(void)
} }
// rjf: write new value // rjf: write new value
n->last_completed_gen = gen; if(got_new_value)
{
n->val = val; n->val = val;
}
n->last_completed_gen = gen;
ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count); ins_atomic_u64_inc_eval(&n->completion_count);
} }
@@ -510,15 +515,15 @@ ac_async_tick(void)
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx); LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
// rjf: compute val // rjf: compute val
B32 retry = 0; AC_Status status = AC_Status_Good;
U64 gen = r->gen; U64 gen = r->gen;
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen); AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
// rjf: restore wide lane ctx // rjf: restore wide lane ctx
lane_ctx(lane_ctx_restore); lane_ctx(lane_ctx_restore);
// rjf: retry? -> resubmit request // rjf: retry? -> resubmit request
if(retry && !ins_atomic_u32_eval(r->cancel_signal)) if(status == AC_Status_NeedRetry && !ins_atomic_u32_eval(r->cancel_signal))
{ {
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx]; AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
MutexScope(batch->mutex) MutexScope(batch->mutex)
@@ -534,7 +539,7 @@ ac_async_tick(void)
// rjf: create function -> cache // rjf: create function -> cache
AC_Cache *cache = 0; AC_Cache *cache = 0;
if(!retry) if(status != AC_Status_NeedRetry)
{ {
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create)); U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count; U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
@@ -553,7 +558,7 @@ ac_async_tick(void)
} }
// rjf: write value into cache // rjf: write value into cache
if(!retry) if(status != AC_Status_NeedRetry)
{ {
U64 hash = u64_hash_from_str8(r->key); U64 hash = u64_hash_from_str8(r->key);
U64 slot_idx = hash%cache->slots_count; U64 slot_idx = hash%cache->slots_count;
@@ -565,8 +570,10 @@ ac_async_tick(void)
{ {
if(str8_match(n->key, r->key, 0)) if(str8_match(n->key, r->key, 0))
{ {
B32 got_new_value = (status == AC_Status_Good);
// rjf: eliminate existing values, if any, if they do not match the current // rjf: eliminate existing values, if any, if they do not match the current
if(cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
{ {
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0)) if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
{ {
@@ -578,8 +585,11 @@ ac_async_tick(void)
} }
// rjf: store // rjf: store
n->last_completed_gen = gen; if(got_new_value)
{
n->val = val; n->val = val;
}
n->last_completed_gen = gen;
ins_atomic_u64_dec_eval(&n->working_count); ins_atomic_u64_dec_eval(&n->working_count);
ins_atomic_u64_inc_eval(&n->completion_count); ins_atomic_u64_inc_eval(&n->completion_count);
} }
+15 -1
View File
@@ -4,6 +4,17 @@
#ifndef ARTIFACT_CACHE_H #ifndef ARTIFACT_CACHE_H
#define ARTIFACT_CACHE_H #define ARTIFACT_CACHE_H
////////////////////////////////
//~ rjf: Artifact Computation Statuses
typedef enum AC_Status
{
AC_Status_Good,
AC_Status_NeedRetry,
AC_Status_Failed,
}
AC_Status;
//////////////////////////////// ////////////////////////////////
//~ rjf: Artifact Handle Type //~ rjf: Artifact Handle Type
@@ -16,7 +27,7 @@ struct AC_Artifact
//////////////////////////////// ////////////////////////////////
//~ rjf: Artifact Computation Function Types //~ rjf: Artifact Computation Function Types
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
typedef void AC_DestroyFunctionType(AC_Artifact artifact); typedef void AC_DestroyFunctionType(AC_Artifact artifact);
typedef U32 AC_Flags; typedef U32 AC_Flags;
@@ -168,6 +179,9 @@ internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_Artif
//////////////////////////////// ////////////////////////////////
//~ rjf: Asynchronous Tick //~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void ac_async_tick(void); internal void ac_async_tick(void);
//////////////////////////////// ////////////////////////////////
+7
View File
@@ -28,6 +28,8 @@ global ArenaTableNode *free_arena_table_node = 0;
internal Arena * internal Arena *
arena_alloc_(ArenaParams *params) arena_alloc_(ArenaParams *params)
{ {
ProfBeginFunction();
U64 reserve_size = params->reserve_size; U64 reserve_size = params->reserve_size;
U64 commit_size = params->commit_size; U64 commit_size = params->commit_size;
@@ -133,12 +135,15 @@ arena_alloc_(ArenaParams *params)
} }
#endif #endif
ProfEnd();
return arena; return arena;
} }
internal void internal void
arena_release(Arena *arena) arena_release(Arena *arena)
{ {
ProfBeginFunction();
#if PROFILE_TELEMETRY #if PROFILE_TELEMETRY
{ {
Arena *base_arena = arena; Arena *base_arena = arena;
@@ -171,6 +176,8 @@ arena_release(Arena *arena)
AsanUnpoisonMemoryRegion(n, n->cmt); AsanUnpoisonMemoryRegion(n, n->cmt);
release_memory(n, n->res); release_memory(n, n->res);
} }
ProfEnd();
} }
//- rjf: arena push/pop core functions //- rjf: arena push/pop core functions
+1 -1
View File
@@ -187,7 +187,7 @@
#endif #endif
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL) #if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues" # define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/raddebugger/issues"
#endif #endif
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND #define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
+3 -2
View File
@@ -101,8 +101,8 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
rd_init(&cmdline); rd_init(&cmdline);
#endif #endif
#if !NO_ASYNC
//- rjf: launch async threads //- rjf: launch async threads
#if NEED_ASYNC
Thread *async_threads = 0; Thread *async_threads = 0;
U64 lane_broadcast_val = 0; U64 lane_broadcast_val = 0;
{ {
@@ -137,9 +137,10 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
//- rjf: call into entry point //- rjf: call into entry point
entry_point(&cmdline); entry_point(&cmdline);
#if !NO_ASYNC
//- rjf: join async threads //- rjf: join async threads
#if NEED_ASYNC
ins_atomic_u32_inc_eval(&global_async_exit); ins_atomic_u32_inc_eval(&global_async_exit);
ins_atomic_u32_inc_eval(&async_loop_again);
cond_var_broadcast(async_tick_start_cond_var); cond_var_broadcast(async_tick_start_cond_var);
for EachIndex(idx, async_threads_count) for EachIndex(idx, async_threads_count)
{ {
+20
View File
@@ -18,6 +18,10 @@ memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
{ {
U64 dst_vaddr = range.min; U64 dst_vaddr = range.min;
{ {
for(;;)
{
U64 start_dst_vaddr = dst_vaddr;
B32 found = 0;
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next) for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
{ {
if(contains_1u64(n->v.vaddr_range, dst_vaddr)) if(contains_1u64(n->v.vaddr_range, dst_vaddr))
@@ -28,9 +32,25 @@ memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible); U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read); MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
dst_vaddr += num_bytes_to_read; dst_vaddr += num_bytes_to_read;
found = 1;
}
}
if(!found || start_dst_vaddr == dst_vaddr)
{
break;
} }
} }
} }
U64 bytes_read = (dst_vaddr - range.min); U64 bytes_read = (dst_vaddr - range.min);
return bytes_read; return bytes_read;
} }
internal String8
memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range)
{
String8 result = {0};
result.size = dim_1u64(range);
result.str = push_array(arena, U8, result.size);
memory_map_read(map, range, result.str);
return result;
}
+1
View File
@@ -34,5 +34,6 @@ struct MemoryMap
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data); internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst); internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) #define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
internal String8 memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range);
#endif // BASE_MEMORY_MAP_H #endif // BASE_MEMORY_MAP_H
+4
View File
@@ -46,18 +46,22 @@ ring_try_read(Ring *ring, U64 size, void *ptr)
internal GuardedRing * internal GuardedRing *
guarded_ring_alloc(Arena *arena, U64 size) guarded_ring_alloc(Arena *arena, U64 size)
{ {
ProfBeginFunction();
GuardedRing *gr = push_array(arena, GuardedRing, 1); GuardedRing *gr = push_array(arena, GuardedRing, 1);
gr->ring = make_ring(arena, size); gr->ring = make_ring(arena, size);
gr->mutex = mutex_alloc(); gr->mutex = mutex_alloc();
gr->cv = cond_var_alloc(); gr->cv = cond_var_alloc();
ProfEnd();
return gr; return gr;
} }
internal void internal void
guarded_ring_release(GuardedRing *ring) guarded_ring_release(GuardedRing *ring)
{ {
ProfBeginFunction();
mutex_release(ring->mutex); mutex_release(ring->mutex);
cond_var_release(ring->cv); cond_var_release(ring->cv);
ProfEnd();
} }
internal RingGuard internal RingGuard
+32 -18
View File
@@ -1025,63 +1025,77 @@ internal U64
cv_name_offset_from_symbol(CV_SymKind kind, String8 data) cv_name_offset_from_symbol(CV_SymKind kind, String8 data)
{ {
U64 offset = data.size; U64 offset = data.size;
switch (kind) { switch(kind)
case CV_SymKind_COMPILE: break; {
case CV_SymKind_OBJNAME: break; case CV_SymKind_COMPILE:{}break;
case CV_SymKind_THUNK32: { case CV_SymKind_OBJNAME:{}break;
case CV_SymKind_THUNK32:
{
offset = sizeof(CV_SymThunk32); offset = sizeof(CV_SymThunk32);
}break; }break;
case CV_SymKind_LABEL32: { case CV_SymKind_LABEL32:
{
offset = sizeof(CV_SymLabel32); offset = sizeof(CV_SymLabel32);
}break; }break;
case CV_SymKind_REGISTER: { case CV_SymKind_REGISTER:
{
offset = sizeof(CV_SymRegister); offset = sizeof(CV_SymRegister);
}break; }break;
case CV_SymKind_CONSTANT: { case CV_SymKind_CONSTANT:
{
offset = sizeof(CV_SymConstant); offset = sizeof(CV_SymConstant);
CV_NumericParsed size; CV_NumericParsed size;
offset += cv_read_numeric(data, offset, &size); offset += cv_read_numeric(data, offset, &size);
}break; }break;
case CV_SymKind_UDT: { case CV_SymKind_UDT:
{
offset = sizeof(CV_SymUDT); offset = sizeof(CV_SymUDT);
}break; }break;
case CV_SymKind_BPREL32: { case CV_SymKind_BPREL32:
{
offset = sizeof(CV_SymBPRel32); offset = sizeof(CV_SymBPRel32);
}break; }break;
case CV_SymKind_LDATA32: case CV_SymKind_LDATA32:
case CV_SymKind_GDATA32: { case CV_SymKind_GDATA32:
{
offset = sizeof(CV_SymData32); offset = sizeof(CV_SymData32);
}break; }break;
case CV_SymKind_PUB32: { case CV_SymKind_PUB32:
{
offset = sizeof(CV_SymPub32); offset = sizeof(CV_SymPub32);
}break; }break;
case CV_SymKind_LPROC32: case CV_SymKind_LPROC32:
case CV_SymKind_GPROC32: case CV_SymKind_GPROC32:
case CV_SymKind_LPROC32_ID: case CV_SymKind_LPROC32_ID:
case CV_SymKind_GPROC32_ID: { case CV_SymKind_GPROC32_ID:
{
offset = sizeof(CV_SymProc32); offset = sizeof(CV_SymProc32);
}break; }break;
case CV_SymKind_REGREL32: { case CV_SymKind_REGREL32:
{
offset = sizeof(CV_SymRegrel32); offset = sizeof(CV_SymRegrel32);
}break; }break;
case CV_SymKind_LTHREAD32: case CV_SymKind_LTHREAD32:
case CV_SymKind_GTHREAD32: { case CV_SymKind_GTHREAD32:
{
offset = sizeof(CV_SymData32); offset = sizeof(CV_SymData32);
}break; }break;
case CV_SymKind_COMPILE2: break; case CV_SymKind_COMPILE2: break;
case CV_SymKind_LOCALSLOT: { case CV_SymKind_LOCALSLOT:
{
offset = sizeof(CV_SymSlot); offset = sizeof(CV_SymSlot);
}break; }break;
case CV_SymKind_PROCREF: case CV_SymKind_PROCREF:
case CV_SymKind_LPROCREF: case CV_SymKind_LPROCREF:
case CV_SymKind_DATAREF: { case CV_SymKind_DATAREF:
{
offset = sizeof(CV_SymRef2); offset = sizeof(CV_SymRef2);
}break; }break;
case CV_SymKind_TRAMPOLINE: break; case CV_SymKind_TRAMPOLINE: break;
case CV_SymKind_LOCAL: { case CV_SymKind_LOCAL:
{
offset = sizeof(CV_SymLocal); offset = sizeof(CV_SymLocal);
}break; }break;
default: InvalidPath;
} }
return offset; return offset;
} }
+1
View File
@@ -162,6 +162,7 @@ enum
}; };
#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask) #define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask)
#define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl) #define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl)
#define COFF_SectionFlags_Reserved 3
typedef struct COFF_SectionHeader COFF_SectionHeader; typedef struct COFF_SectionHeader COFF_SectionHeader;
struct COFF_SectionHeader struct COFF_SectionHeader
+28 -2
View File
@@ -169,8 +169,15 @@ coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_Sec
internal COFF_ParsedSymbol internal COFF_ParsedSymbol
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32) coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
{ {
COFF_ParsedSymbol result = {0}; COFF_ParsedSymbol result = coff_parse_symbol32_no_name(sym32);
result.name = coff_read_symbol_name(string_table, &sym32->name); result.name = coff_read_symbol_name(string_table, &sym32->name);
return result;
}
internal force_inline COFF_ParsedSymbol
coff_parse_symbol32_no_name(COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
result.value = sym32->value; result.value = sym32->value;
result.section_number = sym32->section_number; result.section_number = sym32->section_number;
result.type = sym32->type; result.type = sym32->type;
@@ -183,8 +190,15 @@ coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
internal COFF_ParsedSymbol internal COFF_ParsedSymbol
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16) coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
{ {
COFF_ParsedSymbol result = {0}; COFF_ParsedSymbol result = coff_parse_symbol16_no_name(sym16);
result.name = coff_read_symbol_name(string_table, &sym16->name); result.name = coff_read_symbol_name(string_table, &sym16->name);
return result;
}
internal force_inline COFF_ParsedSymbol
coff_parse_symbol16_no_name(COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
result.value = sym16->value; result.value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) { if (sym16->section_number == COFF_Symbol_DebugSection16) {
result.section_number = COFF_Symbol_DebugSection32; result.section_number = COFF_Symbol_DebugSection32;
@@ -212,6 +226,18 @@ coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symb
return symbol; return symbol;
} }
internal force_inline COFF_ParsedSymbol
coff_parse_symbol_no_name(COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx)
{
COFF_ParsedSymbol symbol;
if (header.is_big_obj) {
symbol = coff_parse_symbol32_no_name((COFF_Symbol32 *)symbol_table.str + symbol_idx);
} else {
symbol = coff_parse_symbol16_no_name((COFF_Symbol16 *)symbol_table.str + symbol_idx);
}
return symbol;
}
internal COFF_Symbol32Array internal COFF_Symbol32Array
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count) coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
{ {
+3
View File
@@ -262,6 +262,9 @@ internal String8 coff_name_from_section_header (String8 str
internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32); internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16); internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16);
internal COFF_ParsedSymbol coff_parse_symbol (COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx); internal COFF_ParsedSymbol coff_parse_symbol (COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx);
internal force_inline COFF_ParsedSymbol coff_parse_symbol32_no_name(COFF_Symbol32 *sym32);
internal force_inline COFF_ParsedSymbol coff_parse_symbol16_no_name(COFF_Symbol16 *sym16);
internal force_inline COFF_ParsedSymbol coff_parse_symbol_no_name (COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
-1
View File
@@ -1,7 +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/)
#define NO_ASYNC 1
#define BUILD_CONSOLE_INTERFACE 1 #define BUILD_CONSOLE_INTERFACE 1
#define BUILD_TITLE "The RAD Debugger (Command Line Launcher)" #define BUILD_TITLE "The RAD Debugger (Command Line Launcher)"
#include "base/base_inc.h" #include "base/base_inc.h"
+3
View File
@@ -238,6 +238,9 @@ internal String8 c_data_from_hash(Access *access, U128 hash);
//////////////////////////////// ////////////////////////////////
//~ rjf: Asynchronous Tick //~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void c_async_tick(void); internal void c_async_tick(void);
#endif // CONTENT_H #endif // CONTENT_H
+75 -30
View File
@@ -1225,9 +1225,26 @@ d_modules_from_dbgi_key(Arena *arena, DI_Key dbgi_key)
return list; return list;
} }
internal D_Entity *
d_process_from_id(U64 id)
{
// TODO(rjf): @multimachine need machine ID here?
D_Entity *process = &d_entity_nil;
D_EntityArray processes = d_entity_array_from_kind(D_EntityKind_Process);
for EachIndex(idx, processes.count)
{
if(processes.v[idx]->id == id)
{
process = processes.v[idx];
}
}
return process;
}
internal D_Entity * internal D_Entity *
d_thread_from_id(U64 id) d_thread_from_id(U64 id)
{ {
// TODO(rjf): @multimachine need machine ID here?
D_Entity *thread = &d_entity_nil; D_Entity *thread = &d_entity_nil;
D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread); D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread);
for EachIndex(idx, threads.count) for EachIndex(idx, threads.count)
@@ -1781,9 +1798,10 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
D_Unwind unwind = { .flags = D_UnwindFlag_Error }; D_Unwind unwind = { .flags = D_UnwindFlag_Error };
////////////////////////////// //////////////////////////////
//- rjf: grab run state pre-unwind computing //- rjf: grab generations pre-unwind computing
// //
U64 run_gen = d_run_gen(); U64 mem_gen = d_mem_gen();
U64 reg_gen = d_reg_gen();
////////////////////////////// //////////////////////////////
//- rjf: unpack args //- rjf: unpack args
@@ -1889,19 +1907,16 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
// stale. if it can't be read, the unwind fails. // stale. if it can't be read, the unwind fails.
if(step.status == UWND_StepStatus_FailedMemoryRead) if(step.status == UWND_StepStatus_FailedMemoryRead)
{ {
D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process_entity->handle, step.missed_read_vaddr_range, 1, endt_us); U64 size_desired = dim_1u64(step.missed_read_vaddr_range);
String8 data = slice.data; U8 *data = push_array(scratch.arena, U8, size_desired);
if(slice.stale) U64 size = d_process_read(process_entity->handle, step.missed_read_vaddr_range, data);
if(size == size_desired)
{ {
unwind.flags |= D_UnwindFlag_Stale; memory_map_push(scratch.arena, &memory_map, step.missed_read_vaddr_range, data);
}
else if(data.size < dim_1u64(step.missed_read_vaddr_range))
{
unwind.flags |= D_UnwindFlag_Error;
} }
else else
{ {
memory_map_push(scratch.arena, &memory_map, step.missed_read_vaddr_range, data.str); unwind.flags |= D_UnwindFlag_Error;
} }
} }
@@ -1949,6 +1964,18 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
} }
} }
//- rjf: if we failed, but our generations changed, mark the 'stale' bit
if(unwind.flags & D_UnwindFlag_Error)
{
U64 post_reg_gen = d_reg_gen();
U64 post_mem_gen = d_mem_gen();
if(post_reg_gen != reg_gen ||
post_mem_gen != mem_gen)
{
unwind.flags |= D_UnwindFlag_Stale;
}
}
//- rjf: bake frames list into result array //- rjf: bake frames list into result array
{ {
unwind.frames.count = frame_node_count; unwind.frames.count = frame_node_count;
@@ -2806,8 +2833,15 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
arena_release(node->arena); arena_release(node->arena);
break; break;
} }
if(node)
{
cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64); cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64);
} }
else
{
break;
}
}
} }
////////////////////////////// //////////////////////////////
@@ -5626,7 +5660,7 @@ d_data_from_process_vaddr_range(Arena *arena, D_Handle process, Rng1U64 vaddr_ra
//- rjf: process memory artifact cache //- rjf: process memory artifact cache
internal AC_Artifact internal AC_Artifact
d_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) d_memory_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
AC_Artifact artifact = {0}; AC_Artifact artifact = {0};
{ {
@@ -5768,7 +5802,7 @@ d_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *g
//- rjf: retry on mem gen "tearing", and if the range is non-empty //- rjf: retry on mem gen "tearing", and if the range is non-empty
if(pre_read_mem_gen != post_read_mem_gen && range_size != 0) if(pre_read_mem_gen != post_read_mem_gen && range_size != 0)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
} }
//- rjf: bundle content key as artifact //- rjf: bundle content key as artifact
@@ -5981,7 +6015,7 @@ d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *
//~ rjf: TLS Address Artifact Cache Hooks / Lookups //~ rjf: TLS Address Artifact Cache Hooks / Lookups
internal AC_Artifact internal AC_Artifact
d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
// rjf: unpack key // rjf: unpack key
D_Handle thread = {0}; D_Handle thread = {0};
@@ -6008,7 +6042,7 @@ d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64
// rjf: if not successful -> retry // rjf: if not successful -> retry
if(!success) if(!success)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
} }
// rjf: package as artifact // rjf: package as artifact
@@ -6017,11 +6051,6 @@ d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64
return artifact; return artifact;
} }
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact)
{
// NOTE(rjf): no-op
}
internal U64 internal U64
d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out) d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out)
{ {
@@ -6029,7 +6058,7 @@ d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_ha
Access *access = access_open(); Access *access = access_open();
D_Handle key_data[] = {thread_handle, module_handle}; D_Handle key_data[] = {thread_handle, module_handle};
String8 key = str8((U8 *)&key_data[0], sizeof(key_data)); String8 key = str8((U8 *)&key_data[0], sizeof(key_data));
AC_Artifact artifact = ac_artifact_from_key(access, key, d_tls_vaddr_artifact_create, d_tls_vaddr_artifact_destroy, endt_us, .stale_out = stale_out); AC_Artifact artifact = ac_artifact_from_key(access, key, d_tls_vaddr_artifact_create, 0, endt_us, .stale_out = stale_out);
result = artifact.u64[0]; result = artifact.u64[0];
access_close(access); access_close(access);
return result; return result;
@@ -6039,7 +6068,7 @@ d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_ha
//~ rjf: Call Stack Artifact Cache Hooks / Lookups //~ rjf: Call Stack Artifact Cache Hooks / Lookups
internal AC_Artifact internal AC_Artifact
d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) d_call_stack_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
AC_Artifact artifact = {0}; AC_Artifact artifact = {0};
{ {
@@ -6168,14 +6197,19 @@ d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U6
pre_reg_gen = d_reg_gen(); pre_reg_gen = d_reg_gen();
pre_mem_gen = d_mem_gen(); pre_mem_gen = d_mem_gen();
unwind = d_unwind_from_thread(arena, thread_handle, now_time_us()+100); unwind = d_unwind_from_thread(arena, thread_handle, now_time_us()+100);
if(!(unwind.flags & D_UnwindFlag_Stale)) if(unwind.flags & D_UnwindFlag_Stale)
{ {
good = 1; retry = 1;
call_stack[0] = d_call_stack_from_unwind(arena, process, &unwind); }
else if(unwind.flags & D_UnwindFlag_Error)
{
good = 0;
retry = 0;
} }
else else
{ {
retry = 1; good = 1;
call_stack[0] = d_call_stack_from_unwind(arena, process, &unwind);
} }
post_reg_gen = d_reg_gen(); post_reg_gen = d_reg_gen();
post_mem_gen = d_mem_gen(); post_mem_gen = d_mem_gen();
@@ -6204,8 +6238,19 @@ d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U6
artifact.u64[1] = (U64)call_stack; artifact.u64[1] = (U64)call_stack;
} }
//- rjf: mark retry //- rjf: mark status
retry_out[0] = retry; if(retry)
{
status_out[0] = AC_Status_NeedRetry;
}
else if(good)
{
status_out[0] = AC_Status_Good;
}
else
{
status_out[0] = AC_Status_Failed;
}
scratch_end(scratch); scratch_end(scratch);
} }
@@ -6243,7 +6288,7 @@ d_call_stack_from_thread(Access *access, D_Handle thread_handle, B32 high_priori
//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups
internal AC_Artifact internal AC_Artifact
d_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) d_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
Access *access = access_open(); Access *access = access_open();
@@ -6354,7 +6399,7 @@ d_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_ou
//- rjf: retry on stale //- rjf: retry on stale
if(stale) if(stale)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
} }
access_close(access); access_close(access);
+5 -5
View File
@@ -519,6 +519,7 @@ internal void d_entity_equip_string(D_EntityCtxRWStore *store, D_Entity *entity,
internal D_EntityCtxLookupAccel *d_thread_entity_ctx_lookup_accel(void); internal D_EntityCtxLookupAccel *d_thread_entity_ctx_lookup_accel(void);
internal D_EntityArray d_entity_array_from_kind(D_EntityKind kind); internal D_EntityArray d_entity_array_from_kind(D_EntityKind kind);
internal D_EntityList d_modules_from_dbgi_key(Arena *arena, DI_Key dbgi_key); internal D_EntityList d_modules_from_dbgi_key(Arena *arena, DI_Key dbgi_key);
internal D_Entity *d_process_from_id(U64 id);
internal D_Entity *d_thread_from_id(U64 id); internal D_Entity *d_thread_from_id(U64 id);
//- rjf: applying events to entity caches //- rjf: applying events to entity caches
@@ -640,7 +641,7 @@ internal String8 d_data_from_process_vaddr_range(Arena *arena, D_Handle process,
#define d_process_write_struct(process, vaddr, ptr) d_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), (ptr)) #define d_process_write_struct(process, vaddr, ptr) d_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), (ptr))
//- rjf: process memory artifact cache //- rjf: process memory artifact cache
internal AC_Artifact d_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact d_memory_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void d_memory_artifact_destroy(AC_Artifact artifact); internal void d_memory_artifact_destroy(AC_Artifact artifact);
internal C_Key d_key_from_process_vaddr_range(D_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale); internal C_Key d_key_from_process_vaddr_range(D_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale);
@@ -652,21 +653,20 @@ internal B32 d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stal
//////////////////////////////// ////////////////////////////////
//~ rjf: TLS Address Artifact Cache Hooks / Lookups //~ rjf: TLS Address Artifact Cache Hooks / Lookups
internal AC_Artifact d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact);
internal U64 d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out); internal U64 d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out);
//////////////////////////////// ////////////////////////////////
//~ rjf: Call Stack Artifact Cache Hooks / Lookups //~ rjf: Call Stack Artifact Cache Hooks / Lookups
internal AC_Artifact d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact d_call_stack_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void d_call_stack_artifact_destroy(AC_Artifact artifact); internal void d_call_stack_artifact_destroy(AC_Artifact artifact);
internal D_CallStack d_call_stack_from_thread(Access *access, D_Handle thread_handle, B32 high_priority, U64 endt_us); internal D_CallStack d_call_stack_from_thread(Access *access, D_Handle thread_handle, B32 high_priority, U64 endt_us);
//////////////////////////////// ////////////////////////////////
//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups //~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups
internal AC_Artifact d_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact d_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void d_call_stack_tree_artifact_destroy(AC_Artifact artifact); internal void d_call_stack_tree_artifact_destroy(AC_Artifact artifact);
internal D_CallStackTree d_call_stack_tree(Access *access, U64 endt_us); internal D_CallStackTree d_call_stack_tree(Access *access, U64 endt_us);
+1 -1
View File
@@ -2004,7 +2004,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
if(params->file_path.size != 0) if(params->file_path.size != 0)
{ {
run_extra_bps.v[0].file_path = params->file_path; run_extra_bps.v[0].file_path = params->file_path;
run_extra_bps.v[0].pt = params->cursor; run_extra_bps.v[0].pt = txt_pt((S64)params->line_num, (S64)params->column_num);
} }
else if(params->vaddr != 0) else if(params->vaddr != 0)
{ {
+2 -1
View File
@@ -65,7 +65,8 @@ struct D_CmdParams
D_Handle entity; D_Handle entity;
String8 string; String8 string;
String8 file_path; String8 file_path;
TxtPt cursor; U64 line_num;
U64 column_num;
U64 vaddr; U64 vaddr;
B32 prefer_disasm; B32 prefer_disasm;
U32 pid; U32 pid;
+2 -2
View File
@@ -1152,7 +1152,7 @@ di_conversion_completion_signal_receiver_thread_entry_point(void *p)
//~ rjf: Search Artifact Cache Hooks / Lookups //~ rjf: Search Artifact Cache Hooks / Lookups
internal AC_Artifact internal AC_Artifact
di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) di_search_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
ProfBeginFunction(); ProfBeginFunction();
Access *access = access_open(); Access *access = access_open();
@@ -1569,7 +1569,7 @@ di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, S
//~ rjf: Match Artifact Cache Hooks / Lookups //~ rjf: Match Artifact Cache Hooks / Lookups
internal AC_Artifact internal AC_Artifact
di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) di_match_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
+5 -2
View File
@@ -352,6 +352,9 @@ internal DI_EventList di_get_events(Arena *arena);
//////////////////////////////// ////////////////////////////////
//~ rjf: Asynchronous Tick //~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void di_async_tick(void); internal void di_async_tick(void);
//////////////////////////////// ////////////////////////////////
@@ -363,14 +366,14 @@ internal void di_conversion_completion_signal_receiver_thread_entry_point(void *
//////////////////////////////// ////////////////////////////////
//~ rjf: Search Artifact Cache Hooks / Lookups //~ rjf: Search Artifact Cache Hooks / Lookups
internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void di_search_artifact_destroy(AC_Artifact artifact); internal void di_search_artifact_destroy(AC_Artifact artifact);
internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out); internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out);
//////////////////////////////// ////////////////////////////////
//~ rjf: Match Artifact Cache Hooks / Lookups //~ rjf: Match Artifact Cache Hooks / Lookups
internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal DI_Match di_match_from_string(String8 string, U32 match_index, U32 unit_idx, B32 allow_other_dbgis, DI_Key preferred_dbgi_key, U64 endt_us); internal DI_Match di_match_from_string(String8 string, U32 match_index, U32 unit_idx, B32 allow_other_dbgis, DI_Key preferred_dbgi_key, U64 endt_us);
#endif // DBG_INFO_H #endif // DBG_INFO_H
+2 -2
View File
@@ -146,7 +146,7 @@ struct DASM_Artifact
}; };
internal AC_Artifact internal AC_Artifact
dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) dasm_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
DASM_Artifact *artifact = 0; DASM_Artifact *artifact = 0;
if(lane_idx() == 0) if(lane_idx() == 0)
@@ -338,7 +338,7 @@ dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_o
//- rjf: if stale, retry //- rjf: if stale, retry
if(stale) if(stale)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
} }
//- rjf: mark dependency on data hash //- rjf: mark dependency on data hash
+1 -1
View File
@@ -201,7 +201,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
//////////////////////////////// ////////////////////////////////
//~ rjf: Artifact Cache Hooks / Lookups //~ rjf: Artifact Cache Hooks / Lookups
internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void dasm_artifact_destroy(AC_Artifact artifact); internal void dasm_artifact_destroy(AC_Artifact artifact);
internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params); internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params);
internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out); internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out);
+1 -2
View File
@@ -709,8 +709,7 @@ e_oplist_from_location(Arena *arena, RDI_Parsed *rdi, RDI_Location loc)
ARCH_RegCode reg_code = arch_reg_code_from_rdi(arch, rdi_regcode); ARCH_RegCode reg_code = arch_reg_code_from_rdi(arch, rdi_regcode);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
U64 byte_size = (U64)dim_1u16(reg_rng); U64 byte_size = (U64)dim_1u16(reg_rng);
U64 byte_pos = reg_rng.min; e_oplist_push_op(arena, &result, RDI_EvalOp_RegRead, e_value_u64(RDI_EncodeRegReadParam(rdi_regcode, byte_size, 0)));
e_oplist_push_op(arena, &result, RDI_EvalOp_RegRead, e_value_u64(RDI_EncodeRegReadParam(rdi_regcode, byte_size, byte_pos)));
}break; }break;
//- rjf: space offsets //- rjf: space offsets
+1
View File
@@ -1874,6 +1874,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
U64 ip_voff = e_base_ctx->thread_ip_voff; U64 ip_voff = e_base_ctx->thread_ip_voff;
{ {
mapped_location = rdi_location_from_location_voff(rdi, local->location, ip_voff); mapped_location = rdi_location_from_location_voff(rdi, local->location, ip_voff);
mapped_bytecode_mode = E_Mode_Null;
if(mapped_location != 0) if(mapped_location != 0)
{ {
got_location_block = 1; got_location_block = 1;
+2 -2
View File
@@ -2579,7 +2579,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array)
//~ rjf: (Built-In Type Hooks) `list` lens //~ rjf: (Built-In Type Hooks) `list` lens
internal AC_Artifact internal AC_Artifact
e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) e_list_gather_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
@@ -2684,7 +2684,7 @@ e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U
//- rjf: retry //- rjf: retry
if(retry) if(retry)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
} }
//- rjf: flatten //- rjf: flatten
+1942 -378
View File
File diff suppressed because it is too large Load Diff
+229 -119
View File
@@ -5,28 +5,15 @@
#define EVAL2_H #define EVAL2_H
//////////////////////////////// ////////////////////////////////
//~ rjf: Operator Info Tables //~ rjf: Expression Parse Info Table Types
typedef enum E2_OpParseKind typedef enum E2_ExprParseKind
{ {
E2_OpParseKind_Null, E2_ExprParseKind_Null,
E2_OpParseKind_UnaryPrefix, E2_ExprParseKind_Prefix,
E2_OpParseKind_Binary, E2_ExprParseKind_Postfix,
E2_OpParseKind_Ternary,
E2_OpParseKind_Call,
} }
E2_OpParseKind; E2_ExprParseKind;
typedef struct E2_OpInfo E2_OpInfo;
struct E2_OpInfo
{
E2_OpParseKind parse_kind;
S64 precedence;
String8 pre;
String8 sep;
String8 post;
String8 chain;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Generated Code //~ rjf: Generated Code
@@ -39,6 +26,7 @@ struct E2_OpInfo
enum enum
{ {
E2_EvalOp_SetCtxID = RDI_EvalOp_COUNT, E2_EvalOp_SetCtxID = RDI_EvalOp_COUNT,
E2_EvalOp_LeafBytecode,
}; };
//////////////////////////////// ////////////////////////////////
@@ -53,18 +41,42 @@ typedef enum E2_ParseStatus
E2_ParseStatus_LastTerminal = E2_ParseStatus_Error, E2_ParseStatus_LastTerminal = E2_ParseStatus_Error,
//- rjf: caller-provided info //- rjf: caller-provided info
E2_ParseStatus_MissedIdentifierResolution, E2_ParseStatus_CheckIdentifierIsType,
E2_ParseStatus_MemberAccess, E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_CheckIdentifierIsType,
E2_ParseStatus_IndexAccess, E2_ParseStatus_LastCallerRequest = E2_ParseStatus_CheckIdentifierIsType,
E2_ParseStatus_Call,
E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_MissedIdentifierResolution,
E2_ParseStatus_LastCallerRequest = E2_ParseStatus_Call,
} }
E2_ParseStatus; E2_ParseStatus;
#define e2_parse_status_is_terminal(s) (E2_ParseStatus_FirstTerminal <= (s) && (s) <= E2_ParseStatus_LastTerminal) #define e2_parse_status_is_terminal(s) (E2_ParseStatus_FirstTerminal <= (s) && (s) <= E2_ParseStatus_LastTerminal)
#define e2_parse_status_is_caller_request(s) (E2_ParseStatus_FirstCallerRequest <= (s) && (s) <= E2_ParseStatus_LastCallerRequest) #define e2_parse_status_is_caller_request(s) (E2_ParseStatus_FirstCallerRequest <= (s) && (s) <= E2_ParseStatus_LastCallerRequest)
////////////////////////////////
//~ rjf: Compiler Statuses
typedef enum E2_CompileStatus
{
//- rjf: terminals
E2_CompileStatus_Good,
E2_CompileStatus_Error,
E2_CompileStatus_FirstTerminal = E2_CompileStatus_Good,
E2_CompileStatus_LastTerminal = E2_CompileStatus_Error,
//- rjf: caller-provided info
E2_CompileStatus_MissedIdentifierResolution,
E2_CompileStatus_NewIdentifierDefinition,
E2_CompileStatus_NewCtxID,
E2_CompileStatus_MemberAccess,
E2_CompileStatus_IndexAccess,
E2_CompileStatus_Call,
E2_CompileStatus_CompileTimeEval,
E2_CompileStatus_FirstCallerRequest = E2_CompileStatus_MissedIdentifierResolution,
E2_CompileStatus_LastCallerRequest = E2_CompileStatus_CompileTimeEval,
}
E2_CompileStatus;
#define e2_compile_status_is_terminal(s) (E2_CompileStatus_FirstTerminal <= (s) && (s) <= E2_CompileStatus_LastTerminal)
#define e2_compile_status_is_caller_request(s) (E2_CompileStatus_FirstCallerRequest <= (s) && (s) <= E2_CompileStatus_LastCallerRequest)
//////////////////////////////// ////////////////////////////////
//~ rjf: Interpretation Statuses //~ rjf: Interpretation Statuses
@@ -133,69 +145,57 @@ struct E2_TypeKeyList
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Unpacked Type Info //~ rjf: Constructed Type Cache Types
typedef enum E2_MemberKind
{
E2_MemberKind_Null,
E2_MemberKind_DataField,
E2_MemberKind_StaticData,
E2_MemberKind_Method,
E2_MemberKind_StaticMethod,
E2_MemberKind_VirtualMethod,
E2_MemberKind_VTablePtr,
E2_MemberKind_Base,
E2_MemberKind_VirtualBase,
E2_MemberKind_NestedType,
E2_MemberKind_Padding,
E2_MemberKind_COUNT
}
E2_MemberKind;
typedef U32 E2_TypeFlags; typedef U32 E2_TypeFlags;
enum enum
{ {
E2_TypeFlag_Const = (1<<0), E2_TypeFlag_Const = (1<<0),
E2_TypeFlag_Volatile = (1<<1), E2_TypeFlag_Volatile = (1<<1),
E2_TypeFlag_Restrict = (1<<2),
}; };
typedef struct E2_EnumVal E2_EnumVal; typedef struct E2_ConsTypeParams E2_ConsTypeParams;
struct E2_EnumVal struct E2_ConsTypeParams
{
String8 name;
U64 val;
};
typedef struct E2_Member E2_Member;
struct E2_Member
{
E2_MemberKind kind;
E2_TypeKey type_key;
String8 name;
U64 off;
E2_TypeKeyList inheritees;
};
typedef struct E2_Type E2_Type;
struct E2_Type
{ {
Arch arch;
E2_TypeKind kind; E2_TypeKind kind;
E2_TypeFlags flags; E2_TypeFlags flags;
String8 name; String8 name;
U64 byte_size; E2_TypeKey direct;
U64 count; U64 count;
U64 depth; U64 depth;
U32 off; E2_TypeKey *param_types;
Arch arch;
E2_TypeKey direct_type_key;
E2_TypeKey owner_type_key;
E2_TypeKey *param_type_keys;
E2_Member *members;
E2_EnumVal *enum_vals;
struct E2_Expr **args; struct E2_Expr **args;
}; };
typedef struct E2_ConsTypeNode E2_ConsTypeNode;
struct E2_ConsTypeNode
{
E2_ConsTypeNode *id_next;
E2_ConsTypeNode *content_next;
U64 id;
E2_ConsTypeParams params;
U64 byte_size;
};
typedef struct E2_ConsTypeSlot E2_ConsTypeSlot;
struct E2_ConsTypeSlot
{
E2_ConsTypeNode *first;
E2_ConsTypeNode *last;
};
typedef struct E2_ConsTypeMap E2_ConsTypeMap;
struct E2_ConsTypeMap
{
Arena *arena;
U64 id_gen;
U64 table_start_arena_pos;
U64 slots_count;
E2_ConsTypeSlot *content_slots;
E2_ConsTypeSlot *id_slots;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Evaluation Values //~ rjf: Evaluation Values
@@ -309,25 +309,24 @@ struct E2_Token
//////////////////////////////// ////////////////////////////////
//~ rjf: Expression Tree Building //~ rjf: Expression Tree Building
typedef struct E2_Expr E2_Expr;
struct E2_Expr
{
E2_Expr *first;
E2_Expr *last;
E2_Expr *next;
Rng1U64 src_range;
String8 string;
RDI_EvalOp op;
E2_TypeKey type_key;
E2_Mode mode;
E2_Val val;
};
typedef struct E2_ExprNode E2_ExprNode; typedef struct E2_ExprNode E2_ExprNode;
struct E2_ExprNode struct E2_ExprNode
{ {
E2_ExprNode *next; E2_ExprNode *next;
E2_Expr *v; struct E2_Expr *v;
};
typedef struct E2_Expr E2_Expr;
struct E2_Expr
{
E2_ExprNode *first_child;
E2_ExprNode *last_child;
U64 child_count;
E2_ExprKind kind;
U32 macro_arg_num;
Rng1U64 src_range;
String8 string;
String8List qualifiers;
}; };
typedef struct E2_ExprMapNode E2_ExprMapNode; typedef struct E2_ExprMapNode E2_ExprMapNode;
@@ -352,19 +351,27 @@ struct E2_ParseTask
Rng1U64 src_range; Rng1U64 src_range;
E2_ExprNode *first_child; E2_ExprNode *first_child;
E2_ExprNode *last_child; E2_ExprNode *last_child;
E2_Expr *next_type_ancestor;
U64 child_count; U64 child_count;
U64 child_count_target; U64 child_count_target;
B32 reverse_children;
S64 max_precedence; S64 max_precedence;
E2_OpKind op_kind; E2_ExprKind expr_kind;
String8 identifier;
String8 expected_closer; String8 expected_closer;
String8 expected_splitter; String8 expected_splitter;
U64 splitter_min_child_count;
B32 splitter_is_required; B32 splitter_is_required;
String8List macro_arg_names;
B32 do_type_ancestors;
E2_Expr *type_lhs;
}; };
typedef struct E2_ParseState E2_ParseState; typedef struct E2_ParseState E2_ParseState;
struct E2_ParseState struct E2_ParseState
{ {
U64 string_off; U64 string_off;
E2_ParseTask start_task;
E2_ParseTask *top_task; E2_ParseTask *top_task;
E2_ParseTask *free_task; E2_ParseTask *free_task;
U64 last_caller_request_string_off; U64 last_caller_request_string_off;
@@ -393,13 +400,84 @@ typedef struct E2_Parse E2_Parse;
struct E2_Parse struct E2_Parse
{ {
E2_ParseStatus status; E2_ParseStatus status;
String8 missed_identifier; String8 identifier;
String8List qualifiers;
E2_Expr *expr; E2_Expr *expr;
String8 member_name; String8 member_name;
E2_Expr *params_expr; E2_Expr *params_expr;
E2_MsgList msgs; E2_MsgList msgs;
}; };
////////////////////////////////
//~ rjf: IR Tree Building
typedef struct E2_IRNodePtrNode E2_IRNodePtrNode;
struct E2_IRNodePtrNode
{
E2_IRNodePtrNode *next;
struct E2_IRNode *v;
};
typedef struct E2_IRNode E2_IRNode;
struct E2_IRNode
{
E2_IRNodePtrNode *first_child;
E2_IRNodePtrNode *last_child;
U64 child_count;
RDI_EvalOp op;
String8 string;
E2_TypeKey type_key;
E2_Mode mode;
E2_Val val;
};
typedef struct E2_IdentifierMapNode E2_IdentifierMapNode;
struct E2_IdentifierMapNode
{
E2_IdentifierMapNode *next;
String8 name;
E2_IRNode *irtree;
};
typedef struct E2_IdentifierMap E2_IdentifierMap;
struct E2_IdentifierMap
{
E2_IdentifierMapNode **slots;
U64 slots_count;
};
typedef struct E2_CompileTask E2_CompileTask;
struct E2_CompileTask
{
E2_CompileTask *next;
E2_Expr *expr;
E2_ExprNode *last_compiled_child_node;
E2_IRNodePtrNode *first_irtree_child;
E2_IRNodePtrNode *last_irtree_child;
U64 irtree_child_count;
};
typedef struct E2_CompileState E2_CompileState;
struct E2_CompileState
{
E2_CompileTask *top_task;
E2_CompileTask *free_task;
U64 caller_request_count;
E2_Ctx selected_ctx;
};
typedef struct E2_Compile E2_Compile;
struct E2_Compile
{
E2_CompileStatus status;
String8 identifier;
String8List qualifiers;
E2_IRNode *irtree;
String8 member_name;
E2_IRNode *params_irtree;
E2_MsgList msgs;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Interpretation //~ rjf: Interpretation
@@ -452,8 +530,11 @@ struct E2_Interp
//~ rjf: Globals //~ rjf: Globals
thread_static E2_Assets *e2_assets = 0; thread_static E2_Assets *e2_assets = 0;
thread_static E2_ConsTypeMap *e2_cons_type_map = 0;
read_only global E2_ConsTypeNode e2_cons_type_node_nil = {&e2_cons_type_node_nil, &e2_cons_type_node_nil};
read_only global E2_DbgInfo e2_dbg_info_nil = {{0}, &rdi_parsed_nil}; read_only global E2_DbgInfo e2_dbg_info_nil = {{0}, &rdi_parsed_nil};
read_only global E2_Expr e2_expr_nil = {&e2_expr_nil, &e2_expr_nil, &e2_expr_nil}; read_only global E2_Expr e2_expr_nil = {0};
read_only global E2_IRNode e2_irnode_nil = {0};
//////////////////////////////// ////////////////////////////////
//~ rjf: Space -> Memory Map Helpers //~ rjf: Space -> Memory Map Helpers
@@ -467,6 +548,12 @@ internal U64 e2_space_map_read(E2_SpaceMap *map, E2_SpaceID space_id, Rng1U64 ad
internal void e2_expr_map_push(Arena *arena, E2_ExprMap *map, String8 name, E2_Expr *expr); internal void e2_expr_map_push(Arena *arena, E2_ExprMap *map, String8 name, E2_Expr *expr);
internal E2_Expr *e2_expr_from_name(E2_ExprMap *map, String8 name); internal E2_Expr *e2_expr_from_name(E2_ExprMap *map, String8 name);
////////////////////////////////
//~ rjf: Identifier Map Helpers
internal void e2_identifier_map_push(Arena *arena, E2_IdentifierMap *map, String8 name, E2_IRNode *irtree);
internal E2_IRNode *e2_irtree_from_identifier(E2_IdentifierMap *map, String8 name);
//////////////////////////////// ////////////////////////////////
//~ rjf: Messages //~ rjf: Messages
@@ -479,6 +566,16 @@ internal E2_Msg *e2_msgf(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, char
internal void e2_select_assets(E2_Assets *assets); internal void e2_select_assets(E2_Assets *assets);
internal E2_DbgInfo *e2_dbgi_from_num(U32 num); internal E2_DbgInfo *e2_dbgi_from_num(U32 num);
////////////////////////////////
//~ rjf: Constructed Types
internal E2_ConsTypeMap *e2_cons_type_map_alloc(void);
internal void e2_select_cons_type_map(E2_ConsTypeMap *map);
internal B32 e2_cons_type_params_match(E2_ConsTypeParams *a, E2_ConsTypeParams *b);
internal E2_ConsTypeNode *e2_cons_type_node_from_params(E2_ConsTypeParams *params);
internal E2_ConsTypeNode *e2_cons_type_node_from_id(U64 id);
internal E2_TypeKey e2_type_key_from_cons_type_node(E2_ConsTypeNode *node);
//////////////////////////////// ////////////////////////////////
//~ rjf: Type Keys //~ rjf: Type Keys
@@ -498,24 +595,12 @@ internal E2_TypeKey e2_type_key_dbgi(E2_TypeKind kind, U32 dbg_info_num, U32 typ
internal E2_TypeKey e2_type_key_reg(Arch arch, ARCH_RegCode reg_code); internal E2_TypeKey e2_type_key_reg(Arch arch, ARCH_RegCode reg_code);
//- rjf: constructed type constructor //- rjf: constructed type constructor
typedef struct E2_ConsTypeParams E2_ConsTypeParams;
struct E2_ConsTypeParams
{
Arch arch;
E2_TypeKind kind;
E2_TypeFlags flags;
String8 name;
E2_TypeKey direct_type_key;
U64 count;
U64 depth;
E2_Expr **args;
};
internal E2_TypeKey e2_type_key_cons_(E2_ConsTypeParams *params); internal E2_TypeKey e2_type_key_cons_(E2_ConsTypeParams *params);
#define e2_type_key_cons(k, ...) e2_type_key_cons_(&(E2_ConsTypeParams){.kind = (k), __VA_ARGS__}) #define e2_type_key_cons(k, ...) e2_type_key_cons_(&(E2_ConsTypeParams){.kind = (k), __VA_ARGS__})
//- rjf: constructed type constructor helpers //- rjf: constructed type constructor helpers
#define e2_type_key_cons_array(element_type_key, count_, ...) e2_type_key_cons(E2_TypeKind_Array, .direct_type_key = (element_type_key), .count = (count_), __VA_ARGS__) #define e2_type_key_cons_array(element_type_key, count_, ...) e2_type_key_cons(E2_TypeKind_Array, .direct = (element_type_key), .count = (count_), __VA_ARGS__)
#define e2_type_key_cons_ptr(arch, ptee_type_key, ...) e2_type_key_cons(E2_TypeKind_Ptr, .direct_type_key = (ptee_type_key), __VA_ARGS__) #define e2_type_key_cons_ptr(arch, ptee_type_key, ...) e2_type_key_cons(E2_TypeKind_Ptr, .direct = (ptee_type_key), __VA_ARGS__)
//- rjf: basic type key type functions //- rjf: basic type key type functions
internal B32 e2_type_key_match(E2_TypeKey a, E2_TypeKey b); internal B32 e2_type_key_match(E2_TypeKey a, E2_TypeKey b);
@@ -526,9 +611,18 @@ internal U64 e2_byte_size_from_type_key(E2_TypeKey k);
internal U32 e2_dbgi_num_from_type_key(E2_TypeKey k); internal U32 e2_dbgi_num_from_type_key(E2_TypeKey k);
internal E2_DbgInfo *e2_dbgi_from_type_key(E2_TypeKey k); internal E2_DbgInfo *e2_dbgi_from_type_key(E2_TypeKey k);
internal U32 e2_dbgi_type_idx_from_key(E2_TypeKey k); internal U32 e2_dbgi_type_idx_from_key(E2_TypeKey k);
internal U64 e2_cons_type_id_from_key(E2_TypeKey k);
internal U64 e2_shift_from_type_key(E2_TypeKey k); internal U64 e2_shift_from_type_key(E2_TypeKey k);
internal U64 e2_mask_count_from_type_key(E2_TypeKey k); internal U64 e2_mask_count_from_type_key(E2_TypeKey k);
internal U64 e2_array_count_from_type_key(E2_TypeKey k);
internal Arch e2_arch_from_type_key(E2_TypeKey k); internal Arch e2_arch_from_type_key(E2_TypeKey k);
internal String8 e2_name_from_type_key(Arena *arena, E2_TypeKey k);
//- rjf: type key -> string
internal String8 e2_string_from_type_key(Arena *arena, E2_TypeKey key);
//- rjf: type deep matches
internal B32 e2_type_deep_match(E2_TypeKey l, E2_TypeKey r);
//- rjf: type graph traversal primitives //- rjf: type graph traversal primitives
internal E2_TypeKey e2_type_key_direct(E2_TypeKey k); internal E2_TypeKey e2_type_key_direct(E2_TypeKey k);
@@ -557,29 +651,45 @@ internal E2_TypeKey e2_coerced_type_key_from_operands(E2_TypeKey lhs, E2_TypeKey
//////////////////////////////// ////////////////////////////////
//~ rjf: Expression Constructors //~ rjf: Expression Constructors
internal E2_Expr *e2_expr(Arena *arena); internal E2_Expr *e2_expr(Arena *arena, E2_ExprKind kind);
internal E2_Expr *e2_expr_const_u64_or_smaller(Arena *arena, U64 u); internal void e2_expr_push_child_node(E2_Expr *parent, E2_ExprNode *node);
internal E2_Expr *e2_expr_const_f32(Arena *arena, F32 f32); internal void e2_expr_push_child(Arena *arena, E2_Expr *parent, E2_Expr *expr);
internal E2_Expr *e2_expr_const_f64(Arena *arena, F64 f64); internal void e2_expr_push_child_node_front(E2_Expr *parent, E2_ExprNode *node);
internal E2_Expr *e2_expr_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *operand); internal void e2_expr_push_child_front(Arena *arena, E2_Expr *parent, E2_Expr *expr);
internal E2_Expr *e2_expr_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *lhs, E2_Expr *rhs);
internal E2_Expr *e2_expr_resolve_to_value(Arena *arena, E2_Expr *expr); ////////////////////////////////
internal E2_Expr *e2_expr_truncate(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key); //~ rjf: IR Tree Constructors
internal E2_Expr *e2_expr_convert_if_possible(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key);
internal void e2_expr_push_child(E2_Expr *parent, E2_Expr *expr); internal E2_IRNode *e2_irnode(Arena *arena);
internal E2_IRNode *e2_irnode_const_u64_or_smaller(Arena *arena, U64 u);
internal E2_IRNode *e2_irnode_const_f32(Arena *arena, F32 f32);
internal E2_IRNode *e2_irnode_const_f64(Arena *arena, F64 f64);
internal E2_IRNode *e2_irnode_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *operand);
internal E2_IRNode *e2_irnode_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *lhs, E2_IRNode *rhs);
internal E2_IRNode *e2_irnode_resolve_to_value(Arena *arena, E2_IRNode *expr);
internal E2_IRNode *e2_irnode_truncate(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
internal E2_IRNode *e2_irnode_convert_if_possible(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
internal E2_IRNode *e2_irnode_type(Arena *arena, E2_TypeKey type_key);
internal void e2_irnode_push_child_node(E2_IRNode *parent, E2_IRNodePtrNode *node);
internal void e2_irnode_push_child(Arena *arena, E2_IRNode *parent, E2_IRNode *expr);
//////////////////////////////// ////////////////////////////////
//~ rjf: String -> Expression //~ rjf: String -> Expression
internal E2_Token e2_token_from_string_off(String8 string, U64 start_off); internal E2_Token e2_token_from_string_off(E2_LangKind lang, String8 string, U64 start_off);
internal U64 e2_read_token(String8 string, U64 off, E2_Token *token_out); internal U64 e2_read_token(E2_LangKind lang, String8 string, U64 off, E2_Token *token_out);
internal B32 e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out); internal B32 e2_try_token(E2_LangKind lang, String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out);
internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, String8 string); internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, B32 identifier_is_type, E2_LangKind lang, String8 string);
//////////////////////////////// ////////////////////////////////
//~ rjf: Expression -> Bytecode //~ rjf: Expression -> IR Tree
internal String8 e2_bytecode_from_expr(Arena *arena, E2_Expr *expr); internal E2_Compile e2_compile_from_expr(Arena *arena, E2_CompileState *state, E2_IRNode *resolve_result, E2_Val compile_time_eval_result, E2_Expr *expr);
////////////////////////////////
//~ rjf: IR Tree -> Bytecode
internal String8 e2_bytecode_from_irnode(Arena *arena, E2_IRNode *irnode);
//////////////////////////////// ////////////////////////////////
//~ rjf: Bytecode -> Result //~ rjf: Bytecode -> Result
+164 -38
View File
@@ -1,53 +1,179 @@
// 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/)
@table(name parse_kind precedence pre sep pos chain) @table(name allow_type_operands is_type_expression is_first_operand_type_maybe target_operand_count)
E2_OpTable: E2_ExprKindTable:
{ {
{Dot Binary 1 "" "." "" "" } //- rjf: leaves
{Index Binary 1 "" "[" "]" "" } {Identifier 0 0 0 0 }
{Call Call 1 "" "(" ")" ","} {MacroArg 0 0 0 0 }
{DerefAsm UnaryPrefix 1 "[" "" "]" "" } {TypeIdentifier 0 1 0 0 }
{SizeOf UnaryPrefix 1 "sizeof " "" "" "" } {Numeric 0 0 0 0 }
{Deref UnaryPrefix 2 "*" "" "" "" } {StringLiteral 0 0 0 0 }
{Address UnaryPrefix 2 "&" "" "" "" } {CharLiteral 0 0 0 0 }
{Pos UnaryPrefix 2 "+" "" "" "" }
{Neg UnaryPrefix 2 "-" "" "" "" } //- rjf: type operators
{LogNot UnaryPrefix 2 "!" "" "" "" } {Ptr 1 1 1 1 }
{BitNot UnaryPrefix 2 "~" "" "" "" } {Array 1 1 1 2 }
{Mul Binary 3 "" "*" "" "" } {Function 1 1 1 0xffffffffffffffffull}
{Div Binary 3 "" "/" "" "" } {Const 1 1 1 1 }
{Mod Binary 3 "" "%" "" "" } {Volatile 1 1 1 1 }
{Add Binary 4 "" "+" "" "" } {Unsigned 1 1 1 1 }
{Sub Binary 4 "" "-" "" "" } {Signed 1 1 1 1 }
{LShift Binary 5 "" "<<" "" "" }
{RShift Binary 5 "" ">>" "" "" } //- rjf: operators
{Less Binary 6 "" "<" "" "" } {Dot 1 0 0 1 }
{LtEq Binary 6 "" "<=" "" "" } {Index 0 0 0 2 }
{Grtr Binary 6 "" ">" "" "" } {Call 0 0 0 0xffffffffffffffffull}
{GrEq Binary 6 "" ">=" "" "" } {DerefAsm 1 0 0 1 }
{EqEq Binary 7 "" "==" "" "" } {SizeOf 1 0 1 1 }
{NtEq Binary 7 "" "!=" "" "" } {TypeOf 1 1 1 1 }
{BitAnd Binary 8 "" "&" "" "" } {Cast 1 0 1 2 }
{BitXor Binary 9 "" "^" "" "" } {Deref 1 0 0 1 }
{BitOr Binary 10 "" "|" "" "" } {Address 1 0 0 1 }
{LogAnd Binary 11 "" "&&" "" "" } {Pos 1 0 0 1 }
{LogOr Binary 12 "" "||" "" "" } {Neg 1 0 0 1 }
{Define Binary 13 "" "=" "" "" } {LogNot 1 0 0 1 }
{Cond Ternary 14 "" "?" "" ":"} {BitNot 1 0 0 1 }
{Mul 0 0 0 2 }
{Div 1 0 0 2 }
{Mod 1 0 0 2 }
{Add 1 0 0 2 }
{Sub 1 0 0 2 }
{LShift 1 0 0 2 }
{RShift 1 0 0 2 }
{Less 1 0 0 2 }
{LtEq 1 0 0 2 }
{Grtr 1 0 0 2 }
{GrEq 1 0 0 2 }
{EqEq 1 0 0 2 }
{NtEq 1 0 0 2 }
{BitAnd 1 0 0 2 }
{BitXor 1 0 0 2 }
{BitOr 1 0 0 2 }
{LogAnd 1 0 0 2 }
{LogOr 1 0 0 2 }
{Define 1 0 0 1 }
{Macro 1 0 0 1 }
{Cond 1 0 0 3 }
} }
@enum E2_OpKind: @enum E2_ExprKind:
{ {
Null, Null,
@expand(E2_OpTable a) `$(a.name)`, @expand(E2_ExprKindTable a) `$(a.name)`,
COUNT, COUNT,
} }
@data(E2_OpInfo) e2_op_kind_info_table: @data(B8) e2_expr_kind_allow_type_operands_table:
{ {
`{0}`, 0,
@expand(E2_OpTable a) `{E2_OpParseKind_$(a.parse_kind), $(a.precedence), str8_lit_comp("$(a.pre)"), str8_lit_comp("$(a.sep)"), str8_lit_comp("$(a.pos)"), str8_lit_comp("$(a.chain)")}` @expand(E2_ExprKindTable a) `$(a.allow_type_operands)`
}
@data(B8) e2_expr_kind_is_type_expr_table:
{
0,
@expand(E2_ExprKindTable a) `$(a.is_type_expression)`
}
@data(B8) e2_expr_kind_is_first_operand_type_maybe_table:
{
0,
@expand(E2_ExprKindTable a) `$(a.is_first_operand_type_maybe)`
}
@data(U64) e2_expr_kind_target_operand_count_table:
{
0,
@expand(E2_ExprKindTable a) `$(a.target_operand_count)`
}
@struct E2_ExprKindParseInfo:
{
`E2_ExprKind expr_kind`;
`E2_ExprParseKind parse_kind`;
`S64 precedence`;
`B8 reverse_children`;
`String8 pre`;
`String8 sep`;
`String8 post`;
`String8 chain`;
}
@table(name name_lower)
E2_LangKindTable:
{
{CLike clike}
}
@enum E2_LangKind:
{
@expand(E2_LangKindTable a) `$(a.name)`
}
@struct E2_LangInfo:
{
`U64 expr_kind_parse_infos_count`;
`E2_ExprKindParseInfo *expr_kind_parse_infos`;
}
@data(E2_LangInfo) e2_lang_kind_info_table:
{
@expand(E2_LangKindTable a) `{ArrayCount(e2_expr_kind_parse_info_table__$(a.name_lower)), (e2_expr_kind_parse_info_table__$(a.name_lower))}`
}
@table(name parse_kind precedence pre sep pos chain reverse_children)
E2_ExprKindParseInfoTable_CLike:
{
{Dot Postfix 1 "" "." "" "" 0}
{Index Postfix 1 "" "[" "]" "" 0}
{Call Postfix 1 "" "(" ")" "," 0}
{Function Postfix 1 "" "(" ")" "," 0}
{DerefAsm Prefix 1 "[" "" "]" "" 0}
{Unsigned Prefix 1 "unsigned " "" "" "" 0}
{Signed Prefix 1 "signed " "" "" "" 0}
{Volatile Prefix 1 "volatile " "" "" "" 0}
{Const Prefix 1 "const " "" "" "" 0}
{SizeOf Prefix 1 "sizeof " "" "" "" 0}
{TypeOf Prefix 1 "typeof " "" "" "" 0}
{SizeOf Prefix 1 "size_of " "" "" "" 0}
{TypeOf Prefix 1 "type_of " "" "" "" 0}
{Cast Prefix 1 "" "" "" "" 0}
{Deref Prefix 2 "*" "" "" "" 0}
{Address Prefix 2 "&" "" "" "" 0}
{Pos Prefix 2 "+" "" "" "" 0}
{Neg Prefix 2 "-" "" "" "" 0}
{LogNot Prefix 2 "!" "" "" "" 0}
{BitNot Prefix 2 "~" "" "" "" 0}
{Cast Prefix 1 "cast " "" "" "" 0}
{Cast Postfix 1 "" "as" "" "" 1}
{Ptr Postfix 1 "" "" "*" "" 0}
{Array Postfix 1 "" "[" "]" "" 0}
{Mul Postfix 3 "" "*" "" "" 0}
{Div Postfix 3 "" "/" "" "" 0}
{Mod Postfix 3 "" "%" "" "" 0}
{Add Postfix 4 "" "+" "" "" 0}
{Sub Postfix 4 "" "-" "" "" 0}
{LShift Postfix 5 "" "<<" "" "" 0}
{RShift Postfix 5 "" ">>" "" "" 0}
{Less Postfix 6 "" "<" "" "" 0}
{LtEq Postfix 6 "" "<=" "" "" 0}
{Grtr Postfix 6 "" ">" "" "" 0}
{GrEq Postfix 6 "" ">=" "" "" 0}
{EqEq Postfix 7 "" "==" "" "" 0}
{NtEq Postfix 7 "" "!=" "" "" 0}
{BitAnd Postfix 8 "" "&" "" "" 0}
{BitXor Postfix 9 "" "^" "" "" 0}
{BitOr Postfix 10 "" "|" "" "" 0}
{LogAnd Postfix 11 "" "&&" "" "" 0}
{LogOr Postfix 12 "" "||" "" "" 0}
{Cond Postfix 14 "" "?" "" ":" 0}
}
@data(E2_ExprKindParseInfo) e2_expr_kind_parse_info_table__clike:
{
@expand(E2_ExprKindParseInfoTable_CLike a) `{E2_ExprKind_$(a.name), E2_ExprParseKind_$(a.parse_kind), $(a.precedence), $(a.reverse_children), str8_lit_comp("$(a.pre)"), str8_lit_comp("$(a.sep)"), str8_lit_comp("$(a.pos)"), str8_lit_comp("$(a.chain)")}`
} }
@table(name basic_string basic_byte_size) @table(name basic_string basic_byte_size)
+257 -33
View File
@@ -4,40 +4,264 @@
//- GENERATED CODE //- GENERATED CODE
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
E2_OpInfo e2_op_kind_info_table[32] = B8 e2_expr_kind_allow_type_operands_table[48] =
{ {
{0}, 0,
{E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("["), str8_lit_comp("]"), str8_lit_comp("")}, 0,
{E2_OpParseKind_Call, 1, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(",")}, 0,
{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("["), str8_lit_comp(""), str8_lit_comp("]"), str8_lit_comp("")}, 0,
{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("/"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("%"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 4, str8_lit_comp(""), str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_Binary, 4, str8_lit_comp(""), str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_Binary, 5, str8_lit_comp(""), str8_lit_comp("<<"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 5, str8_lit_comp(""), str8_lit_comp(">>"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 6, str8_lit_comp(""), str8_lit_comp("<"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 6, str8_lit_comp(""), str8_lit_comp("<="), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(">"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(">="), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 7, str8_lit_comp(""), str8_lit_comp("=="), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 7, str8_lit_comp(""), str8_lit_comp("!="), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 8, str8_lit_comp(""), str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 9, str8_lit_comp(""), str8_lit_comp("^"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 10, str8_lit_comp(""), str8_lit_comp("|"), str8_lit_comp(""), str8_lit_comp("")}, 0,
{E2_OpParseKind_Binary, 11, str8_lit_comp(""), str8_lit_comp("&&"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 12, str8_lit_comp(""), str8_lit_comp("||"), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Binary, 13, str8_lit_comp(""), str8_lit_comp("="), str8_lit_comp(""), str8_lit_comp("")}, 1,
{E2_OpParseKind_Ternary, 14, str8_lit_comp(""), str8_lit_comp("?"), str8_lit_comp(""), str8_lit_comp(":")}, 1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
};
B8 e2_expr_kind_is_type_expr_table[48] =
{
0,
0,
0,
1,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
B8 e2_expr_kind_is_first_operand_type_maybe_table[48] =
{
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
U64 e2_expr_kind_target_operand_count_table[48] =
{
0,
0,
0,
0,
0,
0,
0,
1,
2,
0xffffffffffffffffull,
1,
1,
1,
1,
1,
2,
0xffffffffffffffffull,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
1,
1,
3,
};
E2_LangInfo e2_lang_kind_info_table[1] =
{
{ArrayCount(e2_expr_kind_parse_info_table__clike), (e2_expr_kind_parse_info_table__clike)},
};
E2_ExprKindParseInfo e2_expr_kind_parse_info_table__clike[43] =
{
{E2_ExprKind_Dot, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Index, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp("["), str8_lit_comp("]"), str8_lit_comp("")},
{E2_ExprKind_Call, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(",")},
{E2_ExprKind_Function, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(",")},
{E2_ExprKind_DerefAsm, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("["), str8_lit_comp(""), str8_lit_comp("]"), str8_lit_comp("")},
{E2_ExprKind_Unsigned, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("unsigned "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Signed, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("signed "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Volatile, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("volatile "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Const, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("const "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_SizeOf, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_TypeOf, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("typeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_SizeOf, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("size_of "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_TypeOf, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("type_of "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Cast, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Deref, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Address, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Pos, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Neg, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_LogNot, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_BitNot, E2_ExprParseKind_Prefix, 2, 0, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Cast, E2_ExprParseKind_Prefix, 1, 0, str8_lit_comp("cast "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Cast, E2_ExprParseKind_Postfix, 1, 1, str8_lit_comp(""), str8_lit_comp("as"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Ptr, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("*"), str8_lit_comp("")},
{E2_ExprKind_Array, E2_ExprParseKind_Postfix, 1, 0, str8_lit_comp(""), str8_lit_comp("["), str8_lit_comp("]"), str8_lit_comp("")},
{E2_ExprKind_Mul, E2_ExprParseKind_Postfix, 3, 0, str8_lit_comp(""), str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Div, E2_ExprParseKind_Postfix, 3, 0, str8_lit_comp(""), str8_lit_comp("/"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Mod, E2_ExprParseKind_Postfix, 3, 0, str8_lit_comp(""), str8_lit_comp("%"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Add, E2_ExprParseKind_Postfix, 4, 0, str8_lit_comp(""), str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Sub, E2_ExprParseKind_Postfix, 4, 0, str8_lit_comp(""), str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_LShift, E2_ExprParseKind_Postfix, 5, 0, str8_lit_comp(""), str8_lit_comp("<<"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_RShift, E2_ExprParseKind_Postfix, 5, 0, str8_lit_comp(""), str8_lit_comp(">>"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Less, E2_ExprParseKind_Postfix, 6, 0, str8_lit_comp(""), str8_lit_comp("<"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_LtEq, E2_ExprParseKind_Postfix, 6, 0, str8_lit_comp(""), str8_lit_comp("<="), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Grtr, E2_ExprParseKind_Postfix, 6, 0, str8_lit_comp(""), str8_lit_comp(">"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_GrEq, E2_ExprParseKind_Postfix, 6, 0, str8_lit_comp(""), str8_lit_comp(">="), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_EqEq, E2_ExprParseKind_Postfix, 7, 0, str8_lit_comp(""), str8_lit_comp("=="), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_NtEq, E2_ExprParseKind_Postfix, 7, 0, str8_lit_comp(""), str8_lit_comp("!="), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_BitAnd, E2_ExprParseKind_Postfix, 8, 0, str8_lit_comp(""), str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_BitXor, E2_ExprParseKind_Postfix, 9, 0, str8_lit_comp(""), str8_lit_comp("^"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_BitOr, E2_ExprParseKind_Postfix, 10, 0, str8_lit_comp(""), str8_lit_comp("|"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_LogAnd, E2_ExprParseKind_Postfix, 11, 0, str8_lit_comp(""), str8_lit_comp("&&"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_LogOr, E2_ExprParseKind_Postfix, 12, 0, str8_lit_comp(""), str8_lit_comp("||"), str8_lit_comp(""), str8_lit_comp("")},
{E2_ExprKind_Cond, E2_ExprParseKind_Postfix, 14, 0, str8_lit_comp(""), str8_lit_comp("?"), str8_lit_comp(""), str8_lit_comp(":")},
}; };
U8 e2_type_kind_basic_byte_size_table[61] = U8 e2_type_kind_basic_byte_size_table[61] =
+82 -36
View File
@@ -6,42 +6,63 @@
#ifndef EVAL2_META_H #ifndef EVAL2_META_H
#define EVAL2_META_H #define EVAL2_META_H
typedef enum E2_OpKind typedef enum E2_ExprKind
{ {
E2_OpKind_Null, E2_ExprKind_Null,
E2_OpKind_Dot, E2_ExprKind_Identifier,
E2_OpKind_Index, E2_ExprKind_MacroArg,
E2_OpKind_Call, E2_ExprKind_TypeIdentifier,
E2_OpKind_DerefAsm, E2_ExprKind_Numeric,
E2_OpKind_SizeOf, E2_ExprKind_StringLiteral,
E2_OpKind_Deref, E2_ExprKind_CharLiteral,
E2_OpKind_Address, E2_ExprKind_Ptr,
E2_OpKind_Pos, E2_ExprKind_Array,
E2_OpKind_Neg, E2_ExprKind_Function,
E2_OpKind_LogNot, E2_ExprKind_Const,
E2_OpKind_BitNot, E2_ExprKind_Volatile,
E2_OpKind_Mul, E2_ExprKind_Unsigned,
E2_OpKind_Div, E2_ExprKind_Signed,
E2_OpKind_Mod, E2_ExprKind_Dot,
E2_OpKind_Add, E2_ExprKind_Index,
E2_OpKind_Sub, E2_ExprKind_Call,
E2_OpKind_LShift, E2_ExprKind_DerefAsm,
E2_OpKind_RShift, E2_ExprKind_SizeOf,
E2_OpKind_Less, E2_ExprKind_TypeOf,
E2_OpKind_LtEq, E2_ExprKind_Cast,
E2_OpKind_Grtr, E2_ExprKind_Deref,
E2_OpKind_GrEq, E2_ExprKind_Address,
E2_OpKind_EqEq, E2_ExprKind_Pos,
E2_OpKind_NtEq, E2_ExprKind_Neg,
E2_OpKind_BitAnd, E2_ExprKind_LogNot,
E2_OpKind_BitXor, E2_ExprKind_BitNot,
E2_OpKind_BitOr, E2_ExprKind_Mul,
E2_OpKind_LogAnd, E2_ExprKind_Div,
E2_OpKind_LogOr, E2_ExprKind_Mod,
E2_OpKind_Define, E2_ExprKind_Add,
E2_OpKind_Cond, E2_ExprKind_Sub,
E2_OpKind_COUNT, E2_ExprKind_LShift,
} E2_OpKind; E2_ExprKind_RShift,
E2_ExprKind_Less,
E2_ExprKind_LtEq,
E2_ExprKind_Grtr,
E2_ExprKind_GrEq,
E2_ExprKind_EqEq,
E2_ExprKind_NtEq,
E2_ExprKind_BitAnd,
E2_ExprKind_BitXor,
E2_ExprKind_BitOr,
E2_ExprKind_LogAnd,
E2_ExprKind_LogOr,
E2_ExprKind_Define,
E2_ExprKind_Macro,
E2_ExprKind_Cond,
E2_ExprKind_COUNT,
} E2_ExprKind;
typedef enum E2_LangKind
{
E2_LangKind_CLike,
} E2_LangKind;
typedef enum E2_TypeKind typedef enum E2_TypeKind
{ {
@@ -121,8 +142,33 @@ E2_TypeKind_FirstMeta = E2_TypeKind_MetaExpr,
E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription, E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription,
} E2_TypeKind; } E2_TypeKind;
typedef struct E2_ExprKindParseInfo E2_ExprKindParseInfo;
struct E2_ExprKindParseInfo
{
E2_ExprKind expr_kind;
E2_ExprParseKind parse_kind;
S64 precedence;
B8 reverse_children;
String8 pre;
String8 sep;
String8 post;
String8 chain;
};
typedef struct E2_LangInfo E2_LangInfo;
struct E2_LangInfo
{
U64 expr_kind_parse_infos_count;
E2_ExprKindParseInfo *expr_kind_parse_infos;
};
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
extern E2_OpInfo e2_op_kind_info_table[32]; extern B8 e2_expr_kind_allow_type_operands_table[48];
extern B8 e2_expr_kind_is_type_expr_table[48];
extern B8 e2_expr_kind_is_first_operand_type_maybe_table[48];
extern U64 e2_expr_kind_target_operand_count_table[48];
extern E2_LangInfo e2_lang_kind_info_table[1];
extern E2_ExprKindParseInfo e2_expr_kind_parse_info_table__clike[43];
extern U8 e2_type_kind_basic_byte_size_table[61]; extern U8 e2_type_kind_basic_byte_size_table[61];
extern String8 e2_type_kind_basic_string_table[61]; extern String8 e2_type_kind_basic_string_table[61];
+191
View File
@@ -0,0 +1,191 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
Test(eval2_regressions)
{
E2_ConsTypeMap *cons_types = e2_cons_type_map_alloc();
e2_select_cons_type_map(cons_types);
String8 strings[] =
{
s("int32(*)(int32, int32)"),
s("int32 *(*)(int32, int32)"),
s("int32 **(*)(int32, int32)"),
s("123(1, 2, 3)"),
s("int32 (*) [100]"),
s("(3 * 4) + 2"),
s("cast (float32) 123"),
s("int32 *"),
s("3 * 4 + 2"),
s("int32[100]"),
s("3 * 4"),
s("foo"),
s("foo.bar"),
s("[123]"),
s("123[456]"),
s("2 + (3 * 4)"),
s("int32 == int32"),
s("123, 456"),
s("222.f"),
s("123 as float32"),
s("cast float32 123"),
s("(int32 *)123"),
s("bar(a, b) = a + b"),
s("foo = 123"),
s("1 > 2"),
s("1 ? 123 : 456"),
s("0 ? 123 : 456"),
s("1 ? \"Test\" : 888"),
s("'a'"),
s("'b'"),
s("(float32)222"),
s("(float64)222"),
s("222.0"),
s("123"),
s("123 + 456"),
s("!1"),
s("!0"),
s("1 + 1 + 1"),
s("40 / 0"),
s("123 | 456"),
s("123 + "),
s("-123"),
s("sizeof 123"),
};
for EachElement(idx, strings)
{
Temp scratch = scratch_begin(0, 0);
String8List msgs = {0};
// rjf: string -> expr
E2_Expr *expr = &e2_expr_nil;
{
E2_ParseState state = {0};
B32 identifier_is_type = 0;
for(;;)
{
E2_Parse parse = e2_parse_from_string(scratch.arena, &state, identifier_is_type, E2_LangKind_CLike, strings[idx]);
identifier_is_type = 0;
expr = parse.expr;
for EachNode(n, E2_Msg, parse.msgs.first)
{
str8_list_push(scratch.arena, &msgs, n->string);
}
if(parse.status == E2_ParseStatus_CheckIdentifierIsType)
{
identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("int32"), 0);
identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("float32"), 0);
identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("float64"), 0);
}
if(e2_parse_status_is_terminal(parse.status))
{
break;
}
}
}
// rjf: expr -> ir tree
E2_IRNode *irtree = &e2_irnode_nil;
{
E2_IRNode *resolve_result = &e2_irnode_nil;
E2_Val compile_time_eval_result = {0};
E2_CompileState state = {0};
for(;;)
{
E2_Compile compile = e2_compile_from_expr(scratch.arena, &state, resolve_result, compile_time_eval_result, expr);
irtree = compile.irtree;
resolve_result = &e2_irnode_nil;
if(compile.status == E2_CompileStatus_MissedIdentifierResolution)
{
E2_IRNode *irnode = &e2_irnode_nil;
if(str8_match(compile.identifier, s("float32"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F32));
}
else if(str8_match(compile.identifier, s("float64"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F64));
}
else if(str8_match(compile.identifier, s("int32"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S32));
}
else if(str8_match(compile.identifier, s("int64"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S64));
}
else
{
irnode = e2_irnode_const_u64_or_smaller(scratch.arena, 123);
}
resolve_result = irnode;
}
if(compile.status == E2_CompileStatus_MemberAccess)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 456);
}
if(compile.status == E2_CompileStatus_IndexAccess)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 111);
}
if(compile.status == E2_CompileStatus_Call)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 123456);
}
if(compile.status == E2_CompileStatus_CompileTimeEval)
{
String8 bytecode = e2_bytecode_from_irnode(scratch.arena, irtree);
E2_InterpState interp_state = {0};
E2_SpaceMap space_map = {0};
E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &interp_state, &space_map, bytecode);
compile_time_eval_result = interp.val;
}
if(e2_compile_status_is_terminal(compile.status))
{
break;
}
}
}
// rjf: ir tree -> bytecode
String8 bytecode = e2_bytecode_from_irnode(scratch.arena, irtree);
// rjf: bytecode -> value
E2_Val val = {0};
{
E2_InterpState state = {0};
E2_SpaceMap space_map = {0};
for(;;)
{
E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &state, &space_map, bytecode);
val = interp.val;
if(e2_interp_status_is_terminal(interp.status))
{
if(interp.status != E2_InterpStatus_Good)
{
str8_list_pushf(scratch.arena, &msgs, "Interpretation error (%i).", interp.status);
}
break;
}
}
}
// rjf: message string list -> string
StringJoin join = {.sep = s(" ")};
String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join);
// rjf: log
String8 log = str8f(scratch.arena, "%S -> %I64d (f32: %f) (f64: %f) *%s* (type: %S) %s%S\n",
strings[idx],
val.s64,
val.f32,
val.f64,
irtree->mode == E2_Mode_Type ? "type" :
irtree->mode == E2_Mode_Value ? "value" :
"address",
e2_string_from_type_key(scratch.arena, irtree->type_key),
msgs_string.size != 0 ? " // " : "", msgs_string);
log_info(log);
scratch_end(scratch);
}
}
@@ -208,8 +208,6 @@ ev_view_alloc(void)
view->arena = arena; view->arena = arena;
view->expand_slots_count = 256; view->expand_slots_count = 256;
view->expand_slots = push_array(arena, EV_ExpandSlot, view->expand_slots_count); view->expand_slots = push_array(arena, EV_ExpandSlot, view->expand_slots_count);
view->key_view_rule_slots_count = 256;
view->key_view_rule_slots = push_array(arena, EV_KeyViewRuleSlot, view->key_view_rule_slots_count);
return view; return view;
} }
@@ -246,36 +244,6 @@ ev_expansion_from_key(EV_View *view, EV_Key key)
return (node != 0 && node->expanded); return (node != 0 && node->expanded);
} }
internal String8
ev_view_rule_from_key(EV_View *view, EV_Key key)
{
String8 result = {0};
//- rjf: key -> hash * slot idx * slot
U64 hash = ev_hash_from_key(key);
U64 slot_idx = hash%view->key_view_rule_slots_count;
EV_KeyViewRuleSlot *slot = &view->key_view_rule_slots[slot_idx];
//- rjf: slot -> existing node
EV_KeyViewRuleNode *existing_node = 0;
for(EV_KeyViewRuleNode *n = slot->first; n != 0; n = n->hash_next)
{
if(ev_key_match(n->key, key))
{
existing_node = n;
break;
}
}
//- rjf: node -> result
if(existing_node != 0)
{
result = str8(existing_node->buffer, existing_node->buffer_string_size);
}
return result;
}
internal void internal void
ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded) ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded)
{ {
@@ -348,44 +316,6 @@ ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded)
} }
} }
internal void
ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_string)
{
//- rjf: key -> hash * slot idx * slot
U64 hash = ev_hash_from_key(key);
U64 slot_idx = hash%view->key_view_rule_slots_count;
EV_KeyViewRuleSlot *slot = &view->key_view_rule_slots[slot_idx];
//- rjf: slot -> existing node
EV_KeyViewRuleNode *existing_node = 0;
for(EV_KeyViewRuleNode *n = slot->first; n != 0; n = n->hash_next)
{
if(ev_key_match(n->key, key))
{
existing_node = n;
break;
}
}
//- rjf: existing node * new node -> node
EV_KeyViewRuleNode *node = existing_node;
if(node == 0)
{
node = push_array(view->arena, EV_KeyViewRuleNode, 1);
DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev);
node->key = key;
node->buffer_cap = 512;
node->buffer = push_array(view->arena, U8, node->buffer_cap);
}
//- rjf: mutate node
if(node != 0)
{
node->buffer_string_size = ClampTop(view_rule_string.size, node->buffer_cap);
MemoryCopy(node->buffer, view_rule_string.str, node->buffer_string_size);
}
}
//////////////////////////////// ////////////////////////////////
//~ rjf: View Rule Info Table Building / Selection / Lookups //~ rjf: View Rule Info Table Building / Selection / Lookups
@@ -40,26 +40,6 @@ struct EV_ExpandSlot
EV_ExpandNode *last; EV_ExpandNode *last;
}; };
//- rjf: hash table for view rules
typedef struct EV_KeyViewRuleNode EV_KeyViewRuleNode;
struct EV_KeyViewRuleNode
{
EV_KeyViewRuleNode *hash_next;
EV_KeyViewRuleNode *hash_prev;
EV_Key key;
U8 *buffer;
U64 buffer_cap;
U64 buffer_string_size;
};
typedef struct EV_KeyViewRuleSlot EV_KeyViewRuleSlot;
struct EV_KeyViewRuleSlot
{
EV_KeyViewRuleNode *first;
EV_KeyViewRuleNode *last;
};
//- rjf: view state bundle //- rjf: view state bundle
typedef struct EV_View EV_View; typedef struct EV_View EV_View;
@@ -69,9 +49,6 @@ struct EV_View
EV_ExpandSlot *expand_slots; EV_ExpandSlot *expand_slots;
U64 expand_slots_count; U64 expand_slots_count;
EV_ExpandNode *free_expand_node; EV_ExpandNode *free_expand_node;
EV_KeyViewRuleSlot *key_view_rule_slots;
U64 key_view_rule_slots_count;
EV_KeyViewRuleNode *free_key_view_rule_node;
}; };
//////////////////////////////// ////////////////////////////////
@@ -328,9 +305,7 @@ internal void ev_view_release(EV_View *view);
//- rjf: lookups / mutations //- rjf: lookups / mutations
internal EV_ExpandNode *ev_expand_node_from_key(EV_View *view, EV_Key key); internal EV_ExpandNode *ev_expand_node_from_key(EV_View *view, EV_Key key);
internal B32 ev_expansion_from_key(EV_View *view, EV_Key key); internal B32 ev_expansion_from_key(EV_View *view, EV_Key key);
internal String8 ev_view_rule_from_key(EV_View *view, EV_Key key);
internal void ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded); internal void ev_key_set_expansion(EV_View *view, EV_Key parent_key, EV_Key key, B32 expanded);
internal void ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_string);
//////////////////////////////// ////////////////////////////////
//~ rjf: View Rule Info Table Building / Selection / Lookups //~ rjf: View Rule Info Table Building / Selection / Lookups
+2 -2
View File
@@ -32,7 +32,7 @@ fs_change_gen(void)
//~ rjf: Cache Interaction //~ rjf: Cache Interaction
internal AC_Artifact internal AC_Artifact
fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) fs_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
@@ -146,7 +146,7 @@ fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out
(file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder));
if(!read_good) if(!read_good)
{ {
retry_out[0] = 1; status_out[0] = AC_Status_NeedRetry;
ProfScope("abort") ProfScope("abort")
{ {
arena_release(data_arena); arena_release(data_arena);
+4 -1
View File
@@ -55,7 +55,7 @@ internal U64 fs_change_gen(void);
//////////////////////////////// ////////////////////////////////
//~ rjf: Artifact Cache Hooks / Accessing API //~ rjf: Artifact Cache Hooks / Accessing API
internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void fs_artifact_destroy(AC_Artifact artifact); internal void fs_artifact_destroy(AC_Artifact artifact);
internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us);
@@ -66,6 +66,9 @@ internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us);
//////////////////////////////// ////////////////////////////////
//~ rjf: Asynchronous Tick //~ rjf: Asynchronous Tick
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void fs_async_tick(void); internal void fs_async_tick(void);
#endif // FILE_STREAM_H #endif // FILE_STREAM_H
+3
View File
@@ -161,6 +161,9 @@ internal HTTP_StatusKind http_status_kind_from_code(HTTP_StatusCode code);
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
//~ rjf: @per_os_impl Top-Level Layer Calls //~ rjf: @per_os_impl Top-Level Layer Calls
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void http_init(void); internal void http_init(void);
internal void http_async_tick(void); internal void http_async_tick(void);
+35
View File
@@ -38,6 +38,7 @@
# define raddbg_add_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (1), (size), (r), (w), (x)) # define raddbg_add_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (1), (size), (r), (w), (x))
# define raddbg_remove_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (0), (size), (r), (w), (x)) # define raddbg_remove_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (0), (size), (r), (w), (x))
# define raddbg_annotate_vaddr_range(ptr, size, ...) raddbg_annotate_vaddr_range__impl((ptr), (size), __VA_ARGS__) # define raddbg_annotate_vaddr_range(ptr, size, ...) raddbg_annotate_vaddr_range__impl((ptr), (size), __VA_ARGS__)
# define raddbg_load_module(ptr, size, name, dbg_path) raddbg_load_module__impl((ptr), (size), (name), (dbg_path))
#else #else
# define raddbg_is_attached(...) (0) # define raddbg_is_attached(...) (0)
# define raddbg_thread_id(...) ((void)0) # define raddbg_thread_id(...) ((void)0)
@@ -57,6 +58,7 @@
# define raddbg_add_breakpoint(ptr, size, r, w, x) ((void)0) # define raddbg_add_breakpoint(ptr, size, r, w, x) ((void)0)
# define raddbg_remove_breakpoint(ptr, size, r, w, x) ((void)0) # define raddbg_remove_breakpoint(ptr, size, r, w, x) ((void)0)
# define raddbg_annotate_vaddr_range(ptr, size, ...) ((void)0) # define raddbg_annotate_vaddr_range(ptr, size, ...) ((void)0)
# define raddbg_load_module(ptr, size, name, dbg_path) ((void)0)
#endif #endif
//////////////////////////////// ////////////////////////////////
@@ -466,6 +468,39 @@ raddbg_annotate_vaddr_range__impl(void *ptr, unsigned __int64 size, char *fmt, .
} }
} }
void
raddbg_load_module__impl(void *ptr, unsigned __int64 size, char *name, char *dbg_path)
{
if(raddbg_is_attached())
{
#pragma pack(push, 8)
typedef struct RADDBG_LoadModuleInfo RADDBG_LoadModuleInfo;
struct RADDBG_LoadModuleInfo
{
unsigned __int64 vaddr;
unsigned __int64 size;
unsigned __int64 name_vaddr;
unsigned __int64 dbg_path_vaddr;
};
#pragma pack(pop)
RADDBG_LoadModuleInfo info;
info.vaddr = (unsigned __int64)ptr;
info.size = size;
info.name_vaddr = (unsigned __int64)name;
info.dbg_path_vaddr = (unsigned __int64)dbg_path;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try
{
RaiseException(0x00524157u, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info);
}
__except(1)
{
}
#pragma warning(pop)
}
}
#endif // defined(RADDBG_MARKUP_IMPLEMENTATION) #endif // defined(RADDBG_MARKUP_IMPLEMENTATION)
#endif // defined(_WIN32) && !defined(RADDBG_MARKUP_STUBS) #endif // defined(_WIN32) && !defined(RADDBG_MARKUP_STUBS)
+10 -10
View File
@@ -78,7 +78,7 @@ RDI_EVAL_CTRLBITS(8, 0, 1),
RDI_EVAL_CTRLBITS(16, 0, 1), RDI_EVAL_CTRLBITS(16, 0, 1),
RDI_EVAL_CTRLBITS(32, 0, 1), RDI_EVAL_CTRLBITS(32, 0, 1),
RDI_EVAL_CTRLBITS(64, 0, 1), RDI_EVAL_CTRLBITS(64, 0, 1),
RDI_EVAL_CTRLBITS(1, 0, 1), RDI_EVAL_CTRLBITS(8, 0, 1),
RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
@@ -92,15 +92,15 @@ RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(1, 1, 1),
RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(1, 1, 1),
RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
-17
View File
@@ -1807,29 +1807,12 @@ rdim_bake_name_map_insert(RDIM_Arena *arena, RDIM_BakeNameMapTopology *map_topol
{ {
slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeNameChunkList, 1); slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeNameChunkList, 1);
} }
RDI_S32 is_duplicate = 0;
for(RDIM_BakeNameChunkNode *n = slot->first; n != 0; n = n->next)
{
for(RDI_U64 n_idx = 0; n_idx < n->count; n_idx += 1)
{
if(rdim_str8_match(n->v[n_idx].string, string, 0) &&
n->v[n_idx].idx == idx)
{
is_duplicate = 1;
goto break_all;
}
}
}
break_all:;
if(!is_duplicate)
{
RDIM_BakeName *bstr = rdim_bake_name_chunk_list_push(arena, slot, chunk_cap); RDIM_BakeName *bstr = rdim_bake_name_chunk_list_push(arena, slot, chunk_cap);
bstr->string = string; bstr->string = string;
bstr->idx = idx; bstr->idx = idx;
bstr->hash = hash; bstr->hash = hash;
} }
} }
}
//////////////////////////////// ////////////////////////////////
//~ rjf: [Baking Helpers] Deduplicated Path Baking Tree //~ rjf: [Baking Helpers] Deduplicated Path Baking Tree
+17 -1
View File
@@ -34,6 +34,23 @@ void_list_push(Arena *arena, VoidList *list, void *v)
return n; return n;
} }
internal void
u32_list_push_node(U32List *list, U32Node *n)
{
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
internal U32Node *
u32_list_push(Arena *arena, U32List *list, U32 data)
{
U32Node *n = push_array(arena, U32Node, 1);
n->next = 0;
n->data = data;
u32_list_push_node(list, n);
return n;
}
internal void internal void
u64_list_push_node(U64List *list, U64Node *n) u64_list_push_node(U64List *list, U64Node *n)
{ {
@@ -264,4 +281,3 @@ s64_array_from_list(Arena *arena, S64List *list)
for EachNode(n, S64Node, list->first) { result.v[result.count++] = n->v; } for EachNode(n, S64Node, list->first) { result.v[result.count++] = n->v; }
return result; return result;
} }
+4 -1
View File
@@ -9,6 +9,7 @@ typedef struct U64Node { U64 data; struct U64Node *next; } U64Node;
typedef struct S64Node { S64 v; struct S64Node *next; } S64Node; typedef struct S64Node { S64 v; struct S64Node *next; } S64Node;
typedef struct VoidList { U64 count; VoidNode *first, *last; } VoidList; typedef struct VoidList { U64 count; VoidNode *first, *last; } VoidList;
typedef struct U32List { U64 count; U32Node *first, *last; } U32List;
typedef struct U64List { U64 count; U64Node *first, *last; } U64List; typedef struct U64List { U64 count; U64Node *first, *last; } U64List;
typedef struct S64List { U64 count; S64Node *first, *last; } S64List; typedef struct S64List { U64 count; S64Node *first, *last; } S64List;
@@ -20,6 +21,9 @@ internal U64 void_list_count_nodes (VoidNode *head);
internal void void_node_concat (VoidNode **head, VoidNode *node); internal void void_node_concat (VoidNode **head, VoidNode *node);
internal void void_node_concat_atomic(VoidNode **head, VoidNode *node); internal void void_node_concat_atomic(VoidNode **head, VoidNode *node);
internal void u32_list_push_node (U32List *list, U32Node *n);
internal U32Node * u32_list_push (Arena *arena, U32List *list, U32 v);
internal void u64_list_push_node (U64List *list, U64Node *n); internal void u64_list_push_node (U64List *list, U64Node *n);
internal U64Node * u64_list_push (Arena *arena, U64List *list, U64 v); internal U64Node * u64_list_push (Arena *arena, U64List *list, U64 v);
internal void u64_list_concat_in_place(U64List *list, U64List *to_concat); internal void u64_list_concat_in_place(U64List *list, U64List *to_concat);
@@ -44,4 +48,3 @@ internal void s64_list_push_node (S64List *list, S64Node *n);
internal S64Node * s64_list_push (Arena *arena, S64List *list, S64 v); internal S64Node * s64_list_push (Arena *arena, S64List *list, S64 v);
internal void s64_list_concat_in_place(S64List *list, S64List *to_concat); internal void s64_list_concat_in_place(S64List *list, S64List *to_concat);
internal S64Array s64_array_from_list (Arena *arena, S64List *list); internal S64Array s64_array_from_list (Arena *arena, S64List *list);
+1495 -352
View File
File diff suppressed because it is too large Load Diff
+13 -4
View File
@@ -34,6 +34,7 @@ typedef struct LNK_Input
String8 data; String8 data;
B32 disallow; B32 disallow;
B32 is_thin; B32 is_thin;
B32 owns_file_map;
B32 has_disk_read_failed; B32 has_disk_read_failed;
B32 exclude_from_debug_info; B32 exclude_from_debug_info;
LNK_LibMemberRef *link_member; LNK_LibMemberRef *link_member;
@@ -74,6 +75,7 @@ typedef struct LNK_Inputer
#define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***" #define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***"
#define LNK_SECTION_FLAG_DEBUG (1 << 0) #define LNK_SECTION_FLAG_DEBUG (1 << 0)
#define LNK_SECTION_FLAG_NOICF (1 << 1)
typedef U8 LNK_LibMemberFlags; typedef U8 LNK_LibMemberFlags;
enum enum
@@ -204,6 +206,7 @@ typedef struct LNK_BaseRelocPageArray
typedef struct typedef struct
{ {
B32 search_anti_deps; B32 search_anti_deps;
B32 reset_search_cursor;
LNK_Link *link; LNK_Link *link;
HashMap *imports_hm; HashMap *imports_hm;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
@@ -217,8 +220,10 @@ typedef struct
{ {
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_Config *config; LNK_Config *config;
LNK_ObjList objs; LNK_Obj **objs;
} LNK_OptRefTask; U64 objs_count;
U32Array *obj_indices;
} LNK_OptTask;
typedef struct typedef struct
{ {
@@ -258,6 +263,7 @@ typedef struct LNK_ImageFillNode
typedef struct typedef struct
{ {
LNK_Config *config;
LNK_SymbolTable *symtab; LNK_SymbolTable *symtab;
LNK_SectionTable *sectab; LNK_SectionTable *sectab;
U64 objs_count; U64 objs_count;
@@ -271,6 +277,8 @@ typedef struct
LNK_SectionArray image_sects; LNK_SectionArray image_sects;
union { union {
struct { struct {
Arena *arena;
Rng1U64 *ranges;
HashTable **defns; HashTable **defns;
} gather_sects; } gather_sects;
struct { struct {
@@ -374,6 +382,7 @@ internal LNK_Input * lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config
internal B32 lnk_inputer_has_items(LNK_Inputer *inputer); internal B32 lnk_inputer_has_items(LNK_Inputer *inputer);
internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs); internal LNK_InputPtrArray lnk_inputer_flush(Arena *arena, TP_Context *tp, LNK_Inputer *inputer, LNK_IO_Flags io_flags, LNK_InputList *all_inputs, LNK_InputList *new_inputs);
internal void lnk_inputer_release_file_maps(TP_Context *tp, LNK_Inputer *inputer);
// --- Link Context ------------------------------------------------------------ // --- Link Context ------------------------------------------------------------
@@ -390,7 +399,8 @@ internal LNK_LinkResult lnk_link_image (TP_Context *tp, TP_Arena *arena, LNK_Con
// --- Optimizations ----------------------------------------------------------- // --- Optimizations -----------------------------------------------------------
internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs); internal void lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj **objs, U64 objs_count);
internal void lnk_opt_icf(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj **objs, U64 objs_count);
// --- Win32 Image ------------------------------------------------------------- // --- Win32 Image -------------------------------------------------------------
@@ -403,4 +413,3 @@ internal LNK_ImageContext lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_C
internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *sectab); internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *sectab);
internal void lnk_log_timers(void); internal void lnk_log_timers(void);
+576 -43
View File
@@ -14,6 +14,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Brepro, 0, "BREPRO", "", "No support." }, { LNK_CmdSwitch_Brepro, 0, "BREPRO", "", "No support." },
{ LNK_CmdSwitch_Debug, 0, "DEBUG", "[:{FULL|NONE}]", "Controls debug info level." }, { LNK_CmdSwitch_Debug, 0, "DEBUG", "[:{FULL|NONE}]", "Controls debug info level." },
{ LNK_CmdSwitch_DefaultLib, 1, "DEFAULTLIB", ":LIBNAME", "Set default library." }, { LNK_CmdSwitch_DefaultLib, 1, "DEFAULTLIB", ":LIBNAME", "Set default library." },
{ LNK_CmdSwitch_Def, 1, "DEF", ":FILENAME", "Read exports from a module-definition file." },
{ LNK_CmdSwitch_Delay, 0, "DELAY", ":{NOBIND|UNLOAD}", "Controls emission of unload and bind tables." }, { LNK_CmdSwitch_Delay, 0, "DELAY", ":{NOBIND|UNLOAD}", "Controls emission of unload and bind tables." },
{ LNK_CmdSwitch_DelayLoad, 0, "DELAYLOAD", ":DLL", "Delay load DLL." }, { LNK_CmdSwitch_DelayLoad, 0, "DELAYLOAD", ":DLL", "Delay load DLL." },
{ LNK_CmdSwitch_Dll, 0, "DLL", "", "Link to a DLL." }, { LNK_CmdSwitch_Dll, 0, "DLL", "", "Link to a DLL." },
@@ -24,7 +25,10 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_FailIfMismatch, 1, "FAILIFMISMATCH", "{id=value}", "Fails to link if same ids have conflicting values." }, { LNK_CmdSwitch_FailIfMismatch, 1, "FAILIFMISMATCH", "{id=value}", "Fails to link if same ids have conflicting values." },
{ LNK_CmdSwitch_FileAlign, 0, "FILEALIGN", ":#", "Set section alignment in the file." }, { LNK_CmdSwitch_FileAlign, 0, "FILEALIGN", ":#", "Set section alignment in the file." },
{ LNK_CmdSwitch_Fixed, 0, "FIXED", "[:NO]", "Load the image at the default base address." }, { LNK_CmdSwitch_Fixed, 0, "FIXED", "[:NO]", "Load the image at the default base address." },
{ LNK_CmdSwitch_Force, 0, "FORCE", "", "Force image output despite errors." },
{ LNK_CmdSwitch_FunctionPadMin, 0, "FUNCTIONPADMIN", ":#", "Minimum function byte size." }, { LNK_CmdSwitch_FunctionPadMin, 0, "FUNCTIONPADMIN", ":#", "Minimum function byte size." },
{ LNK_CmdSwitch_Guard, 0, "GUARD", ":{CF|NO|LONGJMP|EHCONT}", "Controls Control Flow Guard metadata." },
{ LNK_CmdSwitch_GuardSym, 1, "GUARDSYM", ":SYMBOL,S", "MSVC guard symbol directive." },
{ LNK_CmdSwitch_Heap, 0, "HEAP", "RESERVE[,COMMIT]", "Set reserve and commit size for the heap." }, { LNK_CmdSwitch_Heap, 0, "HEAP", "RESERVE[,COMMIT]", "Set reserve and commit size for the heap." },
{ LNK_CmdSwitch_HighEntropyVa, 0, "HIGHENTROPYVA", "[:NO]", "Indicate that image supports full 64-bit address space ASLR." }, { LNK_CmdSwitch_HighEntropyVa, 0, "HIGHENTROPYVA", "[:NO]", "Indicate that image supports full 64-bit address space ASLR." },
{ LNK_CmdSwitch_Ignore, 0, "IGNORE", ":#", "Ignore a warning." }, { LNK_CmdSwitch_Ignore, 0, "IGNORE", ":#", "Ignore a warning." },
@@ -55,6 +59,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_PdbPageSize, 0, "PDBPAGESIZE", ":#", "Page size must be power of two." }, { LNK_CmdSwitch_PdbPageSize, 0, "PDBPAGESIZE", ":#", "Page size must be power of two." },
{ LNK_CmdSwitch_PdbStripped, 0, "PDBSTRIPPED", ":FILENAME", "Create a stripped PDB containing public symbols, a section map, and a list of object files." }, { LNK_CmdSwitch_PdbStripped, 0, "PDBSTRIPPED", ":FILENAME", "Create a stripped PDB containing public symbols, a section map, and a list of object files." },
{ LNK_CmdSwitch_Release, 1, "RELEASE", "", "Write image checksum." }, { LNK_CmdSwitch_Release, 1, "RELEASE", "", "Write image checksum." },
{ LNK_CmdSwitch_Section, 1, "SECTION", ":NAME,ATTRS", "Set output section attributes." },
{ LNK_CmdSwitch_Stack, 1, "STACK", ":RESERVE[,COMMIT]", "Set reserve and commit size for the stack." }, { LNK_CmdSwitch_Stack, 1, "STACK", ":RESERVE[,COMMIT]", "Set reserve and commit size for the stack." },
{ LNK_CmdSwitch_SubSystem, 1, "SUBSYSTEM", ":{CONSOLE|NATIVE|WINDOWS}[,#[.##]]", "Set subsystem for the image." }, { LNK_CmdSwitch_SubSystem, 1, "SUBSYSTEM", ":{CONSOLE|NATIVE|WINDOWS}[,#[.##]]", "Set subsystem for the image." },
{ LNK_CmdSwitch_TsAware, 0, "TSAWARE", "[:NO]", "Image is terminal server aware." }, { LNK_CmdSwitch_TsAware, 0, "TSAWARE", "[:NO]", "Image is terminal server aware." },
@@ -97,7 +102,7 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_Rad_ImageAltPath, 0, "RAD_IMAGEALTPATH", ":FILENAME", "Alternative name for the image" }, { LNK_CmdSwitch_Rad_ImageAltPath, 0, "RAD_IMAGEALTPATH", ":FILENAME", "Alternative name for the image" },
{ LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, { LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." },
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." }, { LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
{ LNK_CmdSwitch_Rad_TypeHashAlg, 0, "RAD_TPYE_HASH_ALG", ":{BLAKE3}", "Sets hashing algorithm for type merging." }, { LNK_CmdSwitch_Rad_DebugTypeHash, 0, "RAD_DEBUG_TYPE_HASH", ":{BLAKE3|XXHASH}", "Sets hashing algorithm for debug type merging." },
{ LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, 0, "RAD_UNRESOLVED_SYMBOL_LIMIT", ":#", "Limits number of unresolved symbol errors linker reports." }, { LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, 0, "RAD_UNRESOLVED_SYMBOL_LIMIT", ":#", "Limits number of unresolved symbol errors linker reports." },
{ LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." }, { LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." },
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." }, { LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
@@ -106,6 +111,8 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
{ LNK_CmdSwitch_RadTypeServer, 0, "RAD_TYPE_SERVER", ":FILENAME", "Merge types and store them in the specified file. The filename must have the .rrt extension." }, { LNK_CmdSwitch_RadTypeServer, 0, "RAD_TYPE_SERVER", ":FILENAME", "Merge types and store them in the specified file. The filename must have the .rrt extension." },
{ LNK_CmdSwitch_LLVM_AddrSig, 0, "LLVM_ADDRSIG", "[:NO]", "Use .llvm_addrsig to guide ICF." },
{ LNK_CmdSwitch_Help, 0, "HELP", "", "" }, { LNK_CmdSwitch_Help, 0, "HELP", "", "" },
{ LNK_CmdSwitch_Help, 0, "?", "", "" }, { LNK_CmdSwitch_Help, 0, "?", "", "" },
}; };
@@ -708,6 +715,55 @@ lnk_parse_export_directive(Arena *arena, String8 directive, LNK_Obj *obj, PE_Exp
return is_parsed; return is_parsed;
} }
internal String8
lnk_text_file_string_from_data(Arena *arena, String8 data)
{
String8 result = data;
if (data.size >= 2 && data.str[0] == 0xff && data.str[1] == 0xfe) {
// decode UTF-16LE BOM
result = str8_from_16(arena, str16((U16 *)(data.str + 2), (data.size - 2) / sizeof(U16)));
} else if (data.size >= 3 && data.str[0] == 0xef && data.str[1] == 0xbb && data.str[2] == 0xbf) {
// strip UTF-8 BOM
result = str8_skip(data, 3);
}
return result;
}
internal void
lnk_push_export_to_config(LNK_Config *config, LNK_Obj *obj, PE_ExportParse export_parse)
{
// lookup existing export
String8 export_name = pe_name_from_export_parse(&export_parse);
PE_ExportParseNode *exp_n = hash_map_search_string_raw(&config->export_ht, export_name);
if (exp_n == 0) {
// push new export
if (!export_parse.is_forwarder) {
lnk_include_symbol(config, export_parse.name, 0);
}
exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse);
hash_map_push_string_raw(config->arena, &config->export_ht, export_name, exp_n);
} else {
// merge duplicate export
PE_ExportParse *extant_export = &exp_n->data;
B32 alias_conflict = extant_export->alias.size &&
export_parse.alias.size &&
!str8_match(extant_export->alias, export_parse.alias, 0);
B32 ordinal_conflict = extant_export->ordinal != export_parse.ordinal;
if (alias_conflict || ordinal_conflict) {
lnk_error_obj(LNK_Error_IllExport, obj, "ambiguous symbol export %S", export_parse.name);
}
if (!alias_conflict && !ordinal_conflict && extant_export->alias.size == 0 && export_parse.alias.size != 0) {
extant_export->alias = export_parse.alias;
}
}
}
internal B32 internal B32
lnk_parse_merge_directive(String8 string, LNK_Obj *obj, LNK_MergeDirective *out) lnk_parse_merge_directive(String8 string, LNK_Obj *obj, LNK_MergeDirective *out)
{ {
@@ -725,6 +781,43 @@ lnk_parse_merge_directive(String8 string, LNK_Obj *obj, LNK_MergeDirective *out)
return is_parse_ok; return is_parse_ok;
} }
typedef struct LNK_SectionDirectiveAttr
{
U8 code;
COFF_SectionFlags flag;
B32 is_mem_attr;
B32 negated_sets;
} LNK_SectionDirectiveAttr;
global read_only LNK_SectionDirectiveAttr g_section_directive_attr_map[] =
{
{ 'D', COFF_SectionFlag_MemDiscardable, 0, 0 },
{ 'E', COFF_SectionFlag_MemExecute, 1, 0 },
{ 'K', COFF_SectionFlag_MemNotCached, 0, 1 },
{ 'P', COFF_SectionFlag_MemNotPaged, 0, 1 },
{ 'R', COFF_SectionFlag_MemRead, 1, 0 },
{ 'S', COFF_SectionFlag_MemShared, 0, 0 },
{ 'W', COFF_SectionFlag_MemWrite, 1, 0 },
};
typedef struct LNK_GuardOption
{
String8 name;
LNK_GuardFlags set_flags;
LNK_GuardFlags clear_flags;
} LNK_GuardOption;
global read_only LNK_GuardOption g_guard_option_table[] =
{
{ str8_lit_comp("cf"), LNK_Guard_Cf, 0 },
{ str8_lit_comp("nocf"), 0, LNK_Guard_Cf },
{ str8_lit_comp("longjmp"), LNK_Guard_LongJmp, 0 },
{ str8_lit_comp("nolongjmp"), 0, LNK_Guard_LongJmp },
{ str8_lit_comp("ehcont"), LNK_Guard_EhCont, 0 },
{ str8_lit_comp("noehcont"), 0, LNK_Guard_EhCont },
{ str8_lit_comp("no"), 0, LNK_Guard_All },
};
internal LNK_AltNameNode * internal LNK_AltNameNode *
lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName v) lnk_alt_name_list_push(Arena *arena, LNK_AltNameList *list, LNK_AltName v)
{ {
@@ -745,6 +838,24 @@ lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_Me
return node; return node;
} }
internal COFF_SectionFlags
lnk_apply_section_directives_to_flags(LNK_Config *config, String8 full_section_name, COFF_SectionFlags flags)
{
String8 section_name = {0};
String8 sort_idx = {0};
coff_parse_section_name(full_section_name, &section_name, &sort_idx);
for EachNode(dir_n, LNK_SectionDirectiveNode, config->section_list.first) {
LNK_SectionDirective *dir = &dir_n->v;
if (str8_match(dir->name, section_name, 0)) {
flags &= ~dir->clear_flags;
flags |= dir->set_flags;
}
}
return flags;
}
internal String8 internal String8
lnk_get_image_name(LNK_Config *config) lnk_get_image_name(LNK_Config *config)
{ {
@@ -1088,6 +1199,7 @@ lnk_unwrap_rsp(Arena *arena, String8List arg_list)
if (file_path_exists(name)) { if (file_path_exists(name)) {
// read rsp from disk // read rsp from disk
String8 file = lnk_read_data_from_file_path(scratch.arena, 0, name); String8 file = lnk_read_data_from_file_path(scratch.arena, 0, name);
file = lnk_text_file_string_from_data(scratch.arena, file);
// parse rsp // parse rsp
String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file); String8List rsp_args = lnk_arg_list_parse_windows_rules(scratch.arena, file);
@@ -1132,6 +1244,8 @@ lnk_apply_write_temp_files(Arena *arena, LNK_Config *config)
} }
} }
internal void lnk_apply_def_file_to_config(LNK_Config *config, String8 path, LNK_Obj *obj);
internal void internal void
lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj) lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List value_strings, LNK_Obj *obj)
{ {
@@ -1250,6 +1364,13 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} }
} break; } break;
case LNK_CmdSwitch_Def: {
String8 path = {0};
if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &path)) {
lnk_apply_def_file_to_config(config, path, obj);
}
} break;
case LNK_CmdSwitch_Delay: { case LNK_CmdSwitch_Delay: {
if (value_strings.node_count == 0 || value_strings.node_count > 1) { if (value_strings.node_count == 0 || value_strings.node_count > 1) {
lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj, cmd_switch); lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, obj, cmd_switch);
@@ -1297,42 +1418,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
case LNK_CmdSwitch_Export: { case LNK_CmdSwitch_Export: {
PE_ExportParse export_parse = {0}; PE_ExportParse export_parse = {0};
if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) { if (lnk_parse_export_directive_ex(config->arena, value_strings, obj, &export_parse)) {
String8 export_name = pe_name_from_export_parse(&export_parse); lnk_push_export_to_config(config, obj, export_parse);
PE_ExportParseNode *exp_n = hash_map_search_string_raw(&config->export_ht, export_name);
if (exp_n == 0) {
// make sure export is defined
if (!export_parse.is_forwarder) {
lnk_include_symbol(config, export_parse.name, 0);
}
// push new export
exp_n = pe_export_parse_list_push(config->arena, &config->export_symbol_list, export_parse);
hash_map_push_string_raw(config->arena, &config->export_ht, export_name, exp_n);
} else {
B32 is_ambiguous = 1;
PE_ExportParse *extant_export = &exp_n->data;
if (extant_export->alias.size && export_parse.alias.size && !str8_match(extant_export->alias, export_parse.alias, 0)) {
goto report;
}
if (extant_export->ordinal != export_parse.ordinal) {
goto report;
}
is_ambiguous = 0;
if (extant_export->alias.size == 0 && export_parse.alias.size != 0) {
extant_export->alias = export_parse.alias;
}
report:;
if (is_ambiguous) {
lnk_error_obj(LNK_Error_IllExport, obj, "ambiguous symbol export %S", export_parse.name);
}
}
} }
} break; } break;
@@ -1384,6 +1470,25 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
config->do_function_pad_min = LNK_SwitchState_Yes; config->do_function_pad_min = LNK_SwitchState_Yes;
} break; } break;
case LNK_CmdSwitch_Guard: {
for EachNode(n, String8Node, value_strings.first) {
LNK_GuardOption *option = 0;
for EachElement(i, g_guard_option_table) {
if (str8_matchi(g_guard_option_table[i].name, n->string)) {
option = &g_guard_option_table[i];
break;
}
}
if (option != 0) {
config->guard_flags &= ~option->clear_flags;
config->guard_flags |= option->set_flags;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unknown option \"%S\"", n->string);
}
}
} break;
case LNK_CmdSwitch_Heap: { case LNK_CmdSwitch_Heap: {
Rng1U64 reserve_commit; Rng1U64 reserve_commit;
reserve_commit.v[0] = config->heap_reserve; reserve_commit.v[0] = config->heap_reserve;
@@ -1728,6 +1833,101 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
} }
} break; } break;
case LNK_CmdSwitch_Section: {
LNK_SectionDirective section_dir = {0};
B32 is_parse_ok = 1;
if (value_strings.node_count < 2) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Section, "expected section name and attributes");
is_parse_ok = 0;
} else {
section_dir.name = value_strings.first->string;
B32 has_attr = 0;
B32 has_mem_attr = 0;
for (String8Node *param_n = value_strings.first->next; param_n != 0; param_n = param_n->next) {
String8 param = param_n->string;
if (str8_match_lit("ALIGN=", param, StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)) {
String8 align_string = str8_skip(param, sizeof("ALIGN=") - 1);
U64 align = 0;
if (try_u64_from_str8_c_rules(align_string, &align)) {
COFF_SectionFlags align_flag = coff_section_flag_from_align_size(align);
if (align_flag) {
COFF_SectionFlags align_mask = (COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
section_dir.clear_flags |= align_mask;
section_dir.set_flags &= ~align_mask;
section_dir.set_flags |= align_flag;
section_dir.clear_flags &= ~align_flag;
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Section, "invalid alignment \"%S\"", align_string);
is_parse_ok = 0;
}
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Section, "unable to parse alignment \"%S\"", align_string);
is_parse_ok = 0;
}
continue;
}
B32 negate = 0;
for EachIndex(i, param.size) {
U8 c = upper_from_char(param.str[i]);
if (c == '!') {
negate = 1;
continue;
}
LNK_SectionDirectiveAttr *attr = 0;
for EachElement(attr_idx, g_section_directive_attr_map) {
if (g_section_directive_attr_map[attr_idx].code == c) {
attr = &g_section_directive_attr_map[attr_idx];
break;
}
}
if (attr == 0) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Section, "unknown section attribute '%c' in \"%S\"", c, param);
is_parse_ok = 0;
} else {
has_attr = 1;
has_mem_attr = has_mem_attr || attr->is_mem_attr;
COFF_SectionFlags flags = (negate == attr->negated_sets) ? attr->flag : 0;
section_dir.clear_flags |= attr->flag;
section_dir.set_flags &= ~attr->flag;
section_dir.set_flags |= flags;
section_dir.clear_flags &= ~flags;
}
negate = 0;
}
if (negate) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Section, "dangling '!' in \"%S\"", param);
is_parse_ok = 0;
}
}
if (has_attr) {
section_dir.clear_flags |= COFF_SectionFlag_MemDiscardable|COFF_SectionFlag_MemNotCached|COFF_SectionFlag_MemNotPaged|COFF_SectionFlag_MemShared;
if (has_mem_attr) {
section_dir.clear_flags |= COFF_SectionFlag_MemExecute|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
section_dir.clear_flags &= ~section_dir.set_flags;
}
}
if (is_parse_ok) {
section_dir.name = push_str8_copy(config->arena, section_dir.name);
LNK_SectionDirectiveNode *node = push_array_no_zero(config->arena, LNK_SectionDirectiveNode, 1);
node->v = section_dir;
SLLQueuePush(config->section_list.first, config->section_list.last, node);
config->section_list.count += 1;
}
} break;
case LNK_CmdSwitch_Stack: { case LNK_CmdSwitch_Stack: {
Rng1U64 reserve_commit; Rng1U64 reserve_commit;
reserve_commit.v[0] = config->stack_reserve; reserve_commit.v[0] = config->stack_reserve;
@@ -2125,11 +2325,13 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
lnk_cmd_switch_parse_u32(obj, cmd_switch, value_strings, &config->time_stamp, 0); lnk_cmd_switch_parse_u32(obj, cmd_switch, value_strings, &config->time_stamp, 0);
} break; } break;
case LNK_CmdSwitch_Rad_TypeHashAlg: { case LNK_CmdSwitch_Rad_DebugTypeHash: {
String8 alg = {0}; String8 alg = {0};
if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &alg)) { if (lnk_cmd_switch_parse_string(obj, cmd_switch, value_strings, &alg)) {
if (str8_match(alg, str8_lit("BLAKE3"), StringMatchFlag_CaseInsensitive)) { if (str8_match(alg, str8_lit("BLAKE3"), StringMatchFlag_CaseInsensitive)) {
config->type_hash_alg = LLVM_GHashAlg_BLAKE3; config->debug_types_hash = LNK_HashKind_BLAKE3;
} else if (str8_match(alg, str8_lit("XXHASH"), StringMatchFlag_CaseInsensitive)) {
config->debug_types_hash = LNK_HashKind_XXHash;
} else { } else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unknown hash alg: %S", alg); lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "unknown hash alg: %S", alg);
} }
@@ -2179,6 +2381,335 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "missing type server file path"); lnk_error_cmd_switch(LNK_Error_Cmdl, obj, cmd_switch, "missing type server file path");
} }
} break; } break;
case LNK_CmdSwitch_LLVM_AddrSig: {
lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->llvm_addrsig);
} break;
}
scratch_end(scratch);
}
typedef enum LNK_DefFileStmt
{
LNK_DefFileStmt_Null,
LNK_DefFileStmt_Description,
LNK_DefFileStmt_Exports,
LNK_DefFileStmt_HeapSize,
LNK_DefFileStmt_Imports,
LNK_DefFileStmt_Library,
LNK_DefFileStmt_Name,
LNK_DefFileStmt_Sections,
LNK_DefFileStmt_Segments,
LNK_DefFileStmt_StackSize,
LNK_DefFileStmt_Stub,
LNK_DefFileStmt_Version,
} LNK_DefFileStmt;
global read_only struct
{
String8 name;
LNK_DefFileStmt stmt;
} g_def_file_stmt_map[] =
{
{ str8_lit_comp("DESCRIPTION"), LNK_DefFileStmt_Description },
{ str8_lit_comp("EXPORTS"), LNK_DefFileStmt_Exports },
{ str8_lit_comp("HEAPSIZE"), LNK_DefFileStmt_HeapSize },
{ str8_lit_comp("IMPORTS"), LNK_DefFileStmt_Imports },
{ str8_lit_comp("LIBRARY"), LNK_DefFileStmt_Library },
{ str8_lit_comp("NAME"), LNK_DefFileStmt_Name },
{ str8_lit_comp("SECTIONS"), LNK_DefFileStmt_Sections },
{ str8_lit_comp("SEGMENTS"), LNK_DefFileStmt_Segments },
{ str8_lit_comp("STACKSIZE"), LNK_DefFileStmt_StackSize },
{ str8_lit_comp("STUB"), LNK_DefFileStmt_Stub },
{ str8_lit_comp("VERSION"), LNK_DefFileStmt_Version },
};
typedef struct LNK_DefFileLineNode LNK_DefFileLineNode;
struct LNK_DefFileLineNode
{
LNK_DefFileStmt stmt;
String8 line;
B32 is_keyword;
LNK_DefFileLineNode *next;
};
typedef struct LNK_DefFileLineList LNK_DefFileLineList;
struct LNK_DefFileLineList
{
U64 count;
LNK_DefFileLineNode *first;
LNK_DefFileLineNode *last;
};
internal String8List
lnk_def_file_tokenize(Arena *arena, String8 line)
{
// tokenize with windows quoting rules
line = push_str8_copy(arena, line);
for EachIndex(i, line.size) {
if (line.str[i] == '\t') {
line.str[i] = ' ';
}
}
String8List tokens = lnk_arg_list_parse_windows_rules(arena, line);
String8List result = {0};
for (String8Node *token_n = tokens.first; token_n != 0; token_n = token_n->next) {
String8 token = token_n->string;
String8Node *next_n = token_n->next;
if (token.size == 1 && token.str[0] == '@' && next_n != 0) {
str8_list_push(arena, &result, str8_cat(arena, token, next_n->string));
token_n = next_n;
} else {
str8_list_push(arena, &result, token);
}
}
return result;
}
internal void
lnk_apply_def_file_to_config(LNK_Config *config, String8 path, LNK_Obj *obj)
{
Temp scratch = scratch_begin(&config->arena, 1);
// load DEF file
String8 raw_file = lnk_read_data_from_file_path(scratch.arena, config->io_flags, path);
String8 file = lnk_text_file_string_from_data(scratch.arena, raw_file);
// parse & collect normalized DEF lines
LNK_DefFileLineList def_lines = {0};
LNK_DefFileStmt active_stmt = LNK_DefFileStmt_Null;
String8 rest = file;
while (rest.size != 0) {
String8 line = str8_chop_line(&rest);
// strip comments outside quotes
B32 in_quote = 0;
for EachIndex(i, line.size) {
U8 c = line.str[i];
if (in_quote && c == '\\') {
i += 1;
continue;
}
if (c == '"') {
in_quote = !in_quote;
} else if (c == ';' && !in_quote) {
line = str8_prefix(line, i);
break;
}
}
line = str8_skip_chop_whitespace(line);
if (line.size == 0) { continue; }
// parse statement keyword
String8 tail = line;
LNK_DefFileStmt stmt = LNK_DefFileStmt_Null;
B32 is_keyword = 0;
if (line.size != 0 && line.str[0] != '"') {
U64 keyword_opl = 0;
for (; keyword_opl < line.size; keyword_opl += 1) {
U8 c = line.str[keyword_opl];
if (char_is_space(c) || c == ':' || c == '=') {
break;
}
}
String8 keyword = str8_prefix(line, keyword_opl);
for EachElement(i, g_def_file_stmt_map) {
if (str8_matchi(g_def_file_stmt_map[i].name, keyword)) {
stmt = g_def_file_stmt_map[i].stmt;
break;
}
}
if (stmt != LNK_DefFileStmt_Null) {
U64 tail_pos = keyword_opl;
while (tail_pos < line.size && char_is_space(line.str[tail_pos])) {
tail_pos += 1;
}
if (tail_pos < line.size && (line.str[tail_pos] == ':' || line.str[tail_pos] == '=')) {
tail_pos += 1;
}
tail = str8_skip_chop_whitespace(str8_skip(line, tail_pos));
}
}
if (stmt != LNK_DefFileStmt_Null) {
B32 is_multiline = stmt == LNK_DefFileStmt_Exports ||
stmt == LNK_DefFileStmt_Sections ||
stmt == LNK_DefFileStmt_Imports ||
stmt == LNK_DefFileStmt_Segments;
active_stmt = is_multiline ? stmt : LNK_DefFileStmt_Null;
is_keyword = 1;
line = tail;
} else {
stmt = active_stmt;
}
LNK_DefFileLineNode *node = push_array(scratch.arena, LNK_DefFileLineNode, 1);
node->stmt = stmt;
node->line = line;
node->is_keyword = is_keyword;
SLLQueuePush(def_lines.first, def_lines.last, node);
def_lines.count += 1;
}
// apply collected DEF lines to config
for EachNode(def_line, LNK_DefFileLineNode, def_lines.first) {
String8 line = def_line->line;
LNK_DefFileStmt stmt = def_line->stmt;
switch (stmt) {
case LNK_DefFileStmt_Description: {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "DESCRIPTION is ignored in DEF files");
} break;
case LNK_DefFileStmt_Imports: {
if (def_line->is_keyword) {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "IMPORTS is ignored in DEF files");
} else {
lnk_log(LNK_Log_Debug, "%S: unsupported old-style import specifications", path);
}
} break;
case LNK_DefFileStmt_Stub: {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "STUB is ignored in DEF files");
} break;
case LNK_DefFileStmt_Segments: {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "SEGMENTS is ignored in DEF files");
} break;
case LNK_DefFileStmt_Exports: {
String8List tokens = lnk_def_file_tokenize(scratch.arena, line);
if (tokens.node_count != 0) {
PE_ExportParse export_parse = {0};
if (lnk_parse_export_directive_ex(config->arena, tokens, obj, &export_parse)) {
export_parse.obj_path = path;
lnk_push_export_to_config(config, obj, export_parse);
}
}
} break;
case LNK_DefFileStmt_Library:
case LNK_DefFileStmt_Name: {
String8List tokens = lnk_def_file_tokenize(scratch.arena, line);
String8 name = {0};
for EachNode(token_n, String8Node, tokens.first) {
String8 token = token_n->string;
String8 base_value = {0};
B32 has_base = 0;
U64 sep_pos = str8_find_needle(token, 0, str8_lit("="), 0);
if (sep_pos < token.size) {
String8 key = str8_prefix(token, sep_pos);
if (str8_matchi(key, str8_lit("BASE"))) {
base_value = str8_skip(token, sep_pos + 1);
has_base = 1;
}
} else if (str8_matchi(token, str8_lit("BASE")) ||
str8_match_lit("BASE:", token, StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)) {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Def, "syntax error in DEF file BASE specification");
}
if (has_base) {
String8List values = str8_split_by_string_chars(scratch.arena, base_value, str8_lit(","), 0);
lnk_apply_cmd_option_to_config(config, str8_lit("base"), values, obj);
} else if (name.size == 0) {
name = token;
} else {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "ignoring unexpected DEF token \"%S\"", token);
}
}
if (stmt == LNK_DefFileStmt_Library) {
config->file_characteristics |= PE_ImageFileCharacteristic_FILE_DLL;
}
if (name.size != 0) {
String8 image_name = name;
if (stmt == LNK_DefFileStmt_Library) {
// set DLL import name
String8 file_name = str8_skip_last_slash(name);
B32 has_ext = (str8_skip_last_dot(file_name).size != file_name.size);
if (!has_ext) {
image_name = path_replace_file_extension(scratch.arena, name, str8_lit("dll"));
}
if (config->image_alt_path.size == 0) {
config->image_alt_path = push_str8_copy(config->arena, image_name);
}
}
if (config->out_path.size == 0) {
config->out_path = push_str8_copy(config->arena, image_name);
}
}
} break;
case LNK_DefFileStmt_Sections: {
String8List tokens = lnk_def_file_tokenize(scratch.arena, line);
if (tokens.node_count != 0) {
B32 is_parse_ok = 1;
String8List section_values = {0};
str8_list_push(scratch.arena, &section_values, tokens.first->string);
for (String8Node *token_n = tokens.first->next; token_n != 0; token_n = token_n->next) {
String8 token = token_n->string;
if (str8_matchi(token, str8_lit("CLASS"))) {
if (token_n->next != 0) {
token_n = token_n->next;
}
continue;
}
String8 attr = {0};
if (str8_matchi(token, str8_lit("EXECUTE"))) {
attr = str8_lit("E");
} else if (str8_matchi(token, str8_lit("READ"))) {
attr = str8_lit("R");
} else if (str8_matchi(token, str8_lit("SHARED"))) {
attr = str8_lit("S");
} else if (str8_matchi(token, str8_lit("WRITE"))) {
attr = str8_lit("W");
} else {
lnk_error_cmd_switch(LNK_Error_Cmdl, obj, LNK_CmdSwitch_Def, "unknown DEF SECTIONS specifier \"%S\"", token);
is_parse_ok = 0;
}
if (attr.size != 0) {
str8_list_push(scratch.arena, &section_values, attr);
}
}
if (is_parse_ok) {
lnk_apply_cmd_option_to_config(config, str8_lit("section"), section_values, obj);
}
}
} break;
case LNK_DefFileStmt_StackSize: {
String8List values = str8_split_by_string_chars(scratch.arena, line, str8_lit(" \t,"), 0);
lnk_apply_cmd_option_to_config(config, str8_lit("stack"), values, obj);
} break;
case LNK_DefFileStmt_Version: {
String8List values = str8_split_by_string_chars(scratch.arena, line, str8_lit(" \t"), 0);
lnk_apply_cmd_option_to_config(config, str8_lit("version"), values, obj);
} break;
case LNK_DefFileStmt_HeapSize: {
String8List values = str8_split_by_string_chars(scratch.arena, line, str8_lit(" \t,"), 0);
lnk_apply_cmd_option_to_config(config, str8_lit("heap"), values, obj);
} break;
default: {
lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, LNK_CmdSwitch_Def, "ignoring unrecognized DEF statement \"%S\"", line);
} break;
}
} }
scratch_end(scratch); scratch_end(scratch);
@@ -2208,6 +2739,7 @@ lnk_config_init(LNK_CmdLine cmd_line)
config->arena = arena; config->arena = arena;
config->raw_cmd_line = str8_list_copy(arena, &cmd_line.raw_cmd_line); config->raw_cmd_line = str8_list_copy(arena, &cmd_line.raw_cmd_line);
config->work_dir = get_current_path(arena); config->work_dir = get_current_path(arena);
config->force = lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Force);
// apply command line switches // apply command line switches
for EachNode(cmd, LNK_CmdOption, cmd_line.first_option) { for EachNode(cmd, LNK_CmdOption, cmd_line.first_option) {
@@ -2333,13 +2865,15 @@ lnk_config_init(LNK_CmdLine cmd_line)
config->dll_characteristics |= PE_DllCharacteristic_DYNAMIC_BASE; config->dll_characteristics |= PE_DllCharacteristic_DYNAMIC_BASE;
} }
// set flag for /guard // TODO: Set GUARD_CF only after emitting the Guard CF function tables.
// Marking the image without valid load-config tables makes CFG-enabled
// executables crash on indirect calls.
if (config->guard_flags != LNK_Guard_None) { if (config->guard_flags != LNK_Guard_None) {
config->dll_characteristics |= PE_DllCharacteristic_GUARD_CF; // config->dll_characteristics |= PE_DllCharacteristic_GUARD_CF;
} }
// handle empty /OUT // handle empty /OUT
if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) { if (!config->out_path.size) {
String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]); String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]);
String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe");
config->out_path = path_replace_file_extension(scratch.arena, name, ext); config->out_path = path_replace_file_extension(scratch.arena, name, ext);
@@ -2422,4 +2956,3 @@ lnk_config_init(LNK_CmdLine cmd_line)
ProfEnd(); ProfEnd();
return config; return config;
} }
+33 -4
View File
@@ -47,6 +47,7 @@ typedef enum
LNK_CmdSwitch_Brepro, LNK_CmdSwitch_Brepro,
LNK_CmdSwitch_Debug, LNK_CmdSwitch_Debug,
LNK_CmdSwitch_DefaultLib, LNK_CmdSwitch_DefaultLib,
LNK_CmdSwitch_Def,
LNK_CmdSwitch_Delay, LNK_CmdSwitch_Delay,
LNK_CmdSwitch_DelayLoad, LNK_CmdSwitch_DelayLoad,
LNK_CmdSwitch_DisallowLib, LNK_CmdSwitch_DisallowLib,
@@ -59,6 +60,8 @@ typedef enum
LNK_CmdSwitch_Fixed, LNK_CmdSwitch_Fixed,
LNK_CmdSwitch_Force, LNK_CmdSwitch_Force,
LNK_CmdSwitch_FunctionPadMin, LNK_CmdSwitch_FunctionPadMin,
LNK_CmdSwitch_Guard,
LNK_CmdSwitch_GuardSym,
LNK_CmdSwitch_Heap, LNK_CmdSwitch_Heap,
LNK_CmdSwitch_HighEntropyVa, LNK_CmdSwitch_HighEntropyVa,
LNK_CmdSwitch_Ignore, LNK_CmdSwitch_Ignore,
@@ -88,6 +91,7 @@ typedef enum
LNK_CmdSwitch_PdbPageSize, LNK_CmdSwitch_PdbPageSize,
LNK_CmdSwitch_PdbStripped, LNK_CmdSwitch_PdbStripped,
LNK_CmdSwitch_Release, LNK_CmdSwitch_Release,
LNK_CmdSwitch_Section,
LNK_CmdSwitch_Stack, LNK_CmdSwitch_Stack,
LNK_CmdSwitch_SubSystem, LNK_CmdSwitch_SubSystem,
LNK_CmdSwitch_Time, LNK_CmdSwitch_Time,
@@ -132,7 +136,7 @@ typedef enum
LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers,
LNK_CmdSwitch_Rad_SortImports, LNK_CmdSwitch_Rad_SortImports,
LNK_CmdSwitch_Rad_TimeStamp, LNK_CmdSwitch_Rad_TimeStamp,
LNK_CmdSwitch_Rad_TypeHashAlg, LNK_CmdSwitch_Rad_DebugTypeHash,
LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit,
LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit,
LNK_CmdSwitch_Rad_Version, LNK_CmdSwitch_Rad_Version,
@@ -143,6 +147,8 @@ typedef enum
LNK_CmdSwitch_RadTypeServer, LNK_CmdSwitch_RadTypeServer,
LNK_CmdSwitch_RadTypeServer_MatchObj, LNK_CmdSwitch_RadTypeServer_MatchObj,
LNK_CmdSwitch_LLVM_AddrSig,
LNK_CmdSwitch_Help, LNK_CmdSwitch_Help,
LNK_CmdSwitch_Count LNK_CmdSwitch_Count
@@ -265,6 +271,26 @@ typedef struct LNK_MergeDirectiveList
LNK_MergeDirectiveNode *last; LNK_MergeDirectiveNode *last;
} LNK_MergeDirectiveList; } LNK_MergeDirectiveList;
typedef struct LNK_SectionDirective
{
String8 name;
COFF_SectionFlags set_flags;
COFF_SectionFlags clear_flags;
} LNK_SectionDirective;
typedef struct LNK_SectionDirectiveNode
{
struct LNK_SectionDirectiveNode *next;
LNK_SectionDirective v;
} LNK_SectionDirectiveNode;
typedef struct LNK_SectionDirectiveList
{
U64 count;
LNK_SectionDirectiveNode *first;
LNK_SectionDirectiveNode *last;
} LNK_SectionDirectiveList;
typedef enum typedef enum
{ {
LNK_DebugInfoGuid_Null, LNK_DebugInfoGuid_Null,
@@ -279,7 +305,6 @@ typedef enum
LNK_TypeNameHashMode_Full, LNK_TypeNameHashMode_Full,
} LNK_TypeNameHashMode; } LNK_TypeNameHashMode;
typedef struct LNK_Config typedef struct LNK_Config
{ {
Arena *arena; Arena *arena;
@@ -316,6 +341,7 @@ typedef struct LNK_Config
U64 function_pad_min; U64 function_pad_min;
U64 *manifest_resource_id; U64 *manifest_resource_id;
B32 no_default_libs; B32 no_default_libs;
B32 force;
LNK_SwitchState infer_asan_libs; LNK_SwitchState infer_asan_libs;
Version link_ver; Version link_ver;
Version os_ver; Version os_ver;
@@ -360,6 +386,7 @@ typedef struct LNK_Config
LNK_IncludeSymbolList include_symbol_list; LNK_IncludeSymbolList include_symbol_list;
LNK_AltNameList alt_name_list; LNK_AltNameList alt_name_list;
LNK_MergeDirectiveList merge_list; LNK_MergeDirectiveList merge_list;
LNK_SectionDirectiveList section_list;
U64 data_dir_count; U64 data_dir_count;
B32 build_imp_lib; B32 build_imp_lib;
B32 build_exp; B32 build_exp;
@@ -383,10 +410,11 @@ typedef struct LNK_Config
U64 unresolved_symbol_limit; U64 unresolved_symbol_limit;
U64 unresolved_symbol_ref_limit; U64 unresolved_symbol_ref_limit;
LNK_SwitchState map_lines_for_unresolved_symbols; LNK_SwitchState map_lines_for_unresolved_symbols;
LLVM_GHashAlg type_hash_alg; LNK_HashKind debug_types_hash;
String8 type_server_name; String8 type_server_name;
LNK_SwitchState type_server; LNK_SwitchState type_server;
LNK_SwitchState sort_imports; LNK_SwitchState sort_imports;
LNK_SwitchState llvm_addrsig;
} LNK_Config; } LNK_Config;
// --- MSVC Error Codes -------------------------------------------------------- // --- MSVC Error Codes --------------------------------------------------------
@@ -571,6 +599,8 @@ internal B32 lnk_is_thread_pool_shared(LNK_Config *config);
internal B32 lnk_is_section_removed (LNK_Config *config, String8 section_name); internal B32 lnk_is_section_removed (LNK_Config *config, String8 section_name);
internal B32 lnk_is_dll_delay_load (LNK_Config *config, String8 dll_name); internal B32 lnk_is_dll_delay_load (LNK_Config *config, String8 dll_name);
internal COFF_SectionFlags lnk_apply_section_directives_to_flags(LNK_Config *config, String8 full_section_name, COFF_SectionFlags flags);
internal String8 lnk_get_lib_name (String8 path); internal String8 lnk_get_lib_name (String8 path);
internal void lnk_push_disallow_lib(LNK_Config *config, String8 path); internal void lnk_push_disallow_lib(LNK_Config *config, String8 path);
internal B32 lnk_is_lib_disallowed(LNK_Config *config, String8 path); internal B32 lnk_is_lib_disallowed(LNK_Config *config, String8 path);
@@ -585,4 +615,3 @@ internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, S
internal void lnk_config_pushf(LNK_Config *config, char *fmt, ...); internal void lnk_config_pushf(LNK_Config *config, char *fmt, ...);
internal LNK_Config * lnk_config_init(LNK_CmdLine cmd_line); internal LNK_Config * lnk_config_init(LNK_CmdLine cmd_line);
+362 -191
View File
@@ -57,6 +57,18 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_s_task)
} }
} }
internal int
lnk_symbol_input_task_is_before(void *raw_a, void *raw_b)
{
LNK_SymbolInputTask *a = raw_a, *b = raw_b;
if (a->weight == b->weight) {
return a->input_range.min < b->input_range.min;
}
return a->weight > b->weight;
}
internal internal
THREAD_POOL_TASK_FUNC(lnk_parse_debug_h_task) THREAD_POOL_TASK_FUNC(lnk_parse_debug_h_task)
{ {
@@ -95,11 +107,11 @@ THREAD_POOL_TASK_FUNC(lnk_parse_debug_h_task)
} }
// validate hashing algorithm // validate hashing algorithm
if (ghash.hash_alg != task->config->type_hash_alg) { if (lnk_hash_kind_from_llvm(ghash.hash_alg) != task->config->debug_types_hash) {
lnk_error_obj(LNK_Warning_GHash, task->obj_arr[obj_idx], lnk_error_obj(LNK_Warning_GHash, task->obj_arr[obj_idx],
"mismatched .debug$H hash algorithm: got %S, expected %S", "mismatched .debug$H hash algorithm: got %S, expected %S; types will be rehashed",
llvm_string_from_ghash_alg(ghash.hash_alg), llvm_string_from_ghash_alg(ghash.hash_alg),
llvm_string_from_ghash_alg(task->config->type_hash_alg)); lnk_string_hash_kind(task->config->debug_types_hash));
goto exit; goto exit;
} }
@@ -308,42 +320,45 @@ lnk_string_list_from_rrt(Arena *arena, LNK_RRT *rrt)
str8_list_push(arena, &rrt_data, g_rrt_magic); str8_list_push(arena, &rrt_data, g_rrt_magic);
// (2) version // (2) version
str8_list_push(arena, &rrt_data, str8_struct(&g_rrt_version)); str8_list_push(arena, &rrt_data, str8_struct(push_u64(arena, g_rrt_version)));
// (3) type data ranges // (3) debug types hash
str8_list_push(arena, &rrt_data, str8_struct(&rrt->debug_types_hash));
// (4) type data ranges
str8_list_push(arena, &rrt_data, str8_array_fixed(rrt->type_data_ranges)); str8_list_push(arena, &rrt_data, str8_array_fixed(rrt->type_data_ranges));
// (4) type data // (5) type data
str8_list_push(arena, &rrt_data, rrt->type_data_raw); str8_list_push(arena, &rrt_data, rrt->type_data_raw);
// (5) type index ranges // (6) type index ranges
str8_list_push(arena, &rrt_data, str8_array_fixed(rrt->ti_ranges)); str8_list_push(arena, &rrt_data, str8_array_fixed(rrt->ti_ranges));
// (6) type hashes size // (7) type hashes size
U64 total_hash_count = 0; U64 total_hash_count = 0;
for EachIndex(i, CV_TypeIndexSource_COUNT) { total_hash_count += dim_1u64(rrt->ti_ranges[i]); } for EachIndex(i, CV_TypeIndexSource_COUNT) { total_hash_count += dim_1u64(rrt->ti_ranges[i]); }
U64 type_hashes_size = sizeof(**rrt->type_hashes_unpacked) * total_hash_count; U64 type_hashes_size = sizeof(**rrt->type_hashes_unpacked) * total_hash_count;
str8_list_push(arena, &rrt_data, str8_struct(push_u64(arena, type_hashes_size))); str8_list_push(arena, &rrt_data, str8_struct(push_u64(arena, type_hashes_size)));
// (7) type hashes // (8) type hashes
for EachIndex(i, CV_TypeIndexSource_COUNT) { for EachIndex(i, CV_TypeIndexSource_COUNT) {
U64 type_count = dim_1u64(rrt->ti_ranges[i]); U64 type_count = dim_1u64(rrt->ti_ranges[i]);
str8_list_push(arena, &rrt_data, str8_array(rrt->type_hashes_unpacked[i], type_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->type_hashes_unpacked[i], type_count));
} }
// (8) object count // (9) object count
str8_list_push(arena, &rrt_data, str8_struct(&rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_struct(&rrt->obj_count));
// (9) per object type index ranges // (10) per object type index ranges
str8_list_push(arena, &rrt_data, str8_array(rrt->obj_ti_ranges, rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->obj_ti_ranges, rrt->obj_count));
// (10) per object time stamps // (11) per object time stamps
str8_list_push(arena, &rrt_data, str8_array(rrt->obj_time_stamps, rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->obj_time_stamps, rrt->obj_count));
// (11) per object leaf counts // (12) per object leaf counts
str8_list_push(arena, &rrt_data, str8_array(rrt->obj_leaf_counts, rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->obj_leaf_counts, rrt->obj_count));
// (12) per object file reverse lookup table for type indices // (13) per object file reverse lookup table for type indices
for EachIndex(obj_idx, rrt->obj_count) { for EachIndex(obj_idx, rrt->obj_count) {
CV_TypeIndex *obj_ti_map = rrt->obj_ti_maps[obj_idx]; CV_TypeIndex *obj_ti_map = rrt->obj_ti_maps[obj_idx];
U64 obj_ti_count = rrt->obj_leaf_counts[obj_idx]; U64 obj_ti_count = rrt->obj_leaf_counts[obj_idx];
@@ -351,16 +366,16 @@ lnk_string_list_from_rrt(Arena *arena, LNK_RRT *rrt)
str8_list_push(arena, &rrt_data, str8_array(obj_ti_map, obj_ti_count)); str8_list_push(arena, &rrt_data, str8_array(obj_ti_map, obj_ti_count));
} }
// (13) object file paths size // (14) object file paths size
str8_list_push(arena, &rrt_data, str8_struct(push_u64(arena, obj_paths.size))); str8_list_push(arena, &rrt_data, str8_struct(push_u64(arena, obj_paths.size)));
// (14) object file paths block // (15) object file paths block
str8_list_push(arena, &rrt_data, obj_paths); str8_list_push(arena, &rrt_data, obj_paths);
// (15) PCH type index ranges // (16) PCH type index ranges
str8_list_push(arena, &rrt_data, str8_array(rrt->obj_pch_ti_ranges, rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->obj_pch_ti_ranges, rrt->obj_count));
// (16) PCH object indices // (17) PCH object indices
str8_list_push(arena, &rrt_data, str8_array(rrt->obj_pch_indices, rrt->obj_count)); str8_list_push(arena, &rrt_data, str8_array(rrt->obj_pch_indices, rrt->obj_count));
ProfEnd(); ProfEnd();
@@ -392,11 +407,27 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
// match version // match version
if (version != g_rrt_version) { if (version != g_rrt_version) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT version mismatch, got %llu, expected %llu", path, version, g_rrt_version); lnk_error(LNK_Error_IllData, "ERROR: %S: RRT version mismatch, got %llu, expected 2 or %llu", path, version, g_rrt_version);
goto exit; goto exit;
} }
// (3) type data ranges // (3) debug types hash
LNK_HashKind debug_types_hash = LNK_HashKind_BLAKE3;
if (version == g_rrt_version) {
U64 debug_types_hash_size = str8_deserial_read_struct(rrt_data, cursor, &debug_types_hash);
if (debug_types_hash_size != sizeof(debug_types_hash)) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file does not contain enough bytes to read the debug types hash", path);
goto exit;
}
cursor += debug_types_hash_size;
if (debug_types_hash != LNK_HashKind_BLAKE3 && debug_types_hash != LNK_HashKind_XXHash) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file has invalid debug types hash %u", path, debug_types_hash);
goto exit;
}
}
// (4) type data ranges
Rng1U64 type_data_ranges[CV_TypeIndexSource_COUNT] = {0}; Rng1U64 type_data_ranges[CV_TypeIndexSource_COUNT] = {0};
U64 type_data_ranges_size = str8_deserial_read_array(rrt_data, cursor, type_data_ranges, ArrayCount(type_data_ranges)); U64 type_data_ranges_size = str8_deserial_read_array(rrt_data, cursor, type_data_ranges, ArrayCount(type_data_ranges));
if (type_data_ranges_size != sizeof(type_data_ranges)) { if (type_data_ranges_size != sizeof(type_data_ranges)) {
@@ -409,7 +440,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
U64 total_type_data_size = 0; U64 total_type_data_size = 0;
for EachElement(i, type_data_ranges) total_type_data_size += dim_1u64(type_data_ranges[i]); for EachElement(i, type_data_ranges) total_type_data_size += dim_1u64(type_data_ranges[i]);
// (4) type data // (5) type data
String8 type_data_raw = {0}; String8 type_data_raw = {0};
U64 type_data_raw_size = str8_deserial_read_block(rrt_data, cursor, total_type_data_size, &type_data_raw); U64 type_data_raw_size = str8_deserial_read_block(rrt_data, cursor, total_type_data_size, &type_data_raw);
if (type_data_raw_size != total_type_data_size) { if (type_data_raw_size != total_type_data_size) {
@@ -418,7 +449,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += type_data_raw_size; cursor += type_data_raw_size;
// (5) type index ranges // (6) type index ranges
Rng1U64 ti_ranges[CV_TypeIndexSource_COUNT] = {0}; Rng1U64 ti_ranges[CV_TypeIndexSource_COUNT] = {0};
U64 ti_ranges_size = str8_deserial_read_array(rrt_data, cursor, ti_ranges, ArrayCount(ti_ranges)); U64 ti_ranges_size = str8_deserial_read_array(rrt_data, cursor, ti_ranges, ArrayCount(ti_ranges));
if (ti_ranges_size != sizeof(ti_ranges)) { if (ti_ranges_size != sizeof(ti_ranges)) {
@@ -427,7 +458,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += ti_ranges_size; cursor += ti_ranges_size;
// (6) type hashes size // (7) type hashes size
U64 type_hashes_size = 0; U64 type_hashes_size = 0;
U64 type_hashes_size_size = str8_deserial_read_struct(rrt_data, cursor, &type_hashes_size); U64 type_hashes_size_size = str8_deserial_read_struct(rrt_data, cursor, &type_hashes_size);
if (type_hashes_size_size != sizeof(type_hashes_size)) { if (type_hashes_size_size != sizeof(type_hashes_size)) {
@@ -447,7 +478,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
} }
// (7) type hashes // (8) type hashes
String8 type_hashes = {0}; String8 type_hashes = {0};
U64 type_hashes_read_size = str8_deserial_read_block(rrt_data, cursor, type_hashes_size, &type_hashes); U64 type_hashes_read_size = str8_deserial_read_block(rrt_data, cursor, type_hashes_size, &type_hashes);
if (type_hashes_read_size != type_hashes_size) { if (type_hashes_read_size != type_hashes_size) {
@@ -467,7 +498,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
} }
// (8) object count // (9) object count
U64 obj_count = 0; U64 obj_count = 0;
U64 obj_count_size = str8_deserial_read_struct(rrt_data, cursor, &obj_count); U64 obj_count_size = str8_deserial_read_struct(rrt_data, cursor, &obj_count);
if (obj_count_size == 0) { if (obj_count_size == 0) {
@@ -476,7 +507,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += obj_count_size; cursor += obj_count_size;
// (9) per object type index ranges // (10) per object type index ranges
Rng1U64 *obj_ti_ranges = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_ti_ranges) * obj_count); Rng1U64 *obj_ti_ranges = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_ti_ranges) * obj_count);
if (obj_ti_ranges == 0) { if (obj_ti_ranges == 0) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object type index ranges", path); lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object type index ranges", path);
@@ -484,7 +515,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += sizeof(*obj_ti_ranges) * obj_count; cursor += sizeof(*obj_ti_ranges) * obj_count;
// (10) last observed time stamp of the object files // (11) last observed time stamp of the object files
U64 *obj_time_stamps = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_time_stamps) * obj_count); U64 *obj_time_stamps = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_time_stamps) * obj_count);
if (obj_time_stamps == 0) { if (obj_time_stamps == 0) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object timestamps", path); lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object timestamps", path);
@@ -492,7 +523,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += sizeof(*obj_time_stamps) * obj_count; cursor += sizeof(*obj_time_stamps) * obj_count;
// (11) per object leaf counts // (12) per object leaf counts
U64 *obj_leaf_counts = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_leaf_counts) * obj_count); U64 *obj_leaf_counts = str8_deserial_get_raw_ptr(rrt_data, cursor, sizeof(*obj_leaf_counts) * obj_count);
if (obj_leaf_counts == 0) { if (obj_leaf_counts == 0) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object leaf counts", path); lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is missing the object leaf counts", path);
@@ -500,7 +531,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += sizeof(*obj_leaf_counts) * obj_count; cursor += sizeof(*obj_leaf_counts) * obj_count;
// (12) per object file reverse lookup table for type indices // (13) per object file reverse lookup table for type indices
CV_TypeIndex **obj_ti_maps = push_array(arena, CV_TypeIndex *, obj_count); CV_TypeIndex **obj_ti_maps = push_array(arena, CV_TypeIndex *, obj_count);
for EachIndex(obj_idx, obj_count) { for EachIndex(obj_idx, obj_count) {
U64 obj_ti_count = obj_leaf_counts[obj_idx]; U64 obj_ti_count = obj_leaf_counts[obj_idx];
@@ -512,7 +543,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
cursor += obj_ti_count * sizeof(*obj_ti_maps[obj_idx]); cursor += obj_ti_count * sizeof(*obj_ti_maps[obj_idx]);
} }
// (13) object file paths size // (14) object file paths size
U64 obj_file_paths_size = 0; U64 obj_file_paths_size = 0;
U64 obj_file_paths_size_size = str8_deserial_read_struct(rrt_data, cursor, &obj_file_paths_size); U64 obj_file_paths_size_size = str8_deserial_read_struct(rrt_data, cursor, &obj_file_paths_size);
if (obj_file_paths_size_size == 0) { if (obj_file_paths_size_size == 0) {
@@ -521,7 +552,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += obj_file_paths_size_size; cursor += obj_file_paths_size_size;
// (14) object file paths block // (15) object file paths block
String8 obj_file_paths_block = {0}; String8 obj_file_paths_block = {0};
U64 obj_file_paths_block_size = str8_deserial_read_block(rrt_data, cursor, obj_file_paths_size, &obj_file_paths_block); U64 obj_file_paths_block_size = str8_deserial_read_block(rrt_data, cursor, obj_file_paths_size, &obj_file_paths_block);
if (obj_file_paths_block_size != obj_file_paths_size) { if (obj_file_paths_block_size != obj_file_paths_size) {
@@ -530,7 +561,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
} }
cursor += obj_file_paths_block_size; cursor += obj_file_paths_block_size;
// (15) PCH type index ranges // (16) PCH type index ranges
Rng1U64 *obj_pch_ti_ranges = str8_deserial_get_raw_ptr(rrt_data, cursor, obj_count * sizeof(*obj_pch_ti_ranges)); Rng1U64 *obj_pch_ti_ranges = str8_deserial_get_raw_ptr(rrt_data, cursor, obj_count * sizeof(*obj_pch_ti_ranges));
if (obj_pch_ti_ranges == 0) { if (obj_pch_ti_ranges == 0) {
lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is too small to read object PCH type index ranges"); lnk_error(LNK_Error_IllData, "ERROR: %S: RRT file is too small to read object PCH type index ranges");
@@ -572,6 +603,7 @@ lnk_rrt_from_string(Arena *arena, String8 rrt_data, String8 path, LNK_RRT *rrt_o
// fill out result // fill out result
if (rrt_out) { if (rrt_out) {
rrt_out->path = path; rrt_out->path = path;
rrt_out->debug_types_hash = debug_types_hash;
rrt_out->type_data_raw = type_data_raw; rrt_out->type_data_raw = type_data_raw;
rrt_out->type_hashes = type_hashes; rrt_out->type_hashes = type_hashes;
MemoryCopyArray(rrt_out->type_data_ranges, type_data_ranges); MemoryCopyArray(rrt_out->type_data_ranges, type_data_ranges);
@@ -925,7 +957,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config,
// wire RRT hashes to type servers .debug$H // wire RRT hashes to type servers .debug$H
for EachIndex(ts_idx, ts_arr.count) { for EachIndex(ts_idx, ts_arr.count) {
LNK_TypeServer *ts = &ts_arr.v[ts_idx]; LNK_TypeServer *ts = &ts_arr.v[ts_idx];
if (ts->rrt) { if (ts->rrt && ts->rrt->debug_types_hash == config->debug_types_hash) {
U64 ts_obj_idx = input.ts_obj_range.min + ts_idx; U64 ts_obj_idx = input.ts_obj_range.min + ts_idx;
CV_DebugT *debug_t = &input.debug_t_arr[ts_obj_idx]; CV_DebugT *debug_t = &input.debug_t_arr[ts_obj_idx];
CV_DebugH *debug_h = &input.debug_h_arr[ts_obj_idx]; CV_DebugH *debug_h = &input.debug_h_arr[ts_obj_idx];
@@ -1096,6 +1128,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config,
} }
ProfBegin("Make Ranges"); ProfBegin("Make Ranges");
U64 total_input_size = 0; U64 total_input_size = 0;
for EachIndex(i, input.symbol_input_count) { total_input_size += input.symbol_inputs[i].raw_symbols.size; } for EachIndex(i, input.symbol_input_count) { total_input_size += input.symbol_inputs[i].raw_symbols.size; }
@@ -1112,7 +1145,35 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config,
} }
input.symbol_input_ranges[i] = r1u64(begin, cursor); input.symbol_input_ranges[i] = r1u64(begin, cursor);
} }
ProfEnd(); ProfEnd();
if (input.symbol_input_count) {
ProfBegin("Balance Symbol Inputs");
U64 task_cap = Min(input.symbol_input_count, tp->worker_count * 16);
U64 task_weight = Max(1, CeilIntegerDiv(total_input_size, task_cap));
input.symbol_patch_task = push_array_no_zero(tp_arena->v[0], LNK_SymbolInputTask, task_cap);
cursor = 0;
while (cursor < input.symbol_input_count) {
U64 begin = cursor;
U64 weight = 0;
do {
weight += input.symbol_inputs[cursor++].raw_symbols.size;
} while (cursor < input.symbol_input_count && weight < task_weight);
Assert(input.symbol_patch_task_count < task_cap);
LNK_SymbolInputTask *task = &input.symbol_patch_task[input.symbol_patch_task_count++];
task->input_range = r1u64(begin, cursor);
task->weight = weight;
}
radsort(input.symbol_patch_task, input.symbol_patch_task_count, lnk_symbol_input_task_is_before);
ProfEnd();
}
} }
ProfEnd(); ProfEnd();
@@ -1207,7 +1268,8 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
CV_TypeIndex curr_ti = cv_ti_from_leaf_idx(debug_t, curr_ti_source, leaf_ref.leaf_idx); CV_TypeIndex curr_ti = cv_ti_from_leaf_idx(debug_t, curr_ti_source, leaf_ref.leaf_idx);
// init hasher // init hasher
blake3_hasher hasher; blake3_hasher_init(&hasher); LNK_Hasher hasher;
lnk_hasher_init(&hasher, input->config->debug_types_hash);
// hash bytes around indices // hash bytes around indices
{ {
@@ -1215,14 +1277,14 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
for EachNode(ti_info, CV_TypeIndexInfo, ti_info_list.first) { for EachNode(ti_info, CV_TypeIndexInfo, ti_info_list.first) {
U8 *bytes = leaf.data.str + last_ti_off; U8 *bytes = leaf.data.str + last_ti_off;
U64 size = ti_info->offset - last_ti_off; U64 size = ti_info->offset - last_ti_off;
blake3_hasher_update(&hasher, bytes, size); lnk_hasher_update(&hasher, bytes, size);
last_ti_off = ti_info->offset + sizeof(CV_TypeIndex); last_ti_off = ti_info->offset + sizeof(CV_TypeIndex);
} }
Assert(leaf.data.size >= last_ti_off); Assert(leaf.data.size >= last_ti_off);
U8 *bytes = leaf.data.str + last_ti_off; U8 *bytes = leaf.data.str + last_ti_off;
U64 size = leaf.data.size - last_ti_off; U64 size = leaf.data.size - last_ti_off;
blake3_hasher_update(&hasher, bytes, size); lnk_hasher_update(&hasher, bytes, size);
} }
// mix-in sub leaf hashes // mix-in sub leaf hashes
@@ -1232,7 +1294,7 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
// simple indices are stable across compile units // simple indices are stable across compile units
if (sub_ti < debug_t->ti_ranges[sub_ti_n->source].min) { if (sub_ti < debug_t->ti_ranges[sub_ti_n->source].min) {
blake3_hasher_update(&hasher, &sub_ti, sizeof(sub_ti)); lnk_hasher_update_struct(&hasher, &sub_ti);
continue; continue;
} }
@@ -1244,7 +1306,7 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
memory_write16(leaf_header + OffsetOf(CV_LeafHeader, size), sizeof(CV_LeafKind)); memory_write16(leaf_header + OffsetOf(CV_LeafHeader, size), sizeof(CV_LeafKind));
// reset hasher // reset hasher
blake3_hasher_init(&hasher); lnk_hasher_init(&hasher, input->config->debug_types_hash);
// log error // log error
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
@@ -1266,7 +1328,7 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
memory_write16(leaf_header + OffsetOf(CV_LeafHeader, size), sizeof(CV_LeafKind)); memory_write16(leaf_header + OffsetOf(CV_LeafHeader, size), sizeof(CV_LeafKind));
// reset hasher // reset hasher
blake3_hasher_init(&hasher); lnk_hasher_init(&hasher, input->config->debug_types_hash);
// log error // log error
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
@@ -1283,20 +1345,21 @@ lnk_hash_cv_leaf(LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInf
U64 sub_hash = input->debug_h_arr[sub_ref.obj_idx].v[sub_ref.leaf_idx]; U64 sub_hash = input->debug_h_arr[sub_ref.obj_idx].v[sub_ref.leaf_idx];
// mix-in sub-type hash // mix-in sub-type hash
blake3_hasher_update(&hasher, &sub_hash, sizeof(sub_hash)); lnk_hasher_update_struct(&hasher, &sub_hash);
} }
// hash leaf header // hash leaf header
CV_LeafHeader *leaf_header = cv_debug_t_get_leaf_header(debug_t, leaf_ref.leaf_idx); CV_LeafHeader *leaf_header_ptr = cv_debug_t_get_leaf_header(debug_t, leaf_ref.leaf_idx);
blake3_hasher_update(&hasher, leaf_header, sizeof(*leaf_header)); lnk_hasher_update_struct(&hasher, leaf_header_ptr);
U64 hash; // finalize the type hash
blake3_hasher_finalize(&hasher, (U8 *) &hash, sizeof(hash)); U64 hash = lnk_hasher_digest(&hasher);
Assert(hash != 0); Assert(hash != 0);
Assert(input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] == 0 || Assert(input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] == 0 ||
input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] == 1); input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] == 1);
input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] = hash; input->debug_h_arr[leaf_ref.obj_idx].v[leaf_ref.leaf_idx] = hash;
return hash; return hash;
} }
@@ -1370,29 +1433,21 @@ lnk_hash_cv_leaf_deep(Arena *arena,
temp_end(temp); temp_end(temp);
} }
internal LNK_LeafRef * internal CV_TypeIndex
lnk_leaf_hash_table_search(LNK_LeafHashTable *ht, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref) lnk_assigned_ti_hash_search(LNK_AssignedTiHash *ht, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref)
{ {
LNK_LeafRef *match = 0;
CV_DebugT *debug_t = &input->debug_t_arr[leaf_ref.obj_idx];
CV_DebugH *debug_h = &input->debug_h_arr[leaf_ref.obj_idx]; CV_DebugH *debug_h = &input->debug_h_arr[leaf_ref.obj_idx];
U64 hash = debug_h->v[leaf_ref.leaf_idx]; U64 hash = debug_h->v[leaf_ref.leaf_idx];
U64 best_bucket_idx = hash % ht->cap; U64 best_idx = hash % ht->cap;
U64 bucket_idx = best_bucket_idx; U64 idx = best_idx;
do { do {
LNK_LeafRef *bucket = ht->bucket_arr[bucket_idx]; CV_TypeIndex ti = ht->ti_arr[idx];
if (bucket == 0) { break; } if (ti == 0) { break; }
if (ht->hash_arr[idx] == hash) { return ti; }
idx = (idx + 1) == ht->cap ? 0 : (idx + 1);
} while (idx != best_idx);
if (lnk_match_leaf_ref(input, *bucket, leaf_ref)) { return 0;
match = bucket;
break;
}
bucket_idx = (bucket_idx + 1) == ht->cap ? 0 : (bucket_idx + 1);
} while (bucket_idx != best_bucket_idx);
return match;
} }
internal internal
@@ -1731,10 +1786,7 @@ internal void
lnk_leaf_ref_array_sort(TP_Context *tp, LNK_CodeViewInput *input, LNK_LeafRefArray arr, U64 debug_t_count) lnk_leaf_ref_array_sort(TP_Context *tp, LNK_CodeViewInput *input, LNK_LeafRefArray arr, U64 debug_t_count)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
ProfBeginDynamic("Leaf Sort [Leaf Count: %.*s]", str8_varg(str8_from_count(scratch.arena, arr.count))); ProfBeginDynamic("Leaf Sort [Leaf Count: %.*s]", str8_varg(str8_from_count(scratch.arena, arr.count)));
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
} }
@@ -1747,54 +1799,35 @@ THREAD_POOL_TASK_FUNC(lnk_assign_type_indices_task)
CV_TypeIndexSource ti_source = task->ti_source; CV_TypeIndexSource ti_source = task->ti_source;
LNK_LeafRefArray unique_leaf_refs = task->unique_leaf_refs_arr[ti_source]; LNK_LeafRefArray unique_leaf_refs = task->unique_leaf_refs_arr[ti_source];
CV_TypeIndex min_type_index = task->min_type_indices[ti_source]; CV_TypeIndex min_type_index = task->min_type_indices[ti_source];
U64 assigned_type_cap = task->assigned_type_caps[ti_source]; LNK_AssignedTiHash *assigned = &task->assigned_ti_arr[ti_source];
CV_TypeIndex *assigned_type_ht = task->assigned_type_hts[ti_source]; CV_DebugH *debug_h_arr = task->input->debug_h_arr;
for EachInRange(i, task->ranges[task_id]) { for EachInRange(i, task->ranges[task_id]) {
LNK_LeafRef *leaf_ref = unique_leaf_refs.v[i]; LNK_LeafRef *leaf_ref = unique_leaf_refs.v[i];
CV_TypeIndex type_index = min_type_index + i; CV_TypeIndex type_index = min_type_index + i;
U64 hash = u64_hash_from_str8(str8_struct(leaf_ref)); U64 hash = debug_h_arr[leaf_ref->obj_idx].v[leaf_ref->leaf_idx];
U64 best_idx = hash % assigned_type_cap; U64 best_idx = hash % assigned->cap;
U64 idx = best_idx; U64 idx = best_idx;
B32 is_inserted = 0; B32 is_inserted = 0;
do { do {
CV_TypeIndex curr_type_index = assigned_type_ht[idx]; CV_TypeIndex curr_type_index = assigned->ti_arr[idx];
if (curr_type_index == 0) { if (curr_type_index == 0) {
CV_TypeIndex cmp_type_index = ins_atomic_u32_eval_cond_assign(&assigned_type_ht[idx], type_index, curr_type_index); CV_TypeIndex cmp_type_index = ins_atomic_u32_eval_cond_assign(&assigned->ti_arr[idx], type_index, curr_type_index);
if (cmp_type_index == curr_type_index) { if (cmp_type_index == curr_type_index) {
assigned->hash_arr[idx] = hash;
is_inserted = 1; is_inserted = 1;
break; break;
} }
} }
// advance // advance
idx = (idx + 1) == assigned_type_cap ? 0 : (idx + 1); idx = (idx + 1) == assigned->cap ? 0 : (idx + 1);
} while (idx != best_idx); } while (idx != best_idx);
Assert(is_inserted); Assert(is_inserted);
} }
} }
internal CV_TypeIndex
lnk_assigned_type_ht_search(U64 cap, CV_TypeIndex *ht, CV_TypeIndex min_type_index, LNK_LeafRefArray unique_leaf_refs, LNK_LeafRef *v, U64 hash)
{
U64 best_idx = hash % cap;
U64 idx = best_idx;
do {
CV_TypeIndex type_index = ht[idx];
if (type_index < min_type_index) { break; }
U64 leaf_idx = type_index - min_type_index;
LNK_LeafRef *compar = unique_leaf_refs.v[leaf_idx];
if (MemoryMatchStruct(compar,v)) { return type_index; }
idx = (idx + 1) == cap ? 0 : (idx + 1);
} while(idx != best_idx);
InvalidPath;
return 0;
}
internal void internal void
lnk_fixup_cv_type_indices(LNK_MergeTypes *ctx, U32 obj_idx, String8 data, CV_TypeIndexInfoList ti_info_list) lnk_fixup_cv_type_indices(LNK_MergeTypes *ctx, U32 obj_idx, String8 data, CV_TypeIndexInfoList ti_info_list)
{ {
@@ -1805,26 +1838,15 @@ lnk_fixup_cv_type_indices(LNK_MergeTypes *ctx, U32 obj_idx, String8 data, CV_Typ
// skip basic types // skip basic types
if (ti < ctx->input->min_type_indices[n->source]) { continue; } if (ti < ctx->input->min_type_indices[n->source]) { continue; }
CV_TypeIndex final_ti = 0;
LNK_LeafRef leaf_ref = lnk_leaf_ref_from_ti(ctx->input, obj_idx, n->source, ti); LNK_LeafRef leaf_ref = lnk_leaf_ref_from_ti(ctx->input, obj_idx, n->source, ti);
LNK_LeafHashTable *leaf_ht = &ctx->leaf_ht_arr[n->source]; CV_TypeIndex final_ti = lnk_assigned_ti_hash_search(&ctx->assigned_ti_arr[n->source], ctx->input, leaf_ref);
LNK_LeafRef *final_leaf = lnk_leaf_hash_table_search(leaf_ht, ctx->input, leaf_ref); memory_write32(ti_ptr, final_ti);
if (final_leaf) {
U64 final_hash = u64_hash_from_str8(str8_struct(final_leaf)); #if LNK_PARANOID
final_ti = lnk_assigned_type_ht_search(ctx->assigned_type_caps [n->source], if (final_ti == 0) {
ctx->assigned_type_hts [n->source],
ctx->min_type_indices [n->source],
ctx->unique_leaf_refs_arr[n->source],
final_leaf,
final_hash);
}
#if BUILD_DEBUG
else {
lnk_error_obj(LNK_Error_InvalidTypeIndex, ctx->input->obj_arr[obj_idx], "no itype 0x%x", ti); lnk_error_obj(LNK_Error_InvalidTypeIndex, ctx->input->obj_arr[obj_idx], "no itype 0x%x", ti);
} }
#endif #endif
memory_write32(ti_ptr, final_ti);
} }
} }
@@ -1833,11 +1855,11 @@ THREAD_POOL_TASK_FUNC(lnk_cv_patcher_symbols_task)
{ {
ProfBeginFunction(); ProfBeginFunction();
LNK_MergeTypes *task = raw_task; LNK_MergeTypes *task = raw_task;
Rng1U64 range = task->input->symbol_input_ranges[task_id]; Rng1U64 range = task->input->symbol_patch_task[task_id].input_range;
for EachInRange(i, range) { for EachInRange(i, range) {
LNK_SymbolInput symbols = task->input->symbol_inputs[i]; LNK_SymbolInput symbols = task->input->symbol_inputs[i];
for (U64 cursor = 0; cursor + sizeof(CV_SymbolHeader) <= symbols.raw_symbols.size; ) { for (U64 cursor = 0; cursor + sizeof(CV_SymbolHeader) <= symbols.raw_symbols.size; ) {
Temp temp = temp_begin(task->fixed_arenas[task_id]); Temp temp = temp_begin(task->fixed_arenas[worker_id]);
CV_Symbol symbol = {0}; CV_Symbol symbol = {0};
TryReadBreak(cv_read_symbol(symbols.raw_symbols, cursor, CV_SymbolAlign, &symbol), cursor); TryReadBreak(cv_read_symbol(symbols.raw_symbols, cursor, CV_SymbolAlign, &symbol), cursor);
@@ -1989,22 +2011,8 @@ THREAD_POOL_TASK_FUNC(lnk_build_obj_ti_map)
CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx); CV_Leaf leaf = cv_debug_t_get_leaf(debug_t, leaf_idx);
CV_TypeIndexSource source = cv_type_index_source_from_leaf_kind(leaf.kind); CV_TypeIndexSource source = cv_type_index_source_from_leaf_kind(leaf.kind);
LNK_LeafRef leaf_ref = { obj_idx, leaf_idx }; LNK_LeafRef leaf_ref = { obj_idx, leaf_idx };
LNK_LeafHashTable *leaf_ht = &task->leaf_ht_arr[source]; LNK_AssignedTiHash *assigned = &task->assigned_ti_arr[source];
LNK_LeafRef *final_leaf = lnk_leaf_hash_table_search(leaf_ht, input, leaf_ref); obj_ti_map[leaf_idx] = lnk_assigned_ti_hash_search(assigned, input, leaf_ref);
if (final_leaf) {
U64 final_hash = u64_hash_from_str8(str8_struct(final_leaf));
CV_TypeIndex final_ti = lnk_assigned_type_ht_search(task->assigned_type_caps [source],
task->assigned_type_hts [source],
task->min_type_indices [source],
task->unique_leaf_refs_arr[source],
final_leaf,
final_hash);
obj_ti_map[leaf_idx] = final_ti;
} else {
obj_ti_map[leaf_idx] = 0;
}
} }
task->result.obj_ti_maps[obj_idx] = obj_ti_map; task->result.obj_ti_maps[obj_idx] = obj_ti_map;
@@ -2246,8 +2254,14 @@ lnk_merge_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input, LNK
ProfBegin("Assign type indices"); ProfBegin("Assign type indices");
for EachIndex(ti_source, CV_TypeIndexSource_COUNT) { for EachIndex(ti_source, CV_TypeIndexSource_COUNT) {
task.ti_source = ti_source; task.ti_source = ti_source;
task.assigned_type_caps[ti_source] = (task.unique_leaf_refs_arr[ti_source].count * 13) / 10; task.assigned_ti_arr[ti_source].cap = ((task.unique_leaf_refs_arr[ti_source].count * 13) / 10);
task.assigned_type_hts [ti_source] = push_array(scratch.arena, CV_TypeIndex, task.assigned_type_caps[ti_source]); task.assigned_ti_arr[ti_source].ti_arr = push_array(scratch.arena, CV_TypeIndex, task.assigned_ti_arr[ti_source].cap);
// unique extraction is complete, so the dedup bucket slots can back the
// direct hash table without increasing peak memory
Assert(task.assigned_ti_arr[ti_source].cap <= task.leaf_ht_arr[ti_source].cap);
task.assigned_ti_arr[ti_source].hash_arr = (U64 *)task.leaf_ht_arr[ti_source].bucket_arr;
task.min_type_indices[ti_source] = CV_MinComplexTypeIndex; task.min_type_indices[ti_source] = CV_MinComplexTypeIndex;
task.ranges = tp_divide_work(scratch.arena, task.unique_leaf_refs_arr[ti_source].count, tp->worker_count); task.ranges = tp_divide_work(scratch.arena, task.unique_leaf_refs_arr[ti_source].count, tp->worker_count);
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_assign_type_indices_task, &task, "Assign Type Indices"); tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_assign_type_indices_task, &task, "Assign Type Indices");
@@ -2255,8 +2269,7 @@ lnk_merge_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input, LNK
ProfEnd(); ProfEnd();
if (~merge_flags & LNK_MergeTypeFlag_SkipSymbolTypeFixup) { if (~merge_flags & LNK_MergeTypeFlag_SkipSymbolTypeFixup) {
task.ranges = tp_divide_work(scratch.arena, input->symbol_input_count, tp->worker_count); tp_for_parallel_prof(tp, 0, input->symbol_patch_task_count, lnk_cv_patcher_symbols_task, &task, "Fixup Symbol Type Indices");
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_cv_patcher_symbols_task, &task, "Fixup Symbol Type Indices");
task.ranges = 0; task.ranges = 0;
task.debug_s_arr = input->debug_s_arr; task.debug_s_arr = input->debug_s_arr;
@@ -3029,7 +3042,7 @@ THREAD_POOL_TASK_FUNC(lnk_write_pdb_modules)
String8 name = str8_cstring_capped(string_table.str + header.name_off, string_table.str + string_table.size); String8 name = str8_cstring_capped(string_table.str + header.name_off, string_table.str + string_table.size);
CV_StringBucket *bucket = cv_string_hash_table_lookup(task->string_ht, name); CV_StringBucket *bucket = cv_string_hash_table_lookup(task->string_ht, name);
U64 name_off = task->pdb->info->strtab.size + bucket->u.offset; U64 name_off = task->string_table_base_offset + bucket->u.offset;
// update name offset // update name offset
{ {
@@ -3067,73 +3080,192 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
PDB_DbiModule *mod = task->mod_arr [obj_idx]; PDB_DbiModule *mod = task->mod_arr [obj_idx];
LNK_Obj *obj = task->cv->obj_arr[obj_idx]; LNK_Obj *obj = task->cv->obj_arr[obj_idx];
PDB_DbiSectionContribNode *sc_arr = push_array_no_zero(arena, PDB_DbiSectionContribNode, obj->header.section_count_no_null); PDB_DbiSCNode *sc_arr = push_array_no_zero(arena, PDB_DbiSCNode, obj->header.section_count_no_null);
U64 sc_count = 0; U64 sc_count = 0;
for EachIndex(sect_idx, obj->header.section_count_no_null) { for EachIndex(sect_idx, obj->header.section_count_no_null) {
LNK_ObjSection section = lnk_obj_section_from_sect_idx(obj, sect_idx);
if (*section.flags & COFF_SectionFlag_LnkInfo) { continue; } // filter by section flags
if (*section.flags & COFF_SectionFlag_LnkRemove) { continue; } if (obj->section_flags[sect_idx] & (COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkRemove | LNK_SECTION_FLAG_DEBUG)) { continue; }
if (*section.flags & LNK_SECTION_FLAG_DEBUG) { continue; }
// skip unwind info for the section contribution
String8 section_name = lnk_obj_section_name_from_sect_idx(obj, sect_idx); String8 section_name = lnk_obj_section_name_from_sect_idx(obj, sect_idx);
if (str8_match(section_name, str8_lit(".pdata"), 0)) { continue; } if (str8_match(section_name, str8_lit(".pdata"), 0)) { continue; }
U64 sect_number; // load section and determine its type
String8 sect_data; LNK_ObjSection section = lnk_obj_section_from_sect_idx(obj, sect_idx);
U32 sect_off; B32 is_virt = !!(*section.flags & COFF_SectionFlag_CntUninitializedData);
U32 data_crc;
if (*section.flags & COFF_SectionFlag_CntUninitializedData) {
if (dim_1u64(section.vrange) == 0) { continue; }
U64 search_result = rng1u64_array_num_from_value__binary_search(&task->image_section_virt_ranges, section.vrange.min); // pick section range
sect_number = search_result-1; Rng1U64 section_range = is_virt ? section.vrange : section.frange;
Assert(sect_number < task->image_section_virt_ranges.count); if (dim_1u64(section_range) == 0) { continue; }
sect_data = str8_zero(); // map the SC offset to the image section range that contains it
sect_off = section.vrange.min - task->image_section_virt_ranges.v[sect_number].min; Rng1U64Array *image_ranges = is_virt ? &task->image_section_virt_ranges : &task->image_section_file_ranges;
data_crc = 0; U64 search_result = rng1u64_array_num_from_value__binary_search(image_ranges, section_range.min);
} else {
if (dim_1u64(section.frange) == 0) { continue; }
U64 search_result = rng1u64_array_num_from_value__binary_search(&task->image_section_file_ranges, section.frange.min); // log & skip SC offsets that failed to map
sect_number = search_result-1; if (search_result == 0) {
Assert(sect_number < task->image_section_file_ranges.count); Temp scratch = scratch_begin(0,0);
lnk_log(LNK_Log_Debug, "%S: failed to map section offset 0x%llx into the linked image; skipping this section", lnk_loc_from_obj(scratch.arena, obj), section_range.min);
sect_data = str8_substr(task->image_data, section.frange); scratch_end(scratch);
sect_off = section.frange.min - task->image_section_file_ranges.v[sect_number].min; continue;
data_crc = update_crc32(0, sect_data.str, sect_data.size);
} }
// fill out SC // unpack image range index
PDB_DbiSectionContribNode *sc = sc_arr + sc_count++; U64 range_idx = search_result - 1;
sc->data.base.sec = (U16)sect_number;
// fill out & push section contribution
PDB_DbiSCNode *sc = sc_arr + sc_count++;
sc->data.base.sec = (U16)(is_virt ? range_idx : task->image_section_file_section_numbers[range_idx]);
sc->data.base.pad0 = 0; sc->data.base.pad0 = 0;
sc->data.base.sec_off = sect_off; sc->data.base.sec_off = section_range.min - image_ranges->v[range_idx].min;
sc->data.base.size = dim_1u64(section.vrange); sc->data.base.size = dim_1u64(section_range);
sc->data.base.flags = *section.flags; sc->data.base.flags = *section.flags;
sc->data.base.mod = mod->imod; sc->data.base.mod = mod->imod;
sc->data.base.pad1 = 0; sc->data.base.pad1 = 0;
sc->data.data_crc = 0; sc->data.data_crc = is_virt ? 0 : crc32_from_string(str8_substr(task->image_data, section_range));
sc->data.reloc_crc = 0; sc->data.reloc_crc = 0;
dbi_sec_contrib_list_push_node(&task->sc_list[obj_idx], sc); dbi_sec_contrib_list_push_node(&task->sc_list[obj_idx], sc);
} }
// Mod1::fUpdateSecContrib // find first code section contribution for the Mod1::fUpdateSecContrib
if (sc_count > 0) { for EachIndex(i, sc_count) {
for (U64 sc_idx = 0; sc_idx < sc_count; ++sc_idx) { if (sc_arr[i].data.base.flags & COFF_SectionFlag_CntCode) {
if (sc_arr[sc_idx].data.base.flags & COFF_SectionFlag_CntCode) { mod->first_sc = sc_arr[i].data;
mod->first_sc = sc_arr[sc_idx].data;
break; break;
} }
} }
} }
typedef struct
{
LNK_BackgroundFileWriter *writer;
LNK_BackgroundFile *file;
MSF_StreamNumber *sealed_streams;
U64 sealed_stream_count;
U64 sealed_stream_cap;
} LNK_PdbOutput;
typedef struct LNK_MsfPageCursor
{
MSF_PageDataNode *node;
U64 node_idx;
U64 pages_per_node;
} LNK_MsfPageCursor;
internal U8 *
lnk_msf_data_from_pn(LNK_MsfPageCursor *cursor, MSF_Context *msf, MSF_PageNumber pn)
{
U64 node_idx = pn / cursor->pages_per_node;
if (node_idx < cursor->node_idx) {
cursor->node = msf->page_data_list.first;
cursor->node_idx = 0;
}
while (cursor->node_idx < node_idx) {
cursor->node = cursor->node->next;
cursor->node_idx += 1;
}
Assert(cursor->node != 0);
return cursor->node->data + (pn % cursor->pages_per_node) * msf->page_size;
} }
internal String8List internal void
lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PDB_BuilderFlags builder_flags) lnk_pdb_output_enqueue_stream(LNK_PdbOutput *output, MSF_Context *msf, MSF_StreamNumber sn)
{
if (sn == MSF_INVALID_STREAM_NUMBER) { return; }
Assert(output->sealed_stream_count < output->sealed_stream_cap);
output->sealed_streams[output->sealed_stream_count++] = sn;
MSF_Stream *stream = msf_find_stream(msf, sn);
Assert(stream != 0);
if (stream->page_list.count == 0) { return; }
LNK_MsfPageCursor cursor = {
.node = msf->page_data_list.first,
.pages_per_node = msf_get_data_node_size(msf->page_size) / msf->page_size,
};
MSF_PageNumber run_first_pn = 0;
MSF_PageNumber run_last_pn = 0;
U8 *run_data = 0;
U64 run_size = 0;
for EachNode(page, MSF_PageNode, stream->page_list.first) {
U8 *page_data = lnk_msf_data_from_pn(&cursor, msf, page->pn);
if (run_data != 0 && page->pn == run_last_pn + 1 && page_data == run_data + run_size) {
run_last_pn = page->pn;
run_size += msf->page_size;
} else {
if (run_data != 0) {
lnk_background_file_writer_enqueue(output->writer, output->file, (U64)run_first_pn * msf->page_size, str8(run_data, run_size));
}
run_first_pn = run_last_pn = page->pn;
run_data = page_data;
run_size = msf->page_size;
}
}
if (run_data != 0) {
lnk_background_file_writer_enqueue(output->writer, output->file, (U64)run_first_pn * msf->page_size, str8(run_data, run_size));
}
}
internal void
lnk_pdb_output_finalize_stream(void *user_data, MSF_Context *msf, MSF_StreamNumber sn)
{
lnk_pdb_output_enqueue_stream(user_data, msf, sn);
}
internal void
lnk_pdb_output_enqueue_remaining(LNK_PdbOutput *output, MSF_Context *msf)
{
Temp scratch = scratch_begin(0,0);
U64 save_size = msf_get_save_size(msf);
U64 page_count = CeilIntegerDiv(save_size, msf->page_size);
U8 *is_written = push_array(scratch.arena, U8, page_count);
for EachIndex(i, output->sealed_stream_count) {
MSF_Stream *stream = msf_find_stream(msf, output->sealed_streams[i]);
Assert(stream != 0);
for EachNode(page, MSF_PageNode, stream->page_list.first) {
Assert(page->pn < page_count);
is_written[page->pn] = 1;
}
}
LNK_MsfPageCursor cursor = {
.node = msf->page_data_list.first,
.pages_per_node = msf_get_data_node_size(msf->page_size) / msf->page_size,
};
U64 run_first_pn = 0;
U8 *run_data = 0;
U64 run_size = 0;
for EachIndex(pn, page_count) {
U8 *page_data = lnk_msf_data_from_pn(&cursor, msf, pn);
U64 page_size = Min(msf->page_size, save_size - pn * msf->page_size);
if (!is_written[pn]) {
if (run_data != 0 && page_data == run_data + run_size) {
run_size += page_size;
} else {
if (run_data != 0) {
lnk_background_file_writer_enqueue(output->writer, output->file, run_first_pn * msf->page_size, str8(run_data, run_size));
}
run_first_pn = pn;
run_data = page_data;
run_size = page_size;
}
} else if (run_data != 0) {
lnk_background_file_writer_enqueue(output->writer, output->file, run_first_pn * msf->page_size, str8(run_data, run_size));
run_data = 0;
run_size = 0;
}
}
if (run_data != 0) {
lnk_background_file_writer_enqueue(output->writer, output->file, run_first_pn * msf->page_size, str8(run_data, run_size));
}
scratch_end(scratch);
}
internal LNK_FileArtifact
lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PdbWriter writer, LNK_PDB_BuilderFlags builder_flags)
{ {
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(tp_arena->v, tp_arena->count); Temp scratch = scratch_begin(tp_arena->v, tp_arena->count);
@@ -3154,8 +3286,27 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
.image_section_virt_ranges.count = task.image_section_table_count, .image_section_virt_ranges.count = task.image_section_table_count,
.image_section_virt_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count), .image_section_virt_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count),
.image_section_file_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count), .image_section_file_ranges.v = push_array(scratch.arena, Rng1U64, task.image_section_table_count),
.image_section_file_section_numbers = push_array(scratch.arena, U64, task.image_section_table_count),
}; };
LNK_PdbOutput output = {0};
LNK_PdbOutput *output_ptr = 0;
if (writer.output_path.size > 0) {
output.writer = writer.file_writer;
output.file = lnk_background_file_writer_begin_file(output.writer, writer.output_path, writer.temp_output_path);
if (output.file != 0) {
output.sealed_stream_cap = cv->obj_count + 128;
output.sealed_streams = push_array_no_zero(scratch.arena, MSF_StreamNumber, output.sealed_stream_cap);
output_ptr = &output;
}
}
PDB_BuildHooks build_hooks = {0};
if (output_ptr != 0) {
build_hooks.stream_finalize = lnk_pdb_output_finalize_stream;
build_hooks.user_data = output_ptr;
}
// set min type indices // set min type indices
for EachElement(ti_source, cv_types.min_type_indices) { task.pdb->type_servers[ti_source]->ti_lo = cv_types.min_type_indices[ti_source]; } for EachElement(ti_source, cv_types.min_type_indices) { task.pdb->type_servers[ti_source]->ti_lo = cv_types.min_type_indices[ti_source]; }
@@ -3183,24 +3334,32 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
cv_string_hash_table_assign_buffer_offsets(tp, task.string_ht); cv_string_hash_table_assign_buffer_offsets(tp, task.string_ht);
ProfEnd(); ProfEnd();
if (builder_flags & LNK_PDB_BuilderFlag_Modules) { task.string_table_base_offset = task.pdb->info->strtab.size;
ProfScope ("Alloc Modules")
for EachIndex(obj_idx, cv->obj_count)
task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx]));
ProfScope("Move Global Symbols")
tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task);
ProfScope("Build GSI and PSI")
pdb_build_gsi_psi(tp, task.pdb);
ProfScope("Write Modules")
tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task);
}
ProfBegin("Add string tables"); ProfBegin("Add string tables");
pdb_strtab_add_cv_string_hash_table(&task.pdb->info->strtab, task.string_ht); pdb_strtab_add_cv_string_hash_table(&task.pdb->info->strtab, task.string_ht);
ProfEnd(); ProfEnd();
pdb_build_types(tp, task.pdb, &build_hooks);
if (builder_flags & LNK_PDB_BuilderFlag_Modules) {
ProfScope ("Alloc Modules")
for EachIndex(obj_idx, cv->obj_count) {
task.mod_arr[obj_idx] = dbi_push_module(task.pdb->dbi, cv->obj_arr[obj_idx]->path, lnk_obj_get_lib_path(cv->obj_arr[obj_idx]));
}
ProfScope("Write Modules") tp_for_parallel(tp, 0, tp->worker_count, lnk_write_pdb_modules, &task);
if (output_ptr != 0) {
for EachIndex(obj_idx, cv->obj_count) {
lnk_pdb_output_enqueue_stream(output_ptr, task.pdb->msf, task.mod_arr[obj_idx]->sn);
}
}
ProfScope("Move Global Symbols") tp_for_parallel(tp, 0, tp->worker_count, lnk_move_global_symbols_to_gsi, &task);
ProfScope("Build GSI and PSI") pdb_build_gsi_psi(tp, task.pdb);
if (output_ptr != 0) {
lnk_pdb_output_enqueue_stream(output_ptr, task.pdb->msf, task.pdb->dbi->publics_sn);
lnk_pdb_output_enqueue_stream(output_ptr, task.pdb->msf, task.pdb->dbi->globals_sn);
lnk_pdb_output_enqueue_stream(output_ptr, task.pdb->msf, task.pdb->dbi->symbols_sn);
}
}
if (builder_flags & LNK_PDB_BuilderFlag_SC) { if (builder_flags & LNK_PDB_BuilderFlag_SC) {
ProfBegin("Build Section Contrib Map"); ProfBegin("Build Section Contrib Map");
@@ -3213,13 +3372,17 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
for EachIndex(i, task.image_section_table_count) { for EachIndex(i, task.image_section_table_count) {
COFF_SectionHeader *sect_header = task.image_section_table[i]; COFF_SectionHeader *sect_header = task.image_section_table[i];
if (~sect_header->flags & COFF_SectionFlag_CntUninitializedData) { if (~sect_header->flags & COFF_SectionFlag_CntUninitializedData) {
task.image_section_file_ranges.v[task.image_section_file_ranges.count++] = rng_1u64(sect_header->foff, sect_header->foff + sect_header->fsize); U64 section_file_idx = task.image_section_file_ranges.count++;
task.image_section_file_ranges.v[section_file_idx] = r1u64s(sect_header->foff, sect_header->fsize);
task.image_section_file_section_numbers[section_file_idx] = i;
} }
task.image_section_virt_ranges.v[i] = rng_1u64(sect_header->voff, sect_header->voff + sect_header->vsize); task.image_section_virt_ranges.v[i] = rng_1u64(sect_header->voff, sect_header->voff + sect_header->vsize);
} }
task.sc_list = push_array(scratch.arena, PDB_DbiSectionContribList, cv->obj_count); task.sc_list = push_array(scratch.arena, PDB_DbiSCList, cv->obj_count);
tp_for_parallel(tp, tp_arena, cv->obj_count, lnk_push_dbi_sec_contrib_task, &task); tp_for_parallel(tp, tp_arena, cv->obj_count, lnk_push_dbi_sec_contrib_task, &task);
dbi_sec_list_concat_arr(&task.pdb->dbi->sec_contrib_list, cv->obj_count, task.sc_list); dbi_sec_list_concat_arr(&task.pdb->dbi->sec_contrib_list, cv->obj_count, task.sc_list);
} }
@@ -3258,17 +3421,25 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
ProfEnd(); ProfEnd();
} }
pdb_build(tp, tp_arena, task.pdb, task.string_ht, 0, cv->is_stripped); pdb_build_dbi_info(tp, task.pdb, task.string_ht, 0, cv->is_stripped, &build_hooks);
MSF_Error msf_err = msf_build(task.pdb->msf); MSF_Error msf_err = msf_build(task.pdb->msf);
if (msf_err != MSF_Error_OK) { if (msf_err != MSF_Error_OK) {
lnk_error(LNK_Error_UnableToSerializeMsf, "unable to serialize MSF: %s", msf_error_to_string(msf_err)); lnk_error(LNK_Error_UnableToSerializeMsf, "unable to serialize MSF: %s", msf_error_to_string(msf_err));
} }
if (output_ptr != 0) {
lnk_pdb_output_enqueue_remaining(output_ptr, task.pdb->msf);
}
ProfBegin("Get Page Nodes"); ProfBegin("Get Page Nodes");
String8List page_data_list = msf_get_page_data_nodes(tp_arena->v[0], task.pdb->msf); LNK_FileArtifact artifact = { .data = msf_get_page_data_nodes(tp_arena->v[0], task.pdb->msf) };
ProfEnd(); ProfEnd();
if (output_ptr != 0) {
lnk_background_file_writer_end_file(output_ptr->writer, output_ptr->file, artifact.data.total_size);
}
// NOTE: linker is about to exit so we can skip memory release // NOTE: linker is about to exit so we can skip memory release
// and let windows free memory since it does this faster // and let windows free memory since it does this faster
#if 0 #if 0
@@ -3279,5 +3450,5 @@ lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return page_data_list; return artifact;
} }
+31 -8
View File
@@ -7,11 +7,12 @@
// RRT // RRT
global read_only String8 g_rrt_magic = str8_lit_comp("RAD-TYPE-SERVER\0"); global read_only String8 g_rrt_magic = str8_lit_comp("RAD-TYPE-SERVER\0");
global read_only U64 g_rrt_version = 2; global read_only U64 g_rrt_version = 3;
typedef struct LNK_RRT typedef struct LNK_RRT
{ {
String8 path; String8 path;
LNK_HashKind debug_types_hash;
String8 type_data_raw; String8 type_data_raw;
union { union {
@@ -68,6 +69,12 @@ typedef struct LNK_SymbolInput
String8 raw_symbols; String8 raw_symbols;
} LNK_SymbolInput; } LNK_SymbolInput;
typedef struct LNK_SymbolInputTask
{
Rng1U64 input_range;
U64 weight;
} LNK_SymbolInputTask;
typedef struct typedef struct
{ {
LNK_Config *config; LNK_Config *config;
@@ -98,6 +105,8 @@ typedef struct
U64 symbol_input_count; U64 symbol_input_count;
LNK_SymbolInput *symbol_inputs; // [symbol_input_count] LNK_SymbolInput *symbol_inputs; // [symbol_input_count]
Rng1U64 *symbol_input_ranges; // [worker_count] Rng1U64 *symbol_input_ranges; // [worker_count]
U64 symbol_patch_task_count; //
LNK_SymbolInputTask *symbol_patch_task; // [symbol_patch_task_count]
} LNK_CodeViewInput; } LNK_CodeViewInput;
typedef struct typedef struct
@@ -119,6 +128,13 @@ typedef struct
LNK_LeafRef **bucket_arr; LNK_LeafRef **bucket_arr;
} LNK_LeafHashTable; } LNK_LeafHashTable;
typedef struct
{
U64 cap;
CV_TypeIndex *ti_arr;
U64 *hash_arr;
} LNK_AssignedTiHash;
typedef struct LNK_LeafRange typedef struct LNK_LeafRange
{ {
struct LNK_LeafRange *next; struct LNK_LeafRange *next;
@@ -150,6 +166,7 @@ typedef struct
LNK_CodeViewInput *input; LNK_CodeViewInput *input;
CV_DebugS *debug_s_arr; CV_DebugS *debug_s_arr;
LNK_LeafHashTable leaf_ht_arr[CV_TypeIndexSource_COUNT]; LNK_LeafHashTable leaf_ht_arr[CV_TypeIndexSource_COUNT];
LNK_AssignedTiHash assigned_ti_arr[CV_TypeIndexSource_COUNT];
Arena **fixed_arenas; Arena **fixed_arenas;
CV_TypeIndexSource ti_source; CV_TypeIndexSource ti_source;
U32Array indices; U32Array indices;
@@ -173,9 +190,6 @@ typedef struct
LNK_LeafRef **src; LNK_LeafRef **src;
U64 pass_idx; U64 pass_idx;
// assign type indices
U64 assigned_type_caps [CV_TypeIndexSource_COUNT];
CV_TypeIndex *assigned_type_hts [CV_TypeIndexSource_COUNT];
CV_TypeIndex min_type_indices [CV_TypeIndexSource_COUNT]; CV_TypeIndex min_type_indices [CV_TypeIndexSource_COUNT];
LNK_LeafRefArray unique_leaf_refs_arr[CV_TypeIndexSource_COUNT]; LNK_LeafRefArray unique_leaf_refs_arr[CV_TypeIndexSource_COUNT];
@@ -209,6 +223,7 @@ typedef struct
LNK_CodeViewInput *cv; LNK_CodeViewInput *cv;
PDB_Context *pdb; PDB_Context *pdb;
CV_StringHashTable string_ht; CV_StringHashTable string_ht;
U64 string_table_base_offset;
PDB_DbiModule **mod_arr; // [obj_count] PDB_DbiModule **mod_arr; // [obj_count]
U32Array *obj_indices; // [obj_count] U32Array *obj_indices; // [obj_count]
@@ -218,11 +233,19 @@ typedef struct
PE_BinInfo pe; PE_BinInfo pe;
COFF_SectionHeader **image_section_table; COFF_SectionHeader **image_section_table;
U64 image_section_table_count; U64 image_section_table_count;
Rng1U64Array image_section_file_ranges;
Rng1U64Array image_section_virt_ranges; Rng1U64Array image_section_virt_ranges;
PDB_DbiSectionContribList *sc_list; // [obj_count] Rng1U64Array image_section_file_ranges;
U64 *image_section_file_section_numbers;
PDB_DbiSCList *sc_list; // [obj_count]
} LNK_BuildPdb; } LNK_BuildPdb;
typedef struct
{
LNK_BackgroundFileWriter *file_writer;
String8 output_path;
String8 temp_output_path;
} LNK_PdbWriter;
typedef struct typedef struct
{ {
U64 leaf_count; U64 leaf_count;
@@ -251,11 +274,11 @@ internal B32 lnk_match_leaf_ref (LNK_CodeViewInput
internal U64 lnk_hash_cv_leaf (LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInfoList ti_info_list, B32 discard_cycles); internal U64 lnk_hash_cv_leaf (LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInfoList ti_info_list, B32 discard_cycles);
internal void lnk_hash_cv_leaf_deep (Arena *arena, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInfoList ti_info_list); internal void lnk_hash_cv_leaf_deep (Arena *arena, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref, CV_TypeIndexInfoList ti_info_list);
internal LNK_LeafRef * lnk_leaf_hash_table_insert_or_update(LNK_LeafHashTable *leaf_ht, LNK_CodeViewInput *input, CV_DebugH *hashes, U64 hash, LNK_LeafRef *new_bucket); internal LNK_LeafRef * lnk_leaf_hash_table_insert_or_update(LNK_LeafHashTable *leaf_ht, LNK_CodeViewInput *input, CV_DebugH *hashes, U64 hash, LNK_LeafRef *new_bucket);
internal LNK_LeafRef * lnk_leaf_hash_table_search (LNK_LeafHashTable *ht, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref); internal CV_TypeIndex lnk_assigned_ti_hash_search (LNK_AssignedTiHash *ht, LNK_CodeViewInput *input, LNK_LeafRef leaf_ref);
internal LNK_MergedTypes lnk_merge_types (TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input, LNK_MergeTypeFlags merge_flags); internal LNK_MergedTypes lnk_merge_types (TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input, LNK_MergeTypeFlags merge_flags);
internal void lnk_replace_type_names_with_hashes (TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name); internal void lnk_replace_type_names_with_hashes (TP_Context *tp, TP_Arena *arena, U64 leaf_count, U8 **leaf_arr, LNK_TypeNameHashMode mode, U64 hash_length, String8 map_name);
//////////////////////////////// ////////////////////////////////
// PDB // PDB
internal String8List lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PDB_BuilderFlags builder_flags); internal LNK_FileArtifact lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, String8 image_data, LNK_Config *config, LNK_SymbolTable *symtab, LNK_CodeViewInput *cv, LNK_MergedTypes cv_types, LNK_PdbWriter writer, LNK_PDB_BuilderFlags builder_flags);
+60
View File
@@ -0,0 +1,60 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
lnk_hasher_init(LNK_Hasher *hasher, LNK_HashKind kind)
{
hasher->kind = kind;
switch (kind) {
case LNK_HashKind_BLAKE3: blake3_hasher_init(&hasher->u.blake3); break;
case LNK_HashKind_XXHash: XXH3_64bits_reset(&hasher->u.xxhash); break;
default: InvalidPath; break;
}
}
internal void
lnk_hasher_update(LNK_Hasher *hasher, void *data, U64 size)
{
switch (hasher->kind) {
case LNK_HashKind_BLAKE3: blake3_hasher_update(&hasher->u.blake3, data, size); break;
case LNK_HashKind_XXHash: XXH3_64bits_update(&hasher->u.xxhash, data, size); break;
default: InvalidPath; break;
}
}
internal U64
lnk_hasher_digest(LNK_Hasher *hasher)
{
U64 hash = 0;
switch (hasher->kind) {
case LNK_HashKind_BLAKE3: blake3_hasher_finalize(&hasher->u.blake3, (U8 *)&hash, sizeof(hash)); break;
case LNK_HashKind_XXHash: hash = XXH3_64bits_digest(&hasher->u.xxhash); break;
default: InvalidPath; break;
}
return hash;
}
internal String8
lnk_string_hash_kind(LNK_HashKind hash_kind)
{
#define X(NAME) case LNK_HashKind_##NAME: return str8_lit(Stringify(NAME));
switch (hash_kind) {
LNK_HashKind_XList
}
#undef X
return str8_zero();
}
internal LNK_HashKind
lnk_hash_kind_from_llvm(LLVM_GHashAlgEnum v)
{
switch (v) {
case LLVM_GHashAlg_SHA1:
case LLVM_GHashAlg_SHA1_8:
return LNK_HashKind_Null;
case LLVM_GHashAlg_BLAKE3:
return LNK_HashKind_BLAKE3;
}
return LNK_HashKind_Null;
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#pragma once
#define LNK_HashKind_XList \
X(Null) \
X(BLAKE3) \
X(XXHash)
typedef enum
{
#define X(NAME) LNK_HashKind_##NAME,
LNK_HashKind_XList
#undef X
} LNK_HashKind;
typedef struct LNK_Hasher
{
LNK_HashKind kind;
union
{
blake3_hasher blake3;
XXH3_state_t xxhash;
} u;
} LNK_Hasher;
internal void lnk_hasher_init (LNK_Hasher *hasher, LNK_HashKind kind);
internal void lnk_hasher_update(LNK_Hasher *hasher, void *data, U64 size);
#define lnk_hasher_update_struct(hasher, ptr) lnk_hasher_update(hasher, ptr, sizeof(*ptr))
internal U64 lnk_hasher_digest(LNK_Hasher *hasher);
internal String8 lnk_string_hash_kind(LNK_HashKind hash_kind);
// LLVM extension
internal LNK_HashKind lnk_hash_kind_from_llvm(LLVM_GHashAlgEnum v);
+231
View File
@@ -10,9 +10,11 @@ lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t
shared_function int shared_function int
lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max) lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max)
{ {
ProfBeginFunction();
File handle = file_open(AccessFlag_Write, str8((U8*)path, path_size)); File handle = file_open(AccessFlag_Write, str8((U8*)path, path_size));
Assert(sizeof(handle) <= handle_buffer_max); Assert(sizeof(handle) <= handle_buffer_max);
MemoryCopy(handle_buffer, &handle, sizeof(handle)); MemoryCopy(handle_buffer, &handle, sizeof(handle));
ProfEnd();
return !file_match(handle, file_zero()); return !file_match(handle, file_zero());
} }
@@ -84,6 +86,7 @@ lnk_find_first_file(Arena *arena, String8List dir_list, String8 path)
internal File internal File
lnk_file_open_with_rename_permissions(String8 path) lnk_file_open_with_rename_permissions(String8 path)
{ {
ProfBeginFunction();
File file_handle = file_zero(); File file_handle = file_zero();
#if OS_WINDOWS #if OS_WINDOWS
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
@@ -106,6 +109,7 @@ lnk_file_open_with_rename_permissions(String8 path)
#else #else
file_handle = file_open(AccessFlag_Read|AccessFlag_Write, path); file_handle = file_open(AccessFlag_Read|AccessFlag_Write, path);
#endif #endif
ProfEnd();
return file_handle; return file_handle;
} }
@@ -401,3 +405,230 @@ lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data)
lnk_write_data_list_to_file_path(path, temp_path, data_list); lnk_write_data_list_to_file_path(path, temp_path, data_list);
scratch_end(scratch); scratch_end(scratch);
} }
internal String8
lnk_data_from_file_artifact(Arena *arena, LNK_FileArtifact *artifact)
{
return str8_list_join(arena, &artifact->data, 0);
}
// --- Background Writer -------------------------------------------------------
struct LNK_BackgroundFile
{
LNK_BackgroundFile *next;
String8 path;
String8 temp_path;
String8 open_path;
File file;
U64 bytes_written;
B32 open_with_rename;
B32 is_open;
B32 is_finished;
B32 is_complete;
B32 write_failed;
};
typedef enum
{
LNK_BackgroundFileJobKind_Write,
LNK_BackgroundFileJobKind_EndFile,
LNK_BackgroundFileJobKind_EndWriter,
} LNK_BackgroundFileJobKind;
typedef struct
{
LNK_BackgroundFileJobKind kind;
LNK_BackgroundFile *file;
U64 file_off;
U64 expected_byte_count;
String8 data;
} LNK_BackgroundFileWriteJob;
internal void
lnk_background_file_writer_end_file_on_thread(LNK_BackgroundFile *file, U64 expected_byte_count)
{
B32 is_complete = !file->write_failed && file->bytes_written == expected_byte_count;
if (is_complete && file->open_with_rename) {
if (!lnk_file_set_delete_on_close(file->file, 0)) {
lnk_error(LNK_Error_IO, "failed to update file disposition on %S", file->open_path);
is_complete = 0;
} else if (!lnk_file_rename(file->file, file->path)) {
lnk_error(LNK_Error_IO, "failed to rename %S -> %S", file->temp_path, file->path);
is_complete = 0;
}
}
lnk_close_file(&file->file);
file->is_open = 0;
file->is_complete = is_complete;
if (!is_complete) {
lnk_error(LNK_Error_IO, "incomplete write, %M written, expected %M, file %S", file->bytes_written, expected_byte_count, file->path);
} else if (lnk_get_log_status(LNK_Log_IO_Write)) {
lnk_log(LNK_Log_IO_Write, "File \"%S\" %M written", file->path, expected_byte_count);
}
}
internal void
lnk_background_file_writer_thread(void *raw_writer)
{
ProfBeginFunction();
set_thread_namef("Background File Writer");
LNK_BackgroundFileWriter *writer = raw_writer;
for (;;) {
LNK_BackgroundFileWriteJob job = {0};
RingGuard guard = guarded_ring_open(writer->queue);
B32 is_read = guarded_ring_read_struct_or_wait(&guard, &job, max_U64);
guarded_ring_close(&guard);
Assert(is_read);
if (job.kind == LNK_BackgroundFileJobKind_EndWriter) { break; }
if (job.kind == LNK_BackgroundFileJobKind_Write) {
U64 write_size = lnk_write_file(&job.file->file, job.file_off, job.data.str, job.data.size);
if (write_size != job.data.size) {
job.file->write_failed = 1;
}
job.file->bytes_written += write_size;
} else if (job.kind == LNK_BackgroundFileJobKind_EndFile) {
lnk_background_file_writer_end_file_on_thread(job.file, job.expected_byte_count);
}
}
ProfEnd();
}
internal void
lnk_background_file_writer_begin(LNK_BackgroundFileWriter *writer)
{
ProfBegin("Background File Writer Begin");
writer->queue_arena = arena_alloc(.reserve_size = MB(2), .commit_size = MB(2), .name = "BACKGROUND_FILE_WRITE_QUEUE");
writer->queue = guarded_ring_alloc(writer->queue_arena, MB(1));
ProfEnd();
}
internal LNK_BackgroundFile *
lnk_background_file_writer_begin_file(LNK_BackgroundFileWriter *writer, String8 path, String8 temp_path)
{
ProfBegin("Background File Writer Begin File");
if (!writer->is_running) {
writer->thread = thread_launch(lnk_background_file_writer_thread, writer);
writer->is_running = writer->thread.u64[0] != 0;
if (!writer->is_running) {
lnk_error(LNK_Error_IO, "failed to start background file writer");
ProfEnd();
return 0;
}
}
LNK_BackgroundFile *file = push_array(writer->queue_arena, LNK_BackgroundFile, 1);
file->path = path;
file->temp_path = temp_path;
file->open_with_rename = (temp_path.size > 0);
if (file->open_with_rename) {
file->file = lnk_file_open_with_rename_permissions(temp_path);
file->open_path = temp_path;
} else {
lnk_open_file_write((char *)path.str, path.size, &file->file, sizeof(file->file));
file->open_path = path;
}
file->is_open = !file_match(file->file, file_zero());
if (!file->is_open) {
lnk_error(LNK_Error_NoAccess, "don't have access to write to %S", path);
goto exit;
}
if (file->open_with_rename && !lnk_file_set_delete_on_close(file->file, 1)) {
lnk_error(LNK_Error_IO, "failed to update file disposition on %S", file->open_path);
lnk_close_file(&file->file);
file->is_open = 0;
goto exit;
}
SLLQueuePush(writer->file_first, writer->file_last, file);
exit:;
ProfEnd();
return file->is_open ? file : 0;
}
internal void
lnk_background_file_writer_enqueue(LNK_BackgroundFileWriter *writer, LNK_BackgroundFile *file, U64 file_off, String8 data)
{
ProfBegin("Background File Writer Enqueue");
Assert(writer->is_running);
Assert(file->is_open && !file->is_finished);
if (data.size > 0) {
LNK_BackgroundFileWriteJob job = {
.kind = LNK_BackgroundFileJobKind_Write,
.file = file,
.file_off = file_off,
.data = data,
};
RingGuard guard = guarded_ring_open(writer->queue);
B32 is_written = guarded_ring_write_struct_or_wait(&guard, &job, max_U64);
guarded_ring_close(&guard);
Assert(is_written);
}
ProfEnd();
}
internal void
lnk_background_file_writer_end_file(LNK_BackgroundFileWriter *writer, LNK_BackgroundFile *file, U64 expected_byte_count)
{
ProfBegin("Background File Writer End File");
Assert(writer->is_running);
Assert(file->is_open && !file->is_finished);
file->is_finished = 1;
LNK_BackgroundFileWriteJob job = {
.kind = LNK_BackgroundFileJobKind_EndFile,
.file = file,
.expected_byte_count = expected_byte_count,
};
RingGuard guard = guarded_ring_open(writer->queue);
B32 is_written = guarded_ring_write_struct_or_wait(&guard, &job, max_U64);
guarded_ring_close(&guard);
Assert(is_written);
ProfEnd();
}
internal void
lnk_background_file_writer_end(LNK_BackgroundFileWriter *writer)
{
ProfBegin("Background File Writer End");
if (writer->is_running) {
LNK_BackgroundFileWriteJob job = { .kind = LNK_BackgroundFileJobKind_EndWriter };
RingGuard guard = guarded_ring_open(writer->queue);
B32 is_written = guarded_ring_write_struct_or_wait(&guard, &job, max_U64);
guarded_ring_close(&guard);
Assert(is_written);
thread_join(writer->thread, -1);
}
for EachNode(file, LNK_BackgroundFile, writer->file_first) {
if (file->is_open) {
lnk_error(LNK_Error_IO, "unfinished background write, file %S", file->path);
lnk_close_file(&file->file);
file->is_open = 0;
}
}
guarded_ring_release(writer->queue);
arena_release(writer->queue_arena);
writer->is_running = 0;
ProfEnd();
}
+25
View File
@@ -18,6 +18,23 @@ typedef struct
U8 *buffer; U8 *buffer;
} LNK_DiskReader; } LNK_DiskReader;
typedef struct
{
String8List data;
} LNK_FileArtifact;
typedef struct LNK_BackgroundFile LNK_BackgroundFile;
typedef struct
{
Arena *queue_arena;
GuardedRing *queue;
Thread thread;
LNK_BackgroundFile *file_first;
LNK_BackgroundFile *file_last;
B32 is_running;
} LNK_BackgroundFileWriter;
// --- Shared File API --------------------------------------------------------- // --- Shared File API ---------------------------------------------------------
shared_function int lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max); shared_function int lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max);
@@ -38,4 +55,12 @@ internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Aren
internal void lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List list); internal void lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List list);
internal void lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data); internal void lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data);
internal String8 lnk_data_from_file_artifact(Arena *arena, LNK_FileArtifact *artifact);
// --- Background Writer -------------------------------------------------------
internal void lnk_background_file_writer_begin (LNK_BackgroundFileWriter *writer);
internal LNK_BackgroundFile *lnk_background_file_writer_begin_file(LNK_BackgroundFileWriter *writer, String8 path, String8 temp_path);
internal void lnk_background_file_writer_enqueue (LNK_BackgroundFileWriter *writer, LNK_BackgroundFile *file, U64 file_off, String8 data);
internal void lnk_background_file_writer_end_file (LNK_BackgroundFileWriter *writer, LNK_BackgroundFile *file, U64 expected_byte_count);
internal void lnk_background_file_writer_end (LNK_BackgroundFileWriter *writer);
+4
View File
@@ -15,6 +15,10 @@ typedef struct LNK_Lib
String8Array symbol_names; String8Array symbol_names;
String8 long_names; String8 long_names;
U64 input_idx; U64 input_idx;
struct LNK_SymbolHashTrieChunk **search_cursor_chunks;
U64 *search_cursor_indices;
B32 searched_anti_deps;
} LNK_Lib; } LNK_Lib;
typedef struct LNK_LibNode typedef struct LNK_LibNode
+12
View File
@@ -1,6 +1,11 @@
// 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/)
#if OS_WINDOWS
#include <fcntl.h> // _O_BINARY
#include <io.h> // _setmode
#endif
static Mutex g_log_mutex; static Mutex g_log_mutex;
static B32 g_log_status [LNK_Log_Count]; static B32 g_log_status [LNK_Log_Count];
static LNK_ErrorMode g_error_mode_arr [LNK_Error_Count]; static LNK_ErrorMode g_error_mode_arr [LNK_Error_Count];
@@ -36,7 +41,14 @@ lnk_log_begin(void)
for (int i = LNK_Error_StopFirst; i < LNK_Error_StopLast; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Stop; } for (int i = LNK_Error_StopFirst; i < LNK_Error_StopLast; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Stop; }
for (int i = LNK_Error_ContinueFirst; i < LNK_Error_ContinueLast; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Continue; } for (int i = LNK_Error_ContinueFirst; i < LNK_Error_ContinueLast; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Continue; }
for (int i = LNK_Warning_First; i < LNK_Warning_Last; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Warn; } for (int i = LNK_Warning_First; i < LNK_Warning_Last; ++i) { g_error_mode_arr[i] = LNK_ErrorMode_Warn; }
g_log_mutex = mutex_alloc(); g_log_mutex = mutex_alloc();
// ninja mangles CRLF in captured linker output, so force LF-only output
#if OS_WINDOWS
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
} }
internal void internal void
+1
View File
@@ -24,6 +24,7 @@ typedef enum
LNK_Log_Count LNK_Log_Count
} LNK_LogType; } LNK_LogType;
// TODO: factor into an xlist with explicitly defined error levels and warnings
typedef enum typedef enum
{ {
LNK_Error_Null, LNK_Error_Null,
+212 -84
View File
@@ -94,14 +94,44 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
} }
// //
// error check section headers // section table pass
// - error check headers fields
// - collect section header flags
// - find debug info and meta-data leaders
// //
COFF_SectionHeader *coff_section_table = (COFF_SectionHeader *)raw_coff_section_table.str; COFF_SectionHeader *coff_section_table = (COFF_SectionHeader *)raw_coff_section_table.str;
COFF_SectionFlags *section_flags = push_array_no_zero(arena, COFF_SectionFlags, header.section_count_no_null); COFF_SectionFlags *section_flags = push_array_no_zero(arena, COFF_SectionFlags, header.section_count_no_null);
U32 debug_t_sect_idx = ~0;
U32 debug_p_sect_idx = ~0;
U32 debug_h_sect_idx = ~0;
U32 llvm_addrsig_sect_idx = ~0;
for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) { for (U64 sect_idx = 0; sect_idx < header.section_count_no_null; sect_idx += 1) {
COFF_SectionHeader *coff_sect_header = &coff_section_table[sect_idx]; COFF_SectionHeader *coff_sect_header = &coff_section_table[sect_idx];
section_flags[sect_idx] = coff_sect_header->flags; section_flags[sect_idx] = coff_sect_header->flags & ~3; // linker reserves low 2 bits for internal flags
String8 sect_name = coff_name_from_section_header(raw_coff_string_table, coff_sect_header); String8 sect_name = coff_name_from_section_header(raw_coff_string_table, coff_sect_header);
if (str8_starts_with(sect_name, str8_lit(".debug$"))) {
section_flags[sect_idx] |= LNK_SECTION_FLAG_DEBUG;
}
if (str8_ends_with(sect_name, str8_lit("$fo$"), 0) ||
str8_ends_with(sect_name, str8_lit("$fo_rvas$"), 0) ||
str8_ends_with(sect_name, str8_lit("$fo_bdd$"), 0)) {
section_flags[sect_idx] |= COFF_SectionFlag_LnkInfo;
}
if (task->find_debug_t) {
if (str8_match(sect_name, str8_lit(".debug$T"), 0)) {
debug_t_sect_idx = sect_idx;
} else if (str8_match(sect_name, str8_lit(".debug$P"), 0)) {
debug_p_sect_idx = sect_idx;
} else if (str8_match(sect_name, str8_lit(".debug$H"), 0)) {
debug_h_sect_idx = sect_idx;
}
}
if (task->find_llvm_addrsig && llvm_addrsig_sect_idx == max_U32 &&
str8_match(sect_name, str8_lit(".llvm_addrsig"), 0)) {
llvm_addrsig_sect_idx = sect_idx;
}
if (~section_flags[sect_idx] & COFF_SectionFlag_CntUninitializedData) { if (~section_flags[sect_idx] & COFF_SectionFlag_CntUninitializedData) {
if (coff_sect_header->fsize > 0) { if (coff_sect_header->fsize > 0) {
Rng1U64 sect_range = rng_1u64(coff_sect_header->foff, coff_sect_header->foff + coff_sect_header->fsize); Rng1U64 sect_range = rng_1u64(coff_sect_header->foff, coff_sect_header->foff + coff_sect_header->fsize);
@@ -125,13 +155,38 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
} }
// //
// error check symbol table // error check symbol table and cache name lengths for primary symbols
// //
U64 primary_symbol_count = 0;
{
COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += 1 + symbol.aux_symbol_count) {
symbol = coff_parse_symbol_no_name(header, raw_coff_symbol_table, symbol_idx);
primary_symbol_count += 1;
}
}
U64 name_block_count = CeilIntegerDiv(header.symbol_count, 64);
LNK_SymbolNameCache symbol_name_cache = {
.masks = push_array(arena, U64, name_block_count),
.block_bases = push_array_no_zero(arena, U32, name_block_count),
.name_sizes = push_array_no_zero(arena, U32, primary_symbol_count),
};
{ {
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(input->data, header.section_table_range).str; COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(input->data, header.section_table_range).str;
U64 next_block = 0;
U32 name_count = 0;
COFF_ParsedSymbol symbol; COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx);
U64 block_idx = symbol_idx >> 6;
while (next_block <= block_idx) {
symbol_name_cache.block_bases[next_block++] = name_count;
}
if (symbol.name.size) {
symbol_name_cache.masks[block_idx] |= 1ull << (symbol_idx & 63);
symbol_name_cache.name_sizes[name_count++] = safe_cast_u32(symbol.name.size);
}
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
if (interp == COFF_SymbolValueInterp_Regular) { if (interp == COFF_SymbolValueInterp_Regular) {
if (symbol.section_number == 0 || symbol.section_number > header.section_count_no_null) { if (symbol.section_number == 0 || symbol.section_number > header.section_count_no_null) {
@@ -149,6 +204,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
} }
} }
} }
while (next_block < name_block_count) {
symbol_name_cache.block_bases[next_block++] = name_count;
}
} }
// //
@@ -161,7 +219,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
COFF_ParsedSymbol symbol; COFF_ParsedSymbol symbol;
for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); symbol = coff_parse_symbol_no_name(header, raw_coff_symbol_table, symbol_idx);
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
if (interp == COFF_SymbolValueInterp_Regular) { if (interp == COFF_SymbolValueInterp_Regular) {
@@ -208,7 +266,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
} }
// extract COMDAT info for current section // extract COMDAT info for current section
COFF_ParsedSymbol symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); COFF_ParsedSymbol symbol = coff_parse_symbol_no_name(header, raw_coff_symbol_table, symbol_idx);
COFF_ComdatSelectType select = COFF_ComdatSelect_Null; COFF_ComdatSelectType select = COFF_ComdatSelect_Null;
U32 section_number = 0; U32 section_number = 0;
coff_parse_secdef(symbol, header.is_big_obj, &select, &section_number, 0, 0); coff_parse_secdef(symbol, header.is_big_obj, &select, &section_number, 0, 0);
@@ -247,7 +305,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
{ {
COFF_ParsedSymbol symbol; COFF_ParsedSymbol symbol;
for (U32 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { for (U32 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = coff_parse_symbol(header, raw_coff_string_table, raw_coff_symbol_table, symbol_idx); symbol = coff_parse_symbol_no_name(header, raw_coff_symbol_table, symbol_idx);
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
if (interp == COFF_SymbolValueInterp_Regular && symbol.storage_class == COFF_SymStorageClass_Static && symbol.aux_symbol_count > 0) { if (interp == COFF_SymbolValueInterp_Regular && symbol.storage_class == COFF_SymStorageClass_Static && symbol.aux_symbol_count > 0) {
COFF_ComdatSelectType selection = COFF_ComdatSelect_Null; COFF_ComdatSelectType selection = COFF_ComdatSelect_Null;
@@ -262,28 +320,6 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
} }
} }
//
// mark sections
//
{
for EachIndex(sect_idx, header.section_count_no_null) {
COFF_SectionHeader *sect_header = &coff_section_table[sect_idx];
String8 sect_name = coff_name_from_section_header(raw_coff_string_table, sect_header);
// debug info
if (str8_starts_with(sect_name, str8_lit(".debug$"))) {
section_flags[sect_idx] |= LNK_SECTION_FLAG_DEBUG;
}
// function overrides
if (str8_ends_with(sect_name, str8_lit("$fo$"), 0) ||
str8_ends_with(sect_name, str8_lit("$fo_rvas$"), 0) ||
str8_ends_with(sect_name, str8_lit("$fo_bdd$"), 0)) {
section_flags[sect_idx] |= COFF_SectionFlag_LnkInfo;
}
}
}
B8 hotpatch = 0; B8 hotpatch = 0;
if (header.machine == COFF_MachineType_X64) { if (header.machine == COFF_MachineType_X64) {
hotpatch = 1; hotpatch = 1;
@@ -335,31 +371,17 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
obj->path = push_str8_copy(arena, input->path); obj->path = push_str8_copy(arena, input->path);
obj->header = header; obj->header = header;
obj->section_flags = section_flags; obj->section_flags = section_flags;
obj->symbol_name_cache = symbol_name_cache;
obj->comdats = comdats; obj->comdats = comdats;
obj->exclude_from_debug_info = input->exclude_from_debug_info; obj->exclude_from_debug_info = input->exclude_from_debug_info;
obj->hotpatch = hotpatch; obj->hotpatch = hotpatch;
obj->associated_sections = associated_sections; obj->associated_sections = associated_sections;
obj->self = &task->objs[task_id]; obj->self = &task->objs[task_id];
obj->link_member = input->link_member; obj->link_member = input->link_member;
obj->debug_t_sect_idx = ~0; obj->debug_t_sect_idx = debug_t_sect_idx;
obj->debug_p_sect_idx = ~0; obj->debug_p_sect_idx = debug_p_sect_idx;
obj->debug_h_sect_idx = ~0; obj->debug_h_sect_idx = debug_h_sect_idx;
} obj->llvm_addrsig_sect_idx = llvm_addrsig_sect_idx;
internal
THREAD_POOL_TASK_FUNC(lnk_obj_find_debug_t)
{
LNK_Obj *obj = &((LNK_ObjNode *)raw_task)[task_id].data;
for EachIndex(sect_idx, obj->header.section_count_no_null) {
String8 section_name = lnk_obj_section_name_from_sect_idx(obj, sect_idx);
if (str8_match(section_name, str8_lit(".debug$T"), 0)) {
obj->debug_t_sect_idx = sect_idx;
} else if (str8_match(section_name, str8_lit(".debug$P"), 0)) {
obj->debug_p_sect_idx = sect_idx;
} else if (str8_match(section_name, str8_lit(".debug$H"), 0)) {
obj->debug_h_sect_idx = sect_idx;
}
}
} }
internal LNK_ObjNode * internal LNK_ObjNode *
@@ -368,11 +390,14 @@ lnk_obj_from_input_many(TP_Context *tp, TP_Arena *arena, LNK_Config *config, U64
LNK_ObjNode *objs = 0; LNK_ObjNode *objs = 0;
if (inputs_count) { if (inputs_count) {
objs = push_array(arena->v[0], LNK_ObjNode, inputs_count); objs = push_array(arena->v[0], LNK_ObjNode, inputs_count);
tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &(LNK_ObjIniter){ .inputs = inputs, .objs = objs, .machine = config->machine }); LNK_ObjIniter task = {
.inputs = inputs,
if (lnk_do_debug_info(config)) { .objs = objs,
tp_for_parallel(tp, arena, inputs_count, lnk_obj_find_debug_t, objs); .machine = config->machine,
} .find_debug_t = lnk_do_debug_info(config),
.find_llvm_addrsig = config->opt_icf == LNK_SwitchState_Yes,
};
tp_for_parallel(tp, arena, inputs_count, lnk_obj_initer, &task);
} }
return objs; return objs;
} }
@@ -410,8 +435,9 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
LNK_Obj *obj = task->objs[task_id]; LNK_Obj *obj = task->objs[task_id];
COFF_ParsedSymbol symbol = {0}; COFF_ParsedSymbol symbol = {0};
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); symbol = lnk_parsed_symbol_from_coff_symbol_idx_no_name(obj, symbol_idx);
COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
LNK_SymbolSearchType search_type = lnk_symbol_search_type_from_coff(obj, symbol, interp);
switch (interp) { switch (interp) {
case COFF_SymbolValueInterp_Regular: { case COFF_SymbolValueInterp_Regular: {
if (symbol.storage_class == COFF_SymStorageClass_External) { if (symbol.storage_class == COFF_SymStorageClass_External) {
@@ -419,27 +445,27 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
if (*section.flags & COFF_SectionFlag_LnkRemove) { if (*section.flags & COFF_SectionFlag_LnkRemove) {
break; break;
} }
LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); LNK_Symbol *defn = lnk_make_symbol(arena, lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx), obj, symbol_idx, search_type);
lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn);
} }
} break; } break;
case COFF_SymbolValueInterp_Weak: { case COFF_SymbolValueInterp_Weak: {
LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); LNK_Symbol *defn = lnk_make_symbol(arena, lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx), obj, symbol_idx, search_type);
lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn);
} break; } break;
case COFF_SymbolValueInterp_Undefined: { case COFF_SymbolValueInterp_Undefined: {
if (symbol.storage_class == COFF_SymStorageClass_External) { if (symbol.storage_class == COFF_SymStorageClass_External) {
LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); LNK_Symbol *defn = lnk_make_symbol(arena, lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx), obj, symbol_idx, search_type);
lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn);
} }
} break; } break;
case COFF_SymbolValueInterp_Common: { case COFF_SymbolValueInterp_Common: {
LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); LNK_Symbol *defn = lnk_make_symbol(arena, lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx), obj, symbol_idx, search_type);
lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn);
} break; } break;
case COFF_SymbolValueInterp_Abs: { case COFF_SymbolValueInterp_Abs: {
if (symbol.storage_class == COFF_SymStorageClass_External) { if (symbol.storage_class == COFF_SymStorageClass_External) {
LNK_Symbol *defn = lnk_make_symbol(arena, symbol.name, obj, symbol_idx); LNK_Symbol *defn = lnk_make_symbol(arena, lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx), obj, symbol_idx, search_type);
lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); lnk_symbol_table_push_(task->symtab, arena, worker_id, defn);
} }
} break; } break;
@@ -451,26 +477,96 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
} }
} }
internal LNK_SymbolHashTrie ** internal LNK_ObjSymbolRef *
lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj) lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj)
{ {
LNK_SymbolHashTrie **symlinks = push_array(arena, LNK_SymbolHashTrie *, obj->header.section_count_no_null+1); LNK_ObjSymbolRef *symlinks = push_array(arena, LNK_ObjSymbolRef, obj->header.section_count_no_null + 1);
COFF_ParsedSymbol symbol; COFF_ParsedSymbol symbol = {0};
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); symbol = lnk_parsed_symbol_from_coff_symbol_idx_no_name(obj, symbol_idx);
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol);
if (interp == COFF_SymbolValueInterp_Regular && symbol.aux_symbol_count == 0 && symbol.storage_class == COFF_SymStorageClass_External) { if (interp != COFF_SymbolValueInterp_Regular) { continue; }
LNK_ObjSection section = lnk_obj_section_from_section_number(obj, symbol.section_number);
if (*section.flags & COFF_SectionFlag_LnkCOMDAT) { COFF_SectionFlags section_flags = obj->section_flags[symbol.section_number - 1];
if (symlinks[symbol.section_number] == 0 || symbol.value == 0) { if (~section_flags & COFF_SectionFlag_LnkCOMDAT) { continue; }
symlinks[symbol.section_number] = lnk_symbol_table_search_(symtab, symbol.name);
LNK_ObjSymbolRef *symlink = &symlinks[symbol.section_number];
// external symbols
if (symbol.storage_class == COFF_SymStorageClass_External && symbol.aux_symbol_count == 0) {
String8 symbol_name = lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx);
B32 can_set_symlink = (symlink->obj == 0 || symbol.value == 0);
if (!can_set_symlink && symlink->obj == obj) {
COFF_ParsedSymbol leader = lnk_parsed_symbol_from_coff_symbol_idx_no_name(symlink->obj, symlink->symbol_idx);
B32 leader_is_same_section = leader.section_number == symbol.section_number;
B32 leader_is_static_anchor = (leader_is_same_section && leader.storage_class == COFF_SymStorageClass_Static && leader.aux_symbol_count == 0);
B32 leader_is_vftable = str8_starts_with(lnk_symbol_name_from_coff_symbol_idx(symlink->obj, symlink->symbol_idx), str8_lit(MSCRT_VFTABLE_SYMBOL_PREFIX));
B32 current_is_vftable = str8_starts_with(symbol_name, str8_lit(MSCRT_VFTABLE_SYMBOL_PREFIX));
// prefer public symbols to local static anchors; prefer vftable public
// symbols to other public symbols so ICF keeps vftables in their own color space
can_set_symlink = (leader_is_static_anchor || (leader_is_same_section && current_is_vftable && !leader_is_vftable));
}
if (can_set_symlink) {
LNK_SymbolHashTrie *link_symbol = lnk_symbol_table_search_(symtab, symbol_name);
if (link_symbol) {
*symlink = lnk_ref_from_symbol(link_symbol->symbol);
}
}
}
// static symbols
else if (symbol.storage_class == COFF_SymStorageClass_Static) {
if (symbol.aux_symbol_count == 0) {
if (symlink->obj == 0) {
*symlink = (LNK_ObjSymbolRef){ obj, symbol_idx };
} }
} }
} }
} }
return symlinks; return symlinks;
} }
internal U32List
lnk_obj_collect_associated_sections(Arena *arena, LNK_Obj *obj, U32 root_section, COFF_SectionFlags skip_flags)
{
Temp scratch = scratch_begin(&arena, 1);
// track each child before enqueueing it because COFF associations can cycle
HashMap seen_hm = {0};
U32List queue = {0};
U32Node root_n = { root_section };
u32_list_push_node(&queue, &root_n);
hash_map_push_u64_u64(scratch.arena, &seen_hm, root_section, 1);
// walk the complete descendant chain because associated COMDATs can nest
for EachNode(parent_n, U32Node, queue.first) {
for EachNode(associated_n, U32Node, obj->associated_sections[parent_n->data]) {
U32 child_section = associated_n->data;
if (child_section == 0) { continue; }
if (hash_map_search_u64_u64(&seen_hm, child_section)) { continue; }
if (obj->section_flags[child_section - 1] & skip_flags) { continue; }
hash_map_push_u64_u64(scratch.arena, &seen_hm, child_section, 1);
u32_list_push(arena, &queue, child_section);
}
}
// return only child sections so callers choose whether the root participates
U32List result = {0};
if (queue.count > 1) {
result.first = queue.first->next;
result.last = queue.last;
result.count = queue.count - 1;
}
scratch_end(scratch);
return result;
}
internal internal
THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task) THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task)
{ {
@@ -479,13 +575,21 @@ THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task)
obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj); obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj);
} }
internal void
lnk_assign_comdat_symlinks(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
{
ProfBeginFunction();
LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs };
tp_for_parallel(tp, arena, objs_count, lnk_assign_comdat_symlinks_task, &task);
ProfEnd();
}
internal void internal void
lnk_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs) lnk_push_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs)
{ {
ProfBeginFunction(); ProfBeginFunction();
LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs }; LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs };
tp_for_parallel(tp, arena, objs_count, lnk_input_coff_symbol_table, &task); tp_for_parallel(tp, arena, objs_count, lnk_input_coff_symbol_table, &task);
tp_for_parallel(tp, arena, objs_count, lnk_assign_comdat_symlinks_task, &task);
ProfEnd(); ProfEnd();
} }
@@ -543,11 +647,15 @@ lnk_obj_get_removed_section_number(LNK_Obj *obj)
return obj->header.is_big_obj ? LNK_REMOVED_SECTION_NUMBER_32 : LNK_REMOVED_SECTION_NUMBER_16; return obj->header.is_big_obj ? LNK_REMOVED_SECTION_NUMBER_32 : LNK_REMOVED_SECTION_NUMBER_16;
} }
internal LNK_Symbol * internal B32
lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number) lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number, LNK_ObjSymbolRef *symlink_out)
{ {
LNK_SymbolHashTrie *symlink = obj->symlinks[section_number]; LNK_ObjSymbolRef symlink = obj->symlinks[section_number];
return symlink ? symlink->symbol : 0; B32 is_valid = symlink.obj != 0;
if (is_valid && symlink_out) {
*symlink_out = symlink;
}
return is_valid;
} }
internal COFF_SectionHeader * internal COFF_SectionHeader *
@@ -644,7 +752,7 @@ lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_
Assert(section_number > 0); Assert(section_number > 0);
U32 symbol_idx = obj->comdats[section_number-1]; U32 symbol_idx = obj->comdats[section_number-1];
if (symbol_idx != max_U32) { if (symbol_idx != max_U32) {
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx_no_name(obj, symbol_idx);
coff_parse_secdef(secdef, obj->header.is_big_obj, select_out, section_number_out, section_length_out, check_sum_out); coff_parse_secdef(secdef, obj->header.is_big_obj, select_out, section_number_out, section_length_out, check_sum_out);
return 1; return 1;
} }
@@ -660,19 +768,39 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
return &section_table[sect_idx]; return &section_table[sect_idx];
} }
internal COFF_ParsedSymbol internal force_inline COFF_ParsedSymbol
lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx) lnk_parsed_symbol_from_coff_symbol_idx_no_name(LNK_Obj *obj, U64 symbol_idx)
{ {
String8 string_table = str8_substr(obj->data, obj->header.string_table_range); return coff_parse_symbol_no_name(obj->header, lnk_coff_symbol_table_from_obj(obj), safe_cast_u32(symbol_idx));
String8 symbol_table = str8_substr(obj->data, obj->header.symbol_table_range);
COFF_ParsedSymbol result = {0};
if (obj->header.is_big_obj) {
result = coff_parse_symbol32(string_table, (COFF_Symbol32 *)symbol_table.str + symbol_idx);
} else {
result = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
} }
internal force_inline String8
lnk_symbol_name_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx)
{
String8 result = {0};
U64 block_idx = symbol_idx >> 6;
U64 bit = 1ull << (symbol_idx & 63);
U64 mask = obj->symbol_name_cache.masks[block_idx];
if (mask & bit) {
U64 name_idx = obj->symbol_name_cache.block_bases[block_idx] + count_bits_set64(mask & (bit - 1));
U64 name_size = obj->symbol_name_cache.name_sizes[name_idx];
String8 symbol_table = lnk_coff_symbol_table_from_obj(obj);
COFF_SymbolName *name = obj->header.is_big_obj ? &((COFF_Symbol32 *)symbol_table.str)[symbol_idx].name
: &((COFF_Symbol16 *)symbol_table.str)[symbol_idx].name;
U8 *name_ptr = name->long_name.zeroes == 0
? obj->data.str + obj->header.string_table_range.min + name->long_name.string_table_offset
: name->short_name;
result = str8(name_ptr, name_size);
}
return result;
}
internal force_inline COFF_ParsedSymbol
lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx)
{
COFF_ParsedSymbol result = lnk_parsed_symbol_from_coff_symbol_idx_no_name(obj, symbol_idx);
result.name = lnk_symbol_name_from_coff_symbol_idx(obj, symbol_idx);
return result; return result;
} }
+19 -3
View File
@@ -5,6 +5,13 @@
// --- Input ------------------------------------------------------------------- // --- Input -------------------------------------------------------------------
typedef struct LNK_SymbolNameCache
{
U64 *masks;
U32 *block_bases;
U32 *name_sizes;
} LNK_SymbolNameCache;
typedef struct LNK_Obj typedef struct LNK_Obj
{ {
String8 path; String8 path;
@@ -12,6 +19,7 @@ typedef struct LNK_Obj
COFF_FileHeaderInfo header; COFF_FileHeaderInfo header;
COFF_SectionFlags *section_flags; COFF_SectionFlags *section_flags;
LNK_SymbolNameCache symbol_name_cache;
// flags // flags
B8 hotpatch; B8 hotpatch;
@@ -22,7 +30,7 @@ typedef struct LNK_Obj
// COMDAT // COMDAT
U32 *comdats; U32 *comdats;
U32Node **associated_sections; U32Node **associated_sections;
LNK_SymbolHashTrie **symlinks; LNK_ObjSymbolRef *symlinks;
// link // link
struct LNK_LibMemberRef *link_member; struct LNK_LibMemberRef *link_member;
@@ -33,6 +41,9 @@ typedef struct LNK_Obj
U32 debug_p_sect_idx; U32 debug_p_sect_idx;
U32 debug_h_sect_idx; U32 debug_h_sect_idx;
// ICF
U32 llvm_addrsig_sect_idx;
// @type_server // @type_server
Rng1U64 ti_range; Rng1U64 ti_range;
CV_TypeIndex *ti_map; CV_TypeIndex *ti_map;
@@ -101,6 +112,8 @@ typedef struct
LNK_ObjNode *objs; LNK_ObjNode *objs;
U64 obj_id_base; U64 obj_id_base;
U32 machine; U32 machine;
B32 find_debug_t;
B32 find_llvm_addrsig;
} LNK_ObjIniter; } LNK_ObjIniter;
typedef struct typedef struct
@@ -139,12 +152,15 @@ internal U32 lnk_obj_get_vol_md(LNK_Obj *obj);
internal struct LNK_Lib * lnk_obj_get_lib(LNK_Obj *obj); internal struct LNK_Lib * lnk_obj_get_lib(LNK_Obj *obj);
internal String8 lnk_obj_get_lib_path(LNK_Obj *obj); internal String8 lnk_obj_get_lib_path(LNK_Obj *obj);
internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj); internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj);
internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number); internal B32 lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number, LNK_ObjSymbolRef *symlink_out);
internal U32List lnk_obj_collect_associated_sections(Arena *arena, LNK_Obj *obj, U32 root_section, COFF_SectionFlags skip_flags);
// --- Symbol & Section Helpers ------------------------------------------------ // --- Symbol & Section Helpers ------------------------------------------------
internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number); internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number);
internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx); internal force_inline COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx);
internal force_inline COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx_no_name(LNK_Obj *obj, U64 symbol_idx);
internal force_inline String8 lnk_symbol_name_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx);
internal U64 lnk_obj_sect_idx_from_section_number(LNK_Obj *obj, U64 section_number); internal U64 lnk_obj_sect_idx_from_section_number(LNK_Obj *obj, U64 section_number);
internal U64 lnk_obj_section_number_from_sect_idx(LNK_Obj *obj, U64 sect_idx); internal U64 lnk_obj_section_number_from_sect_idx(LNK_Obj *obj, U64 sect_idx);
internal String8 lnk_obj_section_name_from_section_number(LNK_Obj *obj, U64 section_number); internal String8 lnk_obj_section_name_from_section_number(LNK_Obj *obj, U64 section_number);
+84 -27
View File
@@ -1,8 +1,27 @@
// 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/)
#define LNK_SYMBOL_SEARCH_TYPE_MASK 7ull
internal LNK_SymbolSearchType
lnk_symbol_search_type_from_coff(LNK_Obj *obj, COFF_ParsedSymbol symbol, COFF_SymbolValueInterpType interp)
{
LNK_SymbolSearchType search_type = LNK_SymbolSearch_Null;
if (interp == COFF_SymbolValueInterp_Undefined) {
search_type = LNK_SymbolSearch_Undefined;
} else if (interp == COFF_SymbolValueInterp_Weak) {
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol, obj->header.is_big_obj);
switch (weak_ext->characteristics) {
case COFF_WeakExt_SearchLibrary: search_type = LNK_SymbolSearch_WeakLibrary; break;
case COFF_WeakExt_AntiDependency: search_type = LNK_SymbolSearch_WeakAntiDependency; break;
default: search_type = LNK_SymbolSearch_WeakOther; break;
}
}
return search_type;
}
internal LNK_Symbol * internal LNK_Symbol *
lnk_make_symbol(Arena *arena, String8 name, LNK_Obj *obj, U32 symbol_idx) lnk_make_symbol(Arena *arena, String8 name, LNK_Obj *obj, U32 symbol_idx, LNK_SymbolSearchType search_type)
{ {
LNK_ObjSymbolRefNode *ref = push_array(arena, LNK_ObjSymbolRefNode, 1); LNK_ObjSymbolRefNode *ref = push_array(arena, LNK_ObjSymbolRefNode, 1);
ref->v.obj = obj; ref->v.obj = obj;
@@ -10,11 +29,40 @@ lnk_make_symbol(Arena *arena, String8 name, LNK_Obj *obj, U32 symbol_idx)
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
symbol->name = name; symbol->name = name;
SLLQueuePush(symbol->first_ref, symbol->last_ref, ref); symbol->first_ref = ref;
Assert((IntFromPtr(ref) & LNK_SYMBOL_SEARCH_TYPE_MASK) == 0);
Assert(search_type <= LNK_SymbolSearch_WeakOther);
symbol->last_ref_and_search_type = IntFromPtr(ref) | search_type;
return symbol; return symbol;
} }
internal LNK_ObjSymbolRefNode *
lnk_last_ref_from_symbol(LNK_Symbol *symbol)
{
return PtrFromInt(symbol->last_ref_and_search_type & ~LNK_SYMBOL_SEARCH_TYPE_MASK);
}
internal LNK_SymbolSearchType
lnk_search_type_from_symbol(LNK_Symbol *symbol)
{
return safe_cast_u32(symbol->last_ref_and_search_type & LNK_SYMBOL_SEARCH_TYPE_MASK);
}
internal void
lnk_symbol_set_last_ref(LNK_Symbol *symbol, LNK_ObjSymbolRefNode *last_ref)
{
Assert((IntFromPtr(last_ref) & LNK_SYMBOL_SEARCH_TYPE_MASK) == 0);
symbol->last_ref_and_search_type = IntFromPtr(last_ref) | lnk_search_type_from_symbol(symbol);
}
internal void
lnk_symbol_set_search_type(LNK_Symbol *symbol, LNK_SymbolSearchType search_type)
{
Assert(search_type <= LNK_SymbolSearch_WeakOther);
symbol->last_ref_and_search_type = (symbol->last_ref_and_search_type & ~LNK_SYMBOL_SEARCH_TYPE_MASK) | search_type;
}
internal int internal int
lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b) lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b)
{ {
@@ -105,12 +153,12 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
{ {
B32 can_replace = 0; B32 can_replace = 0;
COFF_ParsedSymbol dst_parsed = lnk_parsed_from_symbol(dst);
COFF_ParsedSymbol src_parsed = lnk_parsed_from_symbol(src);
COFF_SymbolValueInterpType dst_interp = lnk_interp_from_symbol(dst);
COFF_SymbolValueInterpType src_interp = lnk_interp_from_symbol(src);
LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst); LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst);
LNK_ObjSymbolRef src_ref = lnk_ref_from_symbol(src); LNK_ObjSymbolRef src_ref = lnk_ref_from_symbol(src);
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(dst_ref.obj, dst_ref.symbol_idx);
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(src_ref.obj, src_ref.symbol_idx);
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
LNK_Obj *dst_obj = dst_ref.obj; LNK_Obj *dst_obj = dst_ref.obj;
LNK_Obj *src_obj = src_ref.obj; LNK_Obj *src_obj = src_ref.obj;
@@ -209,7 +257,13 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
lnk_error_multiply_defined_symbol(dst, src); lnk_error_multiply_defined_symbol(dst, src);
} }
} else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) {
COFF_ParsedSymbol dst_tag = lnk_parsed_symbol_from_coff_symbol_idx(dst_ref.obj, dst_ext->tag_index);
COFF_ParsedSymbol src_tag = lnk_parsed_symbol_from_coff_symbol_idx(src_ref.obj, src_ext->tag_index);
if (str8_match(dst_tag.name, src_tag.name, 0)) {
can_replace = lnk_symbol_is_before(src, dst);
} else {
lnk_error_multiply_defined_symbol(dst, src); lnk_error_multiply_defined_symbol(dst, src);
}
} else { } else {
can_replace = lnk_symbol_is_before(src, dst); can_replace = lnk_symbol_is_before(src, dst);
} }
@@ -332,9 +386,9 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
internal void internal void
lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src)
{ {
COFF_ParsedSymbol dst_parsed = lnk_parsed_from_symbol(dst);
COFF_SymbolValueInterpType dst_interp = lnk_interp_from_symbol(dst);
LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst); LNK_ObjSymbolRef dst_ref = lnk_ref_from_symbol(dst);
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(dst_ref.obj, dst_ref.symbol_idx);
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
if (dst_interp == COFF_SymbolValueInterp_Regular) { if (dst_interp == COFF_SymbolValueInterp_Regular) {
// remove replaced section from the output // remove replaced section from the output
@@ -351,8 +405,8 @@ lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src)
} }
// merge symbol refs // merge symbol refs
src->last_ref->next = dst->first_ref; lnk_last_ref_from_symbol(src)->next = dst->first_ref;
src->last_ref = dst->last_ref; lnk_symbol_set_last_ref(src, lnk_last_ref_from_symbol(dst));
// assert leader section is live // assert leader section is live
#if BUILD_DEBUG #if BUILD_DEBUG
@@ -531,7 +585,8 @@ lnk_parsed_from_symbol(LNK_Symbol *symbol)
internal COFF_SymbolValueInterpType internal COFF_SymbolValueInterpType
lnk_interp_from_symbol(LNK_Symbol *symbol) lnk_interp_from_symbol(LNK_Symbol *symbol)
{ {
COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); LNK_ObjSymbolRef ref = lnk_ref_from_symbol(symbol);
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(ref.obj, ref.symbol_idx);
return coff_interp_from_parsed_symbol(symbol_parsed); return coff_interp_from_parsed_symbol(symbol_parsed);
} }
@@ -555,9 +610,9 @@ internal void
lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol)
{ {
U64 hash = lnk_symbol_table_hasher(symbol->name); U64 hash = lnk_symbol_table_hasher(symbol->name);
COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol); LNK_SymbolSearchType search_type = lnk_search_type_from_symbol(symbol);
LNK_SymbolHashTrieChunkList *chunks; LNK_SymbolHashTrieChunkList *chunks;
if (interp == COFF_SymbolValueInterp_Weak || interp == COFF_SymbolValueInterp_Undefined) { if (search_type != LNK_SymbolSearch_Null) {
chunks = &symtab->search_chunks[worker_id]; chunks = &symtab->search_chunks[worker_id];
} else { } else {
chunks = &symtab->chunks[worker_id]; chunks = &symtab->chunks[worker_id];
@@ -656,7 +711,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_Ob
goto exit; goto exit;
} }
COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(current_symbol.obj, current_symbol.symbol_idx);
COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class);
if (current_interp == COFF_SymbolValueInterp_Weak) { if (current_interp == COFF_SymbolValueInterp_Weak) {
// record visited symbol // record visited symbol
@@ -665,7 +720,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_Ob
SLLQueuePush(sf, sl, s); SLLQueuePush(sf, sl, s);
// does weak symbol have a definition? // does weak symbol have a definition?
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx));
COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn_symbol); COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn_symbol);
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class);
if (defn_interp != COFF_SymbolValueInterp_Weak) { if (defn_interp != COFF_SymbolValueInterp_Weak) {
@@ -676,19 +731,19 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_Ob
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj);
// no definition -- fallback to default symbol // no definition -- fallback to default symbol
COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(current_symbol.obj, weak_ext->tag_index);
COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class);
current_symbol = (LNK_ObjSymbolRef){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; current_symbol = (LNK_ObjSymbolRef){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index };
if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) {
if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) {
LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index));
tag_interp = lnk_interp_from_symbol(dep_symbol); tag_interp = lnk_interp_from_symbol(dep_symbol);
} }
if (tag_interp == COFF_SymbolValueInterp_Weak) { break; } if (tag_interp == COFF_SymbolValueInterp_Weak) { break; }
} }
} else if (current_interp == COFF_SymbolValueInterp_Undefined) { } else if (current_interp == COFF_SymbolValueInterp_Undefined) {
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx));
COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol);
// unresolved undefined symbol // unresolved undefined symbol
@@ -713,15 +768,15 @@ internal B32
lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out) lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out)
{ {
B32 is_resolved = 1; B32 is_resolved = 1;
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(symbol.obj, symbol.symbol_idx);
COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class); COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class);
switch (symbol_interp) { switch (symbol_interp) {
case COFF_SymbolValueInterp_Regular: { case COFF_SymbolValueInterp_Regular: {
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); LNK_ObjSymbolRef symlink = {0};
*symbol_out = symlink ? lnk_ref_from_symbol(symlink) : symbol; *symbol_out = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number, &symlink) ? symlink : symbol;
} break; } break;
case COFF_SymbolValueInterp_Weak: { case COFF_SymbolValueInterp_Weak: {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); LNK_Symbol *defn = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx));
COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn); COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn);
COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn); COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn);
if (defn_interp != COFF_SymbolValueInterp_Undefined) { if (defn_interp != COFF_SymbolValueInterp_Undefined) {
@@ -731,7 +786,7 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb
} }
} break; } break;
case COFF_SymbolValueInterp_Undefined: { case COFF_SymbolValueInterp_Undefined: {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); LNK_Symbol *defn = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx));
if (defn) { if (defn) {
*symbol_out = lnk_ref_from_symbol(defn); *symbol_out = lnk_ref_from_symbol(defn);
} else { } else {
@@ -739,12 +794,12 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb
} }
} break; } break;
case COFF_SymbolValueInterp_Common: { case COFF_SymbolValueInterp_Common: {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); LNK_Symbol *defn = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx));
*symbol_out = lnk_ref_from_symbol(defn); *symbol_out = lnk_ref_from_symbol(defn);
} break; } break;
case COFF_SymbolValueInterp_Abs: { case COFF_SymbolValueInterp_Abs: {
if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) {
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); LNK_Symbol *defn = lnk_symbol_table_search(symtab, lnk_symbol_name_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx));
*symbol_out = lnk_ref_from_symbol(defn); *symbol_out = lnk_ref_from_symbol(defn);
} else { } else {
*symbol_out = symbol; *symbol_out = symbol;
@@ -763,12 +818,12 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
for EachIndex(i, c->count) { for EachIndex(i, c->count) {
LNK_Symbol *symbol = c->v[i].symbol; LNK_Symbol *symbol = c->v[i].symbol;
LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol); LNK_ObjSymbolRef symbol_ref = lnk_ref_from_symbol(symbol);
COFF_ParsedSymbol symbol_parsed = lnk_parsed_from_symbol(symbol); COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(symbol_ref.obj, symbol_ref.symbol_idx);
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
if (symbol_interp == COFF_SymbolValueInterp_Weak) { if (symbol_interp == COFF_SymbolValueInterp_Weak) {
LNK_ObjSymbolRef resolve = {0}; LNK_ObjSymbolRef resolve = {0};
if (lnk_resolve_weak_symbol(symtab, symbol_ref, &resolve)) { if (lnk_resolve_weak_symbol(symtab, symbol_ref, &resolve)) {
COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx_no_name(resolve.obj, resolve.symbol_idx);
COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed);
if (resolve_interp == COFF_SymbolValueInterp_Weak) { if (resolve_interp == COFF_SymbolValueInterp_Weak) {
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj); COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj);
@@ -783,8 +838,10 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
symbol16->value = 0; symbol16->value = 0;
symbol16->storage_class = COFF_SymStorageClass_External; symbol16->storage_class = COFF_SymStorageClass_External;
} }
lnk_symbol_set_search_type(symbol, LNK_SymbolSearch_Undefined);
} else { } else {
symbol->first_ref->v = resolve; symbol->first_ref->v = resolve;
lnk_symbol_set_search_type(symbol, LNK_SymbolSearch_Null);
} }
} }
} }
+19 -3
View File
@@ -17,13 +17,25 @@ typedef struct LNK_ObjSymbolRefNode
LNK_ObjSymbolRef v; LNK_ObjSymbolRef v;
} LNK_ObjSymbolRefNode; } LNK_ObjSymbolRefNode;
typedef U32 LNK_SymbolSearchType;
enum
{
LNK_SymbolSearch_Null,
LNK_SymbolSearch_Undefined,
LNK_SymbolSearch_WeakLibrary,
LNK_SymbolSearch_WeakAntiDependency,
LNK_SymbolSearch_WeakOther,
};
typedef struct LNK_Symbol typedef struct LNK_Symbol
{ {
String8 name; String8 name;
LNK_ObjSymbolRefNode *first_ref; LNK_ObjSymbolRefNode *first_ref;
LNK_ObjSymbolRefNode *last_ref; U64 last_ref_and_search_type; // Tail pointer with search type in its low bits.
} LNK_Symbol; } LNK_Symbol;
StaticAssert(sizeof(LNK_Symbol) == 32, lnk_symbol_size_check);
// --- Symbol Containers ------------------------------------------------------- // --- Symbol Containers -------------------------------------------------------
typedef struct LNK_SymbolNode typedef struct LNK_SymbolNode
@@ -89,7 +101,12 @@ typedef struct
// --- Symbol ----------------------------------------------------------------- // --- Symbol -----------------------------------------------------------------
internal LNK_Symbol * lnk_make_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); internal LNK_SymbolSearchType lnk_symbol_search_type_from_coff(struct LNK_Obj *obj, COFF_ParsedSymbol symbol, COFF_SymbolValueInterpType interp);
internal LNK_Symbol * lnk_make_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx, LNK_SymbolSearchType search_type);
internal LNK_ObjSymbolRefNode * lnk_last_ref_from_symbol(LNK_Symbol *symbol);
internal LNK_SymbolSearchType lnk_search_type_from_symbol(LNK_Symbol *symbol);
internal void lnk_symbol_set_last_ref(LNK_Symbol *symbol, LNK_ObjSymbolRefNode *last_ref);
internal void lnk_symbol_set_search_type(LNK_Symbol *symbol, LNK_SymbolSearchType search_type);
internal int lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b); internal int lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b);
internal int lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b); internal int lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b);
@@ -138,4 +155,3 @@ internal B32 lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef s
internal B32 lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out); internal B32 lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out);
internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab); internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab);
+478 -47
View File
@@ -1805,6 +1805,274 @@ gsi_record_sort_by_sc(PDB_GsiSortRecord *arr, U64 count)
ProfEnd(); ProfEnd();
} }
#define PDB_PSI_ADDR_MAP_RADIX_BITS 11
#define PDB_PSI_ADDR_MAP_RADIX_COUNT (1 << PDB_PSI_ADDR_MAP_RADIX_BITS)
#define PDB_PSI_ADDR_MAP_RADIX_MIN_COUNT (1 << 17)
typedef struct PDB_PsiAddrMapSortRecord
{
U64 key;
PDB_GsiSortRecord *record;
} PDB_PsiAddrMapSortRecord;
typedef struct PDB_PsiAddrMapSortTask
{
Rng1U64 *ranges;
PDB_GsiSortRecord *gsi_record_arr;
PDB_PsiAddrMapSortRecord *src;
PDB_PsiAddrMapSortRecord *dst;
U64 *counts;
U32 digit_shift;
U32 digit_count;
} PDB_PsiAddrMapSortTask;
typedef struct PDB_PsiAddrMapNameSortTask
{
PDB_PsiAddrMapSortRecord *record_arr;
Rng1U64 *run_arr;
Rng1U64 *batch_arr;
} PDB_PsiAddrMapNameSortTask;
force_inline U64
psi_addr_map_sort_key(PDB_GsiSortRecord *record)
{
U64 key = ((U64)record->isect_off.isect << 32) | record->isect_off.off;
return key;
}
force_inline int
psi_addr_map_name_compar_is_before(void *raw_a, void *raw_b)
{
PDB_PsiAddrMapSortRecord *a = raw_a;
PDB_PsiAddrMapSortRecord *b = raw_b;
int is_before = str8_compar_case_sensitive(&a->record->name, &b->record->name) < 0;
return is_before;
}
internal
THREAD_POOL_TASK_FUNC(psi_addr_map_radix_init_task)
{
ProfBeginFunction();
PDB_PsiAddrMapSortTask *task = raw_task;
Rng1U64 range = task->ranges[task_id];
for EachInRange(i, range) {
PDB_GsiSortRecord *record = &task->gsi_record_arr[i];
task->src[i].key = psi_addr_map_sort_key(record);
task->src[i].record = record;
}
ProfEnd();
}
internal
THREAD_POOL_TASK_FUNC(psi_addr_map_radix_histogram_task)
{
ProfBeginFunction();
PDB_PsiAddrMapSortTask *task = raw_task;
Rng1U64 range = task->ranges[task_id];
U64 *counts = task->counts + task_id * PDB_PSI_ADDR_MAP_RADIX_COUNT;
U32 mask = task->digit_count - 1;
MemoryZeroTyped(counts, task->digit_count);
for EachInRange(i, range) {
U64 digit = (task->src[i].key >> task->digit_shift) & mask;
counts[digit] += 1;
}
ProfEnd();
}
internal
THREAD_POOL_TASK_FUNC(psi_addr_map_radix_sort_task)
{
ProfBeginFunction();
PDB_PsiAddrMapSortTask *task = raw_task;
Rng1U64 range = task->ranges[task_id];
U64 *offsets = task->counts + task_id * PDB_PSI_ADDR_MAP_RADIX_COUNT;
U32 mask = task->digit_count - 1;
for EachInRange(i, range) {
PDB_PsiAddrMapSortRecord record = task->src[i];
U64 digit = (record.key >> task->digit_shift) & mask;
task->dst[offsets[digit]++] = record;
}
ProfEnd();
}
force_inline U64
psi_addr_map_name_sort_work(Rng1U64 run)
{
U64 count = dim_1u64(run);
U64 work = count * (64 - clz64(count));
return work;
}
internal
THREAD_POOL_TASK_FUNC(psi_addr_map_name_sort_task)
{
ProfBeginFunction();
PDB_PsiAddrMapNameSortTask *task = raw_task;
Rng1U64 batch = task->batch_arr[task_id];
for EachInRange(run_idx, batch) {
Rng1U64 run = task->run_arr[run_idx];
radsort(task->record_arr + run.min, dim_1u64(run), psi_addr_map_name_compar_is_before);
}
ProfEnd();
}
internal U32 *
psi_addr_map_from_gsi_records(TP_Context *tp, Arena *arena, PDB_GsiSortRecord *gsi_record_arr, U64 count)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
PDB_PsiAddrMapSortRecord *radix_record_arr = 0;
ProfBegin("Sort");
if (count >= PDB_PSI_ADDR_MAP_RADIX_MIN_COUNT) {
PDB_PsiAddrMapSortTask task = {0};
task.ranges = tp_divide_work(scratch.arena, count, tp->worker_count);
task.gsi_record_arr = gsi_record_arr;
task.src = push_array_no_zero(scratch.arena, PDB_PsiAddrMapSortRecord, count);
task.dst = push_array_no_zero(scratch.arena, PDB_PsiAddrMapSortRecord, count);
task.counts = push_array_no_zero(scratch.arena, U64, tp->worker_count * PDB_PSI_ADDR_MAP_RADIX_COUNT);
tp_for_parallel_prof(tp, 0, tp->worker_count, psi_addr_map_radix_init_task, &task, "psi_addr_map_radix_init_task");
ProfBegin("Radix");
U32 digit_shift[] = { 0, 11, 22, 32, 43 };
U32 digit_count[] = { 1 << 11, 1 << 11, 1 << 10, 1 << 11, 1 << 5 };
for EachIndex(pass_idx, ArrayCount(digit_shift)) {
ProfBeginV("Pass %llu", pass_idx);
task.digit_shift = digit_shift[pass_idx];
task.digit_count = digit_count[pass_idx];
tp_for_parallel_prof(tp, 0, tp->worker_count, psi_addr_map_radix_histogram_task, &task, "psi_addr_map_radix_histogram_task");
U64 cursor = 0;
for EachIndex(digit_idx, task.digit_count) {
for EachIndex(task_id, tp->worker_count) {
U64 *count_ptr = &task.counts[task_id * PDB_PSI_ADDR_MAP_RADIX_COUNT + digit_idx];
U64 digit_item_count = *count_ptr;
*count_ptr = cursor;
cursor += digit_item_count;
}
}
Assert(cursor == count);
tp_for_parallel_prof(tp, 0, tp->worker_count, psi_addr_map_radix_sort_task, &task, "psi_addr_map_radix_sort_task");
Swap(PDB_PsiAddrMapSortRecord *, task.src, task.dst);
ProfEnd();
}
radix_record_arr = task.src;
ProfEnd();
ProfBegin("Get Name Run Count");
U64 name_run_count = 0;
U64 total_name_sort_work = 0;
for (U64 run_first = 0; run_first < count;) {
U64 run_opl = run_first + 1;
while (run_opl < count && radix_record_arr[run_opl].key == radix_record_arr[run_first].key) {
run_opl += 1;
}
if (run_opl - run_first > 1) {
Rng1U64 run = rng_1u64(run_first, run_opl);
name_run_count += 1;
total_name_sort_work += psi_addr_map_name_sort_work(run);
}
run_first = run_opl;
}
ProfEnd();
if (name_run_count) {
ProfBegin("Name Runs");
PDB_PsiAddrMapNameSortTask name_task = {0};
name_task.record_arr = radix_record_arr;
name_task.run_arr = push_array_no_zero(scratch.arena, Rng1U64, name_run_count);
ProfBegin("Gather Run Ranges");
U64 name_run_idx = 0;
for (U64 run_first = 0; run_first < count;) {
U64 run_opl = run_first + 1;
while (run_opl < count && radix_record_arr[run_opl].key == radix_record_arr[run_first].key) {
run_opl += 1;
}
if (run_opl - run_first > 1) {
name_task.run_arr[name_run_idx++] = rng_1u64(run_first, run_opl);
}
run_first = run_opl;
}
Assert(name_run_idx == name_run_count);
ProfEnd();
ProfBegin("Batching");
U64 batch_count = Min(name_run_count, (U64)tp->worker_count * 4);
name_task.batch_arr = push_array_no_zero(scratch.arena, Rng1U64, batch_count);
U64 run_idx = 0;
U64 remaining_work = total_name_sort_work;
for EachIndex(batch_idx, batch_count) {
U64 batch_first = run_idx;
U64 batches_left = batch_count - batch_idx;
U64 run_opl_limit = name_run_count - (batches_left - 1);
U64 target_work = CeilIntegerDiv(remaining_work, batches_left);
U64 batch_work = 0;
while (run_idx < run_opl_limit) {
U64 run_work = psi_addr_map_name_sort_work(name_task.run_arr[run_idx]);
if (run_idx > batch_first && batch_work + run_work > target_work) {
break;
}
batch_work += run_work;
run_idx += 1;
if (batch_work >= target_work) {
break;
}
}
name_task.batch_arr[batch_idx] = rng_1u64(batch_first, run_idx);
remaining_work -= batch_work;
}
Assert(run_idx == name_run_count);
ProfEnd();
tp_for_parallel_prof(tp, 0, batch_count, psi_addr_map_name_sort_task, &name_task, "psi_addr_map_name_sort_task");
ProfEnd();
}
} else {
gsi_record_sort_by_sc(gsi_record_arr, count);
}
ProfEnd();
ProfBegin("Offset Fill");
U32 *addr_map = push_array_no_zero(arena, U32, count);
if (radix_record_arr) {
for EachIndex(i, count) {
addr_map[i] = safe_cast_u32(radix_record_arr[i].record->offset);
}
} else {
for EachIndex(i, count) {
addr_map[i] = safe_cast_u32(gsi_record_arr[i].offset);
}
}
ProfEnd();
scratch_end(scratch);
ProfEnd();
return addr_map;
}
internal internal
THREAD_POOL_TASK_FUNC(gsi_size_buckets_task) THREAD_POOL_TASK_FUNC(gsi_size_buckets_task)
{ {
@@ -2208,18 +2476,9 @@ psi_build(TP_Context *tp, PDB_PsiContext *psi, MSF_Context *msf, MSF_StreamNumbe
ProfBegin("Address Map"); ProfBegin("Address Map");
ProfBegin("Sort");
gsi_record_sort_by_sc(gsi_build.sort_record_arr, gsi_build.hash_record_count);
ProfEnd();
ProfBegin("Offset Fill");
U64 addr_map_count = gsi_build.hash_record_count; U64 addr_map_count = gsi_build.hash_record_count;
U64 addr_map_size = addr_map_count * sizeof(U32); U64 addr_map_size = addr_map_count * sizeof(U32);
U32 *addr_map = push_array_no_zero(scratch.arena, U32, addr_map_count); U32 *addr_map = psi_addr_map_from_gsi_records(tp, scratch.arena, gsi_build.sort_record_arr, addr_map_count);
for (U64 i = 0; i < addr_map_count; i += 1) {
addr_map[i] = gsi_build.sort_record_arr[i].offset;
}
ProfEnd();
ProfEnd(); ProfEnd();
@@ -2263,24 +2522,24 @@ psi_push(PDB_PsiContext *psi, CV_Pub32Flags flags, U32 offset, U16 isect, String
//////////////////////////////// ////////////////////////////////
internal void internal void
dbi_sec_contrib_list_push_node(PDB_DbiSectionContribList *list, PDB_DbiSectionContribNode *node) dbi_sec_contrib_list_push_node(PDB_DbiSCList *list, PDB_DbiSCNode *node)
{ {
node->next = 0; node->next = 0;
SLLQueuePush(list->first, list->last, node); SLLQueuePush(list->first, list->last, node);
list->count += 1; list->count += 1;
} }
internal PDB_DbiSectionContribNode * internal PDB_DbiSCNode *
dbi_sec_contrib_list_push(Arena *arena, PDB_DbiSectionContribList *list) dbi_sec_contrib_list_push(Arena *arena, PDB_DbiSCList *list)
{ {
PDB_DbiSectionContribNode *node = push_array_no_zero(arena, PDB_DbiSectionContribNode, 1); PDB_DbiSCNode *node = push_array_no_zero(arena, PDB_DbiSCNode, 1);
node->next = 0; node->next = 0;
dbi_sec_contrib_list_push_node(list, node); dbi_sec_contrib_list_push_node(list, node);
return node; return node;
} }
internal void internal void
dbi_sec_list_concat_arr(PDB_DbiSectionContribList *list, U64 count, PDB_DbiSectionContribList *to_concat) dbi_sec_list_concat_arr(PDB_DbiSCList *list, U64 count, PDB_DbiSCList *to_concat)
{ {
SLLConcatInPlaceArray(list, to_concat, count); SLLConcatInPlaceArray(list, to_concat, count);
} }
@@ -2405,14 +2664,14 @@ dbi_open_module_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_Db
return list; return list;
} }
internal PDB_DbiSectionContribList internal PDB_DbiSCList
dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header) dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header)
{ {
ProfBeginFunction(); ProfBeginFunction();
PDB_DbiSectionContribList sec_contrib = {0}; PDB_DbiSCList sec_contrib = {0};
if (dbi_header->sec_con_size > sizeof(PDB_DbiSectionContrib)) { if (dbi_header->sec_con_size > sizeof(PDB_DbiSC)) {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
// seek to start of section contrib info // seek to start of section contrib info
@@ -2420,25 +2679,25 @@ dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_Db
msf_stream_seek(msf, sn, sec_con_pos); msf_stream_seek(msf, sn, sec_con_pos);
// read header // read header
PDB_DbiSectionContribVersion version = 0; PDB_DbiSCVersion version = 0;
msf_stream_read_struct(msf, sn, &version); msf_stream_read_struct(msf, sn, &version);
// parse contrib items // parse contrib items
switch (version) { switch (version) {
case PDB_DbiSectionContribVersion_1: { case PDB_DbiSCVersion_1: {
U64 contrib_count = dbi_header->sec_con_size / sizeof(PDB_DbiSectionContrib); U64 contrib_count = dbi_header->sec_con_size / sizeof(PDB_DbiSC);
PDB_DbiSectionContrib *src_contrib_array = push_array(scratch.arena, PDB_DbiSectionContrib, contrib_count); PDB_DbiSC *src_contrib_array = push_array(scratch.arena, PDB_DbiSC, contrib_count);
MSF_UInt sec_con_read = msf_stream_read_array(msf, sn, &src_contrib_array[0], contrib_count); MSF_UInt sec_con_read = msf_stream_read_array(msf, sn, &src_contrib_array[0], contrib_count);
Assert(sec_con_read == sizeof(src_contrib_array[0]) * contrib_count); Assert(sec_con_read == sizeof(src_contrib_array[0]) * contrib_count);
PDB_DbiSectionContribNode *dst_contrib_array = push_array_no_zero(arena, PDB_DbiSectionContribNode, contrib_count); PDB_DbiSCNode *dst_contrib_array = push_array_no_zero(arena, PDB_DbiSCNode, contrib_count);
for (U64 icontrib = 0; icontrib < contrib_count; icontrib += 1) { for (U64 icontrib = 0; icontrib < contrib_count; icontrib += 1) {
dst_contrib_array[icontrib].next = 0; dst_contrib_array[icontrib].next = 0;
dst_contrib_array[icontrib].data = src_contrib_array[icontrib]; dst_contrib_array[icontrib].data = src_contrib_array[icontrib];
dbi_sec_contrib_list_push_node(&sec_contrib, &dst_contrib_array[icontrib]); dbi_sec_contrib_list_push_node(&sec_contrib, &dst_contrib_array[icontrib]);
} }
} break; } break;
case PDB_DbiSectionContribVersion_2: { case PDB_DbiSCVersion_2: {
NotImplemented; NotImplemented;
} break; } break;
default: Assert(!"unknown section contrib version"); break; default: Assert(!"unknown section contrib version"); break;
@@ -2595,7 +2854,7 @@ dbi_build_module_info(Arena *arena, PDB_DbiContext *dbi, MSF_Context *msf)
#if 0 #if 0
int int
dbi_sc_compar(const PDB_DbiSectionContrib *a, const PDB_DbiSectionContrib *b) dbi_sc_compar(const PDB_DbiSC *a, const PDB_DbiSC *b)
{ {
#if 0 #if 0
int cmp = 0; int cmp = 0;
@@ -2621,11 +2880,128 @@ dbi_sc_compar(const PDB_DbiSectionContrib *a, const PDB_DbiSectionContrib *b)
} }
#endif #endif
typedef struct
{
PDB_DbiSC *src;
PDB_DbiSC *dst;
Rng1U64 *range_arr;
U32 *count_arr;
U64 digit_count;
U64 shift;
B32 is_sec_pass;
} LNK_DbiScRadixPass;
internal U64
lnk_dbi_sc_radix_digit(LNK_DbiScRadixPass *pass, PDB_DbiSC *sc)
{
if (pass->is_sec_pass) {
return sc->base.sec;
}
return (sc->base.sec_off >> pass->shift) % pass->digit_count;
}
typedef struct
{
PDB_DbiSC *src;
PDB_DbiSC *dst;
Rng1U64 *range_arr;
} LNK_DbiScCopy;
internal
THREAD_POOL_TASK_FUNC(lnk_dbi_sc_copy_task)
{
LNK_DbiScCopy *copy = raw_task;
Rng1U64 range = copy->range_arr[task_id];
MemoryCopy(copy->dst + range.min, copy->src + range.min, sizeof(copy->src[0]) * dim_1u64(range));
}
internal
THREAD_POOL_TASK_FUNC(lnk_dbi_sc_radix_histo_task)
{
LNK_DbiScRadixPass *pass = raw_task;
U32 *count = pass->count_arr + task_id * pass->digit_count;
Rng1U64 range = pass->range_arr[task_id];
for EachInRange(i, range) {
count[lnk_dbi_sc_radix_digit(pass, &pass->src[i])] += 1;
}
}
internal
THREAD_POOL_TASK_FUNC(lnk_dbi_sc_radix_scatter_task)
{
LNK_DbiScRadixPass *pass = raw_task;
U32 *count = pass->count_arr + task_id * pass->digit_count;
Rng1U64 range = pass->range_arr[task_id];
for EachInRange(i, range) {
PDB_DbiSC *sc = &pass->src[i];
pass->dst[count[lnk_dbi_sc_radix_digit(pass, sc)]++] = *sc;
}
}
internal void internal void
lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_count) lnk_dbi_sc_radix_pass_parallel(TP_Context *tp, Arena *arena, U64 task_count, Rng1U64 *range_arr, PDB_DbiSC **src, PDB_DbiSC **dst, U64 digit_count, U64 shift, B32 is_sec_pass)
{
Temp temp = temp_begin(arena);
LNK_DbiScRadixPass pass = {
.src = *src,
.dst = *dst,
.range_arr = range_arr,
.count_arr = push_array(temp.arena, U32, task_count * digit_count),
.digit_count = digit_count,
.shift = shift,
.is_sec_pass = is_sec_pass,
};
tp_for_parallel(tp, 0, task_count, lnk_dbi_sc_radix_histo_task, &pass);
U32 cursor = 0;
for EachIndex(digit, digit_count) {
for EachIndex(worker_idx, task_count) {
U32 *slot = &pass.count_arr[worker_idx * digit_count + digit];
U32 count = *slot;
*slot = cursor;
cursor += count;
}
}
tp_for_parallel(tp, 0, task_count, lnk_dbi_sc_radix_scatter_task, &pass);
temp_end(temp);
Swap(PDB_DbiSC *, *src, *dst);
}
internal void
lnk_radix_sort_dbi_sc_array(TP_Context *tp, PDB_DbiSC *arr, U64 sc_count, U64 sect_count)
{ {
ProfBeginFunction(); ProfBeginFunction();
if (tp != 0 && tp->worker_count > 1 && sc_count >= KB(64)) {
Temp scratch = scratch_begin(0, 0);
PDB_DbiSC *src = arr;
PDB_DbiSC *dst = push_array_no_zero(scratch.arena, PDB_DbiSC, sc_count);
U64 task_count = tp->worker_count;
Rng1U64 *range_arr = tp_divide_work(scratch.arena, sc_count, task_count);
lnk_dbi_sc_radix_pass_parallel(tp, scratch.arena, task_count, range_arr, &src, &dst, 256, 0, 0);
lnk_dbi_sc_radix_pass_parallel(tp, scratch.arena, task_count, range_arr, &src, &dst, 256, 8, 0);
lnk_dbi_sc_radix_pass_parallel(tp, scratch.arena, task_count, range_arr, &src, &dst, 256, 16, 0);
lnk_dbi_sc_radix_pass_parallel(tp, scratch.arena, task_count, range_arr, &src, &dst, 256, 24, 0);
lnk_dbi_sc_radix_pass_parallel(tp, scratch.arena, task_count, range_arr, &src, &dst, sect_count, 0, 1);
LNK_DbiScCopy copy = { .src = src, .dst = arr, .range_arr = range_arr };
tp_for_parallel(tp, 0, task_count, lnk_dbi_sc_copy_task, &copy);
scratch_end(scratch);
ProfEnd();
return;
}
//
// on small inputs the serial path is 4x faster
//
#if 1 #if 1
// faster but uses more memory // faster but uses more memory
# define RADIX_BIT_COUNT 16 # define RADIX_BIT_COUNT 16
@@ -2638,9 +3014,9 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
PDB_DbiSectionContrib *temp_arr = push_array_no_zero(scratch.arena, PDB_DbiSectionContrib, sc_count); PDB_DbiSC *temp_arr = push_array_no_zero(scratch.arena, PDB_DbiSC, sc_count);
PDB_DbiSectionContrib *src_arr = arr; PDB_DbiSC *src_arr = arr;
PDB_DbiSectionContrib *dst_arr = temp_arr; PDB_DbiSC *dst_arr = temp_arr;
ProfBegin("Count Memzero"); ProfBegin("Count Memzero");
U32 count_8lo[256]; MemoryZeroArray(count_8lo); U32 count_8lo[256]; MemoryZeroArray(count_8lo);
@@ -2651,7 +3027,7 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
ProfBegin("Histogram"); ProfBegin("Histogram");
for (U64 i = 0; i < sc_count; i += 1) { for (U64 i = 0; i < sc_count; i += 1) {
PDB_DbiSectionContrib *sc = src_arr + i; PDB_DbiSC *sc = src_arr + i;
count_arr[sc->base.sec] += 1; count_arr[sc->base.sec] += 1;
U64 digit_8lo = (sc->base.sec_off >> 0) % ArrayCount(count_8lo); U64 digit_8lo = (sc->base.sec_off >> 0) % ArrayCount(count_8lo);
@@ -2693,7 +3069,7 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
ProfBegin("Order 8 Lo"); ProfBegin("Order 8 Lo");
for (U64 i = 0; i < sc_count; i += 1) { for (U64 i = 0; i < sc_count; i += 1) {
PDB_DbiSectionContrib *sc = &src_arr[i]; PDB_DbiSC *sc = &src_arr[i];
U64 digit = (sc->base.sec_off >> 0) % ArrayCount(count_8lo); U64 digit = (sc->base.sec_off >> 0) % ArrayCount(count_8lo);
dst_arr[count_8lo[digit]++] = *sc; dst_arr[count_8lo[digit]++] = *sc;
} }
@@ -2701,7 +3077,7 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
ProfBegin("Order 8 Hi"); ProfBegin("Order 8 Hi");
for (U64 i = 0; i < sc_count; i += 1) { for (U64 i = 0; i < sc_count; i += 1) {
PDB_DbiSectionContrib *sc = &dst_arr[i]; PDB_DbiSC *sc = &dst_arr[i];
U64 digit = (sc->base.sec_off >> 8) % ArrayCount(count_8hi); U64 digit = (sc->base.sec_off >> 8) % ArrayCount(count_8hi);
src_arr[count_8hi[digit]++] = *sc; src_arr[count_8hi[digit]++] = *sc;
} }
@@ -2709,7 +3085,7 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
ProfBegin("Order 16"); ProfBegin("Order 16");
for (U64 i = 0; i < sc_count; i += 1) { for (U64 i = 0; i < sc_count; i += 1) {
PDB_DbiSectionContrib *sc = &src_arr[i]; PDB_DbiSC *sc = &src_arr[i];
U64 digit = (sc->base.sec_off >> 16) % ArrayCount(count_16); U64 digit = (sc->base.sec_off >> 16) % ArrayCount(count_16);
dst_arr[count_16[digit]++] = *sc; dst_arr[count_16[digit]++] = *sc;
} }
@@ -2731,7 +3107,7 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
count_arr[0] = 0; count_arr[0] = 0;
for (U64 i = 0; i < sc_count; i += 1) { for (U64 i = 0; i < sc_count; i += 1) {
PDB_DbiSectionContrib *sc = dst_arr + i; PDB_DbiSC *sc = dst_arr + i;
src_arr[count_arr[sc->base.sec]++] = *sc; src_arr[count_arr[sc->base.sec]++] = *sc;
} }
@@ -2754,30 +3130,52 @@ lnk_radix_sort_dbi_sc_array(PDB_DbiSectionContrib *arr, U64 sc_count, U64 sect_c
} }
internal String8List internal String8List
dbi_build_sec_con(Arena *arena, PDB_DbiContext *dbi) dbi_build_sec_con(Arena *arena, TP_Context *tp, PDB_DbiContext *dbi)
{ {
ProfBeginFunction(); ProfBeginFunction();
PDB_DbiSectionContribVersion *version = push_array(arena, PDB_DbiSectionContribVersion, 1); PDB_DbiSCVersion *version = push_array(arena, PDB_DbiSCVersion, 1);
*version = PDB_DbiSectionContribVersion_1; *version = PDB_DbiSCVersion_1;
// push section contribs V1 // push section contribs V1
ProfBegin("Push sect contribs [Count %llu]", dbi->sec_contrib_list.count); ProfBegin("Push sect contribs [Count %llu]", dbi->sec_contrib_list.count);
PDB_DbiSectionContrib *sc_array = push_array_no_zero(arena, PDB_DbiSectionContrib, dbi->sec_contrib_list.count); PDB_DbiSC *sc_array = push_array_no_zero(arena, PDB_DbiSC, dbi->sec_contrib_list.count);
PDB_DbiSectionContrib *dst = &sc_array[0]; PDB_DbiSC *dst = &sc_array[0];
for (PDB_DbiSectionContribNode *src = dbi->sec_contrib_list.first; src != 0; src = src->next, dst += 1) { for (PDB_DbiSCNode *src = dbi->sec_contrib_list.first; src != 0; src = src->next, dst += 1) {
*dst = src->data; *dst = src->data;
} }
ProfEnd(); ProfEnd();
// sort section contribs so they are binary searchable // sort section contribs so they are binary searchable
lnk_radix_sort_dbi_sc_array(sc_array, dbi->sec_contrib_list.count, dbi->section_list.count + 1); lnk_radix_sort_dbi_sc_array(tp, sc_array, dbi->sec_contrib_list.count, dbi->section_list.count + 1);
// DBI contribution maps an address range to its module, so adjacent same-module runs can share one record
ProfBegin("Coalesce sect contribs");
U64 sc_count = 0;
for EachIndex(read_idx, dbi->sec_contrib_list.count) {
PDB_DbiSC *current = &sc_array[read_idx];
if (sc_count > 0) {
PDB_DbiSC *previous = &sc_array[sc_count - 1];
if (previous->base.sec == current->base.sec &&
previous->base.mod == current->base.mod &&
previous->base.flags == current->base.flags) {
U64 current_end = (U64)current->base.sec_off + (U64)current->base.size;
U64 previous_end = (U64)previous->base.sec_off + (U64)previous->base.size;
if (current_end > previous_end) {
previous->base.size = (U32)(current_end - (U64)previous->base.sec_off);
}
continue;
}
}
sc_array[sc_count++] = *current;
}
ProfEnd();
// push section contrib info // push section contrib info
ProfBegin("List Push"); ProfBegin("List Push");
String8List sec_con_list = {0}; String8List sec_con_list = {0};
str8_list_push(arena, &sec_con_list, str8((U8*)version, sizeof(*version))); str8_list_push(arena, &sec_con_list, str8((U8*)version, sizeof(*version)));
str8_list_push(arena, &sec_con_list, str8((U8*)sc_array, sizeof(sc_array[0])*dbi->sec_contrib_list.count)); str8_list_push(arena, &sec_con_list, str8((U8*)sc_array, sizeof(sc_array[0])*sc_count));
ProfEnd(); ProfEnd();
ProfEnd(); ProfEnd();
@@ -2862,7 +3260,7 @@ dbi_build(TP_Context *tp, PDB_DbiContext *dbi, MSF_Context *msf, MSF_StreamNumbe
ProfBegin("Build"); ProfBegin("Build");
String8List module_info_list = dbi_build_module_info(scratch.arena, dbi, msf); String8List module_info_list = dbi_build_module_info(scratch.arena, dbi, msf);
String8List sec_con_list = dbi_build_sec_con(scratch.arena, dbi); String8List sec_con_list = dbi_build_sec_con(scratch.arena, tp, dbi);
String8List sec_map_list = dbi_build_sec_map(scratch.arena, dbi); String8List sec_map_list = dbi_build_sec_map(scratch.arena, dbi);
String8List file_info_list = dbi_build_file_info(scratch.arena, tp, dbi->module_list, string_ht); String8List file_info_list = dbi_build_file_info(scratch.arena, tp, dbi->module_list, string_ht);
String8List dbg_header_list = dbi_build_dbg_header(scratch.arena, dbi, msf); String8List dbg_header_list = dbi_build_dbg_header(scratch.arena, dbi, msf);
@@ -2956,7 +3354,7 @@ dbi_module_push_section_contrib(PDB_DbiContext *dbi,
{ {
ProfBeginFunction(); ProfBeginFunction();
PDB_DbiSectionContrib sc; PDB_DbiSC sc;
sc.base.sec = safe_cast_u16(isect_off.isect); sc.base.sec = safe_cast_u16(isect_off.isect);
sc.base.sec_off = isect_off.off; sc.base.sec_off = isect_off.off;
sc.base.size = size; sc.base.size = size;
@@ -2965,7 +3363,7 @@ dbi_module_push_section_contrib(PDB_DbiContext *dbi,
sc.data_crc = data_crc; sc.data_crc = data_crc;
sc.reloc_crc = reloc_crc; sc.reloc_crc = reloc_crc;
PDB_DbiSectionContribNode *node = push_array_no_zero(dbi->arena, PDB_DbiSectionContribNode, 1); PDB_DbiSCNode *node = push_array_no_zero(dbi->arena, PDB_DbiSCNode, 1);
node->data = sc; node->data = sc;
dbi_sec_contrib_list_push_node(&dbi->sec_contrib_list, node); dbi_sec_contrib_list_push_node(&dbi->sec_contrib_list, node);
@@ -3159,31 +3557,64 @@ pdb_build_gsi_psi(TP_Context *tp, PDB_Context *pdb)
} }
internal void internal void
pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped) pdb_build_types(TP_Context *tp, PDB_Context *pdb, PDB_BuildHooks *hooks)
{ {
ProfBeginFunction(); ProfBeginFunction();
PDB_InfoContext *info = pdb->info; PDB_InfoContext *info = pdb->info;
PDB_StringTable *strtab = &info->strtab; PDB_StringTable *strtab = &info->strtab;
PDB_DbiContext *dbi = pdb->dbi;
PDB_TypeServer *tpi = pdb->type_servers[CV_TypeIndexSource_TPI]; PDB_TypeServer *tpi = pdb->type_servers[CV_TypeIndexSource_TPI];
PDB_TypeServer *ipi = pdb->type_servers[CV_TypeIndexSource_IPI]; PDB_TypeServer *ipi = pdb->type_servers[CV_TypeIndexSource_IPI];
pdb_type_server_build(tp, tpi, strtab, pdb->msf, PDB_FixedStream_Tpi); pdb_type_server_build(tp, tpi, strtab, pdb->msf, PDB_FixedStream_Tpi);
if (hooks && hooks->stream_finalize) {
hooks->stream_finalize(hooks->user_data, pdb->msf, PDB_FixedStream_Tpi);
hooks->stream_finalize(hooks->user_data, pdb->msf, tpi->hash_sn);
}
if (info->flags & PDB_FeatureFlag_HAS_ID_STREAM) { if (info->flags & PDB_FeatureFlag_HAS_ID_STREAM) {
pdb_type_server_build(tp, ipi, strtab, pdb->msf, PDB_FixedStream_Ipi); pdb_type_server_build(tp, ipi, strtab, pdb->msf, PDB_FixedStream_Ipi);
if (hooks && hooks->stream_finalize) {
hooks->stream_finalize(hooks->user_data, pdb->msf, PDB_FixedStream_Ipi);
hooks->stream_finalize(hooks->user_data, pdb->msf, ipi->hash_sn);
} }
}
ProfEnd();
}
internal void
pdb_build_dbi_info(TP_Context *tp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped, PDB_BuildHooks *hooks)
{
ProfBeginFunction();
if (build_gsi) { if (build_gsi) {
pdb_build_gsi_psi(tp, pdb); pdb_build_gsi_psi(tp, pdb);
} }
dbi_build(tp, pdb->dbi, pdb->msf, PDB_FixedStream_Dbi, string_ht, is_stripped); dbi_build(tp, pdb->dbi, pdb->msf, PDB_FixedStream_Dbi, string_ht, is_stripped);
if (hooks && hooks->stream_finalize) {
hooks->stream_finalize(hooks->user_data, pdb->msf, PDB_FixedStream_Dbi);
for EachElement(i, pdb->dbi->dbg_streams) {
hooks->stream_finalize(hooks->user_data, pdb->msf, pdb->dbi->dbg_streams[i]);
}
}
pdb_info_build(pdb->info, pdb->msf, PDB_FixedStream_Info); pdb_info_build(pdb->info, pdb->msf, PDB_FixedStream_Info);
if (hooks && hooks->stream_finalize) {
hooks->stream_finalize(hooks->user_data, pdb->msf, PDB_FixedStream_Info);
}
ProfEnd(); ProfEnd();
} }
internal void
pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped, PDB_BuildHooks *hooks)
{
ProfBeginFunction();
pdb_build_types(tp, pdb, hooks);
pdb_build_dbi_info(tp, pdb, string_ht, build_gsi, is_stripped, hooks);
ProfEnd();
}
//////////////////////////////// ////////////////////////////////
internal String8 internal String8
+21 -14
View File
@@ -238,7 +238,7 @@ typedef struct PDB_DbiModule
struct PDB_DbiModule *next; struct PDB_DbiModule *next;
MSF_StreamNumber sn; MSF_StreamNumber sn;
CV_ModIndex imod; CV_ModIndex imod;
PDB_DbiSectionContrib first_sc; PDB_DbiSC first_sc;
U64 sym_data_size; U64 sym_data_size;
U64 c11_data_size; U64 c11_data_size;
U64 c13_data_size; U64 c13_data_size;
@@ -255,18 +255,18 @@ typedef struct PDB_DbiModuleList
U64 count; U64 count;
} PDB_DbiModuleList; } PDB_DbiModuleList;
typedef struct PDB_DbiSectionContribNode typedef struct PDB_DbiSCNode
{ {
struct PDB_DbiSectionContribNode *next; struct PDB_DbiSCNode *next;
PDB_DbiSectionContrib data; PDB_DbiSC data;
} PDB_DbiSectionContribNode; } PDB_DbiSCNode;
typedef struct PDB_DbiSectionContribList typedef struct PDB_DbiSCList
{ {
PDB_DbiSectionContribNode *first; PDB_DbiSCNode *first;
PDB_DbiSectionContribNode *last; PDB_DbiSCNode *last;
U64 count; U64 count;
} PDB_DbiSectionContribList; } PDB_DbiSCList;
typedef struct PDB_DbiSectionNode typedef struct PDB_DbiSectionNode
{ {
@@ -290,7 +290,7 @@ typedef struct PDB_DbiContext
MSF_StreamNumber publics_sn; MSF_StreamNumber publics_sn;
MSF_StreamNumber symbols_sn; MSF_StreamNumber symbols_sn;
PDB_DbiModuleList module_list; PDB_DbiModuleList module_list;
PDB_DbiSectionContribList sec_contrib_list; PDB_DbiSCList sec_contrib_list;
PDB_DbiSectionList section_list; PDB_DbiSectionList section_list;
PDB_StringTable ec_names; PDB_StringTable ec_names;
MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT]; MSF_StreamNumber dbg_streams[PDB_DbiStream_COUNT];
@@ -310,6 +310,13 @@ typedef struct PDB_Context
PDB_TypeServer *type_servers[CV_TypeIndexSource_COUNT]; PDB_TypeServer *type_servers[CV_TypeIndexSource_COUNT];
} PDB_Context; } PDB_Context;
typedef void PDB_StreamFinalizeFunc(void *user_data, MSF_Context *msf, MSF_StreamNumber sn);
typedef struct PDB_BuildHooks
{
PDB_StreamFinalizeFunc *stream_finalize;
void *user_data;
} PDB_BuildHooks;
//////////////////////////////// ////////////////////////////////
typedef struct typedef struct
@@ -334,7 +341,9 @@ typedef struct
internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid); internal PDB_Context * pdb_alloc(U64 page_size, COFF_MachineType machine, COFF_TimeStamp time_stamp, U32 age, Guid guid);
internal void pdb_release(PDB_Context *pdb); internal void pdb_release(PDB_Context *pdb);
internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped); internal void pdb_build_types(TP_Context *tp, PDB_Context *pdb, PDB_BuildHooks *hooks);
internal void pdb_build_dbi_info(TP_Context *tp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped, PDB_BuildHooks *hooks);
internal void pdb_build(TP_Context *tp, TP_Arena *pool_temp, PDB_Context *pdb, CV_StringHashTable string_ht, B32 build_gsi, B32 is_stripped, PDB_BuildHooks *hooks);
internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine); internal void pdb_set_machine(PDB_Context *pdb, COFF_MachineType machine);
internal void pdb_set_guid(PDB_Context *pdb, Guid guid); internal void pdb_set_guid(PDB_Context *pdb, Guid guid);
internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp); internal void pdb_set_time_stamp(PDB_Context *pdb, COFF_TimeStamp time_stamp);
@@ -394,7 +403,7 @@ internal String8 dbi_module_read_c13_data(Arena *arena, MSF_Co
internal void dbi_module_push_section_contrib(PDB_DbiContext *dbi, PDB_DbiModule *mod, ISectOff isect_off, U32 size, U32 data_crc, U32 reloc_crc, COFF_SectionFlags flags); internal void dbi_module_push_section_contrib(PDB_DbiContext *dbi, PDB_DbiModule *mod, ISectOff isect_off, U32 size, U32 data_crc, U32 reloc_crc, COFF_SectionFlags flags);
internal String8List * dbi_open_file_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header); internal String8List * dbi_open_file_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_DbiModuleList dbi_open_module_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header, String8List *file_info); internal PDB_DbiModuleList dbi_open_module_info(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header, String8List *file_info);
internal PDB_DbiSectionContribList dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header); internal PDB_DbiSCList dbi_open_sec_contrib(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_StringTable dbi_open_ec_names(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header); internal PDB_StringTable dbi_open_ec_names(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal void dbi_open_dbg_streams(MSF_StreamNumber *dbg_streams, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header); internal void dbi_open_dbg_streams(MSF_StreamNumber *dbg_streams, MSF_Context *msf, MSF_StreamNumber sn, PDB_DbiHeader *dbi_header);
internal PDB_DbiSectionList dbi_open_section_headers(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn); internal PDB_DbiSectionList dbi_open_section_headers(Arena *arena, MSF_Context *msf, MSF_StreamNumber sn);
@@ -461,5 +470,3 @@ internal PDB_TypeHashStreamInfo pdb_type_hash_stream_build(TP_Context *tp, PDB_
// Enum -> String // Enum -> String
internal String8 pdb_string_from_src_error(PDB_SrcError error); internal String8 pdb_string_from_src_error(PDB_SrcError error);
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -4,7 +4,7 @@
internal void internal void
tp_run_tasks(TP_Context *pool, TP_Worker *worker) tp_run_tasks(TP_Context *pool, TP_Worker *worker)
{ {
barrier_wait(pool->barrier); barrier_wait(pool->run_barrier);
for (;;) { for (;;) {
S64 task_left = ins_atomic_u64_dec_eval(&pool->task_left); S64 task_left = ins_atomic_u64_dec_eval(&pool->task_left);
@@ -19,14 +19,11 @@ tp_run_tasks(TP_Context *pool, TP_Worker *worker)
U64 task_id = pool->task_count - (task_left+1); U64 task_id = pool->task_count - (task_left+1);
pool->task_func(arena, worker->id, task_id, pool->task_data, pool); pool->task_func(arena, worker->id, task_id, pool->task_data, pool);
// cache task count so we dont touch pool memory after atomic inc
U64 task_count = pool->task_count;
// update task done count // update task done count
ins_atomic_u64_inc_eval(&pool->task_done); ins_atomic_u64_inc_eval(&pool->task_done);
} }
barrier_wait(pool->barrier); barrier_wait(pool->run_barrier);
} }
internal void internal void
@@ -74,6 +71,7 @@ tp_alloc(Arena *arena, U32 worker_count, U32 max_worker_count, String8 name)
// init pool // init pool
TP_Context *pool = push_array(arena, TP_Context, 1); TP_Context *pool = push_array(arena, TP_Context, 1);
pool->exec_semaphore = exec_semaphore; pool->exec_semaphore = exec_semaphore;
pool->run_barrier = barrier_alloc(worker_count);
pool->barrier = barrier_alloc(worker_count); pool->barrier = barrier_alloc(worker_count);
pool->is_live = 1; pool->is_live = 1;
pool->worker_count = worker_count; pool->worker_count = worker_count;
@@ -113,6 +111,7 @@ tp_release(TP_Context *pool)
if (is_shared) { if (is_shared) {
semaphore_release(pool->exec_semaphore); semaphore_release(pool->exec_semaphore);
} }
barrier_release(pool->run_barrier);
barrier_release(pool->barrier); barrier_release(pool->barrier);
MemoryZeroStruct(pool); MemoryZeroStruct(pool);
@@ -194,13 +193,14 @@ tp_for_parallel(TP_Context *pool, TP_Arena *task_arena, U64 task_count, TP_TaskF
// if we are in shared mode -> ping // if we are in shared mode -> ping
if (*pool->exec_semaphore.u64) { if (*pool->exec_semaphore.u64) {
U64 drop_count64 = Min(task_count, pool->worker_count); U64 drop_count64 = pool->worker_count - 1;
U32 drop_count = safe_cast_u32(drop_count64); U32 drop_count = safe_cast_u32(drop_count64);
semaphore_drop_count(pool->exec_semaphore, drop_count); semaphore_drop_count(pool->exec_semaphore, drop_count);
} }
// run tasks on main worker // run tasks on main worker
tp_run_tasks(pool, pool->worker_arr); tp_run_tasks(pool, pool->worker_arr);
Assert(pool->task_done == task_count);
} }
} }
+1 -1
View File
@@ -32,6 +32,7 @@ typedef struct TP_Context
Semaphore exec_semaphore; Semaphore exec_semaphore;
Semaphore task_semaphore; Semaphore task_semaphore;
Semaphore main_semaphore; Semaphore main_semaphore;
Barrier run_barrier;
Barrier barrier; Barrier barrier;
void *broadcast; void *broadcast;
U64 broadcast_size; U64 broadcast_size;
@@ -58,4 +59,3 @@ internal void tp_temp_end(TP_Temp temp);
internal void tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *task_func, void *task_data); internal void tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *task_func, void *task_data);
internal Rng1U64 * tp_divide_work(Arena *arena, U64 item_count, U32 worker_count); internal Rng1U64 * tp_divide_work(Arena *arena, U64 item_count, U32 worker_count);
#define tp_broadcast(p) tp_broadcast_(tp, task_id, p, sizeof(*p)) #define tp_broadcast(p) tp_broadcast_(tp, task_id, p, sizeof(*p))
+2
View File
@@ -364,6 +364,7 @@ set_platform_thread_name(String8 name)
internal Thread internal Thread
thread_launch(ThreadEntryPointFunctionType *f, void *p) thread_launch(ThreadEntryPointFunctionType *f, void *p)
{ {
ProfBeginFunction();
LNX_Entity *entity = lnx_entity_alloc(LNX_EntityKind_Thread); LNX_Entity *entity = lnx_entity_alloc(LNX_EntityKind_Thread);
entity->thread.func = f; entity->thread.func = f;
entity->thread.ptr = p; entity->thread.ptr = p;
@@ -376,6 +377,7 @@ thread_launch(ThreadEntryPointFunctionType *f, void *p)
} }
} }
Thread handle = {(U64)entity}; Thread handle = {(U64)entity};
ProfEnd();
return handle; return handle;
} }
@@ -757,7 +757,7 @@ wm_graphical_message(B32 error, String8 title, String8 message)
} }
internal String8 internal String8
wm_graphical_pick_file(Arena *arena, String8 initial_path) wm_graphical_pick_file(Arena *arena, String8 title, String8 initial_path)
{ {
return str8_zero(); return str8_zero();
} }
+21
View File
@@ -22,3 +22,24 @@ llvm_hash_size_from_alg(LLVM_GHashAlg v)
} }
return 0; return 0;
} }
internal B32
llvm_is_bitcode(String8 data)
{
if (data.size < 4) {
return 0;
}
// raw LLVM bitcode magic
if (data.str[0] == 'B' && data.str[1] == 'C' && data.str[2] == 0xc0 && data.str[3] == 0xde) {
return 1;
}
// LLVM bitcode wrapper magic
if (data.str[0] == 0xde && data.str[1] == 0xc0 && data.str[2] == 0x17 && data.str[3] == 0x0b) {
return 1;
}
return 0;
}
+1 -1
View File
@@ -25,6 +25,6 @@ typedef struct LLVM_GHash
internal String8 llvm_string_from_ghash_alg(LLVM_GHashAlg v); internal String8 llvm_string_from_ghash_alg(LLVM_GHashAlg v);
internal U64 llvm_hash_size_from_alg(LLVM_GHashAlg v); internal U64 llvm_hash_size_from_alg(LLVM_GHashAlg v);
internal B32 llvm_is_bitcode(String8 data);
#endif // LLVM_H #endif // LLVM_H
+6 -1
View File
@@ -33,6 +33,12 @@
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type. // PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
#define MSCRT_TLS_SYMBOL_NAME "_tls_used" #define MSCRT_TLS_SYMBOL_NAME "_tls_used"
// vftable symbols
#define MSCRT_VFTABLE_SYMBOL_PREFIX "??_7"
// vbptr symbols
#define MSCRT_VBTABLE_SYMBOL_PREFIX "??_8"
//////////////////////////////// ////////////////////////////////
// feature flags in absolute symbol @feat.00 // feature flags in absolute symbol @feat.00
@@ -377,4 +383,3 @@ mscrt_catch_blocks_from_data_x8664(Arena *arena,
internal String8 mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives); internal String8 mscrt_string_from_eh_adjectives(Arena *arena, MSCRT_EhHandlerTypeFlags adjectives);
#endif // MSVC_CRT #endif // MSVC_CRT
+12 -12
View File
@@ -223,11 +223,11 @@ typedef struct PDB_DbiHeader
// "ModuleInfo" DBI range // "ModuleInfo" DBI range
typedef U32 PDB_DbiSectionContribVersion; typedef U32 PDB_DbiSCVersion;
#define PDB_DbiSectionContribVersion_1 (0xeffe0000u + 19970605u) #define PDB_DbiSCVersion_1 (0xeffe0000u + 19970605u)
#define PDB_DbiSectionContribVersion_2 (0xeffe0000u + 20140516u) #define PDB_DbiSCVersion_2 (0xeffe0000u + 20140516u)
typedef struct PDB_DbiSectionContrib40 typedef struct PDB_DbiSC40
{ {
CV_SectionIndex sec; CV_SectionIndex sec;
U16 pad0; U16 pad0;
@@ -236,27 +236,27 @@ typedef struct PDB_DbiSectionContrib40
U32 flags; U32 flags;
CV_ModIndex mod; CV_ModIndex mod;
U16 pad1; U16 pad1;
} PDB_DbiSectionContrib40; } PDB_DbiSC40;
typedef struct PDB_DbiSectionContrib typedef struct PDB_DbiSC
{ {
PDB_DbiSectionContrib40 base; PDB_DbiSC40 base;
U32 data_crc; U32 data_crc;
U32 reloc_crc; U32 reloc_crc;
} PDB_DbiSectionContrib; } PDB_DbiSC;
typedef struct PDB_DbiSectionContrib2 typedef struct PDB_DbiSC2
{ {
PDB_DbiSectionContrib40 base; PDB_DbiSC40 base;
U32 data_crc; U32 data_crc;
U32 reloc_crc; U32 reloc_crc;
U32 sec_coff; U32 sec_coff;
} PDB_DbiSectionContrib2; } PDB_DbiSC2;
typedef struct PDB_DbiCompUnitHeader typedef struct PDB_DbiCompUnitHeader
{ {
U32 unused; U32 unused;
PDB_DbiSectionContrib contribution; PDB_DbiSC contribution;
U16 flags; // unknown U16 flags; // unknown
MSF_StreamNumber sn; MSF_StreamNumber sn;
+8 -8
View File
@@ -700,9 +700,9 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_Sect
{ {
PDB_CompUnitContribution *contributions = 0; PDB_CompUnitContribution *contributions = 0;
U64 count = 0; U64 count = 0;
if(data.size >= sizeof(PDB_DbiSectionContribVersion)) if(data.size >= sizeof(PDB_DbiSCVersion))
{ {
PDB_DbiSectionContribVersion *version = (PDB_DbiSectionContribVersion*)data.str; PDB_DbiSCVersion *version = (PDB_DbiSCVersion*)data.str;
// determine array layout from version // determine array layout from version
U32 item_size = 0; U32 item_size = 0;
@@ -712,16 +712,16 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_Sect
default: default:
{ {
// TODO(allen): do we have a test case for this? // TODO(allen): do we have a test case for this?
item_size = sizeof(PDB_DbiSectionContrib40); item_size = sizeof(PDB_DbiSC40);
}break; }break;
case PDB_DbiSectionContribVersion_1: case PDB_DbiSCVersion_1:
{ {
item_size = sizeof(PDB_DbiSectionContrib); item_size = sizeof(PDB_DbiSC);
array_off = sizeof(*version); array_off = sizeof(*version);
}break; }break;
case PDB_DbiSectionContribVersion_2: case PDB_DbiSCVersion_2:
{ {
item_size = sizeof(PDB_DbiSectionContrib2); item_size = sizeof(PDB_DbiSC2);
array_off = sizeof(*version); array_off = sizeof(*version);
}break; }break;
} }
@@ -739,7 +739,7 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, COFF_Sect
U64 cursor = array_off; U64 cursor = array_off;
for(; cursor + item_size <= data.size; cursor += item_size) for(; cursor + item_size <= data.size; cursor += item_size)
{ {
PDB_DbiSectionContrib40 *sc = (PDB_DbiSectionContrib40*)(data.str + cursor); PDB_DbiSC40 *sc = (PDB_DbiSC40*)(data.str + cursor);
if(sc->size > 0 && 1 <= sc->sec && sc->sec <= section_count) if(sc->size > 0 && 1 <= sc->sec && sc->sec <= section_count)
{ {
U64 voff = section_headers[sc->sec - 1].voff + sc->sec_off; U64 voff = section_headers[sc->sec - 1].voff + sc->sec_off;
+22 -10
View File
@@ -62,13 +62,14 @@ str8_lit_comp(""),
str8_lit_comp(""), str8_lit_comp(""),
}; };
RD_VocabInfo rd_vocab_info_table[368] = RD_VocabInfo rd_vocab_info_table[372] =
{ {
{str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars}, {str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars},
{str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, {str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline},
{str8_lit_comp("watch_pin"), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pin"), str8_lit_comp("Watch Pins"), RD_IconKind_Pin}, {str8_lit_comp("watch_pin"), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pin"), str8_lit_comp("Watch Pins"), RD_IconKind_Pin},
{str8_lit_comp("debug_info"), str8_lit_comp("debug_infos"), str8_lit_comp("Debug Info"), str8_lit_comp("Debug Info"), RD_IconKind_Module}, {str8_lit_comp("debug_info"), str8_lit_comp("debug_infos"), str8_lit_comp("Debug Info"), str8_lit_comp("Debug Info"), RD_IconKind_Module},
{str8_lit_comp("watch"), str8_lit_comp("watches"), str8_lit_comp("Watch"), str8_lit_comp("Watches"), RD_IconKind_Binoculars}, {str8_lit_comp("watch"), str8_lit_comp("watches"), str8_lit_comp("Watch"), str8_lit_comp("Watches"), RD_IconKind_Binoculars},
{str8_lit_comp("watch_expression"), str8_lit_comp("watch_expressions"), str8_lit_comp("Watch Expression"), str8_lit_comp("Watch Expressions"), RD_IconKind_Binoculars},
{str8_lit_comp("view"), str8_lit_comp("views"), str8_lit_comp("View"), str8_lit_comp("Views"), RD_IconKind_Binoculars}, {str8_lit_comp("view"), str8_lit_comp("views"), str8_lit_comp("View"), str8_lit_comp("Views"), RD_IconKind_Binoculars},
{str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled}, {str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled},
{str8_lit_comp("condition"), str8_lit_comp("conditions"), str8_lit_comp("Condition"), str8_lit_comp("Conditions"), RD_IconKind_Null}, {str8_lit_comp("condition"), str8_lit_comp("conditions"), str8_lit_comp("Condition"), str8_lit_comp("Conditions"), RD_IconKind_Null},
@@ -299,6 +300,9 @@ RD_VocabInfo rd_vocab_info_table[368] =
{str8_lit_comp("accept"), str8_lit_comp(""), str8_lit_comp("Accept"), str8_lit_comp(""), RD_IconKind_CheckFilled}, {str8_lit_comp("accept"), str8_lit_comp(""), str8_lit_comp("Accept"), str8_lit_comp(""), RD_IconKind_CheckFilled},
{str8_lit_comp("cancel"), str8_lit_comp(""), str8_lit_comp("Cancel"), str8_lit_comp(""), RD_IconKind_X}, {str8_lit_comp("cancel"), str8_lit_comp(""), str8_lit_comp("Cancel"), str8_lit_comp(""), RD_IconKind_X},
{str8_lit_comp("focus_menu"), str8_lit_comp(""), str8_lit_comp("Focus Menu"), str8_lit_comp(""), RD_IconKind_List}, {str8_lit_comp("focus_menu"), str8_lit_comp(""), str8_lit_comp("Focus Menu"), str8_lit_comp(""), RD_IconKind_List},
{str8_lit_comp("lock"), str8_lit_comp(""), str8_lit_comp("Lock"), str8_lit_comp(""), RD_IconKind_Locked},
{str8_lit_comp("unlock"), str8_lit_comp(""), str8_lit_comp("Unlock"), str8_lit_comp(""), RD_IconKind_Unlocked},
{str8_lit_comp("toggle_lock"), str8_lit_comp(""), str8_lit_comp("Toggle Lock"), str8_lit_comp(""), RD_IconKind_Locked},
{str8_lit_comp("move_left"), str8_lit_comp(""), str8_lit_comp("Move Left"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("move_left"), str8_lit_comp(""), str8_lit_comp("Move Left"), str8_lit_comp(""), RD_IconKind_Null},
{str8_lit_comp("move_right"), str8_lit_comp(""), str8_lit_comp("Move Right"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("move_right"), str8_lit_comp(""), str8_lit_comp("Move Right"), str8_lit_comp(""), RD_IconKind_Null},
{str8_lit_comp("move_up"), str8_lit_comp(""), str8_lit_comp("Move Up"), str8_lit_comp(""), RD_IconKind_Null}, {str8_lit_comp("move_up"), str8_lit_comp(""), str8_lit_comp("Move Up"), str8_lit_comp(""), RD_IconKind_Null},
@@ -456,7 +460,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[39] =
{str8_lit_comp("array"), 1, str8_lit_comp("x:{ @description('An expression of the base address of the array.') 'base_address': expr_string, @description('The number of elements in the array.') count}")}, {str8_lit_comp("array"), 1, str8_lit_comp("x:{ @description('An expression of the base address of the array.') 'base_address': expr_string, @description('The number of elements in the array.') count}")},
{str8_lit_comp("slice"), 1, str8_lit_comp("x:{ @description('An expression of a structure that is to be interpreted as a slice.') 'expression': expr_string}")}, {str8_lit_comp("slice"), 1, str8_lit_comp("x:{ @description('An expression of a structure that is to be interpreted as a slice.') 'expression': expr_string}")},
{str8_lit_comp("list"), 1, str8_lit_comp("x:\n{\n @description(\"An expression describing the first node in the list.\")\n 'expression': expr_string,\n @order(0) @description(\"The name of the member which encodes the link to the next node.\")\n 'member_name': code_string,\n}\n")}, {str8_lit_comp("list"), 1, str8_lit_comp("x:\n{\n @description(\"An expression describing the first node in the list.\")\n 'expression': expr_string,\n @order(0) @description(\"The name of the member which encodes the link to the next node.\")\n 'member_name': code_string,\n}\n")},
{str8_lit_comp("watch"), 0, str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': set,\n}\n")}, {str8_lit_comp("watch"), 0, str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watch_expressions': set,\n}\n")},
{str8_lit_comp("text"), 1, str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @optional @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(1) @display_name('Line Wrapping') @description(\"Splits textual lines into multiple visual lines, so that all text is within the visible area.\")\n 'line_wrapping': bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change': bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, {str8_lit_comp("text"), 1, str8_lit_comp("@inherit(tab) @expand_commands(@output clear_output) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @optional @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(1) @display_name('Line Wrapping') @description(\"Splits textual lines into multiple visual lines, so that all text is within the visible area.\")\n 'line_wrapping': bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change': bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")},
{str8_lit_comp("disasm"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n @optional @description(\"The maximum number of bytes to disassemble.\")\n 'size': expr_string,\n @optional @description(\"The architecture to interpret the data as when disassembling.\")\n 'arch': code_string,\n @optional @description(\"The syntax style to use when displaying the disassembly textually.\")\n 'syntax': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")}, {str8_lit_comp("disasm"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n @optional @description(\"The maximum number of bytes to disassemble.\")\n 'size': expr_string,\n @optional @description(\"The architecture to interpret the data as when disassembling.\")\n 'arch': code_string,\n @optional @description(\"The syntax style to use when displaying the disassembly textually.\")\n 'syntax': code_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")},
{str8_lit_comp("memory"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Base Address\") @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @no_callee_helper @display_name(\"Zoom\") @description(\"The zoom level for displaying bytes in the memory view.\")\n @default(1.0) 'zoom': @range[0.5, 2] f32,\n @optional @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @no_callee_helper @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @no_callee_helper @default(1) @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @optional @expand_if(\"!$.auto_columns\") @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @optional @default(16) @display_name(\"Default Radix\") @description(\"The default radix with which numeric values should be displayed, when peeking.\")\n @or(2, 8, 10, 16)\n 'default_radix': u64,\n @no_callee_helper @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n @no_callee_helper @default(1) @display_name(\"Allow Mutation\") @description(\"Allows operations which mutate memory.\")\n 'allow_mutation': bool,\n @no_callee_helper @default(0) @display_name(\"Automatically Size Columns\") @description(\"Determines the number of columns based on the available space.\")\n 'auto_columns': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Unsigned\") 'peek_as_unsigned': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Signed\") 'peek_as_signed': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Float\") 'peek_as_float': bool,\n @no_callee_helper @display_name(\"Extra Peek Types\") @description(\"A list of types as which to interpret selected memory.\")\n 'peek_types': set,\n}\n")}, {str8_lit_comp("memory"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Base Address\") @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @no_callee_helper @display_name(\"Zoom\") @description(\"The zoom level for displaying bytes in the memory view.\")\n @default(1.0) 'zoom': @range[0.5, 2] f32,\n @optional @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @no_callee_helper @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @no_callee_helper @default(1) @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @optional @expand_if(\"!$.auto_columns\") @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @optional @default(16) @display_name(\"Default Radix\") @description(\"The default radix with which numeric values should be displayed, when peeking.\")\n @or(2, 8, 10, 16)\n 'default_radix': u64,\n @no_callee_helper @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n @no_callee_helper @default(1) @display_name(\"Allow Mutation\") @description(\"Allows operations which mutate memory.\")\n 'allow_mutation': bool,\n @no_callee_helper @default(0) @display_name(\"Automatically Size Columns\") @description(\"Determines the number of columns based on the available space.\")\n 'auto_columns': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Unsigned\") 'peek_as_unsigned': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Signed\") 'peek_as_signed': bool,\n @no_callee_helper @default(1) @display_name(\"Peek As Float\") 'peek_as_float': bool,\n @no_callee_helper @display_name(\"Extra Peek Types\") @description(\"A list of types as which to interpret selected memory.\")\n 'peek_types': set,\n}\n")},
@@ -477,7 +481,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[39] =
{str8_lit_comp("thread"), 0, str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':set}")}, {str8_lit_comp("thread"), 0, str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':set}")},
}; };
String8 rd_reg_slot_code_name_table[52] = String8 rd_reg_slot_code_name_table[54] =
{ {
{0}, {0},
str8_lit_comp("machine"), str8_lit_comp("machine"),
@@ -499,6 +503,8 @@ str8_lit_comp("inline_depth"),
str8_lit_comp("file_path"), str8_lit_comp("file_path"),
str8_lit_comp("cursor"), str8_lit_comp("cursor"),
str8_lit_comp("mark"), str8_lit_comp("mark"),
str8_lit_comp("line_num"),
str8_lit_comp("column_num"),
str8_lit_comp("text_key"), str8_lit_comp("text_key"),
str8_lit_comp("lang_kind"), str8_lit_comp("lang_kind"),
str8_lit_comp("lines"), str8_lit_comp("lines"),
@@ -533,7 +539,7 @@ str8_lit_comp("cmd_name"),
str8_lit_comp("wm_event"), str8_lit_comp("wm_event"),
}; };
Rng1U64 rd_reg_slot_range_table[52] = Rng1U64 rd_reg_slot_range_table[54] =
{ {
{0}, {0},
{OffsetOf(RD_Regs, machine), OffsetOf(RD_Regs, machine) + sizeof(D_Handle)}, {OffsetOf(RD_Regs, machine), OffsetOf(RD_Regs, machine) + sizeof(D_Handle)},
@@ -553,8 +559,10 @@ Rng1U64 rd_reg_slot_range_table[52] =
{OffsetOf(RD_Regs, unwind_count), OffsetOf(RD_Regs, unwind_count) + sizeof(U64)}, {OffsetOf(RD_Regs, unwind_count), OffsetOf(RD_Regs, unwind_count) + sizeof(U64)},
{OffsetOf(RD_Regs, inline_depth), OffsetOf(RD_Regs, inline_depth) + sizeof(U64)}, {OffsetOf(RD_Regs, inline_depth), OffsetOf(RD_Regs, inline_depth) + sizeof(U64)},
{OffsetOf(RD_Regs, file_path), OffsetOf(RD_Regs, file_path) + sizeof(String8)}, {OffsetOf(RD_Regs, file_path), OffsetOf(RD_Regs, file_path) + sizeof(String8)},
{OffsetOf(RD_Regs, cursor), OffsetOf(RD_Regs, cursor) + sizeof(TxtPt)}, {OffsetOf(RD_Regs, cursor), OffsetOf(RD_Regs, cursor) + sizeof(U64)},
{OffsetOf(RD_Regs, mark), OffsetOf(RD_Regs, mark) + sizeof(TxtPt)}, {OffsetOf(RD_Regs, mark), OffsetOf(RD_Regs, mark) + sizeof(U64)},
{OffsetOf(RD_Regs, line_num), OffsetOf(RD_Regs, line_num) + sizeof(U64)},
{OffsetOf(RD_Regs, column_num), OffsetOf(RD_Regs, column_num) + sizeof(U64)},
{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(C_Key)}, {OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(C_Key)},
{OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)}, {OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)},
{OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)}, {OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)},
@@ -589,7 +597,7 @@ Rng1U64 rd_reg_slot_range_table[52] =
{OffsetOf(RD_Regs, wm_event), OffsetOf(RD_Regs, wm_event) + sizeof(WM_Event *)}, {OffsetOf(RD_Regs, wm_event), OffsetOf(RD_Regs, wm_event) + sizeof(WM_Event *)},
}; };
RD_CmdKindInfo rd_cmd_kind_info_table[256] = RD_CmdKindInfo rd_cmd_kind_info_table[259] =
{ {
{0}, {0},
{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets")}}, { str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets")}},
@@ -691,7 +699,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("tab_settings"), str8_lit_comp("Opens settings for a tab."), str8_lit_comp("view,options"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("tab_settings"), str8_lit_comp("Opens settings for a tab."), str8_lit_comp("view,options"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\"")}}, { str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\"")}},
{ str8_lit_comp("open_source_file_from_debug_info"), str8_lit_comp("Opens a source file found within loaded debug info."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:source_files")}}, { str8_lit_comp("open_source_file_from_debug_info"), str8_lit_comp("Opens a source file found within loaded debug info."), str8_lit_comp("code,source,file"), str8_lit_comp("{tab_commands}"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:source_files")}},
{ str8_lit_comp("switch_to_partner_file"), str8_lit_comp("Switches to the focused file's partner; or from header to implementation or vice versa."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("switch_to_partner_file"), str8_lit_comp("Switches to the focused file's partner; or from header to implementation or vice versa."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("show_file_in_explorer"), str8_lit_comp("Opens the operating system's file explorer and shows the selected file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("show_file_in_explorer"), str8_lit_comp("Opens the operating system's file explorer and shows the selected file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("go_to_disassembly"), str8_lit_comp("Goes to the disassembly, if any, for a given source code line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp("{text_pt_commands}"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("go_to_disassembly"), str8_lit_comp("Goes to the disassembly, if any, for a given source code line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp("{text_pt_commands}"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
@@ -714,6 +722,9 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("accept"), str8_lit_comp("Accepts current changes, or answers prompts in the affirmative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("accept"), str8_lit_comp("Accepts current changes, or answers prompts in the affirmative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("cancel"), str8_lit_comp("Rejects current changes, exits temporary menus, or answers prompts in the negative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("cancel"), str8_lit_comp("Rejects current changes, exits temporary menus, or answers prompts in the negative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("focus_menu"), str8_lit_comp("Focuses the menu for the selected interface, if there is one."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("focus_menu"), str8_lit_comp("Focuses the menu for the selected interface, if there is one."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("lock"), str8_lit_comp("Locks the current selection, if applicable."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("unlock"), str8_lit_comp("Unlocks the current selection, if applicable."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("toggle_lock"), str8_lit_comp("Toggles the lock state of the current selection, if applicable."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
@@ -755,7 +766,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("move_next"), str8_lit_comp("Moves the cursor or selection to the next element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("move_next"), str8_lit_comp("Moves the cursor or selection to the next element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("move_prev"), str8_lit_comp("Moves the cursor or selection to the previous element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("move_prev"), str8_lit_comp("Moves the cursor or selection to the previous element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cursor, str8_lit_comp("")}}, { str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_LineNum, str8_lit_comp("")}},
{ str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp("")}}, { str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp("")}},
{ str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
{ str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}}, { str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("")}},
@@ -849,7 +860,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[256] =
{ str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, str8_lit_comp("{tab_commands}"), RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs}, { str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, str8_lit_comp("{tab_commands}"), RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs},
}; };
struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] = struct {String8 string; CFG_Binding binding;} rd_default_binding_table[117] =
{ {
{str8_lit_comp("kill_all"), {WM_Key_F5, 0 |WM_Modifier_Shift }}, {str8_lit_comp("kill_all"), {WM_Key_F5, 0 |WM_Modifier_Shift }},
{str8_lit_comp("step_into_inst"), {WM_Key_F11, 0 |WM_Modifier_Alt}}, {str8_lit_comp("step_into_inst"), {WM_Key_F11, 0 |WM_Modifier_Alt}},
@@ -902,6 +913,7 @@ struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] =
{str8_lit_comp("accept"), {WM_Key_Space, 0 }}, {str8_lit_comp("accept"), {WM_Key_Space, 0 }},
{str8_lit_comp("cancel"), {WM_Key_Esc, 0 }}, {str8_lit_comp("cancel"), {WM_Key_Esc, 0 }},
{str8_lit_comp("focus_menu"), {WM_Key_D, 0 |WM_Modifier_Alt}}, {str8_lit_comp("focus_menu"), {WM_Key_D, 0 |WM_Modifier_Alt}},
{str8_lit_comp("toggle_lock"), {WM_Key_L, 0 |WM_Modifier_Ctrl }},
{str8_lit_comp("move_left"), {WM_Key_Left, 0 }}, {str8_lit_comp("move_left"), {WM_Key_Left, 0 }},
{str8_lit_comp("move_right"), {WM_Key_Right, 0 }}, {str8_lit_comp("move_right"), {WM_Key_Right, 0 }},
{str8_lit_comp("move_up"), {WM_Key_Up, 0 }}, {str8_lit_comp("move_up"), {WM_Key_Up, 0 }},
+14 -5
View File
@@ -28,6 +28,8 @@ RD_RegSlot_InlineDepth,
RD_RegSlot_FilePath, RD_RegSlot_FilePath,
RD_RegSlot_Cursor, RD_RegSlot_Cursor,
RD_RegSlot_Mark, RD_RegSlot_Mark,
RD_RegSlot_LineNum,
RD_RegSlot_ColumnNum,
RD_RegSlot_TextKey, RD_RegSlot_TextKey,
RD_RegSlot_LangKind, RD_RegSlot_LangKind,
RD_RegSlot_Lines, RD_RegSlot_Lines,
@@ -188,6 +190,9 @@ RD_CmdKind_Edit,
RD_CmdKind_Accept, RD_CmdKind_Accept,
RD_CmdKind_Cancel, RD_CmdKind_Cancel,
RD_CmdKind_FocusMenu, RD_CmdKind_FocusMenu,
RD_CmdKind_Lock,
RD_CmdKind_Unlock,
RD_CmdKind_ToggleLock,
RD_CmdKind_MoveLeft, RD_CmdKind_MoveLeft,
RD_CmdKind_MoveRight, RD_CmdKind_MoveRight,
RD_CmdKind_MoveUp, RD_CmdKind_MoveUp,
@@ -478,8 +483,10 @@ E_Space eval_space;
U64 unwind_count; U64 unwind_count;
U64 inline_depth; U64 inline_depth;
String8 file_path; String8 file_path;
TxtPt cursor; U64 cursor;
TxtPt mark; U64 mark;
U64 line_num;
U64 column_num;
C_Key text_key; C_Key text_key;
TXT_LangKind lang_kind; TXT_LangKind lang_kind;
D_LineList lines; D_LineList lines;
@@ -581,6 +588,8 @@ Z(getting_started)\
.file_path = rd_regs()->file_path,\ .file_path = rd_regs()->file_path,\
.cursor = rd_regs()->cursor,\ .cursor = rd_regs()->cursor,\
.mark = rd_regs()->mark,\ .mark = rd_regs()->mark,\
.line_num = rd_regs()->line_num,\
.column_num = rd_regs()->column_num,\
.text_key = rd_regs()->text_key,\ .text_key = rd_regs()->text_key,\
.lang_kind = rd_regs()->lang_kind,\ .lang_kind = rd_regs()->lang_kind,\
.lines = rd_regs()->lines,\ .lines = rd_regs()->lines,\
@@ -617,10 +626,10 @@ Z(getting_started)\
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
extern String8 rd_tab_fast_path_view_name_table[25]; extern String8 rd_tab_fast_path_view_name_table[25];
extern String8 rd_tab_fast_path_query_name_table[25]; extern String8 rd_tab_fast_path_query_name_table[25];
extern RD_VocabInfo rd_vocab_info_table[368]; extern RD_VocabInfo rd_vocab_info_table[372];
extern RD_NameSchemaInfo rd_name_schema_info_table[39]; extern RD_NameSchemaInfo rd_name_schema_info_table[39];
extern String8 rd_reg_slot_code_name_table[52]; extern String8 rd_reg_slot_code_name_table[54];
extern Rng1U64 rd_reg_slot_range_table[52]; extern Rng1U64 rd_reg_slot_range_table[54];
extern String8 rd_binding_version_remap_old_name_table[9]; extern String8 rd_binding_version_remap_old_name_table[9];
extern String8 rd_binding_version_remap_new_name_table[9]; extern String8 rd_binding_version_remap_new_name_table[9];
extern String8 rd_icon_kind_text_table[75]; extern String8 rd_icon_kind_text_table[75];
+209 -202
View File
@@ -94,6 +94,7 @@ RD_VocabTable:
{watch_pin _ "Watch Pin" _ Pin } {watch_pin _ "Watch Pin" _ Pin }
{debug_info _ "Debug Info" "Debug Info" Module } {debug_info _ "Debug Info" "Debug Info" Module }
{watch watches "Watch" "Watches" Binoculars } {watch watches "Watch" "Watches" Binoculars }
{watch_expression _ "Watch Expression" _ Binoculars }
{view _ "View" _ Binoculars } {view _ "View" _ Binoculars }
{breakpoint _ "Breakpoint" _ CircleFilled } {breakpoint _ "Breakpoint" _ CircleFilled }
{condition _ "Condition" _ Null } {condition _ "Condition" _ Null }
@@ -560,7 +561,7 @@ RD_VocabTable:
'label': code_string, 'label': code_string,
@description("The root expression which is evaluated to produce the watch window.") @description("The root expression which is evaluated to produce the watch window.")
'expression': expr_string, 'expression': expr_string,
@no_expand 'watches': set, @no_expand 'watch_expressions': set,
} }
``` ```
} }
@@ -870,8 +871,10 @@ RD_RegTable:
// rjf: code / address location info // rjf: code / address location info
{String8 file_path FilePath } {String8 file_path FilePath }
{TxtPt cursor Cursor } {U64 cursor Cursor }
{TxtPt mark Mark } {U64 mark Mark }
{U64 line_num LineNum }
{U64 column_num ColumnNum }
{C_Key text_key TextKey } {C_Key text_key TextKey }
{TXT_LangKind lang_kind LangKind } {TXT_LangKind lang_kind LangKind }
{D_LineList lines Lines } {D_LineList lines Lines }
@@ -946,302 +949,305 @@ RD_RegTable:
//////////////////////////////// ////////////////////////////////
//~ rjf: Command Table //~ rjf: Command Table
@table(name ui_vis ipc_docs_vis q_expr q_slot q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags filter_tags) @table(name foo ui_vis ipc_docs_vis q_expr q_slot q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags filter_tags)
// / | | | \___ _________________________________________________/ | | | | | | // / | | | | \___ _________________________________________________/ | | | | | |
// / | | | \ / | | | | | | // / | | | | \ / | | | | | |
RD_CmdTable: // | | | | | | | | | | | RD_CmdTable: // | | | | | | | | | | | |
{ {
//- rjf: exiting //- rjf: exiting
{Exit 1 1 "" Null 0 0 0 0 0 0 0 X "exit" "Exit" "Exits the debugger." "quit,close,abort" "" } {Exit 0 1 1 "" Null 0 0 0 0 0 0 0 X "exit" "Exit" "Exits the debugger." "quit,close,abort" "" }
//- rjf: palette //- rjf: palette
{OpenPalette 1 1 "" Null 0 0 0 0 0 0 0 List "open_palette" "Open Palette" "Opens the palette." "help,cmd,lister" "" } {OpenPalette 0 1 1 "" Null 0 0 0 0 0 0 0 List "open_palette" "Open Palette" "Opens the palette." "help,cmd,lister" "" }
//- rjf: command fast-path //- rjf: command fast-path
{RunCommand 0 0 "query:commands" CmdName 0 0 0 0 0 1 1 Null "run_command" "Run Command" "Runs a command from the command palette." "help,cmd" "" } {RunCommand 0 0 0 "query:commands" CmdName 0 0 0 0 0 1 1 Null "run_command" "Run Command" "Runs a command from the command palette." "help,cmd" "" }
//- rjf: external drivers //- rjf: external drivers
{RunExternalDriverTextCommand 0 0 "" Null 0 0 0 0 0 0 0 Null "run_ext_driver_text_command" "Run External Driver Text Command" "" "" "" } {RunExternalDriverTextCommand 0 0 0 "" Null 0 0 0 0 0 0 0 Null "run_ext_driver_text_command" "Run External Driver Text Command" "" "" "" }
{State 0 1 "" Null 0 0 0 0 0 0 0 Null "state" "State" "" "" "" } {State 0 0 1 "" Null 0 0 0 0 0 0 0 Null "state" "State" "" "" "" }
{Eval 0 1 "" Expr 0 0 0 0 0 0 0 Null "eval" "Eval" "" "" "" } {Eval 0 0 1 "" Expr 0 0 0 0 0 0 0 Null "eval" "Eval" "" "" "" }
{LineFromVAddr 0 1 "" Vaddr 0 0 0 0 0 0 0 Null "line_from_vaddr" "Line From Virtual Address" "" "" "" } {LineFromVAddr 0 0 1 "" Vaddr 0 0 0 0 0 0 0 Null "line_from_vaddr" "Line From Virtual Address" "" "" "" }
//- rjf: os event passthrough //- rjf: os event passthrough
{WMEvent 0 0 "" Null 0 0 0 0 0 0 0 Null "wm_event" "OS Event" "" "" "" } {WMEvent 0 0 0 "" Null 0 0 0 0 0 0 0 Null "wm_event" "OS Event" "" "" "" }
//- rjf: thread/frame selection //- rjf: thread/frame selection
{SelectThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Thread "select_thread" "Select Thread" "Selects a thread." "" "" } {SelectThread 0 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Thread "select_thread" "Select Thread" "Selects a thread." "" "" }
{SelectUnwind 0 1 "query:call_stack" Null 0 0 0 0 0 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" "" } {SelectUnwind 0 0 1 "query:call_stack" Null 0 0 0 0 0 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" "" }
{UpOneFrame 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the call stack frame above the currently selected." "" "" } {UpOneFrame 0 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the call stack frame above the currently selected." "" "" }
{DownOneFrame 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the call stack frame below the currently selected." "callstack,unwind" "" } {DownOneFrame 0 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the call stack frame below the currently selected." "callstack,unwind" "" }
{SelectEntity 0 0 "" Null 0 0 0 0 0 0 0 RadioHollow "select_entity" "Select" "Selects a control entity." "" "" } {SelectEntity 0 0 0 "" Null 0 0 0 0 0 0 0 RadioHollow "select_entity" "Select" "Selects a control entity." "" "" }
{DeselectEntity 0 0 "" Null 0 0 0 0 0 0 0 RadioFilled "deselect_entity" "Deselect" "Deselects a control entity." "" "" } {DeselectEntity 0 0 0 "" Null 0 0 0 0 0 0 0 RadioFilled "deselect_entity" "Deselect" "Deselects a control entity." "" "" }
//- rjf: font sizes //- rjf: font sizes
{IncWindowFontSize 1 1 "" Null 0 0 0 0 0 0 0 Null "inc_window_font_size" "Increase Window Font Size" "Increases the window's font size by one point." "" "" } {IncWindowFontSize 0 1 1 "" Null 0 0 0 0 0 0 0 Null "inc_window_font_size" "Increase Window Font Size" "Increases the window's font size by one point." "" "" }
{DecWindowFontSize 1 1 "" Null 0 0 0 0 0 0 0 Null "dec_window_font_size" "Decrease Window Font Size" "Decreases the window's font size by one point." "" "" } {DecWindowFontSize 0 1 1 "" Null 0 0 0 0 0 0 0 Null "dec_window_font_size" "Decrease Window Font Size" "Decreases the window's font size by one point." "" "" }
{IncViewFontSize 1 1 "" Null 0 0 0 0 0 0 0 Null "inc_view_font_size" "Increase View Font Size" "Increases the view's font size by one point." "" "" } {IncViewFontSize 0 1 1 "" Null 0 0 0 0 0 0 0 Null "inc_view_font_size" "Increase View Font Size" "Increases the view's font size by one point." "" "" }
{DecViewFontSize 1 1 "" Null 0 0 0 0 0 0 0 Null "dec_view_font_size" "Decrease View Font Size" "Decreases the view's font size by one point." "" "" } {DecViewFontSize 0 1 1 "" Null 0 0 0 0 0 0 0 Null "dec_view_font_size" "Decrease View Font Size" "Decreases the view's font size by one point." "" "" }
//- rjf: windows //- rjf: windows
{OpenWindow 1 1 "" Null 0 0 0 0 0 0 0 Window "open_window" "Open New Window" "Opens a new window." "" "" } {OpenWindow 0 1 1 "" Null 0 0 0 0 0 0 0 Window "open_window" "Open New Window" "Opens a new window." "" "" }
{WindowSettings 1 1 "" Null 0 0 0 0 0 0 0 Gear "window_settings" "Window Settings" "Opens settings for a window." "" "" } {WindowSettings 0 1 1 "" Null 0 0 0 0 0 0 0 Gear "window_settings" "Window Settings" "Opens settings for a window." "" "" }
{CloseWindow 1 1 "" Null 0 0 0 0 0 0 0 Window "close_window" "Close Window" "Closes an opened window." "" "" } {CloseWindow 0 1 1 "" Null 0 0 0 0 0 0 0 Window "close_window" "Close Window" "Closes an opened window." "" "" }
{ToggleFullscreen 1 1 "" Null 0 0 0 0 0 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" "" } {ToggleFullscreen 0 1 1 "" Null 0 0 0 0 0 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" "" }
{BringToFront 0 1 "" Null 0 0 0 0 0 0 0 Window "bring_to_front" "Bring To Front" "Brings all windows to the front, and focuses the most recently focused window." "top" "" } {BringToFront 0 0 1 "" Null 0 0 0 0 0 0 0 Window "bring_to_front" "Bring To Front" "Brings all windows to the front, and focuses the most recently focused window." "top" "" }
//- rjf: popups //- rjf: popups
{PopupAccept 0 1 "" Null 0 0 0 0 0 0 0 Null "popup_accept" "Popup Accept" "Accepts the active popup prompt." "" "" } {PopupAccept 0 0 1 "" Null 0 0 0 0 0 0 0 Null "popup_accept" "Popup Accept" "Accepts the active popup prompt." "" "" }
{PopupCancel 0 1 "" Null 0 0 0 0 0 0 0 Null "popup_cancel" "Popup Cancel" "Cancels the active popup prompt." "" "" } {PopupCancel 0 0 1 "" Null 0 0 0 0 0 0 0 Null "popup_cancel" "Popup Cancel" "Cancels the active popup prompt." "" "" }
//- rjf: keybindings //- rjf: keybindings
{ResetToDefaultBindings 1 1 "" Null 0 0 0 0 0 0 0 Null "reset_to_default_bindings" "Reset To Default Bindings" "Resets all keybindings to their defaults." "" "" } {ResetToDefaultBindings 0 1 1 "" Null 0 0 0 0 0 0 0 Null "reset_to_default_bindings" "Reset To Default Bindings" "Resets all keybindings to their defaults." "" "" }
//- rjf: panel splitting //- rjf: panel splitting
{ResetToDefaultPanels 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" "" } {ResetToDefaultPanels 0 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" "" }
{ResetToCompactPanels 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_compact_panels" "Reset To Compact Panel Layout" "Resets the window to the compact panel layout." "panel" "" } {ResetToCompactPanels 0 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_compact_panels" "Reset To Compact Panel Layout" "Resets the window to the compact panel layout." "panel" "" }
{ResetToSimplePanels 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_simple_panels" "Reset To Simple Panel Layout" "Resets the window to the simple panel layout." "panel" "" } {ResetToSimplePanels 0 1 1 "" Null 0 0 0 0 0 0 0 Window "reset_to_simple_panels" "Reset To Simple Panel Layout" "Resets the window to the simple panel layout." "panel" "" }
{NewPanelLeft 1 1 "" Null 0 0 0 0 0 0 0 XSplit "new_panel_left" "Split Panel Left" "Creates a new panel to the left of the active panel." "panel" "" } {NewPanelLeft 0 1 1 "" Null 0 0 0 0 0 0 0 XSplit "new_panel_left" "Split Panel Left" "Creates a new panel to the left of the active panel." "panel" "" }
{NewPanelUp 1 1 "" Null 0 0 0 0 0 0 0 YSplit "new_panel_up" "Split Panel Up" "Creates a new panel at the top of the active panel." "panel" "" } {NewPanelUp 0 1 1 "" Null 0 0 0 0 0 0 0 YSplit "new_panel_up" "Split Panel Up" "Creates a new panel at the top of the active panel." "panel" "" }
{NewPanelRight 1 1 "" Null 0 0 0 0 0 0 0 XSplit "new_panel_right" "Split Panel Right" "Creates a new panel to the right of the active panel." "panel" "" } {NewPanelRight 0 1 1 "" Null 0 0 0 0 0 0 0 XSplit "new_panel_right" "Split Panel Right" "Creates a new panel to the right of the active panel." "panel" "" }
{NewPanelDown 1 1 "" Null 0 0 0 0 0 0 0 YSplit "new_panel_down" "Split Panel Down" "Creates a new panel at the bottom of the active panel." "panel" "" } {NewPanelDown 0 1 1 "" Null 0 0 0 0 0 0 0 YSplit "new_panel_down" "Split Panel Down" "Creates a new panel at the bottom of the active panel." "panel" "" }
{SplitPanel 0 0 "" Null 0 0 0 0 0 0 0 Null "split_panel" "Split Panel" "Creates a new panel in a given direction, and moves a tab to it, if specified." "" "" } {SplitPanel 0 0 0 "" Null 0 0 0 0 0 0 0 Null "split_panel" "Split Panel" "Creates a new panel in a given direction, and moves a tab to it, if specified." "" "" }
//- rjf: panel rotation //- rjf: panel rotation
{RotatePanelColumns 1 1 "" Null 0 0 0 0 0 0 0 Null "rotate_panel_columns" "Rotate Panel Columns" "Rotates all panels at the closest column level of the panel hierarchy." "" "" } {RotatePanelColumns 0 1 1 "" Null 0 0 0 0 0 0 0 Null "rotate_panel_columns" "Rotate Panel Columns" "Rotates all panels at the closest column level of the panel hierarchy." "" "" }
//- rjf: focused panel changing //- rjf: focused panel changing
{NextPanel 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "next_panel" "Focus Next Panel" "Cycles the active panel forward." "" "" } {NextPanel 0 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "next_panel" "Focus Next Panel" "Cycles the active panel forward." "" "" }
{PrevPanel 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "prev_panel" "Focus Previous Panel" "Cycles the active panel backwards." "" "" } {PrevPanel 0 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "prev_panel" "Focus Previous Panel" "Cycles the active panel backwards." "" "" }
{FocusPanel 0 0 "" Null 0 0 0 0 0 0 0 Null "focus_panel" "Focus Panel" "Focuses a new panel." "" "" } {FocusPanel 0 0 0 "" Null 0 0 0 0 0 0 0 Null "focus_panel" "Focus Panel" "Focuses a new panel." "" "" }
{FocusPanelRight 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "focus_panel_right" "Focus Panel Right" "Focuses a panel rightward of the currently focused panel." "" "" } {FocusPanelRight 0 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "focus_panel_right" "Focus Panel Right" "Focuses a panel rightward of the currently focused panel." "" "" }
{FocusPanelLeft 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "focus_panel_left" "Focus Panel Left" "Focuses a panel leftward of the currently focused panel." "" "" } {FocusPanelLeft 0 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "focus_panel_left" "Focus Panel Left" "Focuses a panel leftward of the currently focused panel." "" "" }
{FocusPanelUp 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "focus_panel_up" "Focus Panel Up" "Focuses a panel upward of the currently focused panel." "" "" } {FocusPanelUp 0 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "focus_panel_up" "Focus Panel Up" "Focuses a panel upward of the currently focused panel." "" "" }
{FocusPanelDown 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "focus_panel_down" "Focus Panel Down" "Focuses a panel downward of the currently focused panel." "" "" } {FocusPanelDown 0 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "focus_panel_down" "Focus Panel Down" "Focuses a panel downward of the currently focused panel." "" "" }
//- rjf: undo/redo //- rjf: undo/redo
{Undo 0 0 "" Null 0 0 0 0 0 0 0 Undo "undo" "Undo" "Undoes the previous action." "" "" } {Undo 0 0 0 "" Null 0 0 0 0 0 0 0 Undo "undo" "Undo" "Undoes the previous action." "" "" }
{Redo 0 0 "" Null 0 0 0 0 0 0 0 Redo "redo" "Redo" "Redoes the first previously undone action." "" "" } {Redo 0 0 0 "" Null 0 0 0 0 0 0 0 Redo "redo" "Redo" "Redoes the first previously undone action." "" "" }
//- rjf: focus history //- rjf: focus history
{GoBack 0 0 "" Null 0 0 0 0 0 0 0 LeftArrow "go_back" "Go Back" "Returns to the previously selected panel and tab in recorded history." "" "" } {GoBack 0 0 0 "" Null 0 0 0 0 0 0 0 LeftArrow "go_back" "Go Back" "Returns to the previously selected panel and tab in recorded history." "" "" }
{GoForward 0 0 "" Null 0 0 0 0 0 0 0 RightArrow "go_forward" "Go Forward" "Returns to the next selected panel and tab in recorded history." "" "" } {GoForward 0 0 0 "" Null 0 0 0 0 0 0 0 RightArrow "go_forward" "Go Forward" "Returns to the next selected panel and tab in recorded history." "" "" }
//- rjf: panel removal //- rjf: panel removal
{ClosePanel 1 1 "" Null 0 0 0 0 0 0 0 ClosePanel "close_panel" "Close Panel" "Closes the currently active panel." "" "" } {ClosePanel 0 1 1 "" Null 0 0 0 0 0 0 0 ClosePanel "close_panel" "Close Panel" "Closes the currently active panel." "" "" }
//- rjf: panel tab //- rjf: panel tab
{FocusTab 0 0 "" Null 0 0 0 0 0 0 0 Null "focus_tab" "Focus Tab" "Focuses the passed tab within its containing panel." "" "" } {FocusTab 0 0 0 "" Null 0 0 0 0 0 0 0 Null "focus_tab" "Focus Tab" "Focuses the passed tab within its containing panel." "" "" }
{NextTab 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "next_tab" "Focus Next Tab" "Focuses the next tab on the active panel." "" "" } {NextTab 0 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "next_tab" "Focus Next Tab" "Focuses the next tab on the active panel." "" "" }
{PrevTab 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "prev_tab" "Focus Previous Tab" "Focuses the previous tab on the active panel." "" "" } {PrevTab 0 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "prev_tab" "Focus Previous Tab" "Focuses the previous tab on the active panel." "" "" }
{MoveTabRight 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "move_tab_right" "Move Tab Right" "Moves the selected tab right one slot." "" "" } {MoveTabRight 0 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "move_tab_right" "Move Tab Right" "Moves the selected tab right one slot." "" "" }
{MoveTabLeft 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "move_tab_left" "Move Tab Left" "Moves the selected tab left one slot." "" "" } {MoveTabLeft 0 1 1 "" Null 0 0 0 0 0 0 0 LeftArrow "move_tab_left" "Move Tab Left" "Moves the selected tab left one slot." "" "" }
{OpenTab 1 1 "query:tab_commands" CmdName 0 0 0 0 0 1 1 Null "open_tab" "Open New Tab" "Opens a new tab." "" "" } {OpenTab 0 1 1 "query:tab_commands" CmdName 0 0 0 0 0 1 1 Null "open_tab" "Open New Tab" "Opens a new tab." "" "" }
{BuildTab 0 0 "" Null 0 0 0 0 0 0 0 Null "build_tab" "Build Tab" "Opens a new tab with the parameterized view specification." "" "" } {BuildTab 0 0 0 "" Null 0 0 0 0 0 0 0 Null "build_tab" "Build Tab" "Opens a new tab with the parameterized view specification." "" "" }
{DuplicateTab 1 1 "" Tab 0 0 0 0 0 0 0 Duplicate "duplicate_tab" "Duplicate Tab" "Duplicates a tab." "" "" } {DuplicateTab 0 1 1 "" Tab 0 0 0 0 0 0 0 Duplicate "duplicate_tab" "Duplicate Tab" "Duplicates a tab." "" "" }
{CopyTabFullPath 0 0 "" Tab 0 0 0 0 0 0 0 Clipboard "copy_tab_full_path" "Copy Full Path" "Copies the full path of the file being viewed by this tab." "" "" } {CopyTabFullPath 0 0 0 "" Tab 0 0 0 0 0 0 0 Clipboard "copy_tab_full_path" "Copy Full Path" "Copies the full path of the file being viewed by this tab." "" "" }
{CloseTab 1 1 "" Tab 0 0 0 0 0 0 0 X "close_tab" "Close Tab" "Closes the currently opened tab." "" "" } {CloseTab 0 1 1 "" Tab 0 0 0 0 0 0 0 X "close_tab" "Close Tab" "Closes the currently opened tab." "" "" }
{MoveView 0 0 "" Null 0 0 0 0 0 0 0 Null "move_view" "Move View" "Moves a view to a new panel." "" "" } {MoveView 0 0 0 "" Null 0 0 0 0 0 0 0 Null "move_view" "Move View" "Moves a view to a new panel." "" "" }
{TabBarTop 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "tab_bar_top" "Anchor Tab Bar To Top" "Anchors a panel's tab bar to the top of the panel." "" "" } {TabBarTop 0 1 1 "" Null 0 0 0 0 0 0 0 UpArrow "tab_bar_top" "Anchor Tab Bar To Top" "Anchors a panel's tab bar to the top of the panel." "" "" }
{TabBarBottom 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "tab_bar_bottom" "Anchor Tab Bar To Bottom" "Anchors a panel's tab bar to the bottom of the panel." "" "" } {TabBarBottom 0 1 1 "" Null 0 0 0 0 0 0 0 DownArrow "tab_bar_bottom" "Anchor Tab Bar To Bottom" "Anchors a panel's tab bar to the bottom of the panel." "" "" }
{TabSettings 1 1 "" Null 0 0 0 0 0 0 0 Gear "tab_settings" "Selected Tab Settings" "Opens settings for a tab." "view,options" "" } {TabSettings 0 1 1 "" Null 0 0 0 0 0 0 0 Gear "tab_settings" "Selected Tab Settings" "Opens settings for a tab." "view,options" "" }
//- rjf: files //- rjf: files
{SetCurrentPath 0 1 "" Null 0 0 0 0 0 0 0 FileOutline "set_current_path" "Set Current Path" "Sets the debugger's current path, which is used as a starting point when browsing for files." "" "" } {SetCurrentPath 0 0 1 "" Null 0 0 0 0 0 0 0 FileOutline "set_current_path" "Set Current Path" "Sets the debugger's current path, which is used as a starting point when browsing for files." "" "" }
{Open 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 FileOutline "open" "Open" "Opens a file." "code,source,file" "" } {Open 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 FileOutline "open" "Open" "Opens a file." "code,source,file" "" }
{OpenSourceFileFromDebugInfo 1 0 "query:source_files" Cfg 0 0 0 0 0 1 1 FileOutline "open_source_file_from_debug_info" "Open Source File From Debug Info" "Opens a source file found within loaded debug info." "code,source,file" "" } {OpenSourceFileFromDebugInfo 0 1 0 "query:source_files" Cfg 0 0 0 0 0 1 1 FileOutline "open_source_file_from_debug_info" "Open Source File From Debug Info" "Opens a source file found within loaded debug info." "code,source,file" "{tab_commands}" }
{SwitchToPartnerFile 1 1 "" Null 0 0 0 0 0 0 0 FileOutline "switch_to_partner_file" "Switch To Partner File" "Switches to the focused file's partner; or from header to implementation or vice versa." "code,source,file" "" } {SwitchToPartnerFile 0 1 1 "" Null 0 0 0 0 0 0 0 FileOutline "switch_to_partner_file" "Switch To Partner File" "Switches to the focused file's partner; or from header to implementation or vice versa." "code,source,file" "" }
{ShowFileInExplorer 1 1 "" Null 0 0 0 0 0 0 0 FolderClosedFilled "show_file_in_explorer" "Show File In Explorer" "Opens the operating system's file explorer and shows the selected file." "" "" } {ShowFileInExplorer 0 1 1 "" Null 0 0 0 0 0 0 0 FolderClosedFilled "show_file_in_explorer" "Show File In Explorer" "Opens the operating system's file explorer and shows the selected file." "" "" }
//- rjf: source <-> disasm //- rjf: source <-> disasm
{GoToDisassembly 1 1 "" Null 0 0 0 0 0 0 0 Glasses "go_to_disassembly" "Go To Disassembly" "Goes to the disassembly, if any, for a given source code line." "code,source,disassembly,disasm" "{text_pt_commands}" } {GoToDisassembly 0 1 1 "" Null 0 0 0 0 0 0 0 Glasses "go_to_disassembly" "Go To Disassembly" "Goes to the disassembly, if any, for a given source code line." "code,source,disassembly,disasm" "{text_pt_commands}" }
{GoToSource 1 1 "" Null 0 0 0 0 0 0 0 FileOutline "go_to_source" "Go To Source" "Goes to the source code, if any, for a given disassembly line." "code,source,disassembly,disasm" "{disasm_pt_commands}" } {GoToSource 0 1 1 "" Null 0 0 0 0 0 0 0 FileOutline "go_to_source" "Go To Source" "Goes to the source code, if any, for a given disassembly line." "code,source,disassembly,disasm" "{disasm_pt_commands}" }
//- rjf: override file links //- rjf: override file links
{SetFileReplacementPath 0 0 "" Null 0 0 0 0 0 0 0 Null "set_file_replacement_path" "Set File Replacement Path" "Sets the path which should be used as the replacement for the passed file." "" "" } {SetFileReplacementPath 0 0 0 "" Null 0 0 0 0 0 0 0 Null "set_file_replacement_path" "Set File Replacement Path" "Sets the path which should be used as the replacement for the passed file." "" "" }
//- rjf: setting config paths //- rjf: setting config paths
{NewUser 1 1 "" Null 1 0 0 0 0 1 0 Add "new_user" "New User" "Creates a new user file, and sets the current user path as that file's path." "new,user,project,layout" "" } {NewUser 0 1 1 "" Null 1 0 0 0 0 1 0 Add "new_user" "New User" "Creates a new user file, and sets the current user path as that file's path." "new,user,project,layout" "" }
{NewProject 1 1 "" Null 1 0 0 0 0 1 0 Add "new_project" "New Project" "Creates a new project file, and sets the current project path as that file's path." "new,user,project,layout" "" } {NewProject 0 1 1 "" Null 1 0 0 0 0 1 0 Add "new_project" "New Project" "Creates a new project file, and sets the current project path as that file's path." "new,user,project,layout" "" }
{OpenUser 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Person "open_user" "Open User" "Opens a user file path, immediately loading it, and begins autosaving to it." "load,user,project,layout" "" } {OpenUser 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Person "open_user" "Open User" "Opens a user file path, immediately loading it, and begins autosaving to it." "load,user,project,layout" "" }
{OpenProject 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Briefcase "open_project" "Open Project" "Opens a project file path, immediately loading it, and begins autosaving to it." "project,project,session" "" } {OpenProject 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Briefcase "open_project" "Open Project" "Opens a project file path, immediately loading it, and begins autosaving to it." "project,project,session" "" }
{OpenRecentProject 1 1 "query:recent_projects" Cfg 0 0 0 0 0 1 1 Briefcase "open_recent_project" "Open Recent Project" "Opens a recently used project file." "project,project,session" "" } {OpenRecentProject 0 1 1 "query:recent_projects" Cfg 0 0 0 0 0 1 1 Briefcase "open_recent_project" "Open Recent Project" "Opens a recently used project file." "project,project,session" "" }
{SaveUser 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Save "save_user" "Save User" "Saves user data to a file, and sets the current user path as that path." "load,user,project,layout" "" } {SaveUser 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Save "save_user" "Save User" "Saves user data to a file, and sets the current user path as that path." "load,user,project,layout" "" }
{SaveProject 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Save "save_project" "Save Project" "Saves project data to a file, and sets the current project path as that path." "project,project,session" "" } {SaveProject 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Save "save_project" "Save Project" "Saves project data to a file, and sets the current project path as that path." "project,project,session" "" }
{RecordUserAsLastOpened 0 0 "" Null 0 0 0 0 0 0 0 Null "record_user_as_last_opened" "Record User As Last Opened" "Records a file path as the last opened user." "" "" } {RecordUserAsLastOpened 0 0 0 "" Null 0 0 0 0 0 0 0 Null "record_user_as_last_opened" "Record User As Last Opened" "Records a file path as the last opened user." "" "" }
{RecordProjectInUser 0 0 "" Null 0 0 0 0 0 0 0 Null "record_project_in_user" "Records Project In User" "Records a file path as a recent project in user data." "" "" } {RecordProjectInUser 0 0 0 "" Null 0 0 0 0 0 0 0 Null "record_project_in_user" "Records Project In User" "Records a file path as a recent project in user data." "" "" }
//- rjf: writing config changes //- rjf: writing config changes
{WriteUserData 0 1 "" Null 0 0 0 0 0 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" "" } {WriteUserData 0 0 1 "" Null 0 0 0 0 0 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" "" }
{WriteProjectData 0 1 "" Null 0 0 0 0 0 0 0 Null "write_project_data" "Write Project Data" "Writes project data to the active project file." "" "" } {WriteProjectData 0 0 1 "" Null 0 0 0 0 0 0 0 Null "write_project_data" "Write Project Data" "Writes project data to the active project file." "" "" }
//- rjf: opening user/project settings //- rjf: opening user/project settings
{UserSettings 1 1 "" Null 0 0 0 0 0 0 0 Gear "user_settings" "User Settings" "Opens user settings." "" "" } {UserSettings 0 1 1 "" Null 0 0 0 0 0 0 0 Gear "user_settings" "User Settings" "Opens user settings." "" "" }
{ProjectSettings 1 1 "" Null 0 0 0 0 0 0 0 Gear "project_settings" "Project Settings" "Opens project settings." "" "" } {ProjectSettings 0 1 1 "" Null 0 0 0 0 0 0 0 Gear "project_settings" "Project Settings" "Opens project settings." "" "" }
//- rjf: meta controls //- rjf: meta controls
{Edit 1 1 "" Null 0 0 0 0 0 0 0 Pencil "edit" "Edit" "Edits the current selection." "" "" } {Edit 0 1 1 "" Null 0 0 0 0 0 0 0 Pencil "edit" "Edit" "Edits the current selection." "" "" }
{Accept 1 1 "" Null 0 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" "" } {Accept 0 1 1 "" Null 0 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" "" }
{Cancel 1 1 "" Null 0 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" "" } {Cancel 0 1 1 "" Null 0 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" "" }
{FocusMenu 1 1 "" Null 0 0 0 0 0 0 0 List "focus_menu" "Focus Menu" "Focuses the menu for the selected interface, if there is one." "" "" } {FocusMenu 0 1 1 "" Null 0 0 0 0 0 0 0 List "focus_menu" "Focus Menu" "Focuses the menu for the selected interface, if there is one." "" "" }
{Lock 0 1 1 "" Null 0 0 0 0 0 0 0 Locked "lock" "Lock" "Locks the current selection, if applicable." "" "" }
{Unlock 0 1 1 "" Null 0 0 0 0 0 0 0 Unlocked "unlock" "Unlock" "Unlocks the current selection, if applicable." "" "" }
{ToggleLock 0 1 1 "" Null 0 0 0 0 0 0 0 Locked "toggle_lock" "Toggle Lock" "Toggles the lock state of the current selection, if applicable." "" "" }
//- rjf: directional movement & text controls //- rjf: directional movement & text controls
{MoveLeft 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" "" } {MoveLeft 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" "" }
{MoveRight 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" "" } {MoveRight 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" "" }
{MoveUp 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up" "Move Up" "Moves the cursor or selection up." "" "" } {MoveUp 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up" "Move Up" "Moves the cursor or selection up." "" "" }
{MoveDown 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down" "Move Down" "Moves the cursor or selection down." "" "" } {MoveDown 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down" "Move Down" "Moves the cursor or selection down." "" "" }
{MoveLeftSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_select" "Move Left Select" "Moves the cursor or selection left, while selecting." "" "" } {MoveLeftSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_select" "Move Left Select" "Moves the cursor or selection left, while selecting." "" "" }
{MoveRightSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_select" "Move Right Select" "Moves the cursor or selection right, while selecting." "" "" } {MoveRightSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_select" "Move Right Select" "Moves the cursor or selection right, while selecting." "" "" }
{MoveUpSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_select" "Move Up Select" "Moves the cursor or selection up, while selecting." "" "" } {MoveUpSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_select" "Move Up Select" "Moves the cursor or selection up, while selecting." "" "" }
{MoveDownSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_select" "Move Down Select" "Moves the cursor or selection down, while selecting." "" "" } {MoveDownSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_select" "Move Down Select" "Moves the cursor or selection down, while selecting." "" "" }
{MoveLeftChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_chunk" "Move Left Chunk" "Moves the cursor or selection left one chunk." "" "" } {MoveLeftChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_chunk" "Move Left Chunk" "Moves the cursor or selection left one chunk." "" "" }
{MoveRightChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_chunk" "Move Right Chunk" "Moves the cursor or selection right one chunk." "" "" } {MoveRightChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_chunk" "Move Right Chunk" "Moves the cursor or selection right one chunk." "" "" }
{MoveUpChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_chunk" "Move Up Chunk" "Moves the cursor or selection up one chunk." "" "" } {MoveUpChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_chunk" "Move Up Chunk" "Moves the cursor or selection up one chunk." "" "" }
{MoveDownChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_chunk" "Move Down Chunk" "Moves the cursor or selection down one chunk." "" "" } {MoveDownChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_chunk" "Move Down Chunk" "Moves the cursor or selection down one chunk." "" "" }
{MoveUpPage 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_page" "Move Up Page" "Moves the cursor or selection up one page." "" "" } {MoveUpPage 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_page" "Move Up Page" "Moves the cursor or selection up one page." "" "" }
{MoveDownPage 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_page" "Move Down Page" "Moves the cursor or selection down one page." "" "" } {MoveDownPage 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_page" "Move Down Page" "Moves the cursor or selection down one page." "" "" }
{MoveUpWhole 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_whole" "Move Up Whole" "Moves the cursor or selection to the beginning of the relevant content." "" "" } {MoveUpWhole 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_whole" "Move Up Whole" "Moves the cursor or selection to the beginning of the relevant content." "" "" }
{MoveDownWhole 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_whole" "Move Down Whole" "Moves the cursor or selection to the end of the relevant content." "" "" } {MoveDownWhole 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_whole" "Move Down Whole" "Moves the cursor or selection to the end of the relevant content." "" "" }
{MoveLeftChunkSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_chunk_select" "Move Left Chunk Select" "Moves the cursor or selection left one chunk." "" "" } {MoveLeftChunkSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_left_chunk_select" "Move Left Chunk Select" "Moves the cursor or selection left one chunk." "" "" }
{MoveRightChunkSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_chunk_select" "Move Right Chunk Select" "Moves the cursor or selection right one chunk." "" "" } {MoveRightChunkSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_right_chunk_select" "Move Right Chunk Select" "Moves the cursor or selection right one chunk." "" "" }
{MoveUpChunkSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_chunk_select" "Move Up Chunk Select" "Moves the cursor or selection up one chunk." "" "" } {MoveUpChunkSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_chunk_select" "Move Up Chunk Select" "Moves the cursor or selection up one chunk." "" "" }
{MoveDownChunkSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_chunk_select" "Move Down Chunk Select" "Moves the cursor or selection down one chunk." "" "" } {MoveDownChunkSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_chunk_select" "Move Down Chunk Select" "Moves the cursor or selection down one chunk." "" "" }
{MoveUpPageSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_page_select" "Move Up Page Select" "Moves the cursor or selection up one page, while selecting." "" "" } {MoveUpPageSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_page_select" "Move Up Page Select" "Moves the cursor or selection up one page, while selecting." "" "" }
{MoveDownPageSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" "" } {MoveDownPageSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" "" }
{MoveUpWholeSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" "" } {MoveUpWholeSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" "" }
{MoveDownWholeSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" "" } {MoveDownWholeSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" "" }
{MoveUpReorder 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_reorder" "Move Up Reorder" "Moves the cursor or selection up, while swapping the currently selected element with that upward." "" "" } {MoveUpReorder 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_up_reorder" "Move Up Reorder" "Moves the cursor or selection up, while swapping the currently selected element with that upward." "" "" }
{MoveDownReorder 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_reorder" "Move Down Reorder" "Moves the cursor or selection down, while swapping the currently selected element with that downward." "" "" } {MoveDownReorder 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_down_reorder" "Move Down Reorder" "Moves the cursor or selection down, while swapping the currently selected element with that downward." "" "" }
{MoveHome 1 1 "" Null 0 0 0 0 0 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" "" } {MoveHome 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" "" }
{MoveEnd 1 1 "" Null 0 0 0 0 0 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" "" } {MoveEnd 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" "" }
{MoveHomeSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" "" } {MoveHomeSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" "" }
{MoveEndSelect 1 1 "" Null 0 0 0 0 0 0 0 Null "move_end_select" "Move End Select" "Moves the cursor to the end of the line, while selecting." "" "" } {MoveEndSelect 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_end_select" "Move End Select" "Moves the cursor to the end of the line, while selecting." "" "" }
{SelectAll 1 1 "" Null 0 0 0 0 0 0 0 Null "select_all" "Select All" "Selects everything possible." "" "" } {SelectAll 0 1 1 "" Null 0 0 0 0 0 0 0 Null "select_all" "Select All" "Selects everything possible." "" "" }
{DeleteSingle 1 1 "" Null 0 0 0 0 0 0 0 Null "delete_single" "Delete Single" "Deletes a single element to the right of the cursor, or the active selection." "" "" } {DeleteSingle 0 1 1 "" Null 0 0 0 0 0 0 0 Null "delete_single" "Delete Single" "Deletes a single element to the right of the cursor, or the active selection." "" "" }
{DeleteChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "delete_chunk" "Delete Chunk" "Deletes a chunk to the right of the cursor, or the active selection." "" "" } {DeleteChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "delete_chunk" "Delete Chunk" "Deletes a chunk to the right of the cursor, or the active selection." "" "" }
{BackspaceSingle 1 1 "" Null 0 0 0 0 0 0 0 Null "backspace_single" "Backspace Single" "Deletes a single element to the left of the cursor, or the active selection." "" "" } {BackspaceSingle 0 1 1 "" Null 0 0 0 0 0 0 0 Null "backspace_single" "Backspace Single" "Deletes a single element to the left of the cursor, or the active selection." "" "" }
{BackspaceChunk 1 1 "" Null 0 0 0 0 0 0 0 Null "backspace_chunk" "Backspace Chunk" "Deletes a chunk to the left of the cursor, or the active selection." "" "" } {BackspaceChunk 0 1 1 "" Null 0 0 0 0 0 0 0 Null "backspace_chunk" "Backspace Chunk" "Deletes a chunk to the left of the cursor, or the active selection." "" "" }
{Copy 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "copy" "Copy" "Copies the active selection to the clipboard." "" "{text_range_commands}{disasm_range_commands}" } {Copy 0 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "copy" "Copy" "Copies the active selection to the clipboard." "" "{text_range_commands}{disasm_range_commands}" }
{Cut 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "cut" "Cut" "Copies the active selection to the clipboard, then deletes it." "" "" } {Cut 0 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "cut" "Cut" "Copies the active selection to the clipboard, then deletes it." "" "" }
{Paste 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "paste" "Paste" "Pastes the current contents of the clipboard." "" "" } {Paste 0 1 1 "" Null 0 0 0 0 0 0 0 Clipboard "paste" "Paste" "Pastes the current contents of the clipboard." "" "" }
{InsertText 0 1 "" Null 0 0 0 0 0 0 0 Null "insert_text" "Insert Text" "Inserts the text that was used to cause this command." "" "" } {InsertText 0 0 1 "" Null 0 0 0 0 0 0 0 Null "insert_text" "Insert Text" "Inserts the text that was used to cause this command." "" "" }
//- rjf: directionless navigation //- rjf: directionless navigation
{MoveNext 1 1 "" Null 0 0 0 0 0 0 0 Null "move_next" "Move Next" "Moves the cursor or selection to the next element." "" "" } {MoveNext 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_next" "Move Next" "Moves the cursor or selection to the next element." "" "" }
{MovePrev 1 1 "" Null 0 0 0 0 0 0 0 Null "move_prev" "Move Previous" "Moves the cursor or selection to the previous element." "" "" } {MovePrev 0 1 1 "" Null 0 0 0 0 0 0 0 Null "move_prev" "Move Previous" "Moves the cursor or selection to the previous element." "" "" }
//- rjf: code navigation //- rjf: code navigation
{GoToLine 1 1 "" Cursor 0 0 0 0 1 0 1 Null "goto_line" "Go To Line" "Jumps to a line number in the current code file." "" "" } {GoToLine 0 1 1 "" LineNum 0 0 0 0 1 0 1 Null "goto_line" "Go To Line" "Jumps to a line number in the current code file." "" "" }
{GoToAddress 1 1 "" Vaddr 0 0 0 0 1 0 1 Null "goto_address" "Go To Address" "Jumps to an address in the current memory or disassembly view." "" "" } {GoToAddress 0 1 1 "" Vaddr 0 0 0 0 1 0 1 Null "goto_address" "Go To Address" "Jumps to an address in the current memory or disassembly view." "" "" }
{CenterCursor 1 1 "" Null 0 0 0 0 0 0 0 Null "center_cursor" "Center Cursor" "Snaps the current code view to center the cursor." "" "" } {CenterCursor 0 1 1 "" Null 0 0 0 0 0 0 0 Null "center_cursor" "Center Cursor" "Snaps the current code view to center the cursor." "" "" }
{ContainCursor 1 1 "" Null 0 0 0 0 0 0 0 Null "contain_cursor" "Contain Cursor" "Snaps the current code view to contain the cursor." "" "" } {ContainCursor 0 1 1 "" Null 0 0 0 0 0 0 0 Null "contain_cursor" "Contain Cursor" "Snaps the current code view to contain the cursor." "" "" }
{FindNext 1 1 "" Null 0 0 1 0 0 0 0 Find "find_next" "Find Next" "Searches the current code file forward (from the cursor) for the last searched string." "" "" } {FindNext 0 1 1 "" Null 0 0 1 0 0 0 0 Find "find_next" "Find Next" "Searches the current code file forward (from the cursor) for the last searched string." "" "" }
{FindPrev 1 1 "" Null 0 0 1 0 0 0 0 Find "find_prev" "Find Previous" "Searches the current code file backwards (from the cursor) for the last searched string." "" "" } {FindPrev 0 1 1 "" Null 0 0 1 0 0 0 0 Find "find_prev" "Find Previous" "Searches the current code file backwards (from the cursor) for the last searched string." "" "" }
//- rjf: thread finding //- rjf: thread finding
{FindThread 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Find "find_thread" "Find Thread" "Jumps to the passed thread in either source code, disassembly, or both if they're already open." "" "" } {FindThread 0 1 1 "query:threads" Thread 0 0 0 0 0 1 1 Find "find_thread" "Find Thread" "Jumps to the passed thread in either source code, disassembly, or both if they're already open." "" "" }
{FindSelectedThread 1 1 "" Null 0 0 0 0 0 0 0 Find "find_selected_thread" "Find Selected Thread" "Jumps to the selected thread in either source code, disassembly, or both if they're already open." "current,instruction" "{text_pt_commands}{text_range_commands}{disasm_pt_commands}{disasm_range_commands}" } {FindSelectedThread 0 1 1 "" Null 0 0 0 0 0 0 0 Find "find_selected_thread" "Find Selected Thread" "Jumps to the selected thread in either source code, disassembly, or both if they're already open." "current,instruction" "{text_pt_commands}{text_range_commands}{disasm_pt_commands}{disasm_range_commands}" }
//- rjf: name finding //- rjf: name finding
{GoToName 1 1 "query:procedures" String 0 0 0 0 1 1 1 Null "goto_name" "Go To Name" "Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible." "" "" } {GoToName 0 1 1 "query:procedures" String 0 0 0 0 1 1 1 Null "goto_name" "Go To Name" "Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible." "" "" }
{GoToNameAtCursor 1 1 "" Null 0 0 0 0 0 0 0 Null "goto_name_at_cursor" "Go To Name At Cursor" "Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible." "" "{text_pt_commands}{disasm_pt_commands}" } {GoToNameAtCursor 0 1 1 "" Null 0 0 0 0 0 0 0 Null "goto_name_at_cursor" "Go To Name At Cursor" "Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible." "" "{text_pt_commands}{disasm_pt_commands}" }
//- rjf: watch expressions //- rjf: watch expressions
{ToggleWatchExpression 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr" "Toggle Watch Expression" "Adds or removes an expression to an opened watch view." "" "" } {ToggleWatchExpression 0 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr" "Toggle Watch Expression" "Adds or removes an expression to an opened watch view." "" "" }
{ToggleWatchExpressionAtCursor 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_cursor" "Toggle Watch Expression At Cursor" "Adds or removes the expression that the cursor or selection is currently over to an opened watch view." "" "{text_pt_commands}{disasm_pt_commands}" } {ToggleWatchExpressionAtCursor 0 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_cursor" "Toggle Watch Expression At Cursor" "Adds or removes the expression that the cursor or selection is currently over to an opened watch view." "" "{text_pt_commands}{disasm_pt_commands}" }
{ToggleWatchExpressionAtMouse 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_mouse" "Toggle Watch Expression At Mouse" "Adds or removes the expression that the mouse is currently over to an opened watch view." "" "" } {ToggleWatchExpressionAtMouse 0 1 1 "" Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_mouse" "Toggle Watch Expression At Mouse" "Adds or removes the expression that the mouse is currently over to an opened watch view." "" "" }
//- rjf: general config operations //- rjf: general config operations
{EnableCfg 0 0 "" Null 0 0 0 0 0 0 0 CheckHollow "enable_cfg" "Enable" "Enables a config tree." "" "" } {EnableCfg 0 0 0 "" Null 0 0 0 0 0 0 0 CheckHollow "enable_cfg" "Enable" "Enables a config tree." "" "" }
{DisableCfg 0 0 "" Null 0 0 0 0 0 0 0 CheckFilled "disable_cfg" "Disable" "Disables a config tree." "" "" } {DisableCfg 0 0 0 "" Null 0 0 0 0 0 0 0 CheckFilled "disable_cfg" "Disable" "Disables a config tree." "" "" }
{SelectCfg 0 0 "" Null 0 0 0 0 0 0 0 RadioHollow "select_cfg" "Select" "Selects a config tree, disabling all others of the same kind." "" "" } {SelectCfg 0 0 0 "" Null 0 0 0 0 0 0 0 RadioHollow "select_cfg" "Select" "Selects a config tree, disabling all others of the same kind." "" "" }
{DeselectCfg 0 0 "" Null 0 0 0 0 0 0 0 RadioFilled "deselect_cfg" "Deselect" "Deselects a config tree." "" "" } {DeselectCfg 0 0 0 "" Null 0 0 0 0 0 0 0 RadioFilled "deselect_cfg" "Deselect" "Deselects a config tree." "" "" }
{RemoveCfg 0 0 "" Null 0 0 0 0 0 0 0 Trash "remove_cfg" "Remove" "Removes a config tree." "" "" } {RemoveCfg 0 0 0 "" Null 0 0 0 0 0 0 0 Trash "remove_cfg" "Remove" "Removes a config tree." "" "" }
{NameCfg 0 0 "" Null 0 0 0 0 0 0 0 Null "name_cfg" "Name" "Equips a config tree with a label." "" "" } {NameCfg 0 0 0 "" Null 0 0 0 0 0 0 0 Null "name_cfg" "Name" "Equips a config tree with a label." "" "" }
{ConditionCfg 0 0 "" Null 0 0 0 0 0 0 0 Null "condition_cfg" "Condition" "Equips a config tree with a condition string." "" "" } {ConditionCfg 0 0 0 "" Null 0 0 0 0 0 0 0 Null "condition_cfg" "Condition" "Equips a config tree with a condition string." "" "" }
{DuplicateCfg 0 0 "" Null 0 0 0 0 0 0 0 Duplicate "duplicate_cfg" "Duplicate" "Duplicates a config tree." "" "" } {DuplicateCfg 0 0 0 "" Null 0 0 0 0 0 0 0 Duplicate "duplicate_cfg" "Duplicate" "Duplicates a config tree." "" "" }
{RelocateCfg 0 0 "" Null 0 0 0 0 0 0 0 Null "relocate_cfg" "Relocate" "Relocates a config tree." "" "" } {RelocateCfg 0 0 0 "" Null 0 0 0 0 0 0 0 Null "relocate_cfg" "Relocate" "Relocates a config tree." "" "" }
{SaveToProject 0 0 "" Null 0 0 0 0 0 0 0 Briefcase "save_cfg_to_project" "Save To Project" "Saves the config tree to the project." "" "" } {SaveToProject 0 0 0 "" Null 0 0 0 0 0 0 0 Briefcase "save_cfg_to_project" "Save To Project" "Saves the config tree to the project." "" "" }
//- rjf: breakpoints //- rjf: breakpoints
{AddBreakpoint 1 1 "" Null 0 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Line Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" "" } {AddBreakpoint 0 1 1 "" Null 0 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Line Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" "" }
{AddAddressBreakpoint 1 0 "" Expr 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "" } {AddAddressBreakpoint 0 1 0 "" Expr 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "" }
{AddFunctionBreakpoint 1 0 "query:procedures" String 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address of the specified function." "" "" } {AddFunctionBreakpoint 0 1 0 "query:procedures" String 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address of the specified function." "" "" }
{ToggleBreakpoint 1 1 "" Null 0 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Line Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" "{text_pt_commands}{disasm_pt_commands}" } {ToggleBreakpoint 0 1 1 "" Null 0 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Line Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" "{text_pt_commands}{disasm_pt_commands}" }
{RemoveBreakpoint 1 0 "query:breakpoints" Cfg 0 0 0 0 1 1 1 Trash "remove_breakpoint" "Remove Breakpoint" "Removes an existing breakpoint." "delete" "" } {RemoveBreakpoint 0 1 0 "query:breakpoints" Cfg 0 0 0 0 1 1 1 Trash "remove_breakpoint" "Remove Breakpoint" "Removes an existing breakpoint." "delete" "" }
{EnableBreakpoint 1 1 "query:breakpoints" Cfg 0 0 0 0 1 1 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" "" } {EnableBreakpoint 0 1 1 "query:breakpoints" Cfg 0 0 0 0 1 1 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" "" }
{DisableBreakpoint 1 1 "query:breakpoints" Cfg 0 0 0 0 1 1 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" "" } {DisableBreakpoint 0 1 1 "query:breakpoints" Cfg 0 0 0 0 1 1 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" "" }
{ClearBreakpoints 1 1 "" Null 0 0 0 0 0 0 0 Trash "clear_breakpoints" "Clear Breakpoints" "Removes all breakpoints." "" "" } {ClearBreakpoints 0 1 1 "" Null 0 0 0 0 0 0 0 Trash "clear_breakpoints" "Clear Breakpoints" "Removes all breakpoints." "" "" }
//- rjf: output //- rjf: output
{ClearOutput 1 1 "" Null 0 0 0 0 0 0 0 Null "clear_output" "Clear Output" "Clears all output." "" "" } {ClearOutput 0 1 1 "" Null 0 0 0 0 0 0 0 Null "clear_output" "Clear Output" "Clears all output." "" "" }
//- rjf: watch pins //- rjf: watch pins
{AddWatchPin 1 1 "" Expr 0 0 0 0 1 1 1 Pin "add_watch_pin" "Add Watch Pin" "Places a watch pin at a given location (file path and line number or address)." "" "" } {AddWatchPin 0 1 1 "" Expr 0 0 0 0 1 1 1 Pin "add_watch_pin" "Add Watch Pin" "Places a watch pin at a given location (file path and line number or address)." "" "" }
{ToggleWatchPin 1 0 "" Expr 0 0 0 0 1 1 1 Pin "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin at a given location (file path and line number or address)." "" "" } {ToggleWatchPin 0 1 0 "" Expr 0 0 0 0 1 1 1 Pin "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin at a given location (file path and line number or address)." "" "" }
//- rjf: debug infos //- rjf: debug infos
{LoadDebugInfo 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Module "load_debug_info" "Load Debug Info" "Loads a debug info file." "" "" } {LoadDebugInfo 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Module "load_debug_info" "Load Debug Info" "Loads a debug info file." "" "" }
{UnloadDebugInfo 1 1 "query:debug_infos" Cfg 0 0 0 0 1 1 1 Module "unload_debug_info" "Unload Debug Info" "Unloads a debug info file." "" "" } {UnloadDebugInfo 0 1 1 "query:debug_infos" Cfg 0 0 0 0 1 1 1 Module "unload_debug_info" "Unload Debug Info" "Unloads a debug info file." "" "" }
//- rjf: type views //- rjf: type views
{AddTypeView 0 0 "" String 0 0 0 0 0 0 0 Binoculars "add_type_view" "Add Type View" "Adds a new type view." "" "" } {AddTypeView 0 0 0 "" String 0 0 0 0 0 0 0 Binoculars "add_type_view" "Add Type View" "Adds a new type view." "" "" }
//- rjf: file path maps //- rjf: file path maps
{AddFilePathMap 0 0 "" Null 0 0 0 0 0 0 0 FileOutline "add_file_path_map" "Add File Path Map" "Adds a new file path map." "" "" } {AddFilePathMap 0 0 0 "" Null 0 0 0 0 0 0 0 FileOutline "add_file_path_map" "Add File Path Map" "Adds a new file path map." "" "" }
//- rjf: themes //- rjf: themes
{EditUserTheme 0 0 "query:themes" String 0 0 0 0 0 0 0 Palette "edit_user_theme" "Edit User Theme" "Edits the current user's theme." "color" "" } {EditUserTheme 0 0 0 "query:themes" String 0 0 0 0 0 0 0 Palette "edit_user_theme" "Edit User Theme" "Edits the current user's theme." "color" "" }
{EditProjectTheme 0 0 "query:themes" String 0 0 0 0 0 0 0 Palette "edit_project_theme" "Edit Project Theme" "Edits the current project's theme." "color" "" } {EditProjectTheme 0 0 0 "query:themes" String 0 0 0 0 0 0 0 Palette "edit_project_theme" "Edit Project Theme" "Edits the current project's theme." "color" "" }
{AddThemeColor 0 0 "" Null 0 0 0 0 0 0 0 Palette "add_theme_color" "Add Theme Color" "Adds a new theme color." "" "" } {AddThemeColor 0 0 0 "" Null 0 0 0 0 0 0 0 Palette "add_theme_color" "Add Theme Color" "Adds a new theme color." "" "" }
{ForkTheme 0 0 "" Null 0 0 0 0 0 0 0 Palette "fork_theme" "Fork Theme" "Imports all colors from the current theme so they can be individually edited." "" "" } {ForkTheme 0 0 0 "" Null 0 0 0 0 0 0 0 Palette "fork_theme" "Fork Theme" "Imports all colors from the current theme so they can be individually edited." "" "" }
{SaveTheme 0 0 "" String 1 0 0 0 0 1 1 Save "save_theme" "Save Theme" "Saves all theme colors to a new theme file." "" "" } {SaveTheme 0 0 0 "" String 1 0 0 0 0 1 1 Save "save_theme" "Save Theme" "Saves all theme colors to a new theme file." "" "" }
{SaveAndSetTheme 0 0 "" String 1 0 0 0 0 1 1 Save "save_and_set_theme" "Save And Set Theme" "Saves all theme colors to a new theme file, and then sets that theme as the selected theme." "" "" } {SaveAndSetTheme 0 0 0 "" String 1 0 0 0 0 1 1 Save "save_and_set_theme" "Save And Set Theme" "Saves all theme colors to a new theme file, and then sets that theme as the selected theme." "" "" }
//- rjf: line operations //- rjf: line operations
{SetNextStatement 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" "{text_pt_commands}{disasm_pt_commands}" } {SetNextStatement 0 1 1 "" Null 0 0 0 0 0 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" "{text_pt_commands}{disasm_pt_commands}" }
//- rjf: targets //- rjf: targets
{AddTarget 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Target "add_target" "Add Target" "Adds a new target." "application,executable,debug" "" } {AddTarget 0 1 1 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 Target "add_target" "Add Target" "Adds a new target." "application,executable,debug" "" }
{SelectTarget 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Target "select_target" "Select Target" "Selects a target." "" "" } {SelectTarget 0 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Target "select_target" "Select Target" "Selects a target." "" "" }
{EnableTarget 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 CheckFilled "enable_target" "Enable Target" "Enables a target, in addition to all targets currently enabled." "" "" } {EnableTarget 0 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 CheckFilled "enable_target" "Enable Target" "Enables a target, in addition to all targets currently enabled." "" "" }
{DisableTarget 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 CheckHollow "disable_target" "Disable Target" "Disables a target." "" "" } {DisableTarget 0 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 CheckHollow "disable_target" "Disable Target" "Disables a target." "" "" }
{RemoveTarget 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Trash "remove_target" "Remove Target" "Removes a target." "delete" "" } {RemoveTarget 0 1 1 "query:targets" Cfg 0 0 0 0 0 1 1 Trash "remove_target" "Remove Target" "Removes a target." "delete" "" }
//- rjf: attaching //- rjf: attaching
{RegisterAsJITDebugger 1 1 "" Null 0 0 0 0 0 0 0 Null "register_as_jit_debugger" "Register As Just-In-Time (JIT) Debugger" "Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system." "" "" } {RegisterAsJITDebugger 0 1 1 "" Null 0 0 0 0 0 0 0 Null "register_as_jit_debugger" "Register As Just-In-Time (JIT) Debugger" "Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system." "" "" }
//- rjf: snap-to-code-location //- rjf: snap-to-code-location
{FindCodeLocation 0 1 "" FilePath 0 0 0 0 0 1 1 FileOutline "find_code_location" "Find Code Location" "Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary." "" "" } {FindCodeLocation 0 0 1 "" FilePath 0 0 0 0 0 1 1 FileOutline "find_code_location" "Find Code Location" "Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary." "" "" }
//- rjf: snap-to-memory-location //- rjf: snap-to-memory-location
{GoToMemory 0 1 "" Expr 0 0 0 0 1 1 0 Grid "go_to_memory" "Go To Memory" "Finds the specified expression in the memory view. Opens the memory view if necessary." "" "{memory_eval_commands}" } {GoToMemory 0 0 1 "" Expr 0 0 0 0 1 1 0 Grid "go_to_memory" "Go To Memory" "Finds the specified expression in the memory view. Opens the memory view if necessary." "" "{memory_eval_commands}" }
//- rjf: break-when-value-changes //- rjf: break-when-value-changes
{BreakWhenValueChanges 0 1 "" Expr 0 0 0 0 1 1 0 CircleFilled "break_when_value_changes" "Break When Value Changes" "Adds a new write data breakpoint for this variable's range." "" "{memory_eval_commands}" } {BreakWhenValueChanges 0 0 1 "" Expr 0 0 0 0 1 1 0 CircleFilled "break_when_value_changes" "Break When Value Changes" "Adds a new write data breakpoint for this variable's range." "" "{memory_eval_commands}" }
//- rjf: searching //- rjf: searching
{Search 1 1 "" String 0 0 1 1 1 0 1 Find "search" "Search" "Begins searching within the active interface." "sort,search,filter,find" "" } {Search 0 1 1 "" String 0 0 1 1 1 0 1 Find "search" "Search" "Begins searching within the active interface." "sort,search,filter,find" "" }
{SearchBackwards 1 1 "" String 0 0 1 1 1 0 1 Find "search_backwards" "Search Backwards" "Begins searching backwards within the active interface." "sort,search,filter,find" "" } {SearchBackwards 0 1 1 "" String 0 0 1 1 1 0 1 Find "search_backwards" "Search Backwards" "Begins searching backwards within the active interface." "sort,search,filter,find" "" }
//- rjf: queries //- rjf: queries
{PickFile 0 0 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 FileOutline "pick_file" "Pick File" "Opens the file browser to pick a file." "" "" } {PickFile 0 0 0 `folder:\\"$input\\"` FilePath 1 0 0 0 0 1 1 FileOutline "pick_file" "Pick File" "Opens the file browser to pick a file." "" "" }
{PickFolder 0 0 `folder:\\"$input\\"` FilePath 0 1 0 0 0 1 1 FolderOpenFilled "pick_folder" "Pick Folder" "Opens the file browser to pick a folder." "" "" } {PickFolder 0 0 0 `folder:\\"$input\\"` FilePath 0 1 0 0 0 1 1 FolderOpenFilled "pick_folder" "Pick Folder" "Opens the file browser to pick a folder." "" "" }
{PickFileOrFolder 0 0 `folder:\\"$input\\"` FilePath 1 1 0 0 0 1 1 FileOutline "pick_file_or_folder" "Pick File/Folder" "Opens the file browser to pick a file or folder." "" "" } {PickFileOrFolder 0 0 0 `folder:\\"$input\\"` FilePath 1 1 0 0 0 1 1 FileOutline "pick_file_or_folder" "Pick File/Folder" "Opens the file browser to pick a file or folder." "" "" }
//- rjf: query stack //- rjf: query stack
{PushQuery 0 0 "" Null 0 0 0 0 0 0 0 Null "push_query" "Push Query" "Opens a new temporary query interface." "" "" } {PushQuery 0 0 0 "" Null 0 0 0 0 0 0 0 Null "push_query" "Push Query" "Opens a new temporary query interface." "" "" }
{CompleteQuery 0 0 "" Null 0 0 0 0 0 0 0 Null "complete_query" "Complete Query" "Completes and closes a query." "" "" } {CompleteQuery 0 0 0 "" Null 0 0 0 0 0 0 0 Null "complete_query" "Complete Query" "Completes and closes a query." "" "" }
{CancelQuery 0 0 "" Null 0 0 0 0 0 0 0 Null "cancel_query" "Cancel Query" "Closes a query." "" "" } {CancelQuery 0 0 0 "" Null 0 0 0 0 0 0 0 Null "cancel_query" "Cancel Query" "Closes a query." "" "" }
{UpdateQuery 0 0 "" Null 0 0 0 0 0 0 0 Null "update_query" "Update Query" "Updates a query input." "" "" } {UpdateQuery 0 0 0 "" Null 0 0 0 0 0 0 0 Null "update_query" "Update Query" "Updates a query input." "" "" }
//- rjf: event buffers //- rjf: event buffers
{OpenEventBuffer 0 1 "" Null 0 0 0 0 0 0 0 Null "open_event_buffer" "Open Event Buffer" "Opens a new event buffer, to which debugger events will be written, for external processing." "" "" } {OpenEventBuffer 0 0 1 "" Null 0 0 0 0 0 0 0 Null "open_event_buffer" "Open Event Buffer" "Opens a new event buffer, to which debugger events will be written, for external processing." "" "" }
{CloseEventBuffer 0 1 "" Cfg 0 0 0 0 0 0 0 Null "close_event_buffer" "Close Event Buffer" "Closes an existing event buffer." "" "" } {CloseEventBuffer 0 0 1 "" Cfg 0 0 0 0 0 0 0 Null "close_event_buffer" "Close Event Buffer" "Closes an existing event buffer." "" "" }
//- rjf: developer commands //- rjf: developer commands
{ToggleDevMenu 1 1 "" Null 0 0 0 0 0 0 0 Null "toggle_dev_menu" "Toggle Developer Menu" "Opens and closes the developer menu." "" "" } {ToggleDevMenu 0 1 1 "" Null 0 0 0 0 0 0 0 Null "toggle_dev_menu" "Toggle Developer Menu" "Opens and closes the developer menu." "" "" }
{LogMarker 1 1 "" Null 0 0 0 0 0 0 0 Null "log_marker" "Log Marker" "Logs a marker in the application log, to denote specific points in time within the log." "" "" } {LogMarker 0 1 1 "" Null 0 0 0 0 0 0 0 Null "log_marker" "Log Marker" "Logs a marker in the application log, to denote specific points in time within the log." "" "" }
} }
@enum RD_CmdKind: @enum RD_CmdKind:
@@ -1370,6 +1376,7 @@ RD_DefaultBindingTable:
{ "accept" Space 0 0 0 } { "accept" Space 0 0 0 }
{ "cancel" Esc 0 0 0 } { "cancel" Esc 0 0 0 }
{ "focus_menu" D 0 0 alt } { "focus_menu" D 0 0 alt }
{ "toggle_lock" L ctrl 0 0 }
//- rjf: directional movement & text controls //- rjf: directional movement & text controls
{ "move_left" Left 0 0 0 } { "move_left" Left 0 0 0 }
@@ -2522,7 +2529,7 @@ raddbg_readme:
@p "**Configuration files (users and projects):** The RAD Debugger stores configuration in two files. One is the 'user file', the other is the 'project file'. Both files are the same format and can store the same kinds of data, but the user file is preferred by the debugger for more likely user-related data (windows, keybindings, theme), and the project file is preferred by the debugger for more likely project-related data (executable debugging targets, breakpoints, recent source files). Project files are more likely to be what you'd check into source control, whereas a user file is more likely to have your personal debugger settings (which will apply identically regardless of which project file is opened)."; @p "**Configuration files (users and projects):** The RAD Debugger stores configuration in two files. One is the 'user file', the other is the 'project file'. Both files are the same format and can store the same kinds of data, but the user file is preferred by the debugger for more likely user-related data (windows, keybindings, theme), and the project file is preferred by the debugger for more likely project-related data (executable debugging targets, breakpoints, recent source files). Project files are more likely to be what you'd check into source control, whereas a user file is more likely to have your personal debugger settings (which will apply identically regardless of which project file is opened).";
@p "The debugger autosaves user and project files. You do not need to manually save them. To switch which path you are using for either, you can use the `Open User` (Ctrl + Alt + Shift + O, by default), or `Open Project` (Ctrl + Alt + O, by default) commands respectively. If a file does not exist at the path you enter for either, then a new one will be created, and the debugger will begin autosaving to it. If the initial paths to these files are not specified on the command line (via `--user` or `--project`), then the debugger uses default paths for them. The user file path, by default, will be `%appdata%/raddbg/default.raddbg_user`. The project file path will be whatever project path was last loaded for the user, or if no such path exists, `%appdata%/raddbg/default.raddbg_project`. If you suspect that your configuration files are corrupted or causing the debugger to behave poorly, it might help to delete your `%appdata%/raddbg` folder (although it'd also help if you [sent it to us in a bug report](https://github.com/EpicGamesExt/raddebugger/issues), so that we can investigate why they were corrupted to begin with!)."; @p "The debugger autosaves user and project files. You do not need to manually save them. To switch which path you are using for either, you can use the `Open User` (Ctrl + Alt + Shift + O, by default), or `Open Project` (Ctrl + Alt + O, by default) commands respectively. If a file does not exist at the path you enter for either, then a new one will be created, and the debugger will begin autosaving to it. If the initial paths to these files are not specified on the command line (via `--user` or `--project`), then the debugger uses default paths for them. The user file path, by default, will be `%appdata%/raddbg/default.raddbg_user`. The project file path will be whatever project path was last loaded for the user, or if no such path exists, `%appdata%/raddbg/default.raddbg_project`. If you suspect that your configuration files are corrupted or causing the debugger to behave poorly, it might help to delete your `%appdata%/raddbg` folder (although it'd also help if you [sent it to us in a bug report](https://github.com/EpicGames/raddebugger/issues), so that we can investigate why they were corrupted to begin with!).";
@p "For more information, see the `**User & Project Files** section."; @p "For more information, see the `**User & Project Files** section.";
@p "**Watch tabs and visualizers:** 'Watch' tabs in the RAD Debugger allow entering expressions, which can reference variables in your program, and visualize what their value is when your program is stopped at a particular time. These expressions roughly follow C expression syntax, but there are a number of extensions which can be used to visualize expressions in a more useful way. Here are some examples:"; @p "**Watch tabs and visualizers:** 'Watch' tabs in the RAD Debugger allow entering expressions, which can reference variables in your program, and visualize what their value is when your program is stopped at a particular time. These expressions roughly follow C expression syntax, but there are a number of extensions which can be used to visualize expressions in a more useful way. Here are some examples:";
+314 -99
View File
@@ -1671,13 +1671,6 @@ rd_view_ui(Rng2F32 rect)
vs->query_string_size = Min(sizeof(vs->query_buffer), current_input.size); vs->query_string_size = Min(sizeof(vs->query_buffer), current_input.size);
MemoryCopy(vs->query_buffer, current_input.str, vs->query_string_size); MemoryCopy(vs->query_buffer, current_input.str, vs->query_string_size);
//- rjf: clamp cursor
if(vs->query_cursor.column == 0)
{
vs->query_mark = txt_pt(1, 1);
vs->query_cursor = txt_pt(1, vs->query_string_size+1);
}
//- rjf: determine dimensions //- rjf: determine dimensions
F32 search_row_height_target = ui_top_px_height(); F32 search_row_height_target = ui_top_px_height();
F32 search_row_height = search_row_open_t*search_row_height_target; F32 search_row_height = search_row_open_t*search_row_height_target;
@@ -2041,7 +2034,7 @@ rd_view_ui(Rng2F32 rect)
{ {
if(expr_string.size == 0) if(expr_string.size == 0)
{ {
expr_string = str8f(scratch.arena, "query:config.$%I64x.watches", rd_regs()->view); expr_string = str8f(scratch.arena, "query:config.$%I64x.watch_expressions", rd_regs()->view);
} }
E_Eval eval = e_eval_from_string(expr_string); E_Eval eval = e_eval_from_string(expr_string);
RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState); RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState);
@@ -2056,6 +2049,35 @@ rd_view_ui(Rng2F32 rect)
ewv->text_edit_arena = rd_push_view_arena(); ewv->text_edit_arena = rd_push_view_arena();
} }
//////////////////////////////
//- rjf: adjust locked expressions which have been invalidated
//
for(CFG_Node *child = view->first; child != &cfg_nil_node; child = child->next)
{
if(str8_match(child->string, s("watch_expression"), 0))
{
CFG_Node *locked = cfg_node_child_from_string(child, s("locked"));
if(locked != &cfg_nil_node)
{
CFG_Node *pid_cfg = cfg_node_child_from_string_or_alloc(rd_state->cfg, locked, s("pid"));
U64 pid = u64_from_str8(pid_cfg->first->string, 10);
D_Entity *process = d_process_from_id(pid);
if(process == &d_entity_nil)
{
D_Entity *current_process = d_entity_from_handle(rd_regs()->process);
if(current_process != &d_entity_nil)
{
cfg_node_new_replacef(rd_state->cfg, pid_cfg, "%I64u", current_process->id);
}
else
{
cfg_node_release(rd_state->cfg, locked);
}
}
}
}
}
////////////////////////////// //////////////////////////////
//- rjf: unpack arguments //- rjf: unpack arguments
// //
@@ -2622,8 +2644,8 @@ rd_view_ui(Rng2F32 rect)
RD_WatchViewTextEditState *edit_state = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState, 1); RD_WatchViewTextEditState *edit_state = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState, 1);
SLLStackPush_N(ewv->text_edit_state_slots[slot_idx], edit_state, pt_hash_next); SLLStackPush_N(ewv->text_edit_state_slots[slot_idx], edit_state, pt_hash_next);
edit_state->pt = pt; edit_state->pt = pt;
edit_state->cursor = txt_pt(1, string.size+1); edit_state->cursor = string.size;
edit_state->mark = txt_pt(1, 1); edit_state->mark = 0;
edit_state->input_size = string.size; edit_state->input_size = string.size;
MemoryCopy(edit_state->input_buffer, string.str, string.size); MemoryCopy(edit_state->input_buffer, string.str, string.size);
edit_state->initial_size = string.size; edit_state->initial_size = string.size;
@@ -2701,6 +2723,79 @@ rd_view_ui(Rng2F32 rect)
} }
} }
//////////////////////////
//- rjf: [table] do cell-granularity lock operations
//
if(!ewv->text_editing &&
(evt->slot == UI_EventActionSlot_Lock ||
evt->slot == UI_EventActionSlot_Unlock ||
evt->slot == UI_EventActionSlot_ToggleLock) &&
(selection_tbl.min.y != 0 || selection_tbl.max.y != 0))
{
EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1));
EV_WindowedRowNode *row_node = rows.first;
if(row_node != 0)
{
taken = 1;
B32 next_locked = 0;
B32 found_next_locked = 0;
for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row_node != 0; y += 1, row_node = row_node->next)
{
// rjf: unpack row info
EV_Row *row = &row_node->row;
RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row);
CFG_Node *cfg = row_info.group_cfg_child;
// rjf: determine if row can be locked
B32 row_can_be_locked = 0;
if(str8_match(row_info.group_cfg_name, s("watch_expression"), 0) &&
cfg != &cfg_nil_node &&
row->eval.string.size != 0)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
B32 is_memory_eval = (space.kind == D_EvalSpaceKind_Entity && entity->kind == D_EntityKind_Process);
row_can_be_locked = (is_memory_eval &&
(row->eval.irtree.mode == E_Mode_Offset) ||
(row->eval.irtree.mode == E_Mode_Value &&
e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)))));
}
// rjf: determine if row is locked
B32 row_is_locked = (cfg_node_child_from_string(cfg, s("locked")) != &cfg_nil_node);
if(row_can_be_locked && !found_next_locked)
{
found_next_locked = 1;
next_locked = !row_is_locked;
}
// rjf: toggle lock on row
if(row_can_be_locked)
{
if(next_locked)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
CFG_Node *locked = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, s("locked"));
cfg_node_release_all_children(rd_state->cfg, locked);
CFG_Node *mid = cfg_node_new(rd_state->cfg, locked, s("mid"));
cfg_node_newf(rd_state->cfg, mid, "%I64u", entity->handle.machine_id);
CFG_Node *pid = cfg_node_new(rd_state->cfg, locked, s("pid"));
cfg_node_newf(rd_state->cfg, pid, "%I64u", entity->id);
CFG_Node *addr = cfg_node_new(rd_state->cfg, locked, s("addr"));
cfg_node_newf(rd_state->cfg, addr, "0x%I64x", row->eval.value.u64);
CFG_Node *type = cfg_node_new(rd_state->cfg, locked, s("type"));
cfg_node_new(rd_state->cfg, type, e_type_string_from_key(scratch.arena, row->eval.irtree.type_key));
}
else
{
cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, s("locked")));
}
}
}
}
}
////////////////////////// //////////////////////////
//- rjf: [text] apply textual edits //- rjf: [text] apply textual edits
// //
@@ -2733,10 +2828,10 @@ rd_view_ui(Rng2F32 rect)
RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)};
RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt); RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt);
String8 string = str8(edit_state->input_buffer, edit_state->input_size); String8 string = str8(edit_state->input_buffer, edit_state->input_size);
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, r1u64(0, string.size), edit_state->cursor, edit_state->mark);
// rjf: copy // rjf: copy
if(op.flags & UI_TxtOpFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y) if(evt->flags & UI_EventFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
@@ -2748,13 +2843,13 @@ rd_view_ui(Rng2F32 rect)
CFG_Node *window = cfg_node_from_id(rd_regs()->window); CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window); RD_WindowState *ws = rd_window_state_from_cfg(window);
RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info;
String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_string); String8 new_string = ui_push_string_replace_range(scratch.arena, string, autocomp_cursor_info->replaced_range, autocomplete_string);
new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size); new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size);
MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size);
edit_state->input_size = new_string.size; edit_state->input_size = new_string.size;
edit_state->cursor = edit_state->mark = txt_pt(1, 1+autocomp_cursor_info->replaced_range.min+autocomplete_string.size); edit_state->cursor = edit_state->mark = autocomp_cursor_info->replaced_range.min+autocomplete_string.size;
string = str8(edit_state->input_buffer, edit_state->input_size); string = str8(edit_state->input_buffer, edit_state->input_size);
op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, r1u64(0, string.size), edit_state->cursor, edit_state->mark);
} }
// rjf: cancel? -> revert to initial string // rjf: cancel? -> revert to initial string
@@ -2765,9 +2860,9 @@ rd_view_ui(Rng2F32 rect)
// rjf: obtain edited string // rjf: obtain edited string
String8 new_string = string; String8 new_string = string;
if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) if(op.range.min != op.range.max || op.replace.size != 0)
{ {
new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(op.range.min.column, op.range.max.column), op.replace); new_string = ui_push_string_replace_range(scratch.arena, string, op.range, op.replace);
} }
// rjf: commit to edit state // rjf: commit to edit state
@@ -2785,13 +2880,13 @@ rd_view_ui(Rng2F32 rect)
{ {
CFG_Node *cfg = row_info.group_cfg_child; CFG_Node *cfg = row_info.group_cfg_child;
String8 child_key = {0}; // str8_lit("expression"); String8 child_key = {0}; // str8_lit("expression");
if(str8_match(row_info.group_cfg_name, s("watch_expression"), 0))
{
child_key = s("expression");
}
if(cfg == &cfg_nil_node && editing_complete && new_string.size != 0) if(cfg == &cfg_nil_node && editing_complete && new_string.size != 0)
{ {
CFG_Node *new_cfg_parent = row_info.group_cfg_parent; CFG_Node *new_cfg_parent = row_info.group_cfg_parent;
if(new_cfg_parent != &cfg_nil_node)
{
child_key = str8_zero();
}
if(new_cfg_parent == &cfg_nil_node) if(new_cfg_parent == &cfg_nil_node)
{ {
CFG_NodePtrList all_cfgs = cfg_node_top_level_list_from_string(scratch.arena, row_info.group_cfg_name); CFG_NodePtrList all_cfgs = cfg_node_top_level_list_from_string(scratch.arena, row_info.group_cfg_name);
@@ -3533,8 +3628,9 @@ rd_view_ui(Rng2F32 rect)
if(cfg == &cfg_nil_node) if(cfg == &cfg_nil_node)
{ {
cfg = cfg_node_alloc(rd_state->cfg); cfg = cfg_node_alloc(rd_state->cfg);
cfg_node_equip_stringf(rd_state->cfg, cfg, "watch"); cfg_node_equip_stringf(rd_state->cfg, cfg, "watch_expression");
cfg_node_new(rd_state->cfg, cfg, drag_regs->expr); CFG_Node *expr = cfg_node_new(rd_state->cfg, cfg, s("expression"));
cfg_node_new(rd_state->cfg, expr, drag_regs->expr);
} }
cfg_node_insert_child(rd_state->cfg, drag_parent_cfg, drag_prev_cfg, cfg); cfg_node_insert_child(rd_state->cfg, drag_parent_cfg, drag_prev_cfg, cfg);
}break; }break;
@@ -4030,9 +4126,33 @@ rd_view_ui(Rng2F32 rect)
needle = str8_skip_last_slash(needle); needle = str8_skip_last_slash(needle);
} }
// rjf: determine if this cell can be locked
B32 cell_can_be_locked = 0;
if(str8_match(row_info->group_cfg_name, s("watch_expression"), 0) &&
!(cell_info.flags & RD_WatchCellFlag_Expr) &&
cell->eval.string.size != 0)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
B32 is_memory_eval = (space.kind == D_EvalSpaceKind_Entity && entity->kind == D_EntityKind_Process);
cell_can_be_locked = (is_memory_eval &&
(cell->eval.irtree.mode == E_Mode_Offset) ||
(cell->eval.irtree.mode == E_Mode_Value &&
e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(cell->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)))));
}
// rjf: determine if this cell is locked
B32 cell_is_locked = 0;
if(cell_can_be_locked)
{
CFG_Node *cfg = row_info->group_cfg_child;
cell_is_locked = (cfg_node_child_from_string(cfg, s("locked")) != &cfg_nil_node);
}
// rjf: form cell build parameters // rjf: form cell build parameters
UI_Key line_edit_key = {0}; UI_Key line_edit_key = {0};
RD_CellParams cell_params = {0}; RD_CellParams cell_params = {0};
B32 next_cell_is_locked = cell_is_locked;
ProfScope("form cell build parameters") ProfScope("form cell build parameters")
{ {
E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key); E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key);
@@ -4048,6 +4168,7 @@ rd_view_ui(Rng2F32 rect)
cell_params.edit_string_size_out = &cell_edit_state->input_size; cell_params.edit_string_size_out = &cell_edit_state->input_size;
cell_params.line_edit_key_out = &line_edit_key; cell_params.line_edit_key_out = &line_edit_key;
cell_params.expanded_out = &next_row_expanded; cell_params.expanded_out = &next_row_expanded;
cell_params.lock_out = &next_cell_is_locked;
cell_params.search_needle = needle; cell_params.search_needle = needle;
cell_params.meta_fstrs = cell_info.expr_fstrs; cell_params.meta_fstrs = cell_info.expr_fstrs;
cell_params.value_fstrs = cell_info.eval_fstrs; cell_params.value_fstrs = cell_info.eval_fstrs;
@@ -4117,7 +4238,7 @@ rd_view_ui(Rng2F32 rect)
cells_are_editable && cells_are_editable &&
row->eval.expr == &e_expr_nil) row->eval.expr == &e_expr_nil)
{ {
ghost_text = str8_lit("Expression"); ghost_text = s("Add an expression to watch...");
is_non_code = (!cell_selected || !ewv->text_editing); is_non_code = (!cell_selected || !ewv->text_editing);
cell_params.flags &= ~(RD_CellFlag_Expander|RD_CellFlag_ExpanderSpace|RD_CellFlag_ExpanderPlaceholder); cell_params.flags &= ~(RD_CellFlag_Expander|RD_CellFlag_ExpanderSpace|RD_CellFlag_ExpanderPlaceholder);
} }
@@ -4151,6 +4272,12 @@ rd_view_ui(Rng2F32 rect)
cell_params.flags &= ~RD_CellFlag_NoBackground; cell_params.flags &= ~RD_CellFlag_NoBackground;
} }
// rjf: watch expression values -> lock
if(cell_can_be_locked)
{
cell_params.flags |= RD_CellFlag_Lock;
}
// rjf: apply toggle-switch // rjf: apply toggle-switch
if(is_toggle_switch) if(is_toggle_switch)
{ {
@@ -4235,11 +4362,38 @@ rd_view_ui(Rng2F32 rect)
} }
if(ui_is_focus_active() && if(ui_is_focus_active() &&
selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y &&
txt_pt_match(cell_edit_state->cursor, cell_edit_state->mark)) cell_edit_state->cursor == cell_edit_state->mark)
{ {
String8 input = str8(cell_edit_state->input_buffer, cell_edit_state->input_size); String8 input = str8(cell_edit_state->input_buffer, cell_edit_state->input_size);
rd_set_autocomp_regs(cell->eval, .ui_key = line_edit_key, .string = input, .cursor = cell_edit_state->cursor); rd_set_autocomp_regs(cell->eval, .ui_key = line_edit_key, .string = input, .cursor = cell_edit_state->cursor);
} }
// rjf: apply locks
{
CFG_Node *cfg = row_info->group_cfg_child;
if(next_cell_is_locked != cell_is_locked && cfg != &cfg_nil_node)
{
if(next_cell_is_locked)
{
E_Space space = row->eval.space;
D_Entity *entity = rd_ctrl_entity_from_eval_space(space);
CFG_Node *locked = cfg_node_child_from_string_or_alloc(rd_state->cfg, cfg, s("locked"));
cfg_node_release_all_children(rd_state->cfg, locked);
CFG_Node *mid = cfg_node_new(rd_state->cfg, locked, s("mid"));
cfg_node_newf(rd_state->cfg, mid, "%I64u", entity->handle.machine_id);
CFG_Node *pid = cfg_node_new(rd_state->cfg, locked, s("pid"));
cfg_node_newf(rd_state->cfg, pid, "%I64u", entity->id);
CFG_Node *addr = cfg_node_new(rd_state->cfg, locked, s("addr"));
cfg_node_newf(rd_state->cfg, addr, "0x%I64x", row->eval.value.u64);
CFG_Node *type = cfg_node_new(rd_state->cfg, locked, s("type"));
cfg_node_new(rd_state->cfg, type, e_type_string_from_key(scratch.arena, row->eval.irtree.type_key));
}
else
{
cfg_node_release(rd_state->cfg, cfg_node_child_from_string(cfg, s("locked")));
}
}
}
} }
} }
@@ -4548,7 +4702,11 @@ rd_view_ui(Rng2F32 rect)
{ {
String8 file_path = lines.first->v.file_path; String8 file_path = lines.first->v.file_path;
TxtPt pt = lines.first->v.pt; TxtPt pt = lines.first->v.pt;
rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = file_path, .cursor = pt, .vaddr = vaddr, rd_cmd(RD_CmdKind_FindCodeLocation,
.file_path = file_path,
.line_num = (U64)pt.line,
.column_num = (U64)pt.column,
.vaddr = vaddr,
.process = process->handle, .process = process->handle,
.module = module->handle, .module = module->handle,
.dbgi_key = dbgi_key); .dbgi_key = dbgi_key);
@@ -4562,7 +4720,11 @@ rd_view_ui(Rng2F32 rect)
RD_Location loc = rd_location_from_cfg(cfg); RD_Location loc = rd_location_from_cfg(cfg);
if(loc.file_path.size != 0) if(loc.file_path.size != 0)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, .vaddr = 0, .file_path = loc.file_path, .cursor = loc.pt); rd_cmd(RD_CmdKind_FindCodeLocation,
.vaddr = 0,
.file_path = loc.file_path,
.line_num = (U64)loc.pt.line,
.column_num = (U64)loc.pt.column);
} }
else if(loc.expr.size != 0) else if(loc.expr.size != 0)
{ {
@@ -4594,7 +4756,7 @@ rd_view_ui(Rng2F32 rect)
// rjf: is file eval? -> switch to file // rjf: is file eval? -> switch to file
else if(cell_info.file_path.size != 0) else if(cell_info.file_path.size != 0)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, .cfg = 0, .file_path = cell_info.file_path, .cursor = txt_pt(0, 0)); rd_cmd(RD_CmdKind_FindCodeLocation, .cfg = 0, .file_path = cell_info.file_path, .line_num = 0, .column_num = 0);
} }
} }
@@ -5943,8 +6105,10 @@ rd_window_frame(void)
#undef Handle #undef Handle
ui_labelf("file_path: \"%S\"", regs->file_path); ui_labelf("file_path: \"%S\"", regs->file_path);
ui_labelf("expr: \"%S\"", regs->expr); ui_labelf("expr: \"%S\"", regs->expr);
ui_labelf("cursor: (L:%I64d, C:%I64d)", regs->cursor.line, regs->cursor.column); ui_labelf("cursor: %I64u", regs->cursor);
ui_labelf("mark: (L:%I64d, C:%I64d)", regs->mark.line, regs->mark.column); ui_labelf("mark: %I64u", regs->mark);
ui_labelf("line_num: %I64u", regs->line_num);
ui_labelf("column_num: %I64u", regs->column_num);
ui_labelf("unwind_count: %I64u", regs->unwind_count); ui_labelf("unwind_count: %I64u", regs->unwind_count);
ui_labelf("inline_depth: %I64u", regs->inline_depth); ui_labelf("inline_depth: %I64u", regs->inline_depth);
ui_labelf("text_key: [0x%I64x / 0x%I64x:0x%I64x]", regs->text_key.root.u64[0], regs->text_key.id.u128[0].u64[0], regs->text_key.id.u128[0].u64[1]); ui_labelf("text_key: [0x%I64x / 0x%I64x:0x%I64x]", regs->text_key.root.u64[0], regs->text_key.id.u128[0].u64[0], regs->text_key.id.u128[0].u64[1]);
@@ -6086,12 +6250,14 @@ rd_window_frame(void)
{ {
Vec2F32 window_dim = dim_2f32(window_rect); Vec2F32 window_dim = dim_2f32(window_rect);
UI_Box *bg_box = &ui_nil_box; UI_Box *bg_box = &ui_nil_box;
Vec4F32 shadow_color = ui_color_from_name(str8_lit("drop_shadow"));
shadow_color.w += (1.f - shadow_color.w) * 0.5f;
UI_Rect(window_rect) UI_Rect(window_rect)
UI_ChildLayoutAxis(Axis2_X) UI_ChildLayoutAxis(Axis2_X)
UI_Focus(UI_FocusKind_On) UI_Focus(UI_FocusKind_On)
UI_BlurSize(10*rd_state->popup_t)
UI_Transparency(1-rd_state->popup_t) UI_Transparency(1-rd_state->popup_t)
UI_TagF("floating") UI_TagF("floating")
UI_BackgroundColor(shadow_color)
{ {
bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize| bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize|
UI_BoxFlag_Floating| UI_BoxFlag_Floating|
@@ -6099,14 +6265,22 @@ rd_window_frame(void)
UI_BoxFlag_Scroll| UI_BoxFlag_Scroll|
UI_BoxFlag_DefaultFocusNav| UI_BoxFlag_DefaultFocusNav|
UI_BoxFlag_DisableFocusOverlay| UI_BoxFlag_DisableFocusOverlay|
UI_BoxFlag_DrawBackgroundBlur| UI_BoxFlag_DisableFocusBorder|
UI_BoxFlag_DrawBackground, "###popup_%p", ws); UI_BoxFlag_DrawBackground, "###popup_%p", ws);
} }
if(rd_state->popup_active) UI_Parent(bg_box) UI_Transparency(1-rd_state->popup_t) if(rd_state->popup_active) UI_Parent(bg_box) UI_Transparency(1-rd_state->popup_t)
{ {
ui_ctx_menu_close(); ui_ctx_menu_close();
UI_WidthFill UI_PrefHeight(ui_children_sum(1.f)) UI_Column UI_Padding(ui_pct(1, 0)) UI_WidthFill UI_PrefHeight(ui_children_sum(1.f)) UI_Column UI_Padding(ui_pct(1, 0)) UI_TagF("floating")
{ {
ui_set_next_blur_size(10*rd_state->popup_t);
ui_set_next_pref_width(ui_children_sum(1));
ui_set_next_pref_height(ui_children_sum(1));
ui_set_next_child_layout_axis(Axis2_Y);
UI_Box *panel = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawDropShadow, "");
UI_Parent(panel)
{
ui_spacer(ui_em(1.5f, 1.f));
UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Main)) UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(rd_state->popup_title); UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Main)) UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(rd_state->popup_title);
UI_PrefHeight(ui_em(3.f, 1.f)) UI_TagF("weak") ui_label(rd_state->popup_desc); UI_PrefHeight(ui_em(3.f, 1.f)) UI_TagF("weak") ui_label(rd_state->popup_desc);
ui_spacer(ui_em(1.5f, 1.f)); ui_spacer(ui_em(1.5f, 1.f));
@@ -6126,6 +6300,7 @@ rd_window_frame(void)
ui_spacer(ui_em(3.f, 1.f)); ui_spacer(ui_em(3.f, 1.f));
} }
} }
}
ui_signal_from_box(bg_box); ui_signal_from_box(bg_box);
} }
} }
@@ -6579,7 +6754,7 @@ rd_window_frame(void)
} }
if(!ui_key_match(ui_key_zero(), ws->query_regs->ui_key)) if(!ui_key_match(ui_key_zero(), ws->query_regs->ui_key))
{ {
query_width_px = is_small ? (ui_top_font_size()*30.f) : (ui_top_font_size()*60.f); query_width_px = is_small ? (ui_top_font_size()*40.f) : (ui_top_font_size()*60.f);
max_query_height_px = is_small ? (ui_top_font_size()*40.f) : (ui_top_font_size()*80.f); max_query_height_px = is_small ? (ui_top_font_size()*40.f) : (ui_top_font_size()*80.f);
} }
F32 query_height_px = max_query_height_px; F32 query_height_px = max_query_height_px;
@@ -7197,7 +7372,7 @@ rd_window_frame(void)
UI_Row UI_Padding(ui_pct(1, 0)) UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(ui_top_font_size()*2.f, 1)) UI_Row UI_Padding(ui_pct(1, 0)) UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(ui_top_font_size()*2.f, 1))
UI_CornerRadius(ui_top_font_size()*0.5f) UI_CornerRadius(ui_top_font_size()*0.5f)
{ {
String8 url = str8_lit("https://github.com/EpicGamesExt/raddebugger/issues"); String8 url = str8_lit("https://github.com/EpicGames/raddebugger/issues");
UI_Signal sig = ui_button(str8_lit("Submit request, issue, or bug report")); UI_Signal sig = ui_button(str8_lit("Submit request, issue, or bug report"));
if(ui_clicked(sig)) if(ui_clicked(sig))
{ {
@@ -7655,7 +7830,7 @@ rd_window_frame(void)
ui_box_equip_display_fstrs(label, &fstrs); ui_box_equip_display_fstrs(label, &fstrs);
if(ui_clicked(sig)) if(ui_clicked(sig))
{ {
wm_open_in_browser(s("https://github.com/EpicGamesExt/raddebugger/releases/latest")); wm_open_in_browser(s("https://github.com/EpicGames/raddebugger/releases/latest"));
} }
} }
@@ -8004,6 +8179,7 @@ rd_window_frame(void)
{ {
if(panel->first != &cfg_nil_panel_node) {continue;} if(panel->first != &cfg_nil_panel_node) {continue;}
B32 panel_is_focused = (window_is_focused && B32 panel_is_focused = (window_is_focused &&
!rd_state->popup_active &&
!ws->menu_bar_focused && !ws->menu_bar_focused &&
!query_is_open && !query_is_open &&
!ui_any_ctx_menu_is_open() && !ui_any_ctx_menu_is_open() &&
@@ -9597,7 +9773,7 @@ rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs)
U64 cursor_arg_idx = 0; U64 cursor_arg_idx = 0;
if(expr_based_replace) if(expr_based_replace)
{ {
U64 cursor_off = (U64)(regs->cursor.column-1); U64 cursor_off = regs->cursor;
E_Parse parse = e_parse_from_string(regs->string); E_Parse parse = e_parse_from_string(regs->string);
//- rjf: cursor offset -> cursor containing node //- rjf: cursor offset -> cursor containing node
@@ -9802,8 +9978,10 @@ rd_code_color_slot_from_txt_token_kind(TXT_TokenKind kind)
case TXT_TokenKind_Keyword: {color = RD_CodeColorSlot_CodeKeyword;}break; case TXT_TokenKind_Keyword: {color = RD_CodeColorSlot_CodeKeyword;}break;
case TXT_TokenKind_Numeric: {color = RD_CodeColorSlot_CodeNumeric;}break; case TXT_TokenKind_Numeric: {color = RD_CodeColorSlot_CodeNumeric;}break;
case TXT_TokenKind_String: {color = RD_CodeColorSlot_CodeString;}break; case TXT_TokenKind_String: {color = RD_CodeColorSlot_CodeString;}break;
case TXT_TokenKind_Char: {color = RD_CodeColorSlot_CodeString;}break;
case TXT_TokenKind_Meta: {color = RD_CodeColorSlot_CodeMeta;}break; case TXT_TokenKind_Meta: {color = RD_CodeColorSlot_CodeMeta;}break;
case TXT_TokenKind_Comment:{color = RD_CodeColorSlot_CodeComment;}break; case TXT_TokenKind_LineComment: {color = RD_CodeColorSlot_CodeComment;}break;
case TXT_TokenKind_BlockComment:{color = RD_CodeColorSlot_CodeComment;}break;
case TXT_TokenKind_Symbol: {color = RD_CodeColorSlot_CodeDelimiterOperator;}break; case TXT_TokenKind_Symbol: {color = RD_CodeColorSlot_CodeDelimiterOperator;}break;
} }
return color; return color;
@@ -10088,7 +10266,7 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, D_Event *event)
//~ rjf: Source File Checksum Calculations //~ rjf: Source File Checksum Calculations
internal AC_Artifact internal AC_Artifact
rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) rd_md5_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out)
{ {
AC_Artifact result = {0}; AC_Artifact result = {0};
{ {
@@ -10105,7 +10283,7 @@ rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_ou
} }
internal AC_Artifact internal AC_Artifact
rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) rd_sha1_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out)
{ {
AC_Artifact result = {0}; AC_Artifact result = {0};
{ {
@@ -10122,7 +10300,7 @@ rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_o
} }
internal AC_Artifact internal AC_Artifact
rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out) rd_sha256_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out)
{ {
AC_Artifact result = {0}; AC_Artifact result = {0};
{ {
@@ -10478,20 +10656,21 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 query_expr, String8 strin
case RD_RegSlot_FilePath: case RD_RegSlot_FilePath:
{ {
String8TxtPtPair pair = str8_txt_pt_pair_from_string(string); String8TxtPtPair pair = str8_txt_pt_pair_from_string(string);
rd_regs()->string = push_str8_copy(rd_frame_arena(), string); rd_regs()->string = str8_copy(rd_frame_arena(), string);
if(pair.pt.line != 0) if(pair.pt.line != 0)
{ {
rd_regs()->file_path = push_str8_copy(rd_frame_arena(), pair.string); rd_regs()->file_path = str8_copy(rd_frame_arena(), pair.string);
rd_regs()->cursor = pair.pt; rd_regs()->line_num = (U64)pair.pt.line;
rd_regs()->column_num = (U64)pair.pt.column;
} }
}break; }break;
case RD_RegSlot_Expr: case RD_RegSlot_Expr:
{ {
rd_regs()->expr = push_str8_copy(rd_frame_arena(), string); rd_regs()->expr = str8_copy(rd_frame_arena(), string);
}break; }break;
case RD_RegSlot_CmdName: case RD_RegSlot_CmdName:
{ {
rd_regs()->cmd_name = push_str8_copy(rd_frame_arena(), string); rd_regs()->cmd_name = str8_copy(rd_frame_arena(), string);
}break; }break;
//- rjf: ctrl entities //- rjf: ctrl entities
@@ -10563,13 +10742,12 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 query_expr, String8 strin
}break; }break;
//- rjf: line numbers //- rjf: line numbers
case RD_RegSlot_Cursor: case RD_RegSlot_LineNum:
{ {
E_Eval eval = e_value_eval_from_eval(e_eval_from_string(string)); E_Eval eval = e_value_eval_from_eval(e_eval_from_string(string));
if(eval.msgs.max_kind == E_MsgKind_Null) if(eval.msgs.max_kind == E_MsgKind_Null)
{ {
rd_regs()->cursor.column = 1; rd_regs()->line_num = eval.value.u64;
rd_regs()->cursor.line = (S64)eval.value.u64;
} }
else else
{ {
@@ -11168,7 +11346,9 @@ rd_frame(void)
rd_state->hover_regs_slot = RD_RegSlot_Null; rd_state->hover_regs_slot = RD_RegSlot_Null;
} }
B32 allow_text_hotkeys = !rd_state->text_edit_mode; B32 allow_text_hotkeys = !rd_state->text_edit_mode;
B32 allow_text_multiline_hotkeys = !rd_state->text_edit_mode_multiline;
rd_state->text_edit_mode = 0; rd_state->text_edit_mode = 0;
rd_state->text_edit_mode_multiline = 0;
if(rd_state->frame_depth == 1) if(rd_state->frame_depth == 1)
{ {
arena_clear(rd_state->cmd_output_arena); arena_clear(rd_state->cmd_output_arena);
@@ -11688,7 +11868,7 @@ rd_frame(void)
if(key_map_nodes.first != 0) if(key_map_nodes.first != 0)
{ {
U32 hit_char = wm_codepoint_from_modifiers_and_key(event->modifiers, event->key); U32 hit_char = wm_codepoint_from_modifiers_and_key(event->modifiers, event->key);
if(hit_char == 0 || allow_text_hotkeys) if((allow_text_hotkeys || hit_char == 0 || (hit_char == '\n' && allow_text_multiline_hotkeys)))
{ {
String8 cmd_name = key_map_nodes.first->v->name; String8 cmd_name = key_map_nodes.first->v->name;
for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1) for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1)
@@ -11699,11 +11879,8 @@ rd_frame(void)
} }
} }
rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name); rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name);
if(allow_text_hotkeys)
{
wm_text(&events, event->window, hit_char); wm_text(&events, event->window, hit_char);
next = event->next; next = event->next;
}
take = 1; take = 1;
if(event->modifiers & WM_Modifier_Alt) if(event->modifiers & WM_Modifier_Alt)
{ {
@@ -11719,7 +11896,7 @@ rd_frame(void)
} }
//- rjf: try text events //- rjf: try text events
if(!take && event->kind == WM_EventKind_Text) if(!take && event->kind == WM_EventKind_Text && (event->character != '\n' || !allow_text_multiline_hotkeys))
{ {
String32 insertion32 = str32(&event->character, 1); String32 insertion32 = str32(&event->character, 1);
String8 insertion8 = str8_from_32(scratch.arena, insertion32); String8 insertion8 = str8_from_32(scratch.arena, insertion32);
@@ -12183,10 +12360,10 @@ rd_frame(void)
{ {
continue; continue;
} }
if(str8_match(child->string, str8_lit("watch"), 0)) if(str8_match(child->string, str8_lit("watch_expression"), 0))
{ {
CFG_Node *watch = child; CFG_Node *watch = child;
String8 expr = watch->first->string; String8 expr = cfg_node_child_from_string(watch, s("expression"))->first->string;
E_Parse parse = e_parse_from_string(expr); E_Parse parse = e_parse_from_string(expr);
if(parse.msgs.max_kind == E_MsgKind_Null) if(parse.msgs.max_kind == E_MsgKind_Null)
{ {
@@ -12288,12 +12465,17 @@ rd_frame(void)
} }
if(kind == D_EntityKind_Process && d_handle_match(rd_base_regs()->process, entity->handle)) if(kind == D_EntityKind_Process && d_handle_match(rd_base_regs()->process, entity->handle))
{ {
e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_process"), expr); e_string2expr_map_insert(scratch.arena, macro_map, s("current_process"), expr);
} }
if(kind == D_EntityKind_Module && d_handle_match(rd_base_regs()->module, entity->handle)) if(kind == D_EntityKind_Module && d_handle_match(rd_base_regs()->module, entity->handle))
{ {
e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_module"), expr); e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_module"), expr);
} }
if(kind == D_EntityKind_Process)
{
String8 pid_string = str8f(scratch.arena, "process_%I64u", entity->id);
e_string2expr_map_insert(scratch.arena, macro_map, pid_string, expr);
}
} }
} }
@@ -12379,10 +12561,10 @@ rd_frame(void)
.id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment), .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment),
.num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment), .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment),
})); }));
e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watches"), e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watch_expressions"),
e_type_key_cons(.kind = E_TypeKind_Set, e_type_key_cons(.kind = E_TypeKind_Set,
.flags = E_TypeFlag_EditableChildren|E_TypeFlag_StubSingleLineExpansion, .flags = E_TypeFlag_EditableChildren|E_TypeFlag_StubSingleLineExpansion,
.name = str8_lit("watches"), .name = str8_lit("watch_expressions"),
.irext = E_TYPE_IREXT_FUNCTION_NAME(watches), .irext = E_TYPE_IREXT_FUNCTION_NAME(watches),
.access = E_TYPE_ACCESS_FUNCTION_NAME(watches), .access = E_TYPE_ACCESS_FUNCTION_NAME(watches),
.expand = .expand =
@@ -12841,7 +13023,7 @@ rd_frame(void)
{ {
.id = 1, .id = 1,
.method = HTTP_Method_Get, .method = HTTP_Method_Get,
.url = s("https://api.github.com/repos/EpicGamesExt/raddebugger/releases/latest"), .url = s("https://api.github.com/repos/EpicGames/raddebugger/releases/latest"),
.user_agent = s("raddebugger"), .user_agent = s("raddebugger"),
}; };
http_push_request(rd_state->update_check_http_ring, &p, 0); http_push_request(rd_state->update_check_http_ring, &p, 0);
@@ -13028,7 +13210,8 @@ rd_frame(void)
params.entity = rd_regs()->ctrl_entity; params.entity = rd_regs()->ctrl_entity;
params.string = rd_regs()->string; params.string = rd_regs()->string;
params.file_path = rd_regs()->file_path; params.file_path = rd_regs()->file_path;
params.cursor = rd_regs()->cursor; params.line_num = rd_regs()->line_num;
params.column_num = rd_regs()->column_num;
params.vaddr = rd_regs()->vaddr; params.vaddr = rd_regs()->vaddr;
params.prefer_disasm = rd_regs()->prefer_disasm; params.prefer_disasm = rd_regs()->prefer_disasm;
params.pid = rd_regs()->pid; params.pid = rd_regs()->pid;
@@ -13106,7 +13289,12 @@ rd_frame(void)
{ {
current_path_string = path_normalized_from_string(scratch.arena, get_current_path(scratch.arena)); current_path_string = path_normalized_from_string(scratch.arena, get_current_path(scratch.arena));
} }
String8 file_path = wm_graphical_pick_file(scratch.arena, current_path_string); String8 cmd_title = rd_display_from_code_name(info->string);
if(cmd_title.size == 0)
{
cmd_title = info->string;
}
String8 file_path = wm_graphical_pick_file(scratch.arena, cmd_title, current_path_string);
file_path = path_normalized_from_string(scratch.arena, file_path); file_path = path_normalized_from_string(scratch.arena, file_path);
if(file_path.size != 0) if(file_path.size != 0)
{ {
@@ -14650,7 +14838,7 @@ rd_frame(void)
case RD_CmdKind_OpenSourceFileFromDebugInfo: case RD_CmdKind_OpenSourceFileFromDebugInfo:
{ {
String8 path = rd_regs()->file_path; String8 path = rd_regs()->file_path;
rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = path, .cursor = txt_pt(0, 0), .vaddr = 0, .force_focus = 1, .prefer_new_tab = 1); rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = path, .line_num = 0, .vaddr = 0, .force_focus = 1, .prefer_new_tab = 1);
}break; }break;
case RD_CmdKind_SwitchToPartnerFile: case RD_CmdKind_SwitchToPartnerFile:
{ {
@@ -14677,7 +14865,7 @@ rd_frame(void)
FileProperties candidate_props = properties_from_file_path(candidate_path); FileProperties candidate_props = properties_from_file_path(candidate_path);
if(candidate_props.modified != 0) if(candidate_props.modified != 0)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = candidate_path, .cursor = txt_pt(0, 0), .vaddr = 0, .prefer_new_tab = 1); rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = candidate_path, .line_num = 0, .vaddr = 0, .prefer_new_tab = 1);
break; break;
} }
} }
@@ -14713,7 +14901,8 @@ rd_frame(void)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, rd_cmd(RD_CmdKind_FindCodeLocation,
.file_path = rd_regs()->lines.first->v.file_path, .file_path = rd_regs()->lines.first->v.file_path,
.cursor = rd_regs()->lines.first->v.pt, .line_num = (U64)rd_regs()->lines.first->v.pt.line,
.column_num= (U64)rd_regs()->lines.first->v.pt.column,
.vaddr = 0, .vaddr = 0,
.process = d_handle_zero(), .process = d_handle_zero(),
.prefer_disasm = 0); .prefer_disasm = 0);
@@ -15015,7 +15204,8 @@ rd_frame(void)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, rd_cmd(RD_CmdKind_FindCodeLocation,
.file_path = line.file_path, .file_path = line.file_path,
.cursor = line.pt, .line_num = (U64)line.pt.line,
.column_num = (U64)line.pt.column,
.process = process->handle, .process = process->handle,
.voff = rip_voff, .voff = rip_voff,
.vaddr = rip_vaddr, .vaddr = rip_vaddr,
@@ -15163,7 +15353,8 @@ rd_frame(void)
} }
rd_cmd(RD_CmdKind_FindCodeLocation, rd_cmd(RD_CmdKind_FindCodeLocation,
.file_path = lines.first->v.file_path, .file_path = lines.first->v.file_path,
.cursor = lines.first->v.pt, .line_num = (U64)lines.first->v.pt.line,
.column_num= (U64)lines.first->v.pt.column,
.process = process->handle, .process = process->handle,
.module = module->handle, .module = module->handle,
.vaddr = module->vaddr_range.min + lines.first->v.voff_range.min); .vaddr = module->vaddr_range.min + lines.first->v.voff_range.min);
@@ -15173,7 +15364,7 @@ rd_frame(void)
// rjf: name resolved to a file path // rjf: name resolved to a file path
if(name_resolved && file_path.size != 0) if(name_resolved && file_path.size != 0)
{ {
rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = file_path, .cursor = txt_pt(1, 1), .vaddr = 0); rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = file_path, .line_num = 0, .vaddr = 0);
} }
} }
}break; }break;
@@ -15225,7 +15416,8 @@ rd_frame(void)
//- rjf: grab things to find. path * point, process * address, etc. //- rjf: grab things to find. path * point, process * address, etc.
String8 file_path = {0}; String8 file_path = {0};
TxtPt point = {0}; U64 line_num = 0;
U64 column_num = 0;
D_Entity *thread = &d_entity_nil; D_Entity *thread = &d_entity_nil;
D_Entity *process = &d_entity_nil; D_Entity *process = &d_entity_nil;
U64 vaddr = 0; U64 vaddr = 0;
@@ -15233,7 +15425,8 @@ rd_frame(void)
B32 prefer_new_tab = 0; B32 prefer_new_tab = 0;
{ {
file_path = rd_mapped_from_file_path(scratch.arena, rd_regs()->file_path); file_path = rd_mapped_from_file_path(scratch.arena, rd_regs()->file_path);
point = rd_regs()->cursor; line_num = rd_regs()->line_num;
column_num = rd_regs()->column_num;
thread = d_entity_from_handle(rd_regs()->thread); thread = d_entity_from_handle(rd_regs()->thread);
process = d_entity_from_handle(rd_regs()->process); process = d_entity_from_handle(rd_regs()->process);
vaddr = rd_regs()->vaddr; vaddr = rd_regs()->vaddr;
@@ -15262,7 +15455,7 @@ rd_frame(void)
// try to map the src coordinates to a vaddr via line info // try to map the src coordinates to a vaddr via line info
if(vaddr == 0 && file_path.size != 0) if(vaddr == 0 && file_path.size != 0)
{ {
D_LineList lines = d_lines_from_file_path_line_num(scratch.arena, file_path, point.line, max_U64); D_LineList lines = d_lines_from_file_path_line_num(scratch.arena, file_path, (S64)line_num, max_U64);
for(D_LineNode *n = lines.first; n != 0; n = n->next) for(D_LineNode *n = lines.first; n != 0; n = n->next)
{ {
D_EntityList modules = d_modules_from_dbgi_key(scratch.arena, n->v.dbgi_key); D_EntityList modules = d_modules_from_dbgi_key(scratch.arena, n->v.dbgi_key);
@@ -15769,9 +15962,9 @@ rd_frame(void)
rd_cmd(RD_CmdKind_FocusPanel); rd_cmd(RD_CmdKind_FocusPanel);
} }
rd_cmd(RD_CmdKind_FocusTab); rd_cmd(RD_CmdKind_FocusTab);
if(point.line != 0) if(line_num != 0)
{ {
rd_cmd(RD_CmdKind_GoToLine, .cursor = point); rd_cmd(RD_CmdKind_GoToLine, .line_num = line_num);
} }
rd_cmd(cursor_snap_kind); rd_cmd(cursor_snap_kind);
} }
@@ -16037,12 +16230,12 @@ rd_frame(void)
{ {
if(!vs->query_is_open && cmd_kind_info->query.flags & RD_QueryFlag_SelectOldInput) if(!vs->query_is_open && cmd_kind_info->query.flags & RD_QueryFlag_SelectOldInput)
{ {
vs->query_cursor = txt_pt(1, 1+input->first->string.size); vs->query_cursor = input->first->string.size;
vs->query_mark = txt_pt(1, 1); vs->query_mark = 0;
} }
else else
{ {
vs->query_cursor = txt_pt(1, 1+input->first->string.size); vs->query_cursor = input->first->string.size;
vs->query_mark = vs->query_cursor; vs->query_mark = vs->query_cursor;
} }
if(!str8_match(current_query_cmd_name, cmd_name, 0)) if(!str8_match(current_query_cmd_name, cmd_name, 0))
@@ -16114,8 +16307,8 @@ rd_frame(void)
CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input"));
cfg_node_new_replace(rd_state->cfg, input, rd_regs()->string); cfg_node_new_replace(rd_state->cfg, input, rd_regs()->string);
RD_ViewState *vs = rd_view_state_from_cfg(view); RD_ViewState *vs = rd_view_state_from_cfg(view);
vs->query_cursor = vs->query_mark = txt_pt(1, rd_regs()->string.size+1);
vs->query_string_size = Min(sizeof(vs->query_buffer), rd_regs()->string.size); vs->query_string_size = Min(sizeof(vs->query_buffer), rd_regs()->string.size);
vs->query_cursor = vs->query_mark = vs->query_string_size;
MemoryCopy(vs->query_buffer, rd_regs()->string.str, vs->query_string_size); MemoryCopy(vs->query_buffer, rd_regs()->string.str, vs->query_string_size);
}break; }break;
@@ -16222,17 +16415,18 @@ rd_frame(void)
// rjf: attach new location info // rjf: attach new location info
{ {
String8 file_path = rd_regs()->file_path; String8 file_path = rd_regs()->file_path;
TxtPt pt = rd_regs()->cursor; U64 line_num = rd_regs()->line_num;
U64 column_num = rd_regs()->column_num;
String8 expr_string = rd_regs()->expr; String8 expr_string = rd_regs()->expr;
U64 vaddr = rd_regs()->vaddr; U64 vaddr = rd_regs()->vaddr;
if(expr_string.size == 0 && vaddr != 0) if(expr_string.size == 0 && vaddr != 0)
{ {
expr_string = push_str8f(scratch.arena, "0x%I64x", vaddr); expr_string = push_str8f(scratch.arena, "0x%I64x", vaddr);
} }
if(file_path.size != 0 && pt.line != 0) if(file_path.size != 0 && line_num != 0)
{ {
CFG_Node *src_loc = cfg_node_new(rd_state->cfg, cfg, str8_lit("source_location")); CFG_Node *src_loc = cfg_node_new(rd_state->cfg, cfg, str8_lit("source_location"));
cfg_node_newf(rd_state->cfg, src_loc, "%S:%I64d:%I64d", file_path, pt.line, pt.column); cfg_node_newf(rd_state->cfg, src_loc, "%S:%I64u:%I64u", file_path, line_num, column_num);
} }
else if(expr_string.size != 0) else if(expr_string.size != 0)
{ {
@@ -16254,12 +16448,13 @@ rd_frame(void)
case RD_CmdKind_ToggleBreakpoint: case RD_CmdKind_ToggleBreakpoint:
{ {
String8 file_path = rd_regs()->file_path; String8 file_path = rd_regs()->file_path;
TxtPt pt = rd_regs()->cursor; U64 line_num = rd_regs()->line_num;
U64 column_num = rd_regs()->column_num;
U64 vaddr = rd_regs()->vaddr; U64 vaddr = rd_regs()->vaddr;
String8 expr = rd_regs()->expr; String8 expr = rd_regs()->expr;
if(expr.size == 0 && vaddr != 0) if(expr.size == 0 && vaddr != 0)
{ {
expr = push_str8f(scratch.arena, "0x%I64x", vaddr); expr = str8f(scratch.arena, "0x%I64x", vaddr);
} }
if(file_path.size != 0 || expr.size != 0) if(file_path.size != 0 || expr.size != 0)
{ {
@@ -16271,7 +16466,7 @@ rd_frame(void)
CFG_Node *bp = n->v; CFG_Node *bp = n->v;
CFG_Node *cnd = cfg_node_child_from_string(bp, str8_lit("condition")); CFG_Node *cnd = cfg_node_child_from_string(bp, str8_lit("condition"));
RD_Location loc = rd_location_from_cfg(bp); RD_Location loc = rd_location_from_cfg(bp);
B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == line_num);
B32 loc_matches_expr = (expr.size != 0 && str8_match(expr, loc.expr, 0)); B32 loc_matches_expr = (expr.size != 0 && str8_match(expr, loc.expr, 0));
if((loc_matches_file_pt || loc_matches_expr) && cnd->first->string.size == 0) if((loc_matches_file_pt || loc_matches_expr) && cnd->first->string.size == 0)
{ {
@@ -16336,7 +16531,8 @@ rd_frame(void)
case RD_CmdKind_ToggleWatchPin: case RD_CmdKind_ToggleWatchPin:
{ {
String8 file_path = rd_regs()->file_path; String8 file_path = rd_regs()->file_path;
TxtPt pt = rd_regs()->cursor; U64 line_num = rd_regs()->line_num;
U64 column_num = rd_regs()->column_num;
String8 expr_string = rd_regs()->expr; String8 expr_string = rd_regs()->expr;
U64 vaddr = rd_regs()->vaddr; U64 vaddr = rd_regs()->vaddr;
B32 removed_already_existing = 0; B32 removed_already_existing = 0;
@@ -16348,7 +16544,7 @@ rd_frame(void)
CFG_Node *wp = n->v; CFG_Node *wp = n->v;
CFG_Node *expr = cfg_node_child_from_string(wp, str8_lit("expression")); CFG_Node *expr = cfg_node_child_from_string(wp, str8_lit("expression"));
RD_Location loc = rd_location_from_cfg(wp); RD_Location loc = rd_location_from_cfg(wp);
B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == (S64)line_num);
B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr_string, loc.expr, 0)); B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr_string, loc.expr, 0));
if((loc_matches_file_pt || loc_matches_expr) && str8_match(expr->first->string, expr_string, 0)) if((loc_matches_file_pt || loc_matches_expr) && str8_match(expr->first->string, expr_string, 0))
{ {
@@ -16545,7 +16741,7 @@ rd_frame(void)
{ {
continue; continue;
} }
if(str8_match(child->string, str8_lit("watch"), 0) && str8_match(child->first->string, rd_regs()->string, 0)) if(str8_match(child->string, str8_lit("watch_expression"), 0) && str8_match(child->first->string, rd_regs()->string, 0))
{ {
existing_watch = child; existing_watch = child;
break; break;
@@ -16561,8 +16757,9 @@ rd_frame(void)
// rjf: otherwise, create it // rjf: otherwise, create it
else if(watch_tab != &cfg_nil_node) else if(watch_tab != &cfg_nil_node)
{ {
CFG_Node *watch = cfg_node_new(rd_state->cfg, watch_tab, str8_lit("watch")); CFG_Node *watch = cfg_node_new(rd_state->cfg, watch_tab, s("watch_expression"));
cfg_node_new(rd_state->cfg, watch, rd_regs()->string); CFG_Node *expr = cfg_node_new(rd_state->cfg, watch, s("expression"));
cfg_node_new(rd_state->cfg, expr, rd_regs()->string);
} }
}break; }break;
@@ -16574,20 +16771,11 @@ rd_frame(void)
RD_Regs *regs = rd_regs(); RD_Regs *regs = rd_regs();
C_Key text_key = regs->text_key; C_Key text_key = regs->text_key;
TXT_LangKind lang_kind = regs->lang_kind; TXT_LangKind lang_kind = regs->lang_kind;
TxtRng range = txt_rng(regs->cursor, regs->mark); Rng1U64 range = r1u64(regs->cursor, regs->mark);
U128 hash = {0}; U128 hash = {0};
TXT_TextInfo info = txt_text_info_from_key_lang(access, text_key, lang_kind, &hash); TXT_TextInfo info = txt_text_info_from_key_lang(access, text_key, lang_kind, &hash);
String8 data = c_data_from_hash(access, hash); String8 data = c_data_from_hash(access, hash);
Rng1U64 expr_off_range = {0}; String8 expr = str8_substr(data, range);
if(range.min.column != range.max.column)
{
expr_off_range = r1u64(txt_off_from_info_pt(&info, range.min), txt_off_from_info_pt(&info, range.max));
}
else
{
expr_off_range = txt_expr_off_range_from_info_data_pt(&info, data, range.min);
}
String8 expr = str8_substr(data, expr_off_range);
rd_cmd((kind == RD_CmdKind_GoToNameAtCursor ? RD_CmdKind_GoToName : rd_cmd((kind == RD_CmdKind_GoToNameAtCursor ? RD_CmdKind_GoToName :
kind == RD_CmdKind_ToggleWatchExpressionAtCursor ? RD_CmdKind_ToggleWatchExpression : kind == RD_CmdKind_ToggleWatchExpressionAtCursor ? RD_CmdKind_ToggleWatchExpression :
RD_CmdKind_GoToName), RD_CmdKind_GoToName),
@@ -16820,6 +17008,33 @@ rd_frame(void)
evt.slot = UI_EventActionSlot_FocusMenu; evt.slot = UI_EventActionSlot_FocusMenu;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt); ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break; }break;
case RD_CmdKind_Lock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_Lock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
case RD_CmdKind_Unlock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_Unlock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
case RD_CmdKind_ToggleLock:
{
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window);
UI_Event evt = zero_struct;
evt.kind = UI_EventKind_Press;
evt.slot = UI_EventActionSlot_ToggleLock;
ui_event_list_push(scratch.arena, &ws->ui_events, &evt);
}break;
//- rjf: directional movement & text controls //- rjf: directional movement & text controls
// //
+6 -5
View File
@@ -152,8 +152,8 @@ struct RD_ViewState
// rjf: query state // rjf: query state
B32 query_is_open; B32 query_is_open;
TxtPt query_cursor; U64 query_cursor;
TxtPt query_mark; U64 query_mark;
U8 query_buffer[KB(1)]; U8 query_buffer[KB(1)];
U64 query_string_size; U64 query_string_size;
@@ -496,6 +496,7 @@ struct RD_State
// rjf: text editing mode state // rjf: text editing mode state
B32 text_edit_mode; B32 text_edit_mode;
B32 text_edit_mode_multiline;
// rjf: contextual hover info // rjf: contextual hover info
RD_Regs *hover_regs; RD_Regs *hover_regs;
@@ -794,9 +795,9 @@ internal DR_FStrList rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, D_E
//////////////////////////////// ////////////////////////////////
//~ rjf: Source File Checksum Calculations //~ rjf: Source File Checksum Calculations
internal AC_Artifact rd_md5_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out); internal AC_Artifact rd_md5_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out);
internal AC_Artifact rd_sha1_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out); internal AC_Artifact rd_sha1_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out);
internal AC_Artifact rd_sha256_artifact_create(String8 key, B32 *cancel_out, B32 *retry_out, U64 *gen_out); internal AC_Artifact rd_sha256_artifact_create(String8 key, B32 *cancel_out, AC_Status *status_out, U64 *gen_out);
internal MD5 rd_md5_from_hash(U128 hash); internal MD5 rd_md5_from_hash(U128 hash);
internal SHA1 rd_sha1_from_hash(U128 hash); internal SHA1 rd_sha1_from_hash(U128 hash);
internal SHA256 rd_sha256_from_hash(U128 hash); internal SHA256 rd_sha256_from_hash(U128 hash);
+20 -2
View File
@@ -1389,7 +1389,7 @@ E_TYPE_IREXT_FUNCTION_DEF(watches)
for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next) for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next)
{ {
if(rd_cfg_is_project_filtered(child)) {continue;} if(rd_cfg_is_project_filtered(child)) {continue;}
if(str8_match(child->string, str8_lit("watch"), 0)) if(str8_match(child->string, str8_lit("watch_expression"), 0))
{ {
cfg_node_ptr_list_push(scratch.arena, &cfgs, child); cfg_node_ptr_list_push(scratch.arena, &cfgs, child);
} }
@@ -1461,7 +1461,25 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
if(cfg_idx < accel->cfgs.count) if(cfg_idx < accel->cfgs.count)
{ {
CFG_Node *cfg = accel->cfgs.v[cfg_idx]; CFG_Node *cfg = accel->cfgs.v[cfg_idx];
evals_out[idx] = e_eval_from_string(cfg->first->string); CFG_Node *expr = cfg_node_child_from_string(cfg, s("expression"));
CFG_Node *locked = cfg_node_child_from_string(cfg, s("locked"));
if(locked->first->string.size != 0)
{
String8 pid = cfg_node_child_from_string(locked, s("pid"))->first->string;
String8 type = cfg_node_child_from_string(locked, s("type"))->first->string;
String8 addr = cfg_node_child_from_string(locked, s("addr"))->first->string;
String8 lock_expr = str8f(arena, "*(cast(%S *)(process_%S.memory + %S))", type, pid, addr);
evals_out[idx] = e_eval_from_string(lock_expr);
evals_out[idx].string = expr->first->string;
if(evals_out[idx].msgs.count != 0)
{
evals_out[idx] = e_eval_from_string(expr->first->string);
}
}
else
{
evals_out[idx] = e_eval_from_string(expr->first->string);
}
} }
} }
} }
+9
View File
@@ -68,6 +68,15 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: post-0.9.27 TODO notes //~ rjf: post-0.9.27 TODO notes
// //
// [ ] beginning usage UI notes (cakezzz)
// [ ] rebinding a hotkey should be much more visually obvious, & add tooltips to '+' button - very ambiguous
// [ ] pass over default layouts - remove tabs that are secondary/tertiary features, like pins/locals/etc.
// [ ] undo/redo for panel layout changes
// [ ] 'are you sure?' step for closing panel
// [ ] show breakpoint trails from any location - very confusing if they are off-screen but resolve to a line
// [ ] we probably want to just cap the breakpoint 'trailing' too? if it's more than like 100 lines away seems dumb...
// [ ] after above, show breakpoint resolution status - if it can't resolve anywhere, suggest as much in the UI (? icon or whatever)
//
// [ ] debug info loading retry mechanism, in cases where the load failed, but settings/filesystem state changes - // [ ] debug info loading retry mechanism, in cases where the load failed, but settings/filesystem state changes -
// e.g. turn on automatic downloads, already tried to load symbol server cache file that doesn't exist -> // e.g. turn on automatic downloads, already tried to load symbol server cache file that doesn't exist ->
// need to retry // need to retry
+410 -147
View File
@@ -12,6 +12,7 @@ rd_code_view_init(RD_CodeViewState *cv)
{ {
cv->initialized = 1; cv->initialized = 1;
cv->preferred_column = 1; cv->preferred_column = 1;
cv->patch_arena = rd_push_view_arena();
cv->find_text_arena = rd_push_view_arena(); cv->find_text_arena = rd_push_view_arena();
cv->center_cursor = 1; cv->center_cursor = 1;
rd_store_view_loading_info(1, 0, 0); rd_store_view_loading_info(1, 0, 0);
@@ -47,6 +48,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
D_Entity *thread = d_entity_from_handle(rd_regs()->thread); D_Entity *thread = d_entity_from_handle(rd_regs()->thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
B32 do_line_numbers = rd_setting_b32_from_name(str8_lit("show_line_numbers")); B32 do_line_numbers = rd_setting_b32_from_name(str8_lit("show_line_numbers"));
B32 text_is_ready = (text_info->lines_count != 0);
////////////////////////////// //////////////////////////////
//- rjf: unpack information about the viewed source file, if any //- rjf: unpack information about the viewed source file, if any
@@ -65,7 +67,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
default: break; default: break;
case RD_CmdKind_GoToLine: case RD_CmdKind_GoToLine:
{ {
cv->goto_line_num = cmd->regs->cursor.line; cv->goto_line_num = cmd->regs->line_num;
}break; }break;
case RD_CmdKind_CenterCursor: case RD_CmdKind_CenterCursor:
{ {
@@ -119,6 +121,230 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
cv->wrap_cache_slots = push_array(cv->wrap_arena, RD_CodeViewTLineWrapCacheSlot, cv->wrap_cache_slots_count); cv->wrap_cache_slots = push_array(cv->wrap_arena, RD_CodeViewTLineWrapCacheSlot, cv->wrap_cache_slots_count);
} }
//////////////////////////////
//- rjf: do keyboard interaction, compute patched text state
//
TXT_Patched text_patched = txt_patched_from_info_data_patches(scratch.arena, text_info, text_data, &cv->patches);
B32 snap[Axis2_COUNT] = {0};
UI_Focus(UI_FocusKind_On) if(ui_is_focus_active())
{
CFG_Node *view = cfg_node_from_id(rd_regs()->view);
RD_ViewState *vs = rd_view_state_from_cfg(view);
rd_state->text_edit_mode_multiline = (!vs->query_is_open || vs->contents_are_focused);
rd_state->text_edit_mode = 1;
U64 line_count_per_page = ClampBot(num_possible_visible_lines, 10) - 10;
U64 *cursor = &rd_regs()->cursor;
U64 *mark = &rd_regs()->mark;
S64 *preferred_column = &cv->preferred_column;
for(UI_Event *evt = 0; ui_next_event(&evt);)
{
if(evt->kind != UI_EventKind_Navigate && evt->kind != UI_EventKind_Edit && evt->kind != UI_EventKind_Text)
{
continue;
}
B32 taken = 0;
U64 start_cursor = *cursor;
U64 start_mark = *mark;
Vec2S32 delta = evt->delta_2s32;
U64 line_count = text_patched.line_map.total_line_count;
U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
String8 line = {0};
line.size = dim_1u64(line_range);
line.str = push_array(scratch.arena, U8, line.size);
memory_map_read(&text_patched.memory_map, line_range, line.str);
//- rjf: interpret event as single-line text op
UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, evt, line, line_range, *cursor, *mark);
//- TODO(rjf): skip replace-ranges for now
if(single_line_op.replace.size != 0)
{
continue;
}
//- rjf: apply single-line navigations
*cursor = single_line_op.cursor;
*mark = single_line_op.mark;
//- rjf: determine if we need to navigate
B32 need_nav = (start_cursor == start_mark || !(evt->flags & UI_EventFlag_ZeroDeltaOnSelect));
//- rjf: wrap lines right
if(need_nav && evt->delta_unit != UI_EventDeltaUnit_Whole && evt->delta_unit != UI_EventDeltaUnit_Line && delta.x > 0 && start_cursor == line_range.max && line_num+1 <= line_count)
{
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1);
*cursor = next_line_range.min;
*preferred_column = 1;
}
//- rjf: wrap lines left
if(need_nav && evt->delta_unit != UI_EventDeltaUnit_Whole && evt->delta_unit != UI_EventDeltaUnit_Line && delta.x < 0 && start_cursor == line_range.min && line_num-1 >= 1)
{
Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1);
*cursor = prev_line_range.max;
*preferred_column = (S64)dim_1u64(prev_line_range)+1;
}
//- rjf: movement down (plain)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && line_num+1 <= line_count)
{
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1);
*cursor = next_line_range.min + *preferred_column;
*cursor = clamp_1u64(next_line_range, *cursor);
}
//- rjf: movement up (plain)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && line_num > 1)
{
Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1);
*cursor = prev_line_range.min + *preferred_column;
*cursor = clamp_1u64(prev_line_range, *cursor);
}
//- rjf: movement down (chunk)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && line_num+1 <= line_count)
{
B32 done = 0;
for(U64 scan_line_num = line_num+1; !done && scan_line_num <= line_count; scan_line_num += 1)
{
Temp scratch = scratch_begin(&arena, 1);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
String8 line_without_whitespace = str8_skip_chop_whitespace(line);
if(line_without_whitespace.size == 0)
{
*cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
done = 1;
}
else if(scan_line_num == line_count)
{
*cursor = text_patched.size;
}
scratch_end(scratch);
}
}
//- rjf: movement up (chunk)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && line_num > 1)
{
B32 done = 0;
for(U64 scan_line_num = line_num-1; !done && scan_line_num > 0; scan_line_num -= 1)
{
Temp scratch = scratch_begin(&arena, 1);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
String8 line_without_whitespace = str8_skip_chop_whitespace(line);
if(line_without_whitespace.size == 0)
{
*cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
done = 1;
}
else if(scan_line_num == 1)
{
*cursor = 0;
}
scratch_end(scratch);
}
}
//- rjf: movement down (page)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Page && delta.y > 0)
{
U64 advance = line_count_per_page;
U64 next_line = line_num + advance;
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
}
//- rjf: movement up (page)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Page && delta.y < 0)
{
S64 advance = -line_count_per_page;
if(line_num < line_count_per_page)
{
advance = -(line_num - 1);
}
U64 next_line = (U64)((S64)line_num + advance);
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
}
//- rjf: movement to endpoint (+)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0))
{
*cursor = text_patched.size;
}
//- rjf: movement to endpoint (-)
if(need_nav && evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0))
{
*cursor = 0;
}
//- rjf: get replaced-range; adjust based on multi-line logic
Rng1U64 replaced_range = single_line_op.range;
if(*cursor != single_line_op.cursor && (evt->flags & UI_EventFlag_Delete || evt->string.size != 0))
{
replaced_range = r1u64(*mark, *cursor);
}
//- rjf: in some cases, we want to pick a selection side based on the delta
if(*cursor != *mark && evt->flags & UI_EventFlag_PickSelectSide)
{
if(delta.x < 0 || delta.y < 0)
{
*cursor = *mark = Min(*cursor, *mark);
}
else if(delta.x > 0 || delta.y > 0)
{
*cursor = *mark = Max(*cursor, *mark);
}
}
//- rjf: do copy if needed
if(evt->flags & UI_EventFlag_Copy)
{
String8 text = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(*cursor, *mark));
wm_set_clipboard_text(text);
}
//- rjf: stick mark to cursor, when we don't want to keep it in the same spot
if(!(evt->flags & UI_EventFlag_KeepMark))
{
*mark = *cursor;
}
//- rjf: push patch if we have one
if(replaced_range.max != replaced_range.min || single_line_op.replace.size != 0)
{
txt_patch_list_push_new(cv->patch_arena, &cv->patches, replaced_range, single_line_op.replace);
text_patched = txt_patched_from_info_data_patches(scratch.arena, text_info, text_data, &cv->patches);
*cursor = *mark = replaced_range.min + single_line_op.replace.size;
U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
*preferred_column = (*cursor - line_range.min);
}
//- rjf: consume
ui_eat_event(evt);
//- rjf: changed cursor -> snap in X
if(*cursor != start_cursor)
{
snap[Axis2_X] = 1;
}
//- rjf: changed cursor line -> snap in Y
if(*cursor < line_range.min || line_range.max < *cursor)
{
snap[Axis2_Y] = 1;
}
}
}
////////////////////////////// //////////////////////////////
//- rjf: determine visible line range / count //- rjf: determine visible line range / count
// //
@@ -128,12 +354,12 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
scroll_pos.y.idx + 1 + num_possible_visible_lines); scroll_pos.y.idx + 1 + num_possible_visible_lines);
U64 visible_line_count = 0; U64 visible_line_count = 0;
{ {
visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)text_info->lines_count); visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)text_patched.line_map.total_line_count);
visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)text_info->lines_count); visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)text_patched.line_map.total_line_count);
visible_line_num_range.min = Max(1, visible_line_num_range.min); visible_line_num_range.min = Max(1, visible_line_num_range.min);
visible_line_num_range.max = Max(1, visible_line_num_range.max); visible_line_num_range.max = Max(1, visible_line_num_range.max);
target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)text_info->lines_count); target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)text_patched.line_map.total_line_count);
target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)text_info->lines_count); target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)text_patched.line_map.total_line_count);
target_visible_line_num_range.min = Max(1, target_visible_line_num_range.min); target_visible_line_num_range.min = Max(1, target_visible_line_num_range.min);
target_visible_line_num_range.max = Max(1, target_visible_line_num_range.max); target_visible_line_num_range.max = Max(1, target_visible_line_num_range.max);
visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; visible_line_count = (U64)dim_1s64(visible_line_num_range)+1;
@@ -149,7 +375,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120);
line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x);
scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x);
scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)text_info->lines_count-1); scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)text_patched.line_map.total_line_count-1);
} }
////////////////////////////// //////////////////////////////
@@ -167,12 +393,26 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
priority_margin_width_px = floor_f32(big_glyph_advance*3.5f); priority_margin_width_px = floor_f32(big_glyph_advance*3.5f);
catchall_margin_width_px = floor_f32(big_glyph_advance*3.5f); catchall_margin_width_px = floor_f32(big_glyph_advance*3.5f);
} }
TXT_LineTokensSlice slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, text_info, text_data, visible_line_num_range); Rng1U64 visible_byte_range = r1u64(txt_range_from_line_num(&text_patched.line_map, visible_line_num_range.min).min,
txt_range_from_line_num(&text_patched.line_map, visible_line_num_range.max).max);
String8 visible_data = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, visible_byte_range);
//////////////////////////////
//- rjf: find tokens for visible byte range
//
U64 ctx_token_pt_num = txt_token_pt_num_from_off(&text_patched.token_pt_map, visible_byte_range.min);
TXT_TokenPt ctx_token_pt = txt_token_pt_from_num(&text_patched.token_pt_map, ctx_token_pt_num);
TXT_TokenArray tokens = txt_token_array_from_data(scratch.arena, rd_regs()->lang_kind, ctx_token_pt, visible_data, visible_byte_range.min, max_U64);
////////////////////////////// //////////////////////////////
//- rjf: selection on single line, no query? -> set search text //- rjf: selection on single line, no query? -> set search text
// //
if(rd_regs()->cursor.line == rd_regs()->mark.line) {
U64 cursor = rd_regs()->cursor;
U64 mark = rd_regs()->mark;
U64 cursor_line_num = txt_line_num_from_off(&text_patched.line_map, cursor);
Rng1U64 cursor_line_range = txt_range_from_line_num(&text_patched.line_map, cursor_line_num);
if(cursor_line_range.min <= mark && mark <= cursor_line_range.max)
{ {
CFG_Node *view = cfg_node_from_id(rd_regs()->view); CFG_Node *view = cfg_node_from_id(rd_regs()->view);
RD_ViewState *vs = rd_view_state_from_cfg(view); RD_ViewState *vs = rd_view_state_from_cfg(view);
@@ -180,7 +420,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
{ {
CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query")); CFG_Node *query = cfg_node_child_from_string_or_alloc(rd_state->cfg, view, str8_lit("query"));
CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input")); CFG_Node *input = cfg_node_child_from_string_or_alloc(rd_state->cfg, query, str8_lit("input"));
String8 text = txt_string_from_info_data_txt_rng(text_info, text_data, txt_rng(rd_regs()->cursor, rd_regs()->mark)); String8 text = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(cursor, mark));
if(text.size < 256) if(text.size < 256)
{ {
cfg_node_new_replace(rd_state->cfg, input, text); cfg_node_new_replace(rd_state->cfg, input, text);
@@ -191,6 +431,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
} }
} }
} }
}
////////////////////////////// //////////////////////////////
//- rjf: get active search query //- rjf: get active search query
@@ -235,17 +476,50 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
code_slice_params.line_text_max_width_px = (F32)line_size_x; code_slice_params.line_text_max_width_px = (F32)line_size_x;
code_slice_params.margin_float_off_px = scroll_pos.x.idx + floor_f32(scroll_pos.x.off); code_slice_params.margin_float_off_px = scroll_pos.x.idx + floor_f32(scroll_pos.x.off);
// rjf: fill text info // rjf: fill line text / ranges
{ {
S64 line_num = visible_line_num_range.min; S64 line_num = visible_line_num_range.min;
U64 line_idx = visible_line_num_range.min-1; U64 line_idx = visible_line_num_range.min-1;
for(U64 visible_line_idx = 0; for(U64 visible_line_idx = 0;
visible_line_idx < visible_line_count && line_idx < text_info->lines_count; visible_line_idx < visible_line_count && line_idx < text_patched.line_map.total_line_count;
visible_line_idx += 1, line_idx += 1, line_num += 1) visible_line_idx += 1, line_idx += 1, line_num += 1)
{ {
code_slice_params.line_text[visible_line_idx] = str8_substr(text_data, text_info->lines_ranges[line_idx]); Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
code_slice_params.line_ranges[visible_line_idx] = text_info->lines_ranges[line_idx]; String8 line_text = {0};
code_slice_params.line_tokens[visible_line_idx] = slice.line_tokens[visible_line_idx]; line_text.size = dim_1u64(line_range);
line_text.str = push_array(scratch.arena, U8, line_text.size);
memory_map_read(&text_patched.memory_map, line_range, line_text.str);
code_slice_params.line_text[visible_line_idx] = line_text;
code_slice_params.line_ranges[visible_line_idx] = line_range;
}
}
// rjf: bucket tokens by line
{
U64 token_idx = 0;
for EachIndex(line_idx, visible_line_count)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
Rng1U64 line_range = code_slice_params.line_ranges[line_idx];
TXT_TokenList line_tokens = {0};
for(;token_idx < tokens.count;)
{
Rng1U64 token_range = tokens.v[token_idx].range;
if(dim_1u64(intersect_1u64(token_range, line_range)) != 0)
{
txt_token_list_push(scratch2.arena, &line_tokens, &tokens.v[token_idx]);
}
if(token_range.max <= line_range.max || token_range.max <= line_range.min)
{
token_idx += 1;
}
else if(line_range.max <= token_range.max)
{
break;
}
}
code_slice_params.line_tokens[line_idx] = txt_token_array_from_list(scratch.arena, &line_tokens);
scratch_end(scratch2);
} }
} }
@@ -487,111 +761,100 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
//- rjf: do searching operations //- rjf: do searching operations
// //
{ {
U64 search_chunk_size = KB(4);
//- rjf: find text (forward) //- rjf: find text (forward)
if(cv->find_text_fwd.size != 0) if(cv->find_text_fwd.size != 0)
{ {
String8 needle = cv->find_text_fwd;
Rng1U64 ranges[] =
{
r1u64(rd_regs()->cursor+1, text_patched.size),
r1u64(0, rd_regs()->cursor+1),
};
B32 found = 0; B32 found = 0;
B32 first = 1; for EachElement(range_idx, ranges)
S64 line_num_start = rd_regs()->cursor.line;
S64 line_num_last = (S64)text_info->lines_count;
for(S64 line_num = line_num_start; 1 <= line_num && line_num <= line_num_last; first = 0)
{ {
// rjf: gather line info for(U64 off = ranges[range_idx].min; off < ranges[range_idx].max; off += search_chunk_size)
String8 line_string = str8_substr(text_data, text_info->lines_ranges[line_num-1]);
U64 search_start = 0;
if(rd_regs()->cursor.line == line_num && first)
{ {
search_start = rd_regs()->cursor.column; Temp scratch = scratch_begin(&arena, 1);
} String8 data = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(off, off+search_chunk_size));
U64 hint_needle_pos = str8_find_needle(data, 0, needle, StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy);
// rjf: search string if(hint_needle_pos < data.size)
U64 needle_pos = str8_find_needle(line_string, search_start, cv->find_text_fwd, StringMatchFlag_CaseInsensitive); {
if(needle_pos < line_string.size) String8 candidate = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(off+hint_needle_pos, off+hint_needle_pos+needle.size));
if(str8_match(candidate, needle, StringMatchFlag_CaseInsensitive))
{ {
rd_regs()->mark.line = line_num;
rd_regs()->mark.column = needle_pos+1;
rd_regs()->cursor = rd_regs()->mark;
rd_regs()->cursor.column += cv->find_text_fwd.size;
found = 1; found = 1;
break; rd_regs()->mark = off+hint_needle_pos;
rd_regs()->cursor = rd_regs()->mark + needle.size;
} }
}
// rjf: break if circled back around to cursor scratch_end(scratch);
else if(line_num == line_num_start && !first) if(found) { goto done_fwd; }
}
}
done_fwd:;
if(!found)
{ {
break; log_user_errorf("Could not find `%S`", needle);
}
// rjf: increment
line_num += 1;
if(line_num > line_num_last)
{
line_num = 1;
}
} }
cv->center_cursor = found; cv->center_cursor = found;
if(found == 0)
{
log_user_errorf("Could not find `%S`", cv->find_text_fwd);
}
} }
//- rjf: find text (backward) //- rjf: find text (backward)
if(cv->find_text_bwd.size != 0) if(cv->find_text_bwd.size != 0 && rd_regs()->cursor > 0)
{ {
String8 needle = cv->find_text_bwd;
Rng1U64 ranges[] =
{
r1u64(0, Min(rd_regs()->cursor, rd_regs()->mark)),
r1u64(rd_regs()->cursor+1, text_patched.size),
};
B32 found = 0; B32 found = 0;
B32 first = 1; for EachElement(range_idx, ranges)
TxtRng rng = txt_rng(rd_regs()->cursor, rd_regs()->mark);
S64 line_num_start = rng.min.line;
S64 line_num_last = (S64)text_info->lines_count;
for(S64 line_num = line_num_start; 1 <= line_num && line_num <= line_num_last; first = 0)
{ {
// rjf: gather line info U64 start_off = ranges[range_idx].max + (search_chunk_size-1);
String8 line_string = str8_substr(text_data, text_info->lines_ranges[line_num-1]); start_off -= start_off%search_chunk_size;
if(rng.min.line == line_num && first) start_off -= search_chunk_size;
for(U64 off = start_off;; off -= search_chunk_size)
{ {
line_string = str8_prefix(line_string, rng.min.column-1); Temp scratch = scratch_begin(&arena, 1);
String8 data = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(off, Min(off+search_chunk_size, ranges[range_idx].max)));
U64 hint_needle_pos = str8_find_needle(data, 0, needle, StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy);
for(;hint_needle_pos < data.size;)
{
U64 next_hint_needle_pos = str8_find_needle(data, hint_needle_pos+1, needle, StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy);
if(next_hint_needle_pos < data.size)
{
hint_needle_pos = next_hint_needle_pos;
} }
else
// rjf: search string
U64 next_needle_pos = line_string.size;
for(U64 needle_pos = 0; needle_pos < line_string.size;)
{ {
needle_pos = str8_find_needle(line_string, needle_pos, cv->find_text_bwd, StringMatchFlag_CaseInsensitive); break;
if(needle_pos < line_string.size)
{
next_needle_pos = needle_pos;
needle_pos += 1;
} }
} }
if(next_needle_pos < line_string.size) if(hint_needle_pos < data.size)
{
String8 candidate = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(off+hint_needle_pos, off+hint_needle_pos+needle.size));
if(str8_match(candidate, needle, StringMatchFlag_CaseInsensitive))
{ {
rd_regs()->mark.line = line_num;
rd_regs()->mark.column = next_needle_pos+1;
rd_regs()->cursor = rd_regs()->mark;
rd_regs()->cursor.column += cv->find_text_bwd.size;
found = 1; found = 1;
break; rd_regs()->mark = off+hint_needle_pos;
rd_regs()->cursor = rd_regs()->mark + needle.size;
} }
}
// rjf: break if circled back around to cursor line scratch_end(scratch);
else if(line_num == line_num_start && !first) if(found) { goto done_bwd; }
if(off == 0) { break; }
}
}
done_bwd:;
if(!found)
{ {
break; log_user_errorf("Could not find `%S`", needle);
}
// rjf: increment
line_num -= 1;
if(line_num == 0)
{
line_num = line_num_last;
}
} }
cv->center_cursor = found; cv->center_cursor = found;
if(found == 0)
{
log_user_errorf("Could not find `%S`", cv->find_text_bwd);
}
} }
MemoryZeroStruct(&cv->find_text_fwd); MemoryZeroStruct(&cv->find_text_fwd);
@@ -602,27 +865,16 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
////////////////////////////// //////////////////////////////
//- rjf: do goto line //- rjf: do goto line
// //
if(cv->goto_line_num != 0 && text_info->lines_count != 0) if(cv->goto_line_num != 0 && text_is_ready)
{ {
S64 line_num = cv->goto_line_num; S64 line_num = cv->goto_line_num;
cv->goto_line_num = 0; cv->goto_line_num = 0;
line_num = Clamp(1, line_num, text_info->lines_count); line_num = Clamp(1, line_num, text_patched.line_map.total_line_count);
rd_regs()->cursor = rd_regs()->mark = txt_pt(line_num, 1); Rng1U64 range = txt_range_from_line_num(&text_patched.line_map, line_num);
rd_regs()->cursor = rd_regs()->mark = range.min;
cv->center_cursor = !cv->force_contain_only && (!cv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num)); cv->center_cursor = !cv->force_contain_only && (!cv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num));
} }
//////////////////////////////
//- rjf: do keyboard interaction
//
B32 snap[Axis2_COUNT] = {0};
UI_Focus(UI_FocusKind_On)
{
if(ui_is_focus_active() && visible_line_num_range.max >= visible_line_num_range.min)
{
snap[Axis2_X] = snap[Axis2_Y] = rd_do_txt_controls(text_info, text_data, ClampBot(num_possible_visible_lines, 10) - 10, &rd_regs()->cursor, &rd_regs()->mark, &cv->preferred_column);
}
}
////////////////////////////// //////////////////////////////
//- rjf: build container contents //- rjf: build container contents
// //
@@ -662,27 +914,28 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
if(ui_pressed(sig.base) && sig.base.event_flags & WM_Modifier_Ctrl) if(ui_pressed(sig.base) && sig.base.event_flags & WM_Modifier_Ctrl)
{ {
ui_kill_action(); ui_kill_action();
rd_cmd(RD_CmdKind_GoToName, .string = txt_string_from_info_data_txt_rng(text_info, text_data, sig.mouse_expr_rng)); rd_cmd(RD_CmdKind_GoToName, .string = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, sig.mouse_expr_rng));
} }
//- rjf: watch expr at mouse //- rjf: watch expr at mouse
if(cv->watch_expr_at_mouse) if(cv->watch_expr_at_mouse)
{ {
cv->watch_expr_at_mouse = 0; cv->watch_expr_at_mouse = 0;
rd_cmd(RD_CmdKind_ToggleWatchExpression, .string = txt_string_from_info_data_txt_rng(text_info, text_data, sig.mouse_expr_rng)); rd_cmd(RD_CmdKind_ToggleWatchExpression, .string = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, sig.mouse_expr_rng));
} }
} }
////////////////////////////// //////////////////////////////
//- rjf: apply post-build view snapping rules //- rjf: apply post-build view snapping rules
// //
if(text_info->lines_count != 0) if(text_is_ready)
{ {
TxtPt cursor = rd_regs()->cursor; U64 cursor = rd_regs()->cursor;
B32 cursor_in_range = (1 <= cursor.line && cursor.line <= text_info->lines_count); U64 cursor_line_num = txt_line_num_from_off(&text_patched.line_map, cursor);
B32 cursor_in_range = (1 <= cursor_line_num && cursor_line_num <= text_patched.line_map.total_line_count);
// rjf: contain => snap // rjf: contain => snap
if(cv->contain_cursor && text_info->lines_count != 0) if(cv->contain_cursor)
{ {
cv->contain_cursor = 0; cv->contain_cursor = 0;
snap[Axis2_X] = 1; snap[Axis2_X] = 1;
@@ -690,13 +943,14 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
} }
// rjf: center cursor // rjf: center cursor
if(cv->center_cursor && text_info->lines_count != 0) if(cv->center_cursor)
{ {
cv->center_cursor = 0; cv->center_cursor = 0;
if(cursor_in_range) if(cursor_in_range)
{ {
String8 cursor_line = str8_substr(text_data, text_info->lines_ranges[cursor.line-1]); Rng1U64 cursor_line_range = txt_range_from_line_num(&text_patched.line_map, cursor_line_num);
F32 cursor_advance = fnt_dim_from_tag_size_string(code_font, code_font_size, 0, code_tab_size, str8_prefix(cursor_line, cursor.column-1)).x; String8 cursor_line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, cursor_line_range);
F32 cursor_advance = fnt_dim_from_tag_size_string(code_font, code_font_size, 0, code_tab_size, str8_prefix(cursor_line, cursor-cursor_line_range.min)).x;
// rjf: scroll x // rjf: scroll x
{ {
@@ -708,7 +962,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
// rjf: scroll y // rjf: scroll y
{ {
S64 new_idx = (cursor.line-1) - num_possible_visible_lines/2 + 2; S64 new_idx = ((S64)cursor_line_num-1) - num_possible_visible_lines/2 + 2;
new_idx = Clamp(scroll_idx_rng[Axis2_Y].min, new_idx, scroll_idx_rng[Axis2_Y].max); new_idx = Clamp(scroll_idx_rng[Axis2_Y].min, new_idx, scroll_idx_rng[Axis2_Y].max);
ui_scroll_pt_target_idx(&scroll_pos.y, new_idx); ui_scroll_pt_target_idx(&scroll_pos.y, new_idx);
snap[Axis2_Y] = 0; snap[Axis2_Y] = 0;
@@ -719,8 +973,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
// rjf: snap in X // rjf: snap in X
if(snap[Axis2_X] && cursor_in_range) if(snap[Axis2_X] && cursor_in_range)
{ {
String8 cursor_line = str8_substr(text_data, text_info->lines_ranges[cursor.line-1]); Rng1U64 cursor_line_range = txt_range_from_line_num(&text_patched.line_map, cursor_line_num);
S64 cursor_off = (S64)(fnt_dim_from_tag_size_string(code_font, code_font_size, 0, code_tab_size, str8_prefix(cursor_line, cursor.column-1)).x + priority_margin_width_px + catchall_margin_width_px + line_num_width_px); String8 cursor_line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, cursor_line_range);
S64 cursor_off = (S64)(fnt_dim_from_tag_size_string(code_font, code_font_size, 0, code_tab_size, str8_prefix(cursor_line, cursor-cursor_line_range.min)).x + priority_margin_width_px + catchall_margin_width_px + line_num_width_px);
Rng1S64 visible_pixel_range = Rng1S64 visible_pixel_range =
{ {
scroll_pos.x.idx, scroll_pos.x.idx,
@@ -741,13 +996,13 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
// rjf: snap in Y // rjf: snap in Y
if(snap[Axis2_Y]) if(snap[Axis2_Y])
{ {
Rng1S64 cursor_visibility_range = r1s64(cursor.line-4, cursor.line+4); Rng1S64 cursor_visibility_range = r1s64((S64)cursor_line_num-4, (S64)cursor_line_num+4);
cursor_visibility_range.min = ClampBot(0, cursor_visibility_range.min); cursor_visibility_range.min = ClampBot(0, cursor_visibility_range.min);
cursor_visibility_range.max = ClampBot(0, cursor_visibility_range.max); cursor_visibility_range.max = ClampBot(0, cursor_visibility_range.max);
S64 min_delta = Min(0, cursor_visibility_range.min-(target_visible_line_num_range.min)); S64 min_delta = Min(0, cursor_visibility_range.min-(target_visible_line_num_range.min));
S64 max_delta = Max(0, cursor_visibility_range.max-(target_visible_line_num_range.min+num_possible_visible_lines)); S64 max_delta = Max(0, cursor_visibility_range.max-(target_visible_line_num_range.min+num_possible_visible_lines));
S64 new_idx = scroll_pos.y.idx+min_delta+max_delta; S64 new_idx = scroll_pos.y.idx+min_delta+max_delta;
new_idx = Clamp(0, new_idx, (S64)text_info->lines_count-1); new_idx = Clamp(0, new_idx, (S64)text_patched.line_map.total_line_count-1);
ui_scroll_pt_target_idx(&scroll_pos.y, new_idx); ui_scroll_pt_target_idx(&scroll_pos.y, new_idx);
} }
} }
@@ -789,7 +1044,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
////////////////////////////// //////////////////////////////
//- rjf: top-level container interaction (scrolling) //- rjf: top-level container interaction (scrolling)
// //
if(text_info->lines_count != 0) if(text_is_ready)
{ {
UI_Signal sig = ui_signal_from_box(container_box); UI_Signal sig = ui_signal_from_box(container_box);
if(sig.scroll.x != 0) if(sig.scroll.x != 0)
@@ -2079,14 +2334,8 @@ RD_VIEW_UI_FUNCTION_DEF(text)
rd_regs()->file_path = rd_file_path_from_eval(rd_frame_arena(), eval); rd_regs()->file_path = rd_file_path_from_eval(rd_frame_arena(), eval);
rd_regs()->vaddr = 0; rd_regs()->vaddr = 0;
rd_regs()->prefer_disasm = 0; rd_regs()->prefer_disasm = 0;
rd_regs()->cursor.line = rd_view_setting_value_from_name(str8_lit("cursor_line")).s64; rd_regs()->cursor = rd_view_setting_value_from_name(s("cursor")).u64;
rd_regs()->cursor.column = rd_view_setting_value_from_name(str8_lit("cursor_column")).s64; rd_regs()->mark = rd_view_setting_value_from_name(s("mark")).u64;
rd_regs()->mark.line = rd_view_setting_value_from_name(str8_lit("mark_line")).s64;
rd_regs()->mark.column = rd_view_setting_value_from_name(str8_lit("mark_column")).s64;
if(rd_regs()->cursor.line == 0) { rd_regs()->cursor.line = 1; }
if(rd_regs()->cursor.column == 0) { rd_regs()->cursor.column = 1; }
if(rd_regs()->mark.line == 0) { rd_regs()->mark.line = 1; }
if(rd_regs()->mark.column == 0) { rd_regs()->mark.column = 1; }
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, rd_regs()->file_path); String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, rd_regs()->file_path);
Rng1U64 range = rd_space_range_from_eval(eval); Rng1U64 range = rd_space_range_from_eval(eval);
rd_regs()->text_key = rd_key_from_eval_space_range(eval.space, range, 1); rd_regs()->text_key = rd_key_from_eval_space_range(eval.space, range, 1);
@@ -2220,6 +2469,13 @@ RD_VIEW_UI_FUNCTION_DEF(text)
rd_code_view_build(scratch.arena, cv, flags, code_area_rect, hash, data, &info, 0, r1u64(0, 0), di_key_zero()); rd_code_view_build(scratch.arena, cv, flags, code_area_rect, hash, data, &info, 0, r1u64(0, 0), di_key_zero());
} }
//////////////////////////////
//- rjf: produced patched text info, unpack cursor info in patched text
//
TXT_Patched patched = txt_patched_from_info_data_patches(scratch.arena, &info, data, &cv->patches);
U64 cursor_line_num = txt_line_num_from_off(&patched.line_map, rd_regs()->cursor);
Rng1U64 cursor_line_range = txt_range_from_line_num(&patched.line_map, cursor_line_num);
////////////////////////////// //////////////////////////////
//- rjf: unpack cursor info //- rjf: unpack cursor info
// //
@@ -2227,8 +2483,10 @@ RD_VIEW_UI_FUNCTION_DEF(text)
{ {
D_Entity *module = d_entity_from_handle(rd_regs()->module); D_Entity *module = d_entity_from_handle(rd_regs()->module);
DI_Key dbgi_key = d_dbgi_key_from_module(module); DI_Key dbgi_key = d_dbgi_key_from_module(module);
rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, rd_regs()->file_path, rd_regs()->cursor.line, 8); rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, rd_regs()->file_path, (S64)cursor_line_num, 8);
} }
rd_regs()->line_num = cursor_line_num;
rd_regs()->column_num = (rd_regs()->cursor - cursor_line_range.min);
////////////////////////////// //////////////////////////////
//- rjf: determine if file is out-of-date //- rjf: determine if file is out-of-date
@@ -2337,7 +2595,7 @@ RD_VIEW_UI_FUNCTION_DEF(text)
ui_label(rd_regs()->file_path); ui_label(rd_regs()->file_path);
ui_spacer(ui_em(1.5f, 1)); ui_spacer(ui_em(1.5f, 1));
} }
ui_labelf("Line: %I64d, Column: %I64d", rd_regs()->cursor.line, rd_regs()->cursor.column); ui_labelf("Line: %I64d, Column: %I64d, Offset: 0x%I64x", cursor_line_num, 1 + rd_regs()->cursor - cursor_line_range.min, rd_regs()->cursor);
ui_spacer(ui_pct(1, 0)); ui_spacer(ui_pct(1, 0));
ui_labelf("(read only)"); ui_labelf("(read only)");
ui_labelf("%s", ui_labelf("%s",
@@ -2351,10 +2609,8 @@ RD_VIEW_UI_FUNCTION_DEF(text)
////////////////////////////// //////////////////////////////
//- rjf: store params //- rjf: store params
// //
rd_store_view_param_s64(str8_lit("cursor_line"), rd_regs()->cursor.line); rd_store_view_param_u64(s("cursor"), rd_regs()->cursor);
rd_store_view_param_s64(str8_lit("cursor_column"), rd_regs()->cursor.column); rd_store_view_param_u64(s("mark"), rd_regs()->mark);
rd_store_view_param_s64(str8_lit("mark_line"), rd_regs()->mark.line);
rd_store_view_param_s64(str8_lit("mark_column"), rd_regs()->mark.column);
access_close(access); access_close(access);
scratch_end(scratch); scratch_end(scratch);
@@ -2367,8 +2623,8 @@ typedef struct RD_DisasmViewState RD_DisasmViewState;
struct RD_DisasmViewState struct RD_DisasmViewState
{ {
B32 initialized; B32 initialized;
TxtPt cursor; U64 cursor;
TxtPt mark; U64 mark;
D_Handle temp_look_process; D_Handle temp_look_process;
U64 temp_look_vaddr; U64 temp_look_vaddr;
U64 temp_look_run_gen; U64 temp_look_run_gen;
@@ -2390,8 +2646,8 @@ RD_VIEW_UI_FUNCTION_DEF(disasm)
if(dv->initialized == 0) if(dv->initialized == 0)
{ {
dv->initialized = 1; dv->initialized = 1;
dv->cursor = txt_pt(1, 1); dv->cursor = 0;
dv->mark = txt_pt(1, 1); dv->mark = 0;
rd_code_view_init(&dv->cv); rd_code_view_init(&dv->cv);
} }
RD_CodeViewState *cv = &dv->cv; RD_CodeViewState *cv = &dv->cv;
@@ -2563,13 +2819,19 @@ RD_VIEW_UI_FUNCTION_DEF(disasm)
rd_code_view_build(scratch.arena, cv, RD_CodeViewBuildFlag_All, code_area_rect, dasm_text_hash, dasm_text_data, &dasm_text_info, &dasm_info.lines, range, dbgi_key); rd_code_view_build(scratch.arena, cv, RD_CodeViewBuildFlag_All, code_area_rect, dasm_text_hash, dasm_text_data, &dasm_text_info, &dasm_info.lines, range, dbgi_key);
} }
//////////////////////////////
//- rjf: produced patched text info, unpack cursor info in patched text
//
TXT_Patched patched = txt_patched_from_info_data_patches(scratch.arena, &dasm_text_info, dasm_text_data, &cv->patches);
U64 cursor_line_num = txt_line_num_from_off(&patched.line_map, rd_regs()->cursor);
////////////////////////////// //////////////////////////////
//- rjf: unpack cursor info / fill regs //- rjf: unpack cursor info / fill regs
// //
rd_regs()->prefer_disasm = 1; rd_regs()->prefer_disasm = 1;
if(!is_loading && has_disasm) if(!is_loading && has_disasm)
{ {
U64 off = dasm_line_array_code_off_from_idx(&dasm_info.lines, rd_regs()->cursor.line-1); U64 off = dasm_line_array_code_off_from_idx(&dasm_info.lines, cursor_line_num-1);
rd_regs()->vaddr = range.min+off; rd_regs()->vaddr = range.min+off;
rd_regs()->vaddr_range = r1u64(range.min+off, range.min+off); rd_regs()->vaddr_range = r1u64(range.min+off, range.min+off);
rd_regs()->voff_range = d_voff_range_from_vaddr_range(dasm_module, rd_regs()->vaddr_range); rd_regs()->voff_range = d_voff_range_from_vaddr_range(dasm_module, rd_regs()->vaddr_range);
@@ -2589,13 +2851,14 @@ RD_VIEW_UI_FUNCTION_DEF(disasm)
UI_TagF("weak") UI_TagF("weak")
RD_Font(RD_FontSlot_Code) RD_Font(RD_FontSlot_Code)
{ {
U64 cursor_vaddr = (1 <= rd_regs()->cursor.line && rd_regs()->cursor.line <= dasm_info.lines.count) ? (range.min+dasm_info.lines.v[rd_regs()->cursor.line-1].code_off) : 0; U64 cursor_vaddr = (1 <= cursor_line_num && cursor_line_num <= dasm_info.lines.count) ? (range.min+dasm_info.lines.v[cursor_line_num-1].code_off) : 0;
if(dasm_module != &d_entity_nil) if(dasm_module != &d_entity_nil)
{ {
ui_labelf("%S", dasm_module->string); ui_labelf("%S", dasm_module->string);
ui_spacer(ui_em(1.5f, 1)); ui_spacer(ui_em(1.5f, 1));
} }
ui_labelf("Address: 0x%I64x, Line: %I64d, Column: %I64d", cursor_vaddr, rd_regs()->cursor.line, rd_regs()->cursor.column); Rng1U64 cursor_line_range = txt_range_from_line_num(&patched.line_map, cursor_line_num);
ui_labelf("Address: 0x%I64x, Line: %I64d, Column: %I64d", cursor_vaddr, cursor_line_num, 1 + rd_regs()->cursor - cursor_line_range.min);
ui_spacer(ui_pct(1, 0)); ui_spacer(ui_pct(1, 0));
ui_labelf("(read only)"); ui_labelf("(read only)");
ui_labelf("bin"); ui_labelf("bin");
@@ -2629,8 +2892,8 @@ struct RD_MemoryViewState
B32 snap_scroll; B32 snap_scroll;
B32 cell_value_edit_in_progress; B32 cell_value_edit_in_progress;
U8 cell_value_edit_first_digit; U8 cell_value_edit_first_digit;
TxtPt addrbar_cursor; U64 addrbar_cursor;
TxtPt addrbar_mark; U64 addrbar_mark;
U8 addrbar_buffer[1024]; U8 addrbar_buffer[1024];
U64 addrbar_string_size; U64 addrbar_string_size;
B32 addrbar_is_focused; B32 addrbar_is_focused;
@@ -4403,8 +4666,8 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
mv->addrbar_is_focused = 1; mv->addrbar_is_focused = 1;
mv->addrbar_string_size = Min(sizeof(mv->addrbar_buffer), cursor_addr->first->string.size); mv->addrbar_string_size = Min(sizeof(mv->addrbar_buffer), cursor_addr->first->string.size);
MemoryCopy(mv->addrbar_buffer, cursor_addr->first->string.str, mv->addrbar_string_size); MemoryCopy(mv->addrbar_buffer, cursor_addr->first->string.str, mv->addrbar_string_size);
mv->addrbar_cursor = txt_pt(1, mv->addrbar_string_size+1); mv->addrbar_cursor = mv->addrbar_string_size+1;
mv->addrbar_mark = txt_pt(1, 1); mv->addrbar_mark = 0;
} }
if(commit_addrbar) if(commit_addrbar)
{ {
@@ -4504,7 +4767,7 @@ struct RD_BitmapCanvasBoxDrawData
}; };
internal AC_Artifact internal AC_Artifact
rd_bitmap_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) rd_bitmap_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
Access *access = access_open(); Access *access = access_open();
@@ -5130,7 +5393,7 @@ struct RD_Geo3DBoxDrawData
}; };
internal AC_Artifact internal AC_Artifact
rd_geo3d_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out) rd_geo3d_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out)
{ {
Access *access = access_open(); Access *access = access_open();
U128 hash = {0}; U128 hash = {0};
+6 -2
View File
@@ -47,6 +47,10 @@ struct RD_CodeViewState
B32 drifted_for_search; B32 drifted_for_search;
U128 last_hash; U128 last_hash;
// rjf: patch state
Arena *patch_arena;
TXT_PatchList patches;
// rjf: per-frame command info // rjf: per-frame command info
S64 goto_line_num; S64 goto_line_num;
B32 center_cursor; B32 center_cursor;
@@ -159,8 +163,8 @@ struct RD_WatchViewTextEditState
{ {
RD_WatchViewTextEditState *pt_hash_next; RD_WatchViewTextEditState *pt_hash_next;
RD_WatchPt pt; RD_WatchPt pt;
TxtPt cursor; U64 cursor;
TxtPt mark; U64 mark;
U8 input_buffer[1024]; U8 input_buffer[1024];
U64 input_size; U64 input_size;
U8 initial_buffer[1024]; U8 initial_buffer[1024];
+173 -321
View File
@@ -907,19 +907,27 @@ rd_cmd_binding_buttons(String8 name, String8 filter, U64 limit, RD_CmdBindingBut
str8_match(rd_state->bind_change_cmd_name, name, 0) && str8_match(rd_state->bind_change_cmd_name, name, 0) &&
rd_state->bind_change_binding_id == 0); rd_state->bind_change_binding_id == 0);
ui_spacer(ui_em(1.f, 1.f)); ui_spacer(ui_em(1.f, 1.f));
{
UI_Box *box = &ui_nil_box;
RD_Font(RD_FontSlot_Icons) UI_TagF(adding_new_binding ? "pop" : "") UI_CornerRadius(ui_top_font_size()*0.5f) RD_Font(RD_FontSlot_Icons) UI_TagF(adding_new_binding ? "pop" : "") UI_CornerRadius(ui_top_font_size()*0.5f)
{ {
ui_set_next_text_alignment(UI_TextAlign_Center); ui_set_next_text_alignment(UI_TextAlign_Center);
ui_set_next_group_key(ui_key_zero()); ui_set_next_group_key(ui_key_zero());
ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*1.5f, 1)); ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*1.5f, 1));
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|
UI_BoxFlag_Clickable| UI_BoxFlag_Clickable|
UI_BoxFlag_DrawActiveEffects| UI_BoxFlag_DrawActiveEffects|
UI_BoxFlag_DrawHotEffects| UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBorder|
UI_BoxFlag_DrawBackground, UI_BoxFlag_DrawBackground,
"%S###add_binding", rd_icon_kind_text_table[RD_IconKind_Add]); "%S###add_binding", rd_icon_kind_text_table[RD_IconKind_Add]);
}
UI_Signal sig = ui_signal_from_box(box); UI_Signal sig = ui_signal_from_box(box);
if(ui_hovering(sig)) UI_Tooltip
{
ui_state->tooltip_anchor_key = box->key;
ui_labelf("Add New Binding");
}
if(ui_clicked(sig)) if(ui_clicked(sig))
{ {
if(!adding_new_binding && ui_clicked(sig)) if(!adding_new_binding && ui_clicked(sig))
@@ -1283,7 +1291,7 @@ internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions)
} }
internal RD_CodeSliceSignal internal RD_CodeSliceSignal
rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, String8 string) rd_code_slice(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred_column, String8 string)
{ {
RD_CodeSliceSignal result = {0}; RD_CodeSliceSignal result = {0};
ProfBeginFunction(); ProfBeginFunction();
@@ -1879,7 +1887,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
{ {
rd_cmd(RD_CmdKind_AddBreakpoint, rd_cmd(RD_CmdKind_AddBreakpoint,
.file_path = params->line_vaddrs[line_idx] ? str8_zero() : rd_regs()->file_path, .file_path = params->line_vaddrs[line_idx] ? str8_zero() : rd_regs()->file_path,
.cursor = params->line_vaddrs[line_idx] ? txt_pt(0, 0) : txt_pt(line_num, 1), .line_num = params->line_vaddrs[line_idx] ? 0 : line_num,
.vaddr = params->line_vaddrs[line_idx], .vaddr = params->line_vaddrs[line_idx],
.expr = s("")); .expr = s(""));
} }
@@ -1893,7 +1901,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
if(params->flags & RD_CodeSliceFlag_LineNums) UI_Parent(top_container_box) ProfScope("build line numbers") UI_Focus(UI_FocusKind_Off) if(params->flags & RD_CodeSliceFlag_LineNums) UI_Parent(top_container_box) ProfScope("build line numbers") UI_Focus(UI_FocusKind_Off)
UI_TagF("floating") UI_TagF("floating")
{ {
TxtRng select_rng = txt_rng(*cursor, *mark); Rng1U64 select_rng = r1u64(*cursor, *mark);
ui_set_next_fixed_x(floor_f32(params->margin_float_off_px + params->priority_margin_width_px + params->catchall_margin_width_px)); ui_set_next_fixed_x(floor_f32(params->margin_float_off_px + params->priority_margin_width_px + params->catchall_margin_width_px));
ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f)); ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f));
ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f));
@@ -1909,7 +1917,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
line_num <= params->line_num_range.max; line_num <= params->line_num_range.max;
line_num += 1, line_idx += 1) line_num += 1, line_idx += 1)
{ {
B32 line_is_selected = (select_rng.min.line <= line_num && line_num <= select_rng.max.line); Rng1U64 line_range = params->line_ranges[line_idx];
B32 line_is_selected = (dim_1u64(intersect_1u64(select_rng, line_range)) != 0) || (line_range.min <= *cursor && *cursor <= line_range.max);
Vec4F32 bg_color = v4f32(0, 0, 0, 0); Vec4F32 bg_color = v4f32(0, 0, 0, 0);
// rjf: line info on this line -> adjust bg color to visualize // rjf: line info on this line -> adjust bg color to visualize
@@ -1966,63 +1975,57 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
////////////////////////////// //////////////////////////////
//- rjf: mouse -> text coordinates //- rjf: mouse -> text coordinates
// //
TxtPt mouse_pt = {0}; U64 mouse_off = 0;
U64 mouse_y_line_idx = 0;
ProfScope("mouse -> text coordinates") ProfScope("mouse -> text coordinates")
{ {
Vec2F32 mouse = ui_mouse(); Vec2F32 mouse = ui_mouse();
// rjf: mouse y => index // rjf: mouse y => index
U64 mouse_y_line_idx = (U64)((mouse.y - text_container_box->rect.y0) / params->line_height_px); S64 mouse_y_line_idx_signed = ((mouse.y - text_container_box->rect.y0) / params->line_height_px);
mouse_y_line_idx_signed = Clamp(0, mouse_y_line_idx_signed, dim_1s64(params->line_num_range)-1);
mouse_y_line_idx = (U64)mouse_y_line_idx_signed;
// rjf: index => line num // rjf: index => line num
S64 line_num = (params->line_num_range.min + mouse_y_line_idx); S64 line_num = (params->line_num_range.min + mouse_y_line_idx);
Rng1U64 line_range = (params->line_num_range.min <= line_num && line_num <= params->line_num_range.max) ? (params->line_ranges[mouse_y_line_idx]) : r1u64(0, 0);
String8 line_string = (params->line_num_range.min <= line_num && line_num <= params->line_num_range.max) ? (params->line_text[mouse_y_line_idx]) : str8_zero(); String8 line_string = (params->line_num_range.min <= line_num && line_num <= params->line_num_range.max) ? (params->line_text[mouse_y_line_idx]) : str8_zero();
// rjf: mouse x * string => column // rjf: mouse x * string => line offset
S64 column = fnt_char_pos_from_tag_size_string_p(params->font, params->font_size, 0, params->tab_size, line_string, mouse.x-text_container_box->rect.x0-params->line_num_width_px-line_num_padding_px)+1; U64 mouse_line_off = fnt_char_pos_from_tag_size_string_p(params->font, params->font_size, 0, params->tab_size, line_string, mouse.x-text_container_box->rect.x0-params->line_num_width_px-line_num_padding_px);
// rjf: bundle // rjf: compute
mouse_pt = txt_pt(line_num, column); mouse_off = line_range.min + mouse_line_off;
// rjf: clamp // rjf: clamp
{ {
U64 last_line_size = params->line_text[dim_1s64(params->line_num_range)].size; Rng1U64 legal_range = r1u64(params->line_ranges[0].min, params->line_ranges[dim_1s64(params->line_num_range)].max);
TxtRng legal_pt_rng = txt_rng(txt_pt(params->line_num_range.min, 1), mouse_off = clamp_1u64(legal_range, mouse_off);
txt_pt(params->line_num_range.max, last_line_size+1));
if(txt_pt_less_than(mouse_pt, legal_pt_rng.min))
{
mouse_pt = legal_pt_rng.min;
}
if(txt_pt_less_than(legal_pt_rng.max, mouse_pt))
{
mouse_pt = legal_pt_rng.max;
}
} }
result.mouse_pt = mouse_pt; result.mouse_off = mouse_off;
} }
////////////////////////////// //////////////////////////////
//- rjf: mouse point -> mouse token range, mouse line range //- rjf: mouse point -> mouse token range, mouse line range
// //
TxtRng mouse_token_rng = txt_rng(mouse_pt, mouse_pt); Rng1U64 mouse_token_rng = r1u64(mouse_off, mouse_off);
TxtRng mouse_line_rng = txt_rng(mouse_pt, mouse_pt); Rng1U64 mouse_line_rng = r1u64(mouse_off, mouse_off);
if(contains_1s64(params->line_num_range, mouse_pt.line)) if(mouse_y_line_idx < (U64)dim_1s64(params->line_num_range))
{ {
TXT_TokenArray *line_tokens = &params->line_tokens[mouse_pt.line-params->line_num_range.min]; TXT_TokenArray *line_tokens = &params->line_tokens[mouse_y_line_idx];
Rng1U64 line_range = params->line_ranges[mouse_pt.line-params->line_num_range.min]; Rng1U64 line_range = params->line_ranges[mouse_y_line_idx];
U64 mouse_pt_off = (mouse_pt.column-1) + line_range.min;
for(U64 line_token_idx = 0; line_token_idx < line_tokens->count; line_token_idx += 1) for(U64 line_token_idx = 0; line_token_idx < line_tokens->count; line_token_idx += 1)
{ {
TXT_Token *line_token = &line_tokens->v[line_token_idx]; TXT_Token *line_token = &line_tokens->v[line_token_idx];
if(contains_1u64(line_token->range, mouse_pt_off)) if(contains_1u64(line_token->range, mouse_off))
{ {
Rng1U64 line_token_range_clamped = intersect_1u64(line_token->range, line_range); Rng1U64 line_token_range_clamped = intersect_1u64(line_token->range, line_range);
mouse_token_rng = txt_rng(txt_pt(mouse_pt.line, 1+line_token_range_clamped.min-line_range.min), txt_pt(mouse_pt.line, 1+line_token_range_clamped.max-line_range.min)); mouse_token_rng = r1u64(line_token_range_clamped.min, line_token_range_clamped.max);
break; break;
} }
} }
mouse_line_rng = txt_rng(txt_pt(mouse_pt.line, 1), txt_pt(mouse_pt.line, 1+(line_range.max-line_range.min))); mouse_line_rng = line_range;
} }
////////////////////////////// //////////////////////////////
@@ -2034,7 +2037,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
UI_Signal text_container_sig = ui_signal_from_box(text_container_box); UI_Signal text_container_sig = ui_signal_from_box(text_container_box);
{ {
//- rjf: determine mouse drag range //- rjf: determine mouse drag range
TxtRng mouse_drag_rng = txt_rng(mouse_pt, mouse_pt); Rng1U64 mouse_drag_rng = r1u64(mouse_off, mouse_off);
if(text_container_sig.f & UI_SignalFlag_LeftTripleDragging) if(text_container_sig.f & UI_SignalFlag_LeftTripleDragging)
{ {
mouse_drag_rng = mouse_line_rng; mouse_drag_rng = mouse_line_rng;
@@ -2047,24 +2050,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
//- rjf: clicking/dragging over the text container //- rjf: clicking/dragging over the text container
if(!ctrlified && ui_dragging(text_container_sig)) if(!ctrlified && ui_dragging(text_container_sig))
{ {
if(mouse_pt.line == 0)
{
mouse_pt.column = 1;
if(ui_mouse().y <= top_container_box->rect.y0)
{
mouse_pt.line = params->line_num_range.min - 2;
}
else if(ui_mouse().y >= top_container_box->rect.y1)
{
mouse_pt.line = params->line_num_range.max + 2;
}
}
if(ui_pressed(text_container_sig)) if(ui_pressed(text_container_sig))
{ {
*cursor = mouse_drag_rng.max; *cursor = mouse_drag_rng.max;
*mark = mouse_drag_rng.min; *mark = mouse_drag_rng.min;
} }
if(txt_pt_less_than(mouse_pt, *mark)) if(mouse_off < *mark)
{ {
*cursor = mouse_drag_rng.min; *cursor = mouse_drag_rng.min;
} }
@@ -2072,7 +2063,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
{ {
*cursor = mouse_drag_rng.max; *cursor = mouse_drag_rng.max;
} }
*preferred_column = cursor->column; *preferred_column = *cursor - mouse_line_rng.min;
} }
//- rjf: dragging will invalidate the search string, so we don't want to draw it while dragging/releasing //- rjf: dragging will invalidate the search string, so we don't want to draw it while dragging/releasing
@@ -2084,25 +2075,25 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
//- rjf: right-click => code context menu //- rjf: right-click => code context menu
if(ui_right_clicked(text_container_sig)) if(ui_right_clicked(text_container_sig))
{ {
if(txt_pt_match(*cursor, *mark)) if(*cursor == *mark)
{ {
*cursor = *mark = mouse_pt; *cursor = *mark = mouse_off;
} }
U64 vaddr = 0; U64 vaddr = 0;
D_LineList lines = {0}; D_LineList lines = {0};
if(params->line_num_range.min <= cursor->line && cursor->line < params->line_num_range.max) if(mouse_y_line_idx < (U64)dim_1s64(params->line_num_range))
{ {
vaddr = params->line_vaddrs[cursor->line - params->line_num_range.min]; vaddr = params->line_vaddrs[mouse_y_line_idx];
lines = params->line_infos[cursor->line - params->line_num_range.min]; lines = params->line_infos[mouse_y_line_idx];
} }
String8 commands_expr; String8 commands_expr;
if(vaddr != 0) if(vaddr != 0)
{ {
commands_expr = txt_pt_match(*cursor, *mark) ? s("query:disasm_pt_commands") : s("query:disasm_range_commands"); commands_expr = (*cursor == *mark) ? s("query:disasm_pt_commands") : s("query:disasm_range_commands");
} }
else else
{ {
commands_expr = txt_pt_match(*cursor, *mark) ? s("query:text_pt_commands") : s("query:text_range_commands"); commands_expr = (*cursor == *mark) ? s("query:text_pt_commands") : s("query:text_range_commands");
} }
rd_cmd(RD_CmdKind_FocusPanel); rd_cmd(RD_CmdKind_FocusPanel);
rd_cmd(RD_CmdKind_PushQuery, rd_cmd(RD_CmdKind_PushQuery,
@@ -2119,40 +2110,38 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
} }
//- rjf: drop target is dropped -> process //- rjf: drop target is dropped -> process
if(drop_can_hit_lines && ui_key_match(ui_drop_hot_key(), drop_site_key) && rd_drag_drop()) if(drop_can_hit_lines && ui_key_match(ui_drop_hot_key(), drop_site_key) && rd_drag_drop() &&
mouse_y_line_idx < (U64)dim_1s64(params->line_num_range))
{ {
if(rd_state->drag_drop_regs_slot == RD_RegSlot_Expr) if(rd_state->drag_drop_regs_slot == RD_RegSlot_Expr)
{ {
S64 line_num = mouse_pt.line; U64 line_num = (U64)params->line_num_range.min + mouse_y_line_idx;
U64 line_idx = line_num - params->line_num_range.min; U64 line_vaddr = params->line_vaddrs[mouse_y_line_idx];
U64 line_vaddr = params->line_vaddrs[line_idx];
rd_cmd(RD_CmdKind_AddWatchPin, rd_cmd(RD_CmdKind_AddWatchPin,
.expr = rd_state->drag_drop_regs->expr, .expr = rd_state->drag_drop_regs->expr,
.file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(), .file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(),
.cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0), .line_num = line_vaddr == 0 ? line_num : 0,
.vaddr = line_vaddr); .vaddr = line_vaddr);
} }
if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &cfg_nil_node) if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &cfg_nil_node)
{ {
S64 line_num = mouse_pt.line; U64 line_num = (U64)params->line_num_range.min + mouse_y_line_idx;
U64 line_idx = line_num - params->line_num_range.min; U64 line_vaddr = params->line_vaddrs[mouse_y_line_idx];
U64 line_vaddr = params->line_vaddrs[line_idx];
rd_cmd(RD_CmdKind_RelocateCfg, rd_cmd(RD_CmdKind_RelocateCfg,
.cfg = drop_cfg->id, .cfg = drop_cfg->id,
.file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(), .file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(),
.cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0), .line_num = line_vaddr == 0 ? line_num : 0,
.vaddr = line_vaddr); .vaddr = line_vaddr);
} }
if(drop_thread != &d_entity_nil) if(drop_thread != &d_entity_nil)
{ {
S64 line_num = mouse_pt.line; U64 line_num = (U64)params->line_num_range.min + mouse_y_line_idx;
U64 line_idx = line_num - params->line_num_range.min; U64 line_vaddr = params->line_vaddrs[mouse_y_line_idx];
U64 line_vaddr = params->line_vaddrs[line_idx];
D_Entity *thread = drop_thread; D_Entity *thread = drop_thread;
U64 new_rip_vaddr = line_vaddr; U64 new_rip_vaddr = line_vaddr;
if(params->line_vaddrs[line_idx] == 0) if(params->line_vaddrs[mouse_y_line_idx] == 0)
{ {
D_LineList *lines = &params->line_infos[line_idx]; D_LineList *lines = &params->line_infos[mouse_y_line_idx];
for(D_LineNode *n = lines->first; n != 0; n = n->next) for(D_LineNode *n = lines->first; n != 0; n = n->next)
{ {
D_EntityList modules = d_modules_from_dbgi_key(scratch.arena, n->v.dbgi_key); D_EntityList modules = d_modules_from_dbgi_key(scratch.arena, n->v.dbgi_key);
@@ -2178,7 +2167,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
TXT_ScopeNode *cursor_scope_node = &txt_scope_node_nil; TXT_ScopeNode *cursor_scope_node = &txt_scope_node_nil;
if(params->text_info != 0) if(params->text_info != 0)
{ {
cursor_scope_node = txt_scope_node_from_info_pt(params->text_info, rd_regs()->cursor); cursor_scope_node = txt_scope_node_from_info_off(params->text_info, *cursor);
} }
////////////////////////////// //////////////////////////////
@@ -2206,7 +2195,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
scope_line_color.w = scope_line_color_t*0.5f; scope_line_color.w = scope_line_color_t*0.5f;
Rng1U64 token_idx_range = scope_n->token_idx_range; Rng1U64 token_idx_range = scope_n->token_idx_range;
Rng1U64 off_range = r1u64(params->text_info->tokens.v[token_idx_range.min].range.min, params->text_info->tokens.v[token_idx_range.max].range.min); Rng1U64 off_range = r1u64(params->text_info->tokens.v[token_idx_range.min].range.min, params->text_info->tokens.v[token_idx_range.max].range.min);
TxtRng txt_range = txt_rng(txt_pt_from_info_off__linear_scan(params->text_info, off_range.min), txt_pt_from_info_off__linear_scan(params->text_info, off_range.max)); TxtRng txt_range = txt_rng(txt_pt_from_off__linear_scan(params->text_info, params->patches, off_range.min), txt_pt_from_off__linear_scan(params->text_info, params->patches, off_range.max));
//- rjf: single-line scopes (underline) //- rjf: single-line scopes (underline)
if(txt_range.min.line == txt_range.max.line && contains_1s64(params->line_num_range, txt_range.min.line)) if(txt_range.min.line == txt_range.max.line && contains_1s64(params->line_num_range, txt_range.min.line))
@@ -2615,40 +2604,37 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
////////////////////////////// //////////////////////////////
//- rjf: mouse -> expression range info //- rjf: mouse -> expression range info
// //
TxtRng mouse_expr_rng = {0}; Rng1U64 mouse_expr_rng = {0};
Vec2F32 mouse_expr_baseline_pos = {0}; Vec2F32 mouse_expr_baseline_pos = {0};
String8 mouse_expr = {0}; String8 mouse_expr = {0};
B32 mouse_expr_is_explicit = 0; B32 mouse_expr_is_explicit = 0;
if(ui_hovering(text_container_sig) && contains_1s64(params->line_num_range, mouse_pt.line)) ProfScope("mouse -> expression range") if(ui_hovering(text_container_sig) && mouse_y_line_idx < (U64)dim_1s64(params->line_num_range))
{ {
TxtRng selected_rng = txt_rng(*cursor, *mark); Rng1U64 selected_rng = r1u64(*cursor, *mark);
if(!txt_pt_match(*cursor, *mark) && cursor->line == mark->line && if(*cursor != *mark && contains_1u64(selected_rng, mouse_off))
((txt_pt_less_than(selected_rng.min, mouse_pt) || txt_pt_match(selected_rng.min, mouse_pt)) &&
txt_pt_less_than(mouse_pt, selected_rng.max)))
{ {
U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; String8 line_text = params->line_text[mouse_y_line_idx];
String8 line_text = params->line_text[line_slice_idx]; Rng1U64 line_range = params->line_ranges[mouse_y_line_idx];
F32 expr_hoff_px = params->line_num_width_px + fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, str8_prefix(line_text, selected_rng.min.column-1)).x; Rng1U64 selected_in_line_range = intersect_1u64(line_range, selected_rng);
result.mouse_expr_rng = mouse_expr_rng = selected_rng; F32 expr_hoff_px = params->line_num_width_px + fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, str8_prefix(line_text, selected_in_line_range.min)).x;
result.mouse_expr_rng = mouse_expr_rng = selected_in_line_range;
mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px, mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px,
text_container_box->rect.y0+line_slice_idx*params->line_height_px + params->line_height_px*0.85f); text_container_box->rect.y0+mouse_y_line_idx*params->line_height_px + params->line_height_px*0.85f);
mouse_expr = str8_substr(line_text, r1u64(selected_rng.min.column-1, selected_rng.max.column-1)); mouse_expr = str8_substr(line_text, selected_in_line_range);
mouse_expr_is_explicit = 1; mouse_expr_is_explicit = 1;
} }
else else
{ {
U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; String8 line_text = params->line_text[mouse_y_line_idx];
String8 line_text = params->line_text[line_slice_idx]; TXT_TokenArray line_tokens = params->line_tokens[mouse_y_line_idx];
TXT_TokenArray line_tokens = params->line_tokens[line_slice_idx]; Rng1U64 line_range = params->line_ranges[mouse_y_line_idx];
Rng1U64 line_range = params->line_ranges[line_slice_idx]; Rng1U64 expr_off_rng = txt_expr_off_range_from_line_off_range_string_tokens(mouse_off, line_range, line_text, &line_tokens);
U64 mouse_pt_off = line_range.min + (mouse_pt.column-1);
Rng1U64 expr_off_rng = txt_expr_off_range_from_line_off_range_string_tokens(mouse_pt_off, line_range, line_text, &line_tokens);
if(expr_off_rng.max != expr_off_rng.min) if(expr_off_rng.max != expr_off_rng.min)
{ {
F32 expr_hoff_px = params->line_num_width_px + fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, str8_prefix(line_text, expr_off_rng.min-line_range.min)).x; F32 expr_hoff_px = params->line_num_width_px + fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, str8_prefix(line_text, expr_off_rng.min-line_range.min)).x;
result.mouse_expr_rng = mouse_expr_rng = txt_rng(txt_pt(mouse_pt.line, 1+(expr_off_rng.min-line_range.min)), txt_pt(mouse_pt.line, 1+(expr_off_rng.max-line_range.min))); result.mouse_expr_rng = mouse_expr_rng = expr_off_rng;
mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px, mouse_expr_baseline_pos = v2f32(text_container_box->rect.x0+expr_hoff_px,
text_container_box->rect.y0+line_slice_idx*params->line_height_px + params->line_height_px*0.85f); text_container_box->rect.y0+mouse_y_line_idx*params->line_height_px + params->line_height_px*0.85f);
mouse_expr = str8_substr(line_text, r1u64(expr_off_rng.min-line_range.min, expr_off_rng.max-line_range.min)); mouse_expr = str8_substr(line_text, r1u64(expr_off_rng.min-line_range.min, expr_off_rng.max-line_range.min));
} }
} }
@@ -2657,11 +2643,10 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
////////////////////////////// //////////////////////////////
//- rjf: mouse -> set global frontend hovered line info //- rjf: mouse -> set global frontend hovered line info
// //
if(ui_hovering(text_container_sig) && contains_1s64(params->line_num_range, mouse_pt.line) && (ui_mouse().x - text_container_box->rect.x0 < params->line_num_width_px + line_num_padding_px)) if(ui_hovering(text_container_sig) && mouse_y_line_idx < (U64)dim_1s64(params->line_num_range) && (ui_mouse().x - text_container_box->rect.x0 < params->line_num_width_px + line_num_padding_px))
{ {
U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; D_LineList *lines = &params->line_infos[mouse_y_line_idx];
D_LineList *lines = &params->line_infos[line_slice_idx]; if(lines->first != 0 && (params->line_vaddrs[mouse_y_line_idx] != 0 || lines->first->v.pt.line == params->line_num_range.min + mouse_y_line_idx))
if(lines->first != 0 && (params->line_vaddrs[line_slice_idx] != 0 || lines->first->v.pt.line == mouse_pt.line))
{ {
RD_RegsScope(.process = selected_thread_process->handle, RD_RegsScope(.process = selected_thread_process->handle,
.vaddr_range = d_vaddr_range_from_voff_range(selected_thread_module, lines->first->v.voff_range), .vaddr_range = d_vaddr_range_from_voff_range(selected_thread_module, lines->first->v.voff_range),
@@ -2685,10 +2670,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
if(eval.msgs.max_kind == E_MsgKind_Null && (eval_implicit_hover || mouse_expr_is_explicit)) if(eval.msgs.max_kind == E_MsgKind_Null && (eval_implicit_hover || mouse_expr_is_explicit))
{ {
U64 line_vaddr = 0; U64 line_vaddr = 0;
if(contains_1s64(params->line_num_range, mouse_pt.line)) if(mouse_y_line_idx < (U64)dim_1s64(params->line_num_range))
{ {
U64 line_idx = mouse_pt.line-params->line_num_range.min; line_vaddr = params->line_vaddrs[mouse_y_line_idx];
line_vaddr = params->line_vaddrs[line_idx];
} }
rd_set_hover_eval(mouse_expr_baseline_pos, mouse_expr); rd_set_hover_eval(mouse_expr_baseline_pos, mouse_expr);
} }
@@ -2705,9 +2689,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
Vec4F32 color = drop_color; Vec4F32 color = drop_color;
color.w *= 0.2f; color.w *= 0.2f;
Rng2F32 drop_line_rect = r2f32p(top_container_box->rect.x0, Rng2F32 drop_line_rect = r2f32p(top_container_box->rect.x0,
top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min) * params->line_height_px, top_container_box->rect.y0 + mouse_y_line_idx*params->line_height_px,
top_container_box->rect.x1, top_container_box->rect.x1,
top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min + 1) * params->line_height_px); top_container_box->rect.y0 + (mouse_y_line_idx+1)*params->line_height_px);
R_Rect2DInst *inst = dr_rect(drop_line_rect, color, 0, 0, 1.f); R_Rect2DInst *inst = dr_rect(drop_line_rect, color, 0, 0, 1.f);
inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, 0); inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, 0);
} }
@@ -2721,7 +2705,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
struct TxtRngColorPairNode struct TxtRngColorPairNode
{ {
TxtRngColorPairNode *next; TxtRngColorPairNode *next;
TxtRng rng; Rng1U64 range;
Vec4F32 color; Vec4F32 color;
}; };
TxtRngColorPairNode *first_txt_rng_color_pair = 0; TxtRngColorPairNode *first_txt_rng_color_pair = 0;
@@ -2730,16 +2714,16 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
// rjf: push initial for cursor/mark // rjf: push initial for cursor/mark
{ {
TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1);
n->rng = txt_rng(*cursor, *mark); n->range = r1u64(*cursor, *mark);
n->color = ui_color_from_name(s("selection")); n->color = ui_color_from_name(s("selection"));
SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n);
} }
// rjf: push for ctrlified mouse expr // rjf: push for ctrlified mouse expr
if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) UI_Tag(s("pop")) if(ctrlified && result.mouse_expr_rng.max != result.mouse_expr_rng.min) UI_Tag(s("pop"))
{ {
TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1);
n->rng = result.mouse_expr_rng; n->range = result.mouse_expr_rng;
n->color = ui_color_from_name(s("background")); n->color = ui_color_from_name(s("background"));
n->color.w *= 0.2f; n->color.w *= 0.2f;
SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n);
@@ -2832,33 +2816,22 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
// rjf: extra rendering for list(text_range*color) // rjf: extra rendering for list(text_range*color)
{ {
U64 prev_line_size = (line_idx > 0) ? params->line_text[line_idx-1].size : 0; Rng1U64 prev_line_range = (line_idx > 0) ? params->line_ranges[line_idx-1] : r1u64(0, 0);
U64 next_line_size = (line_idx+1 < dim_1s64(params->line_num_range)) ? params->line_text[line_idx+1].size : 0; Rng1U64 next_line_range = (line_idx+1 < dim_1s64(params->line_num_range)) ? params->line_ranges[line_idx+1] : r1u64(0, 0);
for(TxtRngColorPairNode *n = first_txt_rng_color_pair; n != 0; n = n->next) for(TxtRngColorPairNode *n = first_txt_rng_color_pair; n != 0; n = n->next)
{ {
TxtRng select_range = n->rng; Rng1U64 select_range = n->range;
TxtRng line_range = txt_rng(txt_pt(line_num, 1), txt_pt(line_num, line_string.size+1)); Rng1U64 select_range_in_line = intersect_1u64(select_range, line_range);
TxtRng select_range_in_line = txt_rng_intersect(select_range, line_range); if(select_range_in_line.min < select_range_in_line.max)
if(!txt_pt_match(select_range_in_line.min, select_range_in_line.max) &&
txt_pt_less_than(select_range_in_line.min, select_range_in_line.max))
{ {
TxtRng prev_line_range = txt_rng(txt_pt(line_num-1, 1), txt_pt(line_num-1, prev_line_size+1)); Rng1U64 select_range_in_prev_line = intersect_1u64(prev_line_range, select_range);
TxtRng next_line_range = txt_rng(txt_pt(line_num+1, 1), txt_pt(line_num+1, next_line_size+1)); Rng1U64 select_range_in_next_line = intersect_1u64(next_line_range, select_range);
TxtRng select_range_in_prev_line = txt_rng_intersect(prev_line_range, select_range); B32 prev_line_good = (select_range_in_prev_line.min < select_range_in_prev_line.max);
TxtRng select_range_in_next_line = txt_rng_intersect(next_line_range, select_range); B32 next_line_good = (select_range_in_next_line.min < select_range_in_next_line.max);
B32 prev_line_good = (!txt_pt_match(select_range_in_prev_line.min, select_range_in_prev_line.max) &&
txt_pt_less_than(select_range_in_prev_line.min, select_range_in_prev_line.max));
B32 next_line_good = (!txt_pt_match(select_range_in_next_line.min, select_range_in_next_line.max) &&
txt_pt_less_than(select_range_in_next_line.min, select_range_in_next_line.max));
Rng1S64 select_column_range_in_line =
{
(select_range.min.line == line_num) ? select_range.min.column : 1,
(select_range.max.line == line_num) ? select_range.max.column : (S64)(line_string.size+1),
};
Rng1F32 select_column_pixel_off_range = Rng1F32 select_column_pixel_off_range =
{ {
fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, select_column_range_in_line.min-1)).x, fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, select_range_in_line.min - line_range.min)).x,
fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, select_column_range_in_line.max-1)).x, fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, select_range_in_line.max - line_range.min)).x,
}; };
Rng2F32 select_rect = Rng2F32 select_rect =
{ {
@@ -2874,20 +2847,22 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
} }
F32 rounded_radius = params->font_size*0.4f; F32 rounded_radius = params->font_size*0.4f;
R_Rect2DInst *inst = dr_rect(select_rect, color, rounded_radius, 0, 1); R_Rect2DInst *inst = dr_rect(select_rect, color, rounded_radius, 0, 1);
inst->corner_radii[Corner_00] = !prev_line_good || select_range_in_prev_line.min.column > select_range_in_line.min.column ? rounded_radius : 0.f; Rng1U64 prev_line_selection_off_range = r1u64(select_range_in_prev_line.min - prev_line_range.min, select_range_in_prev_line.max - prev_line_range.min);
inst->corner_radii[Corner_10] = (!prev_line_good || select_range_in_line.max.column > select_range_in_prev_line.max.column || select_range_in_line.max.column < select_range_in_prev_line.min.column) ? rounded_radius : 0.f; Rng1U64 next_line_selection_off_range = r1u64(select_range_in_next_line.min - next_line_range.min, select_range_in_next_line.max - next_line_range.min);
inst->corner_radii[Corner_01] = (!next_line_good || select_range_in_next_line.min.column > select_range_in_line.min.column || select_range_in_next_line.max.column < select_range_in_line.min.column) ? rounded_radius : 0.f; Rng1U64 crnt_line_selection_off_range = r1u64(select_range_in_line.min - line_range.min, select_range_in_line.max - line_range.min);
inst->corner_radii[Corner_11] = !next_line_good || select_range_in_line.max.column > select_range_in_next_line.max.column ? rounded_radius : 0.f; inst->corner_radii[Corner_00] = !prev_line_good || prev_line_selection_off_range.min > crnt_line_selection_off_range.min ? rounded_radius : 0.f;
inst->corner_radii[Corner_10] = (!prev_line_good || crnt_line_selection_off_range.max > prev_line_selection_off_range.max || crnt_line_selection_off_range.max < prev_line_selection_off_range.min) ? rounded_radius : 0.f;
inst->corner_radii[Corner_01] = (!next_line_good || next_line_selection_off_range.min > crnt_line_selection_off_range.min || next_line_selection_off_range.max < crnt_line_selection_off_range.min) ? rounded_radius : 0.f;
inst->corner_radii[Corner_11] = !next_line_good || crnt_line_selection_off_range.max > next_line_selection_off_range.max ? rounded_radius : 0.f;
} }
} }
} }
// rjf: extra rendering for cursor position // rjf: extra rendering for cursor position
if(cursor->line == line_num) if(line_range.min <= *cursor && *cursor <= line_range.max)
{ {
S64 column = cursor->column; Vec2F32 advance = fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, *cursor - line_range.min));
Vec2F32 advance = fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, column-1)); F32 cursor_y = text_container_box->rect.y0 + line_idx*params->line_height_px - params->font_size*0.125f;
F32 cursor_y = line_box->rect.y0-params->font_size*0.125f;
F32 cursor_y__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_y_px"), cursor_y); F32 cursor_y__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_y_px"), cursor_y);
F32 cursor_off_pixels = advance.x; F32 cursor_off_pixels = advance.x;
F32 cursor_off_pixels__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_off_px"), cursor_off_pixels); F32 cursor_off_pixels__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_off_px"), cursor_off_pixels);
@@ -2978,7 +2953,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
} }
internal RD_CodeSliceSignal internal RD_CodeSliceSignal
rd_code_slicef(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...) rd_code_slicef(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred_column, char *fmt, ...)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
va_list args; va_list args;
@@ -2991,179 +2966,11 @@ rd_code_slicef(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *pref
} }
internal B32 internal B32
rd_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) rd_do_txt_controls(TXT_TextInfo *info, String8 data, TXT_PatchList *patches, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
B32 change = 0; B32 change = 0;
for(UI_Event *evt = 0; ui_next_event(&evt);)
{
if(evt->kind != UI_EventKind_Navigate && evt->kind != UI_EventKind_Edit)
{
continue;
}
B32 taken = 0;
String8 line = txt_string_from_info_data_line_num(info, data, cursor->line);
UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, evt, line, *cursor, *mark);
//- rjf: invalid single-line op or endpoint units => try multiline
if(evt->delta_unit == UI_EventDeltaUnit_Whole || single_line_op.flags & UI_TxtOpFlag_Invalid)
{
U64 line_count = info->lines_count;
String8 prev_line = txt_string_from_info_data_line_num(info, data, cursor->line-1);
String8 next_line = txt_string_from_info_data_line_num(info, data, cursor->line+1);
Vec2S32 delta = evt->delta_2s32;
//- rjf: wrap lines right
if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count)
{
cursor->line += 1;
cursor->column = 1;
*preferred_column = 1;
change = 1;
taken = 1;
}
//- rjf: wrap lines left
if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1)
{
cursor->line -= 1;
cursor->column = prev_line.size+1;
*preferred_column = prev_line.size+1;
change = 1;
taken = 1;
}
//- rjf: movement down (plain)
if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && cursor->line+1 <= line_count)
{
cursor->line += 1;
cursor->column = Min(*preferred_column, next_line.size+1);
change = 1;
taken = 1;
}
//- rjf: movement up (plain)
if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && cursor->line-1 >= 1)
{
cursor->line -= 1;
cursor->column = Min(*preferred_column, prev_line.size+1);
change = 1;
taken = 1;
}
//- rjf: movement down (chunk)
if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && cursor->line+1 <= line_count)
{
for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1)
{
String8 line = txt_string_from_info_data_line_num(info, data, line_num);
U64 line_size = line.size;
if(line_size == 0)
{
cursor->line = line_num;
cursor->column = 1;
break;
}
else if(line_num == line_count)
{
cursor->line = line_num;
cursor->column = line_size+1;
}
}
change = 1;
taken = 1;
}
//- rjf: movement up (chunk)
if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && cursor->line-1 >= 1)
{
for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1)
{
String8 line = txt_string_from_info_data_line_num(info, data, line_num);
U64 line_size = line.size;
if(line_size == 0)
{
cursor->line = line_num;
cursor->column = 1;
break;
}
else if(line_num == 1)
{
cursor->line = line_num;
cursor->column = 1;
}
}
change = 1;
taken = 1;
}
//- rjf: movement down (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y > 0)
{
cursor->line += line_count_per_page;
cursor->column = 1;
cursor->line = Clamp(1, cursor->line, line_count);
change = 1;
taken = 1;
}
//- rjf: movement up (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y < 0)
{
cursor->line -= line_count_per_page;
cursor->column = 1;
cursor->line = Clamp(1, cursor->line, line_count);
change = 1;
taken = 1;
}
//- rjf: movement to endpoint (+)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0))
{
*cursor = txt_pt(line_count, info->lines_count ? dim_1u64(info->lines_ranges[info->lines_count-1])+1 : 1);
change = 1;
taken = 1;
}
//- rjf: movement to endpoint (-)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0))
{
*cursor = txt_pt(1, 1);
change = 1;
taken = 1;
}
//- rjf: stick mark to cursor, when we don't want to keep it in the same spot
if(!(evt->flags & UI_EventFlag_KeepMark))
{
*mark = *cursor;
}
}
//- rjf: valid single-line op => do single-line op
else
{
*cursor = single_line_op.cursor;
*mark = single_line_op.mark;
*preferred_column = cursor->column;
change = 1;
taken = 1;
}
//- rjf: copy
if(evt->flags & UI_EventFlag_Copy)
{
String8 text = txt_string_from_info_data_txt_rng(info, data, txt_rng(*cursor, *mark));
wm_set_clipboard_text(text);
taken = 1;
}
//- rjf: consume
if(taken)
{
ui_eat_event(evt);
}
}
scratch_end(scratch); scratch_end(scratch);
return change; return change;
@@ -3610,6 +3417,52 @@ rd_cell(RD_CellParams *params, String8 string)
} }
} }
//////////////////////////////
//- rjf: build lock
//
if(params->flags & RD_CellFlag_Lock && !is_focus_active && !is_focus_active_disabled) UI_Parent(box) UI_Focus(UI_FocusKind_Off)
{
// TODO(rjf): @hack
{
ui_spacer(ui_em(0.5f, 1.f));
}
B32 is_locked = (params->lock_out && params->lock_out[0]);
UI_PrefWidth(ui_em(2.f, 1.f))
UI_TagF(".")
UI_TagF(is_locked ? "pop" : "weak")
UI_TagF("implicit")
UI_Column
UI_Padding(ui_pct(1, 0))
UI_PrefHeight(ui_em(2.f, 1.f))
UI_CornerRadius(ui_top_font_size()*0.5f)
RD_Font(RD_FontSlot_Icons)
UI_TextAlignment(UI_TextAlign_Center)
{
UI_Box *lock_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|
UI_BoxFlag_DrawHotEffects|
UI_BoxFlag_DrawBorder|
UI_BoxFlag_DrawBackground|
UI_BoxFlag_DisableFocusOverlay|
UI_BoxFlag_DisableFocusBorder|
UI_BoxFlag_Clickable,
"%S###lock", rd_icon_kind_text_table[is_locked ? RD_IconKind_Locked : RD_IconKind_Unlocked]);
UI_Signal sig = ui_signal_from_box(lock_box);
if(ui_hovering(sig)) UI_Tooltip RD_Font(RD_FontSlot_Main)
{
ui_state->tooltip_anchor_key = lock_box->key;
UI_PrefWidth(ui_children_sum(1)) UI_Row
{
UI_PrefWidth(ui_text_dim(10, 1)) ui_label(is_locked ? s("Unlock Location") : s("Lock Location"));
rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_ToggleLock].string, s(""), 1, RD_CmdBindingButtonFlag_NoEdit);
}
}
if(ui_pressed(sig) && params->lock_out)
{
params->lock_out[0] ^= 1;
}
}
}
////////////////////////////// //////////////////////////////
//- rjf: build left-hand-side container box //- rjf: build left-hand-side container box
// //
@@ -4043,8 +3896,8 @@ rd_cell(RD_CellParams *params, String8 string)
{ {
ui_kill_action(); ui_kill_action();
} }
params->cursor[0] = txt_pt(1, edit_string.size+1); params->cursor[0] = edit_string.size;
params->mark[0] = txt_pt(1, 1); params->mark[0] = 0;
focus_started = 1; focus_started = 1;
} }
} }
@@ -4080,7 +3933,7 @@ rd_cell(RD_CellParams *params, String8 string)
} }
// rjf: map this action to an op // rjf: map this action to an op
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), params->cursor[0], params->mark[0]);
// rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op // rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op
if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0)
@@ -4088,27 +3941,27 @@ rd_cell(RD_CellParams *params, String8 string)
CFG_Node *window = cfg_node_from_id(rd_regs()->window); CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window); RD_WindowState *ws = rd_window_state_from_cfg(window);
RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info;
String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_hint_string); String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, autocomp_cursor_info->replaced_range, autocomplete_hint_string);
new_string.size = Min(params->edit_buffer_size, new_string.size); new_string.size = Min(params->edit_buffer_size, new_string.size);
MemoryCopy(params->edit_buffer, new_string.str, new_string.size); MemoryCopy(params->edit_buffer, new_string.str, new_string.size);
params->edit_string_size_out[0] = new_string.size; params->edit_string_size_out[0] = new_string.size;
params->cursor[0] = params->mark[0] = txt_pt(1, 1+autocomp_cursor_info->replaced_range.min+autocomplete_hint_string.size); params->cursor[0] = params->mark[0] = autocomp_cursor_info->replaced_range.min+autocomplete_hint_string.size;
edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]);
op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), params->cursor[0], params->mark[0]);
MemoryZeroStruct(&autocomplete_hint_string); MemoryZeroStruct(&autocomplete_hint_string);
} }
// rjf: perform replace range // rjf: perform replace range
if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) if(op.range.min != op.range.max || op.replace.size != 0)
{ {
String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace); String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, op.range, op.replace);
new_string.size = Min(params->edit_buffer_size, new_string.size); new_string.size = Min(params->edit_buffer_size, new_string.size);
MemoryCopy(params->edit_buffer, new_string.str, new_string.size); MemoryCopy(params->edit_buffer, new_string.str, new_string.size);
params->edit_string_size_out[0] = new_string.size; params->edit_string_size_out[0] = new_string.size;
} }
// rjf: perform copy // rjf: perform copy
if(op.flags & UI_TxtOpFlag_Copy) if(evt->flags & UI_EventFlag_Copy)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
@@ -4186,9 +4039,9 @@ rd_cell(RD_CellParams *params, String8 string)
CFG_Node *window = cfg_node_from_id(rd_regs()->window); CFG_Node *window = cfg_node_from_id(rd_regs()->window);
RD_WindowState *ws = rd_window_state_from_cfg(window); RD_WindowState *ws = rd_window_state_from_cfg(window);
RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info;
String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor->column-1 - autocomp_cursor_info->replaced_range.min); String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor[0] - autocomp_cursor_info->replaced_range.min);
U64 off = 0; U64 off = 0;
U64 cursor_off = params->cursor->column-1; U64 cursor_off = params->cursor[0];
DR_FStrNode *prev_n = 0; DR_FStrNode *prev_n = 0;
for(DR_FStrNode *n = edit_string_fstrs.first; n != 0; n = n->next) for(DR_FStrNode *n = edit_string_fstrs.first; n != 0; n = n->next)
{ {
@@ -4255,7 +4108,7 @@ rd_cell(RD_CellParams *params, String8 string)
////////////////////////////// //////////////////////////////
//- rjf: build scrolled contents //- rjf: build scrolled contents
// //
TxtPt mouse_pt = {0}; U64 mouse_off = {0};
F32 cursor_off = 0; F32 cursor_off = 0;
if(scrollable_box != &ui_nil_box) UI_Parent(scrollable_box) if(scrollable_box != &ui_nil_box) UI_Parent(scrollable_box)
{ {
@@ -4292,9 +4145,8 @@ rd_cell(RD_CellParams *params, String8 string)
{ {
font = rd_font_from_slot(RD_FontSlot_Code); font = rd_font_from_slot(RD_FontSlot_Code);
} }
U64 mouse_pt_off = fnt_char_pos_from_tag_size_string_p(font, font_size, 0, ui_top_tab_size(), edit_string, text2mouse.x); mouse_off = fnt_char_pos_from_tag_size_string_p(font, font_size, 0, ui_top_tab_size(), edit_string, text2mouse.x);
mouse_pt = txt_pt(1, 1+mouse_pt_off); cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, params->cursor[0])).x;
cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, params->cursor->column-1)).x;
} }
} }
@@ -4305,13 +4157,13 @@ rd_cell(RD_CellParams *params, String8 string)
{ {
if(ui_pressed(sig)) if(ui_pressed(sig))
{ {
params->mark[0] = mouse_pt; params->mark[0] = mouse_off;
} }
params->cursor[0] = mouse_pt; params->cursor[0] = mouse_off;
} }
if(!is_focus_active && is_focus_active_disabled && ui_pressed(sig)) if(!is_focus_active && is_focus_active_disabled && ui_pressed(sig))
{ {
params->cursor[0] = params->mark[0] = mouse_pt; params->cursor[0] = params->mark[0] = mouse_off;
} }
////////////////////////////// //////////////////////////////
+19 -14
View File
@@ -27,19 +27,20 @@ enum
//- rjf: extra button extensions //- rjf: extra button extensions
RD_CellFlag_EmptyEditButton = (1<<6), RD_CellFlag_EmptyEditButton = (1<<6),
RD_CellFlag_RevertButton = (1<<7), RD_CellFlag_RevertButton = (1<<7),
RD_CellFlag_Lock = (1<<8),
//- rjf: behavior //- rjf: behavior
RD_CellFlag_DisableEdit = (1<<8), RD_CellFlag_DisableEdit = (1<<9),
RD_CellFlag_KeyboardClickable = (1<<9), RD_CellFlag_KeyboardClickable = (1<<10),
RD_CellFlag_SingleClickActivate = (1<<10), RD_CellFlag_SingleClickActivate = (1<<11),
//- rjf: contents description //- rjf: contents description
RD_CellFlag_CodeContents = (1<<11), RD_CellFlag_CodeContents = (1<<12),
//- rjf: appearance //- rjf: appearance
RD_CellFlag_Border = (1<<12), RD_CellFlag_Border = (1<<13),
RD_CellFlag_NoBackground = (1<<13), RD_CellFlag_NoBackground = (1<<14),
RD_CellFlag_Button = (1<<14), RD_CellFlag_Button = (1<<15),
}; };
typedef struct RD_CellParams RD_CellParams; typedef struct RD_CellParams RD_CellParams;
@@ -59,6 +60,9 @@ struct RD_CellParams
//- rjf: expander r/w info //- rjf: expander r/w info
B32 *expanded_out; B32 *expanded_out;
//- rjf: lock r/w info
B32 *lock_out;
//- rjf: toggle-switch r/w info //- rjf: toggle-switch r/w info
B32 *toggled_out; B32 *toggled_out;
@@ -72,8 +76,8 @@ struct RD_CellParams
B32 *revert_out; B32 *revert_out;
//- rjf: text editing r/w info //- rjf: text editing r/w info
TxtPt *cursor; U64 *cursor;
TxtPt *mark; U64 *mark;
U8 *edit_buffer; U8 *edit_buffer;
U64 edit_buffer_size; U64 edit_buffer_size;
U64 *edit_string_size_out; U64 *edit_string_size_out;
@@ -108,6 +112,7 @@ struct RD_CodeSliceParams
D_LineList *line_infos; D_LineList *line_infos;
DI_KeyList relevant_dbgi_keys; DI_KeyList relevant_dbgi_keys;
TXT_TextInfo *text_info; TXT_TextInfo *text_info;
TXT_PatchList *patches;
String8 text_data; String8 text_data;
// rjf: visual parameters // rjf: visual parameters
@@ -127,8 +132,8 @@ typedef struct RD_CodeSliceSignal RD_CodeSliceSignal;
struct RD_CodeSliceSignal struct RD_CodeSliceSignal
{ {
UI_Signal base; UI_Signal base;
TxtPt mouse_pt; U64 mouse_off;
TxtRng mouse_expr_rng; Rng1U64 mouse_expr_rng;
}; };
//////////////////////////////// ////////////////////////////////
@@ -171,10 +176,10 @@ internal UI_Signal rd_icon_buttonf(RD_IconKind kind, FuzzyMatchRangeList *matche
internal UI_BOX_CUSTOM_DRAW(rd_code_slice_text_draw_extensions); internal UI_BOX_CUSTOM_DRAW(rd_code_slice_text_draw_extensions);
internal UI_BOX_CUSTOM_DRAW(rd_thread_box_draw_extensions); internal UI_BOX_CUSTOM_DRAW(rd_thread_box_draw_extensions);
internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions); internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions);
internal RD_CodeSliceSignal rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, String8 string); internal RD_CodeSliceSignal rd_code_slice(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred_column, String8 string);
internal RD_CodeSliceSignal rd_code_slicef(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...); internal RD_CodeSliceSignal rd_code_slicef(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred_column, char *fmt, ...);
internal B32 rd_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); internal B32 rd_do_txt_controls(TXT_TextInfo *info, String8 data, TXT_PatchList *patches, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column);
//////////////////////////////// ////////////////////////////////
//~ rjf: UI Widgets: Fancy Labels //~ rjf: UI Widgets: Fancy Labels
+1 -1
View File
@@ -72,7 +72,7 @@ rd_test__exemplar_test_finish(Arena *arena, TestCtx *ctx, String8List test_log_s
} }
str8_list_push(scratch.arena, &exemplar_data_lines_sanitized, line_trimmed); str8_list_push(scratch.arena, &exemplar_data_lines_sanitized, line_trimmed);
} }
exemplar_data = str8_list_join(scratch.arena, &exemplar_data_lines_sanitized, &(StringJoin){.sep = s("\n")}); exemplar_data = str8_list_join(scratch.arena, &exemplar_data_lines_sanitized, &(StringJoin){.sep = s("\n"), .post = s("\n")});
// rjf: if exemplar data is empty -> just save our output as the new exemplar // rjf: if exemplar data is empty -> just save our output as the new exemplar
if(exemplar_data.size == 0) if(exemplar_data.size == 0)
+10 -10
View File
@@ -1213,7 +1213,7 @@ RDI_EvalOpTable:
{ConstU128 15 16 0 1} {ConstU128 15 16 0 1}
{ConstU256 16 32 0 1} {ConstU256 16 32 0 1}
{ConstU512 17 64 0 1} {ConstU512 17 64 0 1}
{ConstString 18 1 0 1} {ConstString 18 8 0 1}
{Abs 19 2 1 1} {Abs 19 2 1 1}
{Neg 20 2 1 1} {Neg 20 2 1 1}
{Add 21 2 2 1} {Add 21 2 2 1}
@@ -1227,15 +1227,15 @@ RDI_EvalOpTable:
{BitOr 29 2 2 1} {BitOr 29 2 2 1}
{BitXor 30 2 2 1} {BitXor 30 2 2 1}
{BitNot 31 2 1 1} {BitNot 31 2 1 1}
{LogAnd 32 1 2 1 FirstLogical} {LogAnd 32 2 2 1 FirstLogical}
{LogOr 33 1 2 1} {LogOr 33 2 2 1}
{LogNot 34 1 1 1} {LogNot 34 2 1 1}
{EqEq 35 1 2 1} {EqEq 35 2 2 1}
{NtEq 36 1 2 1} {NtEq 36 2 2 1}
{LsEq 37 1 2 1} {LsEq 37 2 2 1}
{GrEq 38 1 2 1} {GrEq 38 2 2 1}
{Less 39 1 2 1} {Less 39 2 2 1}
{Grtr 40 1 2 1 LastLogical} {Grtr 40 2 2 1 LastLogical}
{Trunc 41 1 1 1} {Trunc 41 1 1 1}
{TruncSigned 42 1 1 1} {TruncSigned 42 1 1 1}
{Convert 43 2 1 1} {Convert 43 2 1 1}
+39
View File
@@ -76,6 +76,15 @@ fully_qualified_from_rdi_string_and_container(Arena *arena, RDI_Parsed *rdi, U32
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
String8List parts = {0}; String8List parts = {0};
{ {
typedef struct VisitedNode VisitedNode;
struct VisitedNode
{
VisitedNode *next;
U32 idx;
RDI_ContainerFlags flags;
};
U64 visited_slots_count = 6;
VisitedNode **visited_slots = push_array(scratch.arena, VisitedNode *, visited_slots_count);
str8_list_push(scratch.arena, &parts, str8_from_rdi_string_idx(rdi, name_string_idx)); str8_list_push(scratch.arena, &parts, str8_from_rdi_string_idx(rdi, name_string_idx));
RDI_ContainerFlags container_flags = start_container_flags; RDI_ContainerFlags container_flags = start_container_flags;
RDI_ContainerFlags next_container_flags = 0; RDI_ContainerFlags next_container_flags = 0;
@@ -83,6 +92,36 @@ fully_qualified_from_rdi_string_and_container(Arena *arena, RDI_Parsed *rdi, U32
container_idx != 0; container_idx != 0;
container_idx = next_container_idx, container_flags = next_container_flags) container_idx = next_container_idx, container_flags = next_container_flags)
{ {
// rjf: determine if we visited this container already - add this container if not
B32 visited_already = 0;
{
U64 hash = u64_hash_from_seed_str8(0, str8_struct(&container_idx));
hash = u64_hash_from_seed_str8(hash, str8_struct(&container_flags));
U64 slot_idx = hash%visited_slots_count;
for EachNode(n, VisitedNode, visited_slots[slot_idx])
{
if(n->idx == container_idx && n->flags == container_flags)
{
visited_already = 1;
break;
}
}
if(!visited_already)
{
VisitedNode *n = push_array(scratch.arena, VisitedNode, 1);
SLLStackPush(visited_slots[slot_idx], n);
n->idx = container_idx;
n->flags = container_flags;
}
}
// rjf: early-out if we found a cycle
if(visited_already)
{
break;
}
// rjf: push this container's string
next_container_idx = 0; next_container_idx = 0;
next_container_flags = 0; next_container_flags = 0;
switch(container_flags & RDI_ContainerFlag_KindMask) switch(container_flags & RDI_ContainerFlag_KindMask)
+4
View File
@@ -1623,6 +1623,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
{ {
//- rjf: try to find an already-computed hash for this task //- rjf: try to find an already-computed hash for this task
U64 already_computed_hash = 0; U64 already_computed_hash = 0;
U64 already_computed_dependency_count = 0;
B32 found_already_computed_hash = 0; B32 found_already_computed_hash = 0;
{ {
U64 off_hash = u64_hash_from_str8(str8_struct(&top_task->start_off)); U64 off_hash = u64_hash_from_str8(str8_struct(&top_task->start_off));
@@ -1634,6 +1635,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
{ {
found_already_computed_hash = 1; found_already_computed_hash = 1;
already_computed_hash = n->dst_hash; already_computed_hash = n->dst_hash;
already_computed_dependency_count = n->dependency_count;
break; break;
} }
} }
@@ -1643,6 +1645,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
if(found_already_computed_hash) if(found_already_computed_hash)
{ {
top_task->hash = already_computed_hash; top_task->hash = already_computed_hash;
top_task->dependency_count = already_computed_dependency_count;
} }
//- rjf: determine if we're done with this hash //- rjf: determine if we're done with this hash
@@ -1793,6 +1796,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
D2R_UnitDedupedTagNode *n = push_array(scratch.arena, D2R_UnitDedupedTagNode, 1); D2R_UnitDedupedTagNode *n = push_array(scratch.arena, D2R_UnitDedupedTagNode, 1);
n->src_info_off = top_task->start_off; n->src_info_off = top_task->start_off;
n->dst_hash = top_task->hash; n->dst_hash = top_task->hash;
n->dependency_count = top_task->dependency_count;
for(B32 inserted = 0; !inserted;) for(B32 inserted = 0; !inserted;)
{ {
U64 slot_head_val = ins_atomic_u64_eval(&unit_deduped_tag_maps[origin_unit_idx].slots[info_off_slot_idx]); U64 slot_head_val = ins_atomic_u64_eval(&unit_deduped_tag_maps[origin_unit_idx].slots[info_off_slot_idx]);
+1
View File
@@ -45,6 +45,7 @@ struct D2R_UnitDedupedTagNode
D2R_UnitDedupedTagNode *next; D2R_UnitDedupedTagNode *next;
U64 src_info_off; U64 src_info_off;
U64 dst_hash; U64 dst_hash;
U64 dependency_count;
}; };
typedef struct D2R_UnitDedupedTagMap D2R_UnitDedupedTagMap; typedef struct D2R_UnitDedupedTagMap D2R_UnitDedupedTagMap;
@@ -64,7 +64,7 @@ SkippedTest(d2r_regressions)
} }
} }
SkippedTest(d2r_determinism) Test(d2r_determinism)
{ {
U64 num_repeats_per_bin = 16; U64 num_repeats_per_bin = 16;
String8 radbin_path = test_build_exe_path(arena, s("radbin")); String8 radbin_path = test_build_exe_path(arena, s("radbin"));
+125 -27
View File
@@ -34,28 +34,64 @@
internal void internal void
entry_point(CmdLine *cmdline) entry_point(CmdLine *cmdline)
{ {
E2_ConsTypeMap *cons_types = e2_cons_type_map_alloc();
e2_select_cons_type_map(cons_types);
String8 strings[] = String8 strings[] =
{ {
s("[123]"), // (A)B
// (A) & B
// (A)
// int & B
// (1 + (int)&B)
s("foo!bar"),
s("int32(*)(int32, int32)"),
s("int32 *(*)(int32, int32)"),
s("int32 **(*)(int32, int32)"),
s("123(1, 2, 3)"),
s("int32 (*) [100]"),
s("(3 * 4) + 2"),
s("cast (float32) 123"),
s("int32 *"),
s("3 * 4 + 2"),
s("int32[100]"),
s("3 * 4"),
s("foo"), s("foo"),
s("foo.bar"), s("foo.bar"),
s("[123]"),
s("123[456]"), s("123[456]"),
s("2 + (3 * 4)"),
s("int32 == int32"),
s("123, 456"),
s("222.f"),
s("123 as float32"),
s("cast float32 123"),
s("(int32 *)123"),
s("bar(a, b) = a + b"),
s("foo = 123"),
s("1 > 2"),
s("1 ? 123 : 456"),
s("0 ? 123 : 456"),
s("1 ? \"Test\" : 888"),
s("'a'"),
s("'b'"),
s("(float32)222"),
s("(float64)222"),
s("222.0"),
s("123"), s("123"),
s("123 + 456"), s("123 + 456"),
s("!1"), s("!1"),
s("!0"), s("!0"),
s("1 + 1 + 1"), s("1 + 1 + 1"),
s("40 / 0"), s("40 / 0"),
s("3 * 4"),
s("3 * 4 + 2"),
s("(3 * 4) + 2"),
s("2 + (3 * 4)"),
s("123 | 456"), s("123 | 456"),
s("123 + "), s("123 + "),
s("-123"), s("-123"),
s("sizeof 123"), s("sizeof 123"),
s("1 ? 123 : 456"), #if 0
s("123(1, 2, 3)"), // TODO(rjf): these are ambiguous with regular C type expressions with a naive parse:
// s("float32(111)"),
// s("float64(111)"),
#endif
}; };
for EachElement(idx, strings) for EachElement(idx, strings)
{ {
@@ -66,28 +102,21 @@ entry_point(CmdLine *cmdline)
E2_Expr *expr = &e2_expr_nil; E2_Expr *expr = &e2_expr_nil;
{ {
E2_ParseState state = {0}; E2_ParseState state = {0};
E2_ExprMap expr_map = {0}; B32 identifier_is_type = 0;
E2_Expr *access_expr = &e2_expr_nil;
for(;;) for(;;)
{ {
E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, access_expr, strings[idx]); E2_Parse parse = e2_parse_from_string(scratch.arena, &state, identifier_is_type, E2_LangKind_CLike, strings[idx]);
identifier_is_type = 0;
expr = parse.expr; expr = parse.expr;
access_expr = &e2_expr_nil;
for EachNode(n, E2_Msg, parse.msgs.first) for EachNode(n, E2_Msg, parse.msgs.first)
{ {
str8_list_push(scratch.arena, &msgs, n->string); str8_list_push(scratch.arena, &msgs, n->string);
} }
if(parse.status == E2_ParseStatus_MissedIdentifierResolution) if(parse.status == E2_ParseStatus_CheckIdentifierIsType)
{ {
e2_expr_map_push(scratch.arena, &expr_map, parse.missed_identifier, e2_expr_const_u64_or_smaller(scratch.arena, 123)); identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("int32"), 0);
} identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("float32"), 0);
if(parse.status == E2_ParseStatus_IndexAccess) identifier_is_type = identifier_is_type || str8_match(parse.identifier, s("float64"), 0);
{
access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 111);
}
if(parse.status == E2_ParseStatus_MemberAccess)
{
access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 456);
} }
if(e2_parse_status_is_terminal(parse.status)) if(e2_parse_status_is_terminal(parse.status))
{ {
@@ -96,8 +125,71 @@ entry_point(CmdLine *cmdline)
} }
} }
// rjf: expr -> bytecode // rjf: expr -> ir tree
String8 bytecode = e2_bytecode_from_expr(scratch.arena, expr); E2_IRNode *irtree = &e2_irnode_nil;
{
E2_IRNode *resolve_result = &e2_irnode_nil;
E2_Val compile_time_eval_result = {0};
E2_CompileState state = {0};
for(;;)
{
E2_Compile compile = e2_compile_from_expr(scratch.arena, &state, resolve_result, compile_time_eval_result, expr);
irtree = compile.irtree;
resolve_result = &e2_irnode_nil;
if(compile.status == E2_CompileStatus_MissedIdentifierResolution)
{
E2_IRNode *irnode = &e2_irnode_nil;
if(str8_match(compile.identifier, s("float32"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F32));
}
else if(str8_match(compile.identifier, s("float64"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F64));
}
else if(str8_match(compile.identifier, s("int32"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S32));
}
else if(str8_match(compile.identifier, s("int64"), 0))
{
irnode = e2_irnode_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S64));
}
else
{
irnode = e2_irnode_const_u64_or_smaller(scratch.arena, 123);
}
resolve_result = irnode;
}
if(compile.status == E2_CompileStatus_MemberAccess)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 456);
}
if(compile.status == E2_CompileStatus_IndexAccess)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 111);
}
if(compile.status == E2_CompileStatus_Call)
{
resolve_result = e2_irnode_const_u64_or_smaller(scratch.arena, 123456);
}
if(compile.status == E2_CompileStatus_CompileTimeEval)
{
String8 bytecode = e2_bytecode_from_irnode(scratch.arena, irtree);
E2_InterpState interp_state = {0};
E2_SpaceMap space_map = {0};
E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &interp_state, &space_map, bytecode);
compile_time_eval_result = interp.val;
}
if(e2_compile_status_is_terminal(compile.status))
{
break;
}
}
}
// rjf: ir tree -> bytecode
String8 bytecode = e2_bytecode_from_irnode(scratch.arena, irtree);
// rjf: bytecode -> value // rjf: bytecode -> value
E2_Val val = {0}; E2_Val val = {0};
@@ -124,12 +216,18 @@ entry_point(CmdLine *cmdline)
String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join); String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join);
// rjf: log // rjf: log
printf("%.*s -> %I64d *%s* %s%.*s\n", str8_varg(strings[idx]), String8 log = str8f(scratch.arena, "%S -> %I64d (f32: %f) (f64: %f) *%s* (type: %S) %s%S\n",
strings[idx],
val.s64, val.s64,
expr->mode == E2_Mode_Type ? "type" : val.f32,
expr->mode == E2_Mode_Value ? "value" : val.f64,
irtree->mode == E2_Mode_Type ? "type" :
irtree->mode == E2_Mode_Value ? "value" :
"address", "address",
msgs_string.size != 0 ? " // " : "", str8_varg(msgs_string)); e2_string_from_type_key(scratch.arena, irtree->type_key),
msgs_string.size != 0 ? " // " : "", msgs_string);
raddbg_log("%S", log);
printf("%.*s", str8_varg(log));
fflush(stdout); fflush(stdout);
scratch_end(scratch); scratch_end(scratch);
+4
View File
@@ -11,6 +11,10 @@ typedef enum SMSV_Status
} }
SMSV_Status; SMSV_Status;
#if !defined(NEED_ASYNC)
# define NEED_ASYNC 1
#endif
internal void smsv_init(void); internal void smsv_init(void);
internal void smsv_async_tick(void); internal void smsv_async_tick(void);
internal String8 smsv_cache_path(void); internal String8 smsv_cache_path(void);
+2 -2
View File
@@ -157,8 +157,8 @@ str8_lit_comp("->"),
TXT_TokenizerRule txt_tokenizer_rules__c[7] = TXT_TokenizerRule txt_tokenizer_rules__c[7] =
{ {
{TXT_TokenKind_Comment, str8_lit_comp("//"), str8_lit_comp("\n"), 0, 0, 1, 0}, {TXT_TokenKind_LineComment, str8_lit_comp("//"), str8_lit_comp("\n"), 0, 0, 1, 0},
{TXT_TokenKind_Comment, str8_lit_comp("/*"), str8_lit_comp("*/"), 2, 0, 0, 0}, {TXT_TokenKind_BlockComment, str8_lit_comp("/*"), str8_lit_comp("*/"), 2, 0, 0, 0},
{TXT_TokenKind_Meta, str8_lit_comp("#"), str8_lit_comp("\n"), 0, 0, 1, 0}, {TXT_TokenKind_Meta, str8_lit_comp("#"), str8_lit_comp("\n"), 0, 0, 1, 0},
{TXT_TokenKind_String, str8_lit_comp("\""), str8_lit_comp("\""), 1, 0, 1, 0}, {TXT_TokenKind_String, str8_lit_comp("\""), str8_lit_comp("\""), 1, 0, 1, 0},
{TXT_TokenKind_String, str8_lit_comp("'"), str8_lit_comp("'"), 1, 0, 1, 0}, {TXT_TokenKind_String, str8_lit_comp("'"), str8_lit_comp("'"), 1, 0, 1, 0},
+1327 -78
View File
File diff suppressed because it is too large Load Diff
+105 -6
View File
@@ -25,8 +25,10 @@ typedef enum TXT_TokenKind
TXT_TokenKind_Identifier, TXT_TokenKind_Identifier,
TXT_TokenKind_Numeric, TXT_TokenKind_Numeric,
TXT_TokenKind_String, TXT_TokenKind_String,
TXT_TokenKind_Char,
TXT_TokenKind_Symbol, TXT_TokenKind_Symbol,
TXT_TokenKind_Comment, TXT_TokenKind_LineComment,
TXT_TokenKind_BlockComment,
TXT_TokenKind_Meta, // preprocessor, etc. TXT_TokenKind_Meta, // preprocessor, etc.
TXT_TokenKind_COUNT TXT_TokenKind_COUNT
} }
@@ -65,6 +67,13 @@ struct TXT_Token
Rng1U64 range; Rng1U64 range;
}; };
typedef struct TXT_TokenPt TXT_TokenPt;
struct TXT_TokenPt
{
TXT_TokenKind kind;
U64 off;
};
typedef struct TXT_TokenChunkNode TXT_TokenChunkNode; typedef struct TXT_TokenChunkNode TXT_TokenChunkNode;
struct TXT_TokenChunkNode struct TXT_TokenChunkNode
{ {
@@ -150,6 +159,8 @@ struct TXT_TextInfo
Rng1U64 *lines_ranges; Rng1U64 *lines_ranges;
U64 lines_max_size; U64 lines_max_size;
TXT_LineEndKind line_end_kind; TXT_LineEndKind line_end_kind;
U64 big_token_pts_count;
TXT_TokenPt *big_token_pts;
TXT_TokenArray tokens; TXT_TokenArray tokens;
TXT_ScopePtArray scope_pts; TXT_ScopePtArray scope_pts;
TXT_ScopeNodeArray scope_nodes; TXT_ScopeNodeArray scope_nodes;
@@ -163,6 +174,78 @@ struct TXT_LineTokensSlice
TXT_TokenArray *line_tokens; TXT_TokenArray *line_tokens;
}; };
////////////////////////////////
//~ rjf: Value Modification Patches
typedef struct TXT_Patch TXT_Patch;
struct TXT_Patch
{
Rng1U64 range;
String8 replace;
};
typedef struct TXT_PatchNode TXT_PatchNode;
struct TXT_PatchNode
{
TXT_PatchNode *next;
TXT_PatchNode *prev;
TXT_Patch v;
};
typedef struct TXT_PatchList TXT_PatchList;
struct TXT_PatchList
{
TXT_PatchNode *first;
TXT_PatchNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Value Reading Types
typedef struct TXT_LineMapRangeNode TXT_LineMapRangeNode;
struct TXT_LineMapRangeNode
{
TXT_LineMapRangeNode *next;
Rng1U64 num_range;
Rng1U64 *ranges;
S64 delta;
};
typedef struct TXT_LineMap TXT_LineMap;
struct TXT_LineMap
{
TXT_LineMapRangeNode *first_range;
TXT_LineMapRangeNode *last_range;
U64 total_line_count;
};
typedef struct TXT_TokenPtMapRangeNode TXT_TokenPtMapRangeNode;
struct TXT_TokenPtMapRangeNode
{
TXT_TokenPtMapRangeNode *next;
Rng1U64 num_range;
TXT_TokenPt *pts;
S64 delta;
};
typedef struct TXT_TokenPtMap TXT_TokenPtMap;
struct TXT_TokenPtMap
{
TXT_TokenPtMapRangeNode *first_range;
TXT_TokenPtMapRangeNode *last_range;
U64 total_pt_count;
};
typedef struct TXT_Patched TXT_Patched;
struct TXT_Patched
{
MemoryMap memory_map;
U64 size;
TXT_LineMap line_map;
TXT_TokenPtMap token_pt_map;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Generated Code //~ rjf: Generated Code
@@ -202,6 +285,11 @@ internal void txt_token_list_push(Arena *arena, TXT_TokenList *list, TXT_Token *
internal TXT_TokenArray txt_token_array_from_chunk_list(Arena *arena, TXT_TokenChunkList *list); internal TXT_TokenArray txt_token_array_from_chunk_list(Arena *arena, TXT_TokenChunkList *list);
internal TXT_TokenArray txt_token_array_from_list(Arena *arena, TXT_TokenList *list); internal TXT_TokenArray txt_token_array_from_list(Arena *arena, TXT_TokenList *list);
////////////////////////////////
//~ rjf: Patch Functions
internal void txt_patch_list_push_new(Arena *arena, TXT_PatchList *list, Rng1U64 range, String8 replace);
//////////////////////////////// ////////////////////////////////
//~ rjf: Lexing Functions //~ rjf: Lexing Functions
@@ -217,22 +305,33 @@ internal TXT_TokenArray txt_token_array_from_string__disasm_x64_intel(Arena *are
//////////////////////////////// ////////////////////////////////
//~ rjf: Text Info Extractor Helpers //~ rjf: Text Info Extractor Helpers
internal U64 txt_off_from_info_pt(TXT_TextInfo *info, TxtPt pt); internal void txt_line_map_push(Arena *arena, TXT_LineMap *map, Rng1U64 num_range, Rng1U64 *ranges, S64 delta);
internal TxtPt txt_pt_from_info_off__linear_scan(TXT_TextInfo *info, U64 off); internal U64 txt_line_num_from_off(TXT_LineMap *map, U64 off);
internal Rng1U64 txt_range_from_line_num(TXT_LineMap *map, U64 num);
internal void txt_token_pt_map_push(Arena *arena, TXT_TokenPtMap *map, Rng1U64 num_range, TXT_TokenPt *pts, S64 delta);
internal U64 txt_token_pt_num_from_off(TXT_TokenPtMap *map, U64 off);
internal TXT_TokenPt txt_token_pt_from_num(TXT_TokenPtMap *map, U64 num);
internal TXT_TokenArray txt_token_array_from_data(Arena *arena, TXT_LangKind lang_kind, TXT_TokenPt ctx_token_pt, String8 data, U64 base_off, U64 limit);
internal TXT_Patched txt_patched_from_info_data_patches(Arena *arena, TXT_TextInfo *info, String8 data, TXT_PatchList *patches);
//~ TODO(rjf): old unpatched text viz code:
internal U64 txt_off_from_pt(TXT_TextInfo *info, TXT_PatchList *patches, TxtPt pt);
internal TxtPt txt_pt_from_off__linear_scan(TXT_TextInfo *info, TXT_PatchList *patches, U64 off);
internal TXT_TokenArray txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num); internal TXT_TokenArray txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num);
internal Rng1U64 txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens); internal Rng1U64 txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens);
internal Rng1U64 txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt); internal Rng1U64 txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt);
internal String8 txt_string_from_info_data_txt_rng(TXT_TextInfo *info, String8 data, TxtRng rng); internal String8 txt_string_from_info_data_txt_rng(TXT_TextInfo *info, String8 data, TXT_PatchList *patches, TxtRng rng);
internal String8 txt_string_from_info_data_line_num(TXT_TextInfo *info, String8 data, S64 line_num); internal String8 txt_string_from_info_data_line_num(TXT_TextInfo *info, String8 data, S64 line_num);
internal TXT_LineTokensSlice txt_line_tokens_slice_from_info_data_line_range(Arena *arena, TXT_TextInfo *info, String8 data, Rng1S64 line_range); internal TXT_LineTokensSlice txt_line_tokens_slice_from_info_data_line_range(Arena *arena, TXT_TextInfo *info, String8 data, Rng1S64 line_range);
internal TXT_ScopeNode *txt_scope_node_from_info_num(TXT_TextInfo *info, U64 num); internal TXT_ScopeNode *txt_scope_node_from_info_num(TXT_TextInfo *info, U64 num);
internal TXT_ScopeNode *txt_scope_node_from_info_off(TXT_TextInfo *info, U64 off); internal TXT_ScopeNode *txt_scope_node_from_info_off(TXT_TextInfo *info, U64 off);
internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt); internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TXT_PatchList *patches, TxtPt pt);
//////////////////////////////// ////////////////////////////////
//~ rjf: Artifact Cache Hooks / Lookups //~ rjf: Artifact Cache Hooks / Lookups
internal AC_Artifact txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out); internal AC_Artifact txt_artifact_create(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
internal void txt_artifact_destroy(AC_Artifact artifact); internal void txt_artifact_destroy(AC_Artifact artifact);
internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang); internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang);
internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out); internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out);
+2 -2
View File
@@ -118,8 +118,8 @@ txt_multichar_symbols__c:
@table(token_kind open_string close_string close_advance nesting escaping parent_num) txt_tokenizer_rules__c: @table(token_kind open_string close_string close_advance nesting escaping parent_num) txt_tokenizer_rules__c:
{ {
{Comment "//" "\\n" 0 0 1 0} {LineComment "//" "\\n" 0 0 1 0}
{Comment "/*" "*/" 2 0 0 0} {BlockComment "/*" "*/" 2 0 0 0}
{Meta "#" "\\n" 0 0 1 0} {Meta "#" "\\n" 0 0 1 0}
{String '\\"' '\\"' 1 0 1 0} {String '\\"' '\\"' 1 0 1 0}
{String "'" "'" 1 0 1 0} {String "'" "'" 1 0 1 0}
+52
View File
@@ -179,7 +179,57 @@ t_run_caller(void *raw_ctx)
.result_out = &ctx->result, .result_out = &ctx->result,
.test_out = &test_out, .test_out = &test_out,
}; };
log_scope_begin();
ctx->test->test_fn(scratch.arena, &test_ctx); ctx->test->test_fn(scratch.arena, &test_ctx);
LogScopeResult log_scope_result = log_scope_end(scratch.arena);
if(log_scope_result.strings[LogMsgKind_Info].size != 0)
{
String8 current_path = str8f(scratch.arena, "%S/current", g_wdir);
String8 exemplar_path = str8f(scratch.arena, "%S/exemplar_%S_%S", g_exemplar_dir, lower_from_str8(scratch.arena, string_from_operating_system(OperatingSystem_CURRENT)), lower_from_str8(scratch.arena, string_from_arch(Arch_CURRENT)));
String8 current = log_scope_result.strings[LogMsgKind_Info];
String8 exemplar = data_from_file_path(scratch.arena, exemplar_path);
write_data_to_file_path(current_path, current);
if(exemplar.size == 0)
{
make_directory(g_exemplar_dir);
copy_file_path(exemplar_path, current_path);
}
else
{
// TODO(rjf): @hack, see below
TestCtx *ctx = &test_ctx;
String8List exemplar_lines = str8_split(scratch.arena, exemplar, (U8 *)"\n", 1, StringSplitFlag_KeepEmpties);
String8List exemplar_lines_sanitized = {0};
for EachNode(n, String8Node, exemplar_lines.first)
{
String8 line_trimmed = n->string;
if(line_trimmed.size != 0 && line_trimmed.str[line_trimmed.size-1] == '\r')
{
line_trimmed.size -= 1;
}
str8_list_push(scratch.arena, &exemplar_lines_sanitized, line_trimmed);
}
StringJoin join = {.sep = s("\n"), .post = s("\n")};
String8 exemplar_sanitized = str8_list_join(scratch.arena, &exemplar_lines_sanitized, &join);
B32 current_matches_exemplar = str8_match(exemplar_sanitized, current, 0);
if(!current_matches_exemplar)
{
// TODO(rjf): @hack, because we need to do test things in the outer scope, but this is
// not a test function - all test helpers should wrap a 100% parameterized layer
Arena *arena = scratch.arena;
String8 diff_cmd = str8f(scratch.arena, "diff %S %S",
path_normalized_from_string(scratch.arena, exemplar_path),
path_normalized_from_string(scratch.arena, current_path));
test_outf("Current log does not match exemplar; run `%S`\n", diff_cmd);
// TODO(rjf): @hack need to hack this in, because TestCheck assumes `return`
ctx->result_out[0] = (TestResult){.fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = "current_matches_exemplar"};
if(debugger_is_attached())
{
Trap();
}
}
}
}
} }
if (ctx->result.status == TestStatus_Fail || ctx->result.status == TestStatus_Crash) { if (ctx->result.status == TestStatus_Fail || ctx->result.status == TestStatus_Crash) {
@@ -1054,6 +1104,8 @@ internal void
t_entry_point(CmdLine *cmdline) t_entry_point(CmdLine *cmdline)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
Log *log = log_alloc();
log_select(log);
U64 exit_code = max_U64; U64 exit_code = max_U64;
U64 dashes_size = 9999; U64 dashes_size = 9999;
+3 -1
View File
@@ -16,7 +16,6 @@
#define R_INIT_MANUAL 1 #define R_INIT_MANUAL 1
#define FNT_INIT_MANUAL 1 #define FNT_INIT_MANUAL 1
#define RD_INIT_MANUAL 1 #define RD_INIT_MANUAL 1
#define NO_ASYNC 1
//////////////////////////////// ////////////////////////////////
@@ -77,6 +76,7 @@
#include "stap/stap_parse.h" #include "stap/stap_parse.h"
#include "demon/demon_inc.h" #include "demon/demon_inc.h"
#include "eval/eval_inc.h" #include "eval/eval_inc.h"
#include "eval2/eval2.h"
#include "dbg_engine/dbg_engine_inc.h" #include "dbg_engine/dbg_engine_inc.h"
#include "eval_visualization/eval_visualization_inc.h" #include "eval_visualization/eval_visualization_inc.h"
#include "font_provider/font_provider_inc.h" #include "font_provider/font_provider_inc.h"
@@ -157,6 +157,7 @@
#include "stap/stap_parse.c" #include "stap/stap_parse.c"
#include "demon/demon_inc.c" #include "demon/demon_inc.c"
#include "eval/eval_inc.c" #include "eval/eval_inc.c"
#include "eval2/eval2.c"
#include "dbg_engine/dbg_engine_inc.c" #include "dbg_engine/dbg_engine_inc.c"
#include "eval_visualization/eval_visualization_inc.c" #include "eval_visualization/eval_visualization_inc.c"
#include "font_provider/font_provider_inc.c" #include "font_provider/font_provider_inc.c"
@@ -185,6 +186,7 @@
#include "rdi_from_dwarf/tests/rdi_from_dwarf_tests.c" #include "rdi_from_dwarf/tests/rdi_from_dwarf_tests.c"
#include "rdi_from_pdb/tests/rdi_from_pdb_tests.c" #include "rdi_from_pdb/tests/rdi_from_pdb_tests.c"
#include "raddbg/tests/raddbg_tests.c" #include "raddbg/tests/raddbg_tests.c"
#include "eval2/tests/eval2_tests.c"
internal B32 frame(void) { return 0; } internal B32 frame(void) { return 0; }
+20 -20
View File
@@ -129,8 +129,8 @@ typedef struct UI_LineEditDrawData UI_LineEditDrawData;
struct UI_LineEditDrawData struct UI_LineEditDrawData
{ {
String8 edited_string; String8 edited_string;
TxtPt cursor; U64 cursor;
TxtPt mark; U64 mark;
B32 trail; B32 trail;
}; };
@@ -148,11 +148,11 @@ internal UI_BOX_CUSTOM_DRAW(ui_line_edit_draw)
trail_color.w *= 0.25f; trail_color.w *= 0.25f;
Vec2F32 text_position = ui_box_text_position(box); Vec2F32 text_position = ui_box_text_position(box);
String8 edited_string = draw_data->edited_string; String8 edited_string = draw_data->edited_string;
TxtPt cursor = draw_data->cursor; U64 cursor = draw_data->cursor;
TxtPt mark = draw_data->mark; U64 mark = draw_data->mark;
F32 cursor_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, cursor.column-1)).x; F32 cursor_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, cursor)).x;
F32 cursor_pixel_off__animated = ui_anim(ui_key_from_stringf(box->key, "cursor_off_px"), cursor_pixel_off); F32 cursor_pixel_off__animated = ui_anim(ui_key_from_stringf(box->key, "cursor_off_px"), cursor_pixel_off);
F32 mark_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, mark.column-1)).x; F32 mark_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, mark)).x;
F32 cursor_thickness = ClampBot(1.f, floor_f32(font_size/10.f)); F32 cursor_thickness = ClampBot(1.f, floor_f32(font_size/10.f));
Rng2F32 cursor_rect = Rng2F32 cursor_rect =
{ {
@@ -196,7 +196,7 @@ internal UI_BOX_CUSTOM_DRAW(ui_line_edit_draw)
} }
internal UI_Signal internal UI_Signal
ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, String8 string) ui_line_edit(U64 *cursor, U64 *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, String8 string)
{ {
//- rjf: make key //- rjf: make key
UI_Key key = ui_key_from_string(ui_active_seed_key(), string); UI_Key key = ui_key_from_string(ui_active_seed_key(), string);
@@ -238,19 +238,19 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
} }
// rjf: map this action to an op // rjf: map this action to an op
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, *cursor, *mark); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), *cursor, *mark);
// rjf: perform replace range // rjf: perform replace range
if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) if(op.range.min != op.range.max || op.replace.size != 0)
{ {
String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace); String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, op.range, op.replace);
new_string.size = Min(edit_buffer_size, new_string.size); new_string.size = Min(edit_buffer_size, new_string.size);
MemoryCopy(edit_buffer, new_string.str, new_string.size); MemoryCopy(edit_buffer, new_string.str, new_string.size);
edit_string_size_out[0] = new_string.size; edit_string_size_out[0] = new_string.size;
} }
// rjf: perform copy // rjf: perform copy
if(op.flags & UI_TxtOpFlag_Copy) if(evt->flags & UI_EventFlag_Copy)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
@@ -269,7 +269,7 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
} }
//- rjf: build contents //- rjf: build contents
TxtPt mouse_pt = {0}; U64 mouse_off = {0};
F32 cursor_off = 0; F32 cursor_off = 0;
UI_Parent(box) UI_Parent(box)
{ {
@@ -289,14 +289,14 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
ui_set_next_pref_width(ui_px(total_text_width+ui_top_font_size()*5, 1.f)); ui_set_next_pref_width(ui_px(total_text_width+ui_top_font_size()*5, 1.f));
UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr");
UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1);
draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); draw_data->edited_string = str8_copy(ui_build_arena(), edit_string);
draw_data->cursor = *cursor; draw_data->cursor = *cursor;
draw_data->mark = *mark; draw_data->mark = *mark;
draw_data->trail = 1; draw_data->trail = 1;
ui_box_equip_display_string(editstr_box, edit_string); ui_box_equip_display_string(editstr_box, edit_string);
ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data);
mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); mouse_off = ui_box_char_pos_from_xy(editstr_box, ui_mouse());
cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, cursor->column-1)).x; cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, *cursor)).x;
} }
} }
@@ -310,8 +310,8 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
edit_string_size_out[0] = edit_string.size; edit_string_size_out[0] = edit_string.size;
ui_set_auto_focus_active_key(key); ui_set_auto_focus_active_key(key);
ui_kill_action(); ui_kill_action();
*cursor = txt_pt(1, edit_string.size+1); *cursor = edit_string.size;
*mark = txt_pt(1, 1); *mark = 0;
} }
if(is_focus_active && sig.f&UI_SignalFlag_KeyboardPressed) if(is_focus_active && sig.f&UI_SignalFlag_KeyboardPressed)
{ {
@@ -322,9 +322,9 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
{ {
if(ui_pressed(sig)) if(ui_pressed(sig))
{ {
*mark = mouse_pt; *mark = mouse_off;
} }
*cursor = mouse_pt; *cursor = mouse_off;
} }
//- rjf: focus cursor //- rjf: focus cursor
@@ -349,7 +349,7 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
} }
internal UI_Signal internal UI_Signal
ui_line_editf(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, char *fmt, ...) ui_line_editf(U64 *cursor, U64 *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, String8 pre_edit_value, char *fmt, ...)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
va_list args; va_list args;

Some files were not shown because too many files have changed in this diff Show More