mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
239
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b99e10224f | ||
|
|
435f6c4ef6 | ||
|
|
b631d431fa | ||
|
|
2562d04fbf | ||
|
|
b52a008748 | ||
|
|
b16d930d13 | ||
|
|
26be351354 | ||
|
|
77b2172a85 | ||
|
|
f1c5c97a1b | ||
|
|
6be2792659 | ||
|
|
c42e7837ac | ||
|
|
fe657987d6 | ||
|
|
48c7bb788e | ||
|
|
080a001183 | ||
|
|
81c7c7a7c4 | ||
|
|
95fe497056 | ||
|
|
8994cb04bc | ||
|
|
ce90b63079 | ||
|
|
6cf9b82857 | ||
|
|
cefbd40e2c | ||
|
|
420f089fda | ||
|
|
ff45952f07 | ||
|
|
fa4f9621b0 | ||
|
|
4c0ebc851c | ||
|
|
5a79518dcb | ||
|
|
713cc2c693 | ||
|
|
dcec3c07d9 | ||
|
|
b03c1766c6 | ||
|
|
4278f7db1e | ||
|
|
ff90a90744 | ||
|
|
626665911d | ||
|
|
f09f059af2 | ||
|
|
e95afcd5aa | ||
|
|
a8b1805749 | ||
|
|
a8b2266fc0 | ||
|
|
bc446d8520 | ||
|
|
9808157f45 | ||
|
|
0ec6b8e8a8 | ||
|
|
3e0c150ccb | ||
|
|
fd1906b034 | ||
|
|
2bbf3ff987 | ||
|
|
880d7a4139 | ||
|
|
c6caec657d | ||
|
|
3d7fc6fce5 | ||
|
|
0d0951bf08 | ||
|
|
3a190ae2c3 | ||
|
|
420c2ec208 | ||
|
|
f9abd3efb9 | ||
|
|
5893ab94cb | ||
|
|
ff2e9df705 | ||
|
|
5aeee47f98 | ||
|
|
31f25d0fe7 | ||
|
|
bd4f82c8e8 | ||
|
|
680ea2ffdc | ||
|
|
f7d7f6633f | ||
|
|
04c1488cd4 | ||
|
|
5232ba298d | ||
|
|
65ada18d1d | ||
|
|
8e6a0ae4db | ||
|
|
e297460697 | ||
|
|
cf8c0e7442 | ||
|
|
776c8daa27 | ||
|
|
69b43c76d4 | ||
|
|
d114a0e961 | ||
|
|
d177e39a54 | ||
|
|
158dd742ad | ||
|
|
0773b6d282 | ||
|
|
15d43d7c99 | ||
|
|
7650a83d1e | ||
|
|
daeb08e79f | ||
|
|
ef5287d2a9 | ||
|
|
db04792073 | ||
|
|
4091373517 | ||
|
|
214be8c433 | ||
|
|
f807dc4785 | ||
|
|
0dd05169ee | ||
|
|
ce9d43a92e | ||
|
|
0886963d93 | ||
|
|
27cd7a21a3 | ||
|
|
7bb88f480e | ||
|
|
fad817fb9e | ||
|
|
1d42f1bd66 | ||
|
|
a5dd35b874 | ||
|
|
a89af7f6fd | ||
|
|
5a19ab9c31 | ||
|
|
e204fe28c1 | ||
|
|
d036eb9fc5 | ||
|
|
1621e504ce | ||
|
|
44b8c9e87c | ||
|
|
4a0e21d447 | ||
|
|
3cd32fa235 | ||
|
|
c3a672cd02 | ||
|
|
9ce0bc5dbf | ||
|
|
ffb21277e9 | ||
|
|
a40edbba51 | ||
|
|
c2855a9a46 | ||
|
|
61e7aaadeb | ||
|
|
5a0efe1261 | ||
|
|
6d55d21643 | ||
|
|
4164b30aac | ||
|
|
aded54c97f | ||
|
|
79bcbe4b39 | ||
|
|
86d9b792d8 | ||
|
|
f3a36ece13 | ||
|
|
c5d198e3e9 | ||
|
|
eba7500f73 | ||
|
|
339f43919c | ||
|
|
f3fbf10754 | ||
|
|
4a2e1dd8d0 | ||
|
|
ee65ea3692 | ||
|
|
baead67a99 | ||
|
|
e085dae636 | ||
|
|
eba6765541 | ||
|
|
002e479a2d | ||
|
|
8848080729 | ||
|
|
e1166abc63 | ||
|
|
6ffc065712 | ||
|
|
15b1ebcd21 | ||
|
|
37b27a9cff | ||
|
|
327fec3155 | ||
|
|
d0b97a3010 | ||
|
|
1b5321ad8e | ||
|
|
4769d0a8d4 | ||
|
|
41cddf96b8 | ||
|
|
100d3523d3 | ||
|
|
f0b1b46840 | ||
|
|
e9666e2edd | ||
|
|
8f932bdbf7 | ||
|
|
c3c9539f9b | ||
|
|
13341a458a | ||
|
|
62659c5161 | ||
|
|
1ecabff7b6 | ||
|
|
45f5a2d18f | ||
|
|
bcd16a4f29 | ||
|
|
6d7858d445 | ||
|
|
c67f1a8b4a | ||
|
|
340396f9f7 | ||
|
|
eb6aabe2d1 | ||
|
|
9ec7fb61ed | ||
|
|
dcffefd0c6 | ||
|
|
5be2b5dfd9 | ||
|
|
7260baea85 | ||
|
|
a802f2186b | ||
|
|
a43678e311 | ||
|
|
edee84dd03 | ||
|
|
4a211de2b3 | ||
|
|
d0915ec9a7 | ||
|
|
52245a8e5a | ||
|
|
dbcecd99af | ||
|
|
68c0906570 | ||
|
|
26611c5454 | ||
|
|
05d4faeb49 | ||
|
|
d5c2e50e9a | ||
|
|
800a2349e5 | ||
|
|
46390ba0b8 | ||
|
|
f1a0e7233d | ||
|
|
9d60dcc099 | ||
|
|
f792da5d31 | ||
|
|
1344270b5a | ||
|
|
c03844fb1a | ||
|
|
d04e86c007 | ||
|
|
669574df5a | ||
|
|
3aa4b2ea03 | ||
|
|
2f5e55d52f | ||
|
|
14ad67d59a | ||
|
|
b2bdb893a0 | ||
|
|
98dfedfff5 | ||
|
|
1f633a029c | ||
|
|
b3d6b2913e | ||
|
|
53c624a27c | ||
|
|
1865c33704 | ||
|
|
e17a089564 | ||
|
|
eb9212b6f7 | ||
|
|
0ac090cab2 | ||
|
|
7827e1b1c7 | ||
|
|
36f3924160 | ||
|
|
00dd4ad6ec | ||
|
|
7f7f7f2873 | ||
|
|
c8a5fc4806 | ||
|
|
652dcafbbf | ||
|
|
72f987533c | ||
|
|
5fd835c4d4 | ||
|
|
c50d9276ba | ||
|
|
1214cb0968 | ||
|
|
3099759c0b | ||
|
|
95d31f5608 | ||
|
|
687323fc2e | ||
|
|
51dce36ede | ||
|
|
b61f4d550f | ||
|
|
d8d8762869 | ||
|
|
d2db4542cb | ||
|
|
7adf08cc7b | ||
|
|
a202999655 | ||
|
|
ae3a43c694 | ||
|
|
2f7434cd92 | ||
|
|
b02c67bfa6 | ||
|
|
992be37801 | ||
|
|
4727a01b9f | ||
|
|
e376ad8113 | ||
|
|
23ad094a68 | ||
|
|
2b407b5861 | ||
|
|
79390f4a95 | ||
|
|
aedfb556be | ||
|
|
78039c86a0 | ||
|
|
186e8cbabe | ||
|
|
5ec0a0e406 | ||
|
|
9c016004c2 | ||
|
|
9c1f8ef37b | ||
|
|
938af75efb | ||
|
|
38173a7154 | ||
|
|
74ee3b9850 | ||
|
|
2edb65b5bd | ||
|
|
9e6aa8506f | ||
|
|
648fa7cdab | ||
|
|
6612f4a32d | ||
|
|
e65bc121ed | ||
|
|
e1575f815c | ||
|
|
0b50d8718e | ||
|
|
4671458e8e | ||
|
|
bb86072dfa | ||
|
|
d5988d0066 | ||
|
|
932df7bf68 | ||
|
|
0cf553e39a | ||
|
|
1bcd66329f | ||
|
|
c3e2e2e91b | ||
|
|
c34d7e2062 | ||
|
|
b1d6ebf77b | ||
|
|
9535652cfb | ||
|
|
3ae1d8e401 | ||
|
|
7e98df22d7 | ||
|
|
65b5176468 | ||
|
|
e61dfd793a | ||
|
|
97abec11a2 | ||
|
|
b223a61cad | ||
|
|
94fb5056c2 | ||
|
|
88dced7d2a | ||
|
|
e92543d3f8 | ||
|
|
078cbf6afd | ||
|
|
3d34a26205 |
@@ -0,0 +1 @@
|
||||
*.sh text=auto eol=lf
|
||||
@@ -28,3 +28,5 @@ jobs:
|
||||
call build rdi_from_pdb clang debug || exit /b 1
|
||||
call build rdi_from_dwarf clang debug || exit /b 1
|
||||
call build rdi_dump clang debug || exit /b 1
|
||||
call build radlink msvc debug || exit /b 1
|
||||
call build radlink clang debug || exit /b 1
|
||||
@@ -158,6 +158,45 @@ like remote debugging, porting to different architectures, further improving
|
||||
the debugger's features (like improving the visualization engine), and so on.
|
||||
But for now, we're mostly focused on those first two phases.
|
||||
|
||||
---
|
||||
|
||||
# The RAD Linker
|
||||
|
||||
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries. It is designed to be very fast when creating gigantic executables. It generates standard PDB files for debugging, but it can also optionally create RAD Debugger debug info too (useful for huge executables that otherwise create broken PDBs that overflow internal 32-bit tables).
|
||||
|
||||
The RAD Linker is primarily optimized to handle huge linking projects - in our test cases (where debug info is multiple gigabytes), we see 50% faster link times.
|
||||
|
||||
The command line syntax is fully compatible with MSVC and you can get a full list of implemented switches from `/help`.
|
||||
|
||||
Our current designed-for use case for the linker is to help with the compile-debug cycle of huge projects. We don't yet have support for dead-code-elimination or link-time-optimizations, but these features are on the road map.
|
||||
|
||||
By default, the RAD linker spawns as many threads as there are cores, so if you plan to run multiple linkers in parallel, you can limit the number of thread workers via `/rad_workers`.
|
||||
|
||||
We also have support for large memory pages, which, when enabled, reduce link time by
|
||||
another 25%. To link with large pages, you need to explicitly request them via `/rad_large_pages`. Large pages are off by default, since Windows support for large pages is a bit buggy - we recommend they only be used in Docker or VM images where the environment is reset after each link. In a standard Windows environment, using large pages otherwise will fragment memory quickly forcing a reboot. We are working on a Linux port of the linker that will be able to build with large pages robustly.
|
||||
|
||||
## Short Term Roadmap
|
||||
- Porting linker to Linux (for Windows executables, just running on Linux).
|
||||
- Debug info features
|
||||
- Get DWARF debug info converter up-and-running.
|
||||
- Smooth out rough edges in RADDBGI builder.
|
||||
- Improve build speed further (especially for tiny and mid sizes projects).
|
||||
- Other features to come
|
||||
- Dead-code-elimination via `/opt:ref`.
|
||||
- Link Time Optimizations with the help of clang (we won't support LTCG from MSVC compiler since it is undocumented).
|
||||
|
||||
## To build the RAD Linker
|
||||
- Setup development environment, [see](#Development-Setup-Instructions)
|
||||
- Run `build radlink release` or if you have clang installed `build radlink release clang`. We favor latter option for better code generation.
|
||||
|
||||
If build was successful linker executable is placed in `build` folder under `radlink.exe`.
|
||||
|
||||
## Benchmarks
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Top-Level Directory Descriptions
|
||||
|
||||
- `data`: Small binary files which are used when building, either to embed
|
||||
@@ -202,6 +241,8 @@ not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `async` (`ASYNC_`): Implements a system for asynchronous work to be queued
|
||||
and executed on a thread pool.
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||
on no other codebase layers.
|
||||
@@ -336,8 +377,6 @@ A list of the layers in the codebase and their associated namespaces is below:
|
||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||
layer.
|
||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
||||
- `task_system` (`TS_`): Implements a system for kicking off asynchronous tasks
|
||||
and obtaining artifacts from those tasks once they've completed.
|
||||
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for visualization.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
setlocal
|
||||
setlocal enabledelayedexpansion
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||
@@ -48,13 +48,24 @@ set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_fl
|
||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
|
||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" /pdbaltpath:%%%%_PDB%%%% logo.res
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%%
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%%
|
||||
set cl_out= /out:
|
||||
set clang_out= -o
|
||||
|
||||
:: --- NATVIS -----------------------------------------------------------------
|
||||
set natvis= /NATVIS:"%~dp0\src\natvis\base.natvis"
|
||||
if "%radlink%"=="1" set natvis= %natvis% /NATVIS:"%~dp0\src\linker\linker.natvis"
|
||||
|
||||
if "%clang%"=="1" (
|
||||
set result=
|
||||
for %%n in (%natvis%) do set result= !result! -Xlinker %%n
|
||||
set natvis= !result!
|
||||
)
|
||||
|
||||
:: --- Per-Build Settings -----------------------------------------------------
|
||||
set link_dll=-DLL
|
||||
set link_icon=logo.res
|
||||
if "%msvc%"=="1" set only_compile=/c
|
||||
if "%clang%"=="1" set only_compile=-c
|
||||
if "%msvc%"=="1" set EHsc=/EHsc
|
||||
@@ -76,6 +87,9 @@ if "%clang%"=="1" set out=%clang_out%
|
||||
if "%debug%"=="1" set compile=%compile_debug%
|
||||
if "%release%"=="1" set compile=%compile_release%
|
||||
|
||||
:: --- Append NATVIS to link line ---------------------------------------------
|
||||
set compile_link= %compile_link% %natvis%
|
||||
|
||||
:: --- Prep Directories -------------------------------------------------------
|
||||
if not exist build mkdir build
|
||||
if not exist local mkdir local
|
||||
@@ -86,7 +100,8 @@ pushd build
|
||||
popd
|
||||
|
||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
||||
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
||||
|
||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||
if "%no_meta%"=="1" echo [skipping metagen]
|
||||
@@ -99,12 +114,16 @@ if not "%no_meta%"=="1" (
|
||||
|
||||
:: --- Build Everything (@build_targets) --------------------------------------
|
||||
pushd build
|
||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %out%raddbg.exe || exit /b 1
|
||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %out%radlink.exe || exit /b 1
|
||||
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
|
||||
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||
if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
|
||||
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1
|
||||
if "%tester%"=="1" set didbuild=1 && %compile% ..\src\tester\tester_main.c %compile_link% %out%tester.exe || exit /b 1
|
||||
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
||||
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
|
||||
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
|
||||
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
|
||||
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
|
||||
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
|
||||
@@ -118,16 +137,6 @@ if "%mule_peb_trample%"=="1" (
|
||||
)
|
||||
popd
|
||||
|
||||
:: --- Unset ------------------------------------------------------------------
|
||||
for %%a in (%*) do set "%%a=0"
|
||||
set raddbg=
|
||||
set compile=
|
||||
set compile_link=
|
||||
set out=
|
||||
set msvc=
|
||||
set debug=
|
||||
set release=
|
||||
|
||||
:: --- Warn On No Builds ------------------------------------------------------
|
||||
if "%didbuild%"=="" (
|
||||
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
|
||||
|
||||
@@ -14,13 +14,17 @@ if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi
|
||||
# --- Unpack Command Line Build Arguments -------------------------------------
|
||||
auto_compile_flags=''
|
||||
|
||||
# --- Get Current Git Commit Id -----------------------------------------------
|
||||
git_hash=$(git rev-parse HEAD)
|
||||
git_hash_full=$(git rev-parse HEAD)
|
||||
|
||||
# --- Compile/Link Line Definitions -------------------------------------------
|
||||
clang_common='-I../src/ -I../local/ -g -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf'
|
||||
clang_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
|
||||
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
|
||||
clang_link="-lpthread -lm -lrt -ldl"
|
||||
clang_out="-o"
|
||||
gcc_common='-I../src/ -I../local/ -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf'
|
||||
gcc_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${gcc_common} ${auto_compile_flags}"
|
||||
gcc_link="-lpthread -lm -lrt -ldl"
|
||||
@@ -59,6 +63,7 @@ fi
|
||||
# --- Build Everything (@build_targets) ---------------------------------------
|
||||
cd build
|
||||
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $out raddbg; fi
|
||||
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
|
||||
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
|
||||
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
|
||||
if [ -v rdi_dump ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump; fi
|
||||
|
||||
@@ -49,6 +49,8 @@ commands =
|
||||
.f1 = { .win = "build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f2 = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f3 = { .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project --xuto_run && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "build textperf release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f3 = { .win = "pushd build && textperf.exe --capture && popd",.linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: local target builds
|
||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /D "%~dp0"
|
||||
|
||||
echo --- getting test data folder path ---------------------------------------------
|
||||
if not exist .\local\test_data_path.txt (
|
||||
echo error: You must first store the full path of your test data folder inside of `local/test_data_path.txt`.
|
||||
goto :EOF
|
||||
)
|
||||
set /p test_data_folder=<.\local\test_data_path.txt
|
||||
echo test data path: %test_data_folder%
|
||||
echo:
|
||||
|
||||
echo --- building all testing executables ------------------------------------------
|
||||
call build rdi_from_pdb rdi_dump raddbg radlink tester
|
||||
echo:
|
||||
|
||||
echo --- running tests -------------------------------------------------------------
|
||||
pushd build
|
||||
call tester.exe --test_data:%test_data_folder%
|
||||
popd
|
||||
@@ -0,0 +1,240 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void
|
||||
async_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
async_shared = push_array(arena, ASYNC_Shared, 1);
|
||||
async_shared->arena = arena;
|
||||
for EachEnumVal(ASYNC_Priority, p)
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[p];
|
||||
ring->ring_size = MB(8);
|
||||
ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size);
|
||||
ring->ring_mutex = os_mutex_alloc();
|
||||
ring->ring_cv = os_condition_variable_alloc();
|
||||
}
|
||||
async_shared->ring_mutex = os_mutex_alloc();
|
||||
async_shared->ring_cv = os_condition_variable_alloc();
|
||||
async_shared->work_threads_count = Max(1, os_get_system_info()->logical_processor_count-1);
|
||||
async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count);
|
||||
for EachIndex(idx, async_shared->work_threads_count)
|
||||
{
|
||||
async_shared->work_threads[idx] = os_thread_launch(async_work_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64
|
||||
async_thread_count(void)
|
||||
{
|
||||
return async_shared->work_threads_count;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32
|
||||
async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
// rjf: choose ring
|
||||
ASYNC_Ring *ring = &async_shared->rings[params->priority];
|
||||
|
||||
// rjf: build work package
|
||||
ASYNC_Work work = {0};
|
||||
work.work_function = work_function;
|
||||
work.input = params->input;
|
||||
work.output = params->output;
|
||||
work.semaphore = params->semaphore;
|
||||
work.completion_counter = params->completion_counter;
|
||||
|
||||
// rjf: loop; try to write into user -> writer ring buffer. if we're on a
|
||||
// worker thread, determine if we need to execute this task locally on this
|
||||
// thread, and skip ring buffer if so.
|
||||
B32 queued_in_ring_buffer = 0;
|
||||
B32 need_to_execute_on_this_thread = 0;
|
||||
OS_MutexScope(ring->ring_mutex) for(;;)
|
||||
{
|
||||
U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count));
|
||||
if(num_available_work_threads == 0 && async_work_thread_depth > 0)
|
||||
{
|
||||
need_to_execute_on_this_thread = 1;
|
||||
break;
|
||||
}
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
U64 available_size = ring->ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(work))
|
||||
{
|
||||
queued_in_ring_buffer = 1;
|
||||
if(!os_handle_match(params->semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_take(params->semaphore, max_U64);
|
||||
}
|
||||
ring->ring_write_pos += ring_write_struct(ring->ring_base, ring->ring_size, ring->ring_write_pos, &work);
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= params->endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(ring->ring_cv, ring->ring_mutex, params->endt_us);
|
||||
}
|
||||
|
||||
// rjf: broadcast ring buffer cv if we wrote successfully
|
||||
if(queued_in_ring_buffer)
|
||||
{
|
||||
os_condition_variable_broadcast(ring->ring_cv);
|
||||
os_condition_variable_broadcast(async_shared->ring_cv);
|
||||
}
|
||||
|
||||
// rjf: if we did not queue successfully, and we have determined that
|
||||
// we need to execute this work on the current thread, then execute the
|
||||
// work before returning
|
||||
if(need_to_execute_on_this_thread)
|
||||
{
|
||||
async_execute_work(work);
|
||||
}
|
||||
|
||||
// rjf: return success signal
|
||||
B32 result = (queued_in_ring_buffer || need_to_execute_on_this_thread);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void
|
||||
async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t)
|
||||
{
|
||||
ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
n->v = t;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal ASYNC_Task *
|
||||
async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
ASYNC_Task *task = push_array(arena, ASYNC_Task, 1);
|
||||
task->semaphore = os_semaphore_alloc(1, 1, str8_zero());
|
||||
ASYNC_WorkParams params_refined = {0};
|
||||
MemoryCopyStruct(¶ms_refined, params);
|
||||
params_refined.endt_us = max_U64;
|
||||
params_refined.semaphore = task->semaphore;
|
||||
if(params_refined.output == 0)
|
||||
{
|
||||
params_refined.output = &task->output;
|
||||
}
|
||||
async_push_work_(work_function, ¶ms_refined);
|
||||
return task;
|
||||
}
|
||||
|
||||
internal void *
|
||||
async_task_join(ASYNC_Task *task)
|
||||
{
|
||||
void *result = 0;
|
||||
if(task != 0 && !os_handle_match(task->semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_take(task->semaphore, max_U64);
|
||||
os_semaphore_release(task->semaphore);
|
||||
MemoryZeroStruct(&task->semaphore);
|
||||
result = (void *)ins_atomic_u64_eval(&task->output);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work
|
||||
async_pop_work(void)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
ASYNC_Work work = {0};
|
||||
B32 done = 0;
|
||||
ASYNC_Priority taken_priority = ASYNC_Priority_Low;
|
||||
OS_MutexScope(async_shared->ring_mutex) for(;!done;)
|
||||
{
|
||||
for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1))
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[priority];
|
||||
OS_MutexScope(ring->ring_mutex)
|
||||
{
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(work))
|
||||
{
|
||||
ring->ring_read_pos += ring_read_struct(ring->ring_base, ring->ring_size, ring->ring_read_pos, &work);
|
||||
done = 1;
|
||||
taken_priority = priority;
|
||||
}
|
||||
}
|
||||
if(done)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(priority == ASYNC_Priority_Low)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!done)
|
||||
{
|
||||
os_condition_variable_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64);
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(async_shared->ring_cv);
|
||||
os_condition_variable_broadcast(async_shared->rings[taken_priority].ring_cv);
|
||||
ProfEnd();
|
||||
return work;
|
||||
}
|
||||
|
||||
internal void
|
||||
async_execute_work(ASYNC_Work work)
|
||||
{
|
||||
//- rjf: run work
|
||||
async_work_thread_depth += 1;
|
||||
void *work_out = work.work_function(async_work_thread_idx, work.input);
|
||||
async_work_thread_depth -= 1;
|
||||
|
||||
//- rjf: store output
|
||||
if(work.output != 0)
|
||||
{
|
||||
ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out);
|
||||
}
|
||||
|
||||
//- rjf: release semaphore
|
||||
if(!os_handle_match(work.semaphore, os_handle_zero()))
|
||||
{
|
||||
os_semaphore_drop(work.semaphore);
|
||||
}
|
||||
|
||||
//- rjf: increment completion counter
|
||||
if(work.completion_counter != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(work.completion_counter);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void
|
||||
async_work_thread__entry_point(void *p)
|
||||
{
|
||||
U64 thread_idx = (U64)p;
|
||||
ThreadNameF("[async] work thread #%I64u", thread_idx);
|
||||
async_work_thread_idx = thread_idx;
|
||||
for(;;)
|
||||
{
|
||||
ASYNC_Work work = async_pop_work();
|
||||
ins_atomic_u64_inc_eval(&async_shared->work_threads_live_count);
|
||||
async_execute_work(work);
|
||||
ins_atomic_u64_dec_eval(&async_shared->work_threads_live_count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ASYNC_H
|
||||
#define ASYNC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Function Type
|
||||
|
||||
#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input)
|
||||
#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name)
|
||||
typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Types
|
||||
|
||||
typedef enum ASYNC_Priority
|
||||
{
|
||||
ASYNC_Priority_Low,
|
||||
ASYNC_Priority_High,
|
||||
ASYNC_Priority_COUNT
|
||||
}
|
||||
ASYNC_Priority;
|
||||
|
||||
typedef struct ASYNC_WorkParams ASYNC_WorkParams;
|
||||
struct ASYNC_WorkParams
|
||||
{
|
||||
void *input;
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 endt_us;
|
||||
ASYNC_Priority priority;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Work ASYNC_Work;
|
||||
struct ASYNC_Work
|
||||
{
|
||||
ASYNC_WorkFunctionType *work_function;
|
||||
void *input;
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Types
|
||||
|
||||
typedef struct ASYNC_Task ASYNC_Task;
|
||||
struct ASYNC_Task
|
||||
{
|
||||
OS_Handle semaphore;
|
||||
void *output;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskNode ASYNC_TaskNode;
|
||||
struct ASYNC_TaskNode
|
||||
{
|
||||
ASYNC_TaskNode *next;
|
||||
ASYNC_Task *v;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskList ASYNC_TaskList;
|
||||
struct ASYNC_TaskList
|
||||
{
|
||||
ASYNC_TaskNode *first;
|
||||
ASYNC_TaskNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct ASYNC_Ring ASYNC_Ring;
|
||||
struct ASYNC_Ring
|
||||
{
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Shared ASYNC_Shared;
|
||||
struct ASYNC_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user -> work thread ring buffers
|
||||
ASYNC_Ring rings[ASYNC_Priority_COUNT];
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
|
||||
// rjf: work threads
|
||||
OS_Handle *work_threads;
|
||||
U64 work_threads_count;
|
||||
U64 work_threads_live_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static B32 async_work_thread_depth = 0;
|
||||
thread_static U64 async_work_thread_idx = 0;
|
||||
global ASYNC_Shared *async_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void async_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64 async_thread_count(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, .priority = ASYNC_Priority_High, __VA_ARGS__})
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t);
|
||||
internal ASYNC_Task *async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_task_launch(arena, work_function, ...) async_task_launch_((arena), (work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__})
|
||||
internal void *async_task_join(ASYNC_Task *task);
|
||||
#define async_task_join_struct(task, T) (T *)async_task_join(task)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work async_pop_work(void);
|
||||
internal void async_execute_work(ASYNC_Work work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void async_work_thread__entry_point(void *p);
|
||||
|
||||
#endif // ASYNC_H
|
||||
+53
-9
@@ -52,12 +52,16 @@ arena_alloc_(ArenaParams *params)
|
||||
Arena *arena = (Arena *)base;
|
||||
arena->current = arena;
|
||||
arena->flags = params->flags;
|
||||
arena->cmt_size = (U32)params->commit_size;
|
||||
arena->cmt_size = params->commit_size;
|
||||
arena->res_size = params->reserve_size;
|
||||
arena->base_pos = 0;
|
||||
arena->pos = ARENA_HEADER_SIZE;
|
||||
arena->cmt = commit_size;
|
||||
arena->res = reserve_size;
|
||||
#if ARENA_FREE_LIST
|
||||
arena->free_size = 0;
|
||||
arena->free_last = 0;
|
||||
#endif
|
||||
AsanPoisonMemoryRegion(base, commit_size);
|
||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
||||
return arena;
|
||||
@@ -85,18 +89,46 @@ arena_push(Arena *arena, U64 size, U64 align)
|
||||
// rjf: chain, if needed
|
||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
||||
{
|
||||
U64 res_size = current->res_size;
|
||||
U64 cmt_size = current->cmt_size;
|
||||
if(size + ARENA_HEADER_SIZE > res_size)
|
||||
Arena *new_block = 0;
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
Arena *prev_block;
|
||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
||||
{
|
||||
res_size = size + ARENA_HEADER_SIZE;
|
||||
cmt_size = size + ARENA_HEADER_SIZE;
|
||||
if(new_block->res >= AlignPow2(size, align))
|
||||
{
|
||||
if(prev_block)
|
||||
{
|
||||
prev_block->prev = new_block->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
arena->free_last = new_block->prev;
|
||||
}
|
||||
arena->free_size -= new_block->res_size;
|
||||
AsanUnpoisonMemoryRegion((U8*)new_block + ARENA_HEADER_SIZE, new_block->res_size - ARENA_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Arena *new_block = arena_alloc(.reserve_size = res_size,
|
||||
.commit_size = cmt_size,
|
||||
.flags = current->flags);
|
||||
#endif
|
||||
|
||||
if(new_block == 0)
|
||||
{
|
||||
U64 res_size = current->res_size;
|
||||
U64 cmt_size = current->cmt_size;
|
||||
if(size + ARENA_HEADER_SIZE > res_size)
|
||||
{
|
||||
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
||||
}
|
||||
new_block = arena_alloc(.reserve_size = res_size,
|
||||
.commit_size = cmt_size,
|
||||
.flags = current->flags);
|
||||
}
|
||||
|
||||
new_block->base_pos = current->base_pos + current->res;
|
||||
SLLStackPush_N(arena->current, new_block, prev);
|
||||
|
||||
current = new_block;
|
||||
pos_pre = AlignPow2(current->pos, align);
|
||||
pos_pst = pos_pre + size;
|
||||
@@ -155,11 +187,23 @@ arena_pop_to(Arena *arena, U64 pos)
|
||||
{
|
||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
||||
Arena *current = arena->current;
|
||||
|
||||
#if ARENA_FREE_LIST
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
prev = current->prev;
|
||||
current->pos = ARENA_HEADER_SIZE;
|
||||
arena->free_size += current->res_size;
|
||||
SLLStackPush_N(arena->free_last, current, prev);
|
||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res_size - ARENA_HEADER_SIZE);
|
||||
}
|
||||
#else
|
||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
||||
{
|
||||
prev = current->prev;
|
||||
os_release(current, current->res);
|
||||
}
|
||||
#endif
|
||||
arena->current = current;
|
||||
U64 new_pos = big_pos - current->base_pos;
|
||||
AssertAlways(new_pos <= current->pos);
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Constants
|
||||
|
||||
#define ARENA_HEADER_SIZE 64
|
||||
#define ARENA_HEADER_SIZE 128
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Types
|
||||
|
||||
typedef U32 ArenaFlags;
|
||||
typedef U64 ArenaFlags;
|
||||
enum
|
||||
{
|
||||
ArenaFlag_NoChain = (1<<0),
|
||||
@@ -34,12 +34,16 @@ struct Arena
|
||||
Arena *prev; // previous arena in chain
|
||||
Arena *current; // current arena in chain
|
||||
ArenaFlags flags;
|
||||
U32 cmt_size;
|
||||
U64 cmt_size;
|
||||
U64 res_size;
|
||||
U64 base_pos;
|
||||
U64 pos;
|
||||
U64 cmt;
|
||||
U64 res;
|
||||
#if ARENA_FREE_LIST
|
||||
U64 free_size;
|
||||
Arena *free_last;
|
||||
#endif
|
||||
};
|
||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
||||
|
||||
|
||||
@@ -98,9 +98,10 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
next = node->next;
|
||||
String8 option_name = node->string;
|
||||
|
||||
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||
// a flag option. All arguments after a single "--" (with no trailing string
|
||||
// on the command line will be considered as input files.
|
||||
// NOTE(rjf): Look at --, -, or / (only on Windows) at the start of an
|
||||
// argument to determine if it's a flag option. All arguments after a
|
||||
// single "--" (with no trailing string on the command line will be
|
||||
// considered as input files.
|
||||
B32 is_option = 1;
|
||||
if(after_passthrough_option == 0)
|
||||
{
|
||||
@@ -117,6 +118,11 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else if(operating_system_from_context() == OperatingSystem_Windows &&
|
||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
||||
{
|
||||
option_name = str8_skip(option_name, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_option = 0;
|
||||
@@ -184,6 +190,18 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: fill argc/argv
|
||||
parsed.argc = command_line.node_count;
|
||||
parsed.argv = push_array(arena, char *, parsed.argc);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for(String8Node *n = command_line.first; n != 0; n = n->next)
|
||||
{
|
||||
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ struct CmdLine
|
||||
String8List inputs;
|
||||
U64 option_table_size;
|
||||
CmdLineOpt **option_table;
|
||||
U64 argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -155,11 +155,11 @@
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_MINOR)
|
||||
# define BUILD_VERSION_MINOR 0
|
||||
# define BUILD_VERSION_MINOR 9
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 0
|
||||
# define BUILD_VERSION_PATCH 14
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
|
||||
+11
-23
@@ -143,12 +143,6 @@ bswap_u64(U64 x)
|
||||
|
||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
return __popcnt16(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
@@ -195,46 +189,40 @@ clz64(U64 mask)
|
||||
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
|
||||
internal U64
|
||||
count_bits_set16(U16 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
count_bits_set64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_popcountll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz32(U32 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_clz(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
ctz64(U64 val)
|
||||
{
|
||||
return __builtin_ctzll(val);
|
||||
}
|
||||
|
||||
internal U64
|
||||
clz64(U64 val)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
return __builtin_clzll(val);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
+59
-30
@@ -40,6 +40,12 @@
|
||||
# define thread_static __thread
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define force_inline __forceinline
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define force_inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Linkage Keyword Macros
|
||||
|
||||
@@ -172,42 +178,49 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Atomic Operations
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <tmmintrin.h>
|
||||
# include <wmmintrin.h>
|
||||
#if COMPILER_MSVC
|
||||
# include <intrin.h>
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
|
||||
# define ins_atomic_u32_eval(x,c) InterlockedAdd((volatile LONG *)(x), 0)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
|
||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((volatile LONG *)x)
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||
# define ins_atomic_u32_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||
# endif
|
||||
#elif OS_LINUX
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u64_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||
# define ins_atomic_u64_dec_eval(x) __sync_fetch_and_sub((volatile U64 *)(x), 1)
|
||||
# define ins_atomic_u64_eval_assign(x,c) __sync_lock_test_and_set((volatile U64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) __sync_fetch_and_add((volatile U64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U64 *)(x),(c),(k))
|
||||
# define ins_atomic_u32_eval(x,c) __sync_fetch_and_add((volatile U32 *)(x), 0)
|
||||
# define ins_atomic_u32_eval_assign(x,c) __sync_lock_test_and_set((volatile U32 *)(x),(c))
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) __sync_val_compare_and_swap((volatile U32 *)(x),(c),(k))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
||||
# endif
|
||||
#elif COMPILER_CLANG || COMPILER_GCC
|
||||
# define ins_atomic_u64_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_inc_eval(x) (__atomic_fetch_add((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u64_dec_eval(x) (__atomic_fetch_sub((volatile U64 *)(x), 1, __ATOMIC_SEQ_CST) - 1)
|
||||
# define ins_atomic_u64_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u64_add_eval(x,c) (__atomic_fetch_add((volatile U64 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((volatile U64 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
# define ins_atomic_u32_eval(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_inc_eval(x) (__atomic_fetch_add((volatile U32 *)(x), 1, __ATOMIC_SEQ_CST) + 1)
|
||||
# define ins_atomic_u32_add_eval(x,c) (__atomic_fetch_add((volatile U32 *)(x), c, __ATOMIC_SEQ_CST) + (c))
|
||||
# define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n(x, c, __ATOMIC_SEQ_CST)
|
||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((volatile U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
||||
#else
|
||||
# error Atomic intrinsics not defined for this operating system.
|
||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
||||
#endif
|
||||
|
||||
#if ARCH_64BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u64_eval_cond_assign((volatile U64 *)(x), (U64)(k), (U64)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile U64 *)(x), (U64)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u64_eval((volatile U64 *)x)
|
||||
#elif ARCH_32BIT
|
||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void*)ins_atomic_u32_eval_cond_assign((volatile U32 *)(x), (U32)(k), (U32)(c))
|
||||
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u32_eval_assign((volatile U32 *)(x), (U32)(c))
|
||||
# define ins_atomic_ptr_eval(x) (void*)ins_atomic_u32_eval((volatile U32 *)x)
|
||||
#else
|
||||
# error Atomic intrinsics for pointers not defined for this architecture.
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
@@ -479,6 +492,23 @@ struct TxtRng
|
||||
TxtPt max;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
typedef union Guid Guid;
|
||||
union Guid
|
||||
{
|
||||
struct
|
||||
{
|
||||
U32 data1;
|
||||
U16 data2;
|
||||
U16 data3;
|
||||
U8 data4[8];
|
||||
};
|
||||
U8 v[16];
|
||||
};
|
||||
StaticAssert(sizeof(Guid) == 16, g_guid_size_check);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Constants
|
||||
|
||||
@@ -745,7 +775,6 @@ internal U16 bswap_u16(U16 x);
|
||||
internal U32 bswap_u32(U32 x);
|
||||
internal U64 bswap_u64(U64 x);
|
||||
|
||||
internal U64 count_bits_set16(U16 val);
|
||||
internal U64 count_bits_set32(U32 val);
|
||||
internal U64 count_bits_set64(U64 val);
|
||||
|
||||
|
||||
+25
-22
@@ -1,22 +1,24 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
global U64 global_update_tick_idx = 0;
|
||||
|
||||
internal void
|
||||
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
|
||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ThreadNameF("[main thread]");
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist U8 tm_data[MB(64)];
|
||||
local_persist char tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), (char *)tm_data);
|
||||
tmInitialize(sizeof(tm_data), tm_data);
|
||||
#endif
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, arguments_count, arguments);
|
||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||
|
||||
//- rjf: begin captures
|
||||
@@ -26,9 +28,16 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
ProfBeginCapture(arguments[0]);
|
||||
}
|
||||
|
||||
#if PROFILE_TELEMETRY
|
||||
tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE);
|
||||
#endif
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
|
||||
ts_init();
|
||||
#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL)
|
||||
async_init();
|
||||
#endif
|
||||
#if defined(RDI_FROM_PDB_H) && !defined(P2R_INIT_MANUAL)
|
||||
p2r_init();
|
||||
#endif
|
||||
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
|
||||
hs_init();
|
||||
@@ -45,12 +54,9 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
|
||||
dasm_init();
|
||||
#endif
|
||||
#if defined(DBGI_H) && !defined(DBGI_INIT_MANUAL)
|
||||
#if defined(DBGI_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
|
||||
fzy_init();
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
#endif
|
||||
@@ -90,6 +96,7 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -102,22 +109,18 @@ supplement_thread_base_entry_point(void (*entry_point)(void *params), void *para
|
||||
tctx_release();
|
||||
}
|
||||
|
||||
internal U64
|
||||
update_tick_idx(void)
|
||||
{
|
||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
update(void)
|
||||
{
|
||||
ProfTick(0);
|
||||
#if defined(TEXT_CACHE_H)
|
||||
txt_user_clock_tick();
|
||||
#endif
|
||||
#if defined(DASM_CACHE_H)
|
||||
dasm_user_clock_tick();
|
||||
#endif
|
||||
#if defined(GEO_CACHE_H)
|
||||
geo_user_clock_tick();
|
||||
#endif
|
||||
#if defined(TEXTURE_CACHE_H)
|
||||
tex_user_clock_tick();
|
||||
#endif
|
||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
||||
#if OS_FEATURE_GRAPHICAL
|
||||
B32 result = frame();
|
||||
#else
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#ifndef BASE_ENTRY_POINT_H
|
||||
#define BASE_ENTRY_POINT_H
|
||||
|
||||
internal void main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||
internal U64 update_tick_idx(void);
|
||||
internal B32 update(void);
|
||||
|
||||
#endif // BASE_ENTRY_POINT_H
|
||||
|
||||
@@ -195,6 +195,30 @@ read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, st
|
||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
||||
read_only global Type *type_kind_type_table[] =
|
||||
{
|
||||
&type_nil,
|
||||
type(void),
|
||||
type(U8),
|
||||
type(U16),
|
||||
type(U32),
|
||||
type(U64),
|
||||
type(S8),
|
||||
type(S16),
|
||||
type(S32),
|
||||
type(S64),
|
||||
type(B8),
|
||||
type(B16),
|
||||
type(B32),
|
||||
type(B64),
|
||||
type(F32),
|
||||
type(F64),
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
&type_nil,
|
||||
};
|
||||
|
||||
//- rjf: Rng1U64
|
||||
struct_members(Rng1U64)
|
||||
|
||||
+36
-14
@@ -43,26 +43,48 @@
|
||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||
# define ProfColor(color) tmZoneColorSticky(color)
|
||||
# define ProfBeginV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
# define ProfNoteV(...) \
|
||||
if (TM_API_PTR) { \
|
||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
||||
Temp scratch = scratch_begin(0,0); \
|
||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
||||
scratch_end(scratch); \
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Zeroify Undefined Defines
|
||||
|
||||
#if !defined(ProfBegin)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBegin(...) (0)
|
||||
# define ProfBeginDynamic(...) (0)
|
||||
# define ProfEnd(...) (0)
|
||||
# define ProfTick(...) (0)
|
||||
# define ProfIsCapturing(...) (0)
|
||||
# define ProfBeginCapture(...) (0)
|
||||
# define ProfEndCapture(...) (0)
|
||||
# define ProfThreadName(...) (0)
|
||||
# define ProfMsg(...) (0)
|
||||
# define ProfBeginLockWait(...) (0)
|
||||
# define ProfEndLockWait(...) (0)
|
||||
# define ProfLockTake(...) (0)
|
||||
# define ProfLockDrop(...) (0)
|
||||
# define ProfColor(...) (0)
|
||||
# define ProfBeginV(...) (0)
|
||||
# define ProfNoteV(...) (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
+297
-42
@@ -215,12 +215,42 @@ str32_cstring(U32 *c){
|
||||
internal String8
|
||||
str8_cstring_capped(void *cstr, void *cap)
|
||||
{
|
||||
char *ptr = (char*)cstr;
|
||||
char *opl = (char*)cap;
|
||||
char *ptr = (char *)cstr;
|
||||
char *opl = (char *)cap;
|
||||
for (;ptr < opl && *ptr != 0; ptr += 1);
|
||||
U64 size = (U64)(ptr - (char *)cstr);
|
||||
String8 result = {(U8*)cstr, size};
|
||||
return(result);
|
||||
String8 result = str8((U8*)cstr, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String16
|
||||
str16_cstring_capped(void *cstr, void *cap)
|
||||
{
|
||||
U16 *ptr = (U16 *)cstr;
|
||||
U16 *opl = (U16 *)cap;
|
||||
for (;ptr < opl && *ptr != 0; ptr += 1);
|
||||
U64 size = (U64)(ptr - (U16 *)cstr);
|
||||
String16 result = str16(cstr, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_cstring_capped_reverse(void *raw_start, void *raw_cap)
|
||||
{
|
||||
U8 *start = raw_start;
|
||||
U8 *ptr = raw_cap;
|
||||
for(; ptr > start; )
|
||||
{
|
||||
ptr -= 1;
|
||||
|
||||
if (*ptr == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
U64 size = (U64)(ptr - start);
|
||||
String8 result = str8(start, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -263,31 +293,41 @@ backslashed_from_str8(Arena *arena, String8 string)
|
||||
//~ rjf: String Matching
|
||||
|
||||
internal B32
|
||||
str8_match(String8 a, String8 b, StringMatchFlags flags){
|
||||
str8_match(String8 a, String8 b, StringMatchFlags flags)
|
||||
{
|
||||
B32 result = 0;
|
||||
if (a.size == b.size || (flags & StringMatchFlag_RightSideSloppy)){
|
||||
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
|
||||
if(a.size == b.size && flags == 0)
|
||||
{
|
||||
result = MemoryMatch(a.str, b.str, b.size);
|
||||
}
|
||||
else if(a.size == b.size || (flags & StringMatchFlag_RightSideSloppy))
|
||||
{
|
||||
B32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
|
||||
B32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
|
||||
U64 size = Min(a.size, b.size);
|
||||
U64 size = Min(a.size, b.size);
|
||||
result = 1;
|
||||
for (U64 i = 0; i < size; i += 1){
|
||||
for(U64 i = 0; i < size; i += 1)
|
||||
{
|
||||
U8 at = a.str[i];
|
||||
U8 bt = b.str[i];
|
||||
if (case_insensitive){
|
||||
if(case_insensitive)
|
||||
{
|
||||
at = char_to_upper(at);
|
||||
bt = char_to_upper(bt);
|
||||
}
|
||||
if (slash_insensitive){
|
||||
if(slash_insensitive)
|
||||
{
|
||||
at = char_to_correct_slash(at);
|
||||
bt = char_to_correct_slash(bt);
|
||||
}
|
||||
if (at != bt){
|
||||
if(at != bt)
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
@@ -322,6 +362,22 @@ str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal U64
|
||||
str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags)
|
||||
{
|
||||
U64 result = 0;
|
||||
for(S64 i = string.size - start_pos - needle.size; i >= 0; --i)
|
||||
{
|
||||
String8 haystack = str8_substr(string, rng_1u64(i, i + needle.size));
|
||||
if(str8_match(haystack, needle, flags))
|
||||
{
|
||||
result = (U64)i + needle.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
str8_ends_with(String8 string, String8 end, StringMatchFlags flags){
|
||||
String8 postfix = str8_postfix(string, end.size);
|
||||
@@ -544,21 +600,121 @@ try_s64_from_str8_c_rules(String8 string, S64 *x){
|
||||
//- rjf: integer -> string
|
||||
|
||||
internal String8
|
||||
str8_from_memory_size(Arena *arena, U64 z){
|
||||
String8 result = {0};
|
||||
if (z < KB(1)){
|
||||
result = push_str8f(arena, "%llu b", z);
|
||||
str8_from_memory_size(Arena *arena, U64 size)
|
||||
{
|
||||
String8 result;
|
||||
|
||||
if(size < KB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu Bytes", size);
|
||||
}
|
||||
else if (z < MB(1)){
|
||||
result = push_str8f(arena, "%llu.%02llu Kb", z/KB(1), ((100*z)/KB(1))%100);
|
||||
else if(size < MB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu KiB", size / KB(1), ((size * 100) / KB(1)) % 100);
|
||||
}
|
||||
else if (z < GB(1)){
|
||||
result = push_str8f(arena, "%llu.%02llu Mb", z/MB(1), ((100*z)/MB(1))%100);
|
||||
else if(size < GB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu MiB", size / MB(1), ((size * 100) / MB(1)) % 100);
|
||||
}
|
||||
else{
|
||||
result = push_str8f(arena, "%llu.%02llu Gb", z/GB(1), ((100*z)/GB(1))%100);
|
||||
else if(size < TB(1))
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu GiB", size / GB(1), ((size * 100) / GB(1)) % 100);
|
||||
}
|
||||
return(result);
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_count(Arena *arena, U64 count)
|
||||
{
|
||||
String8 result;
|
||||
|
||||
if(count < 1 * 1000)
|
||||
{
|
||||
result = push_str8f(arena, "%llu", count);
|
||||
}
|
||||
else if(count < 1000000)
|
||||
{
|
||||
U64 frac = ((count * 100) / 1000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluK", count / 1000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluK", count / 1000);
|
||||
}
|
||||
}
|
||||
else if(count < 1000000000)
|
||||
{
|
||||
U64 frac = ((count * 100) / 1000000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluM", count / 1000000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluM", count / 1000000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 frac = ((count * 100) * 1000000000) % 100;
|
||||
if(frac > 0)
|
||||
{
|
||||
result = push_str8f(arena, "%llu.%02lluB", count / 1000000000, frac);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "%lluB", count / 1000000000, frac);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u32(Arena *arena, U32 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 20) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 16) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 12) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 8) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 4) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena, "%c%c%c%c%c%c%c%c", c0, c1, c2, c3, c4, c5, c6, c7);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
str8_from_bits_u64(Arena *arena, U64 x)
|
||||
{
|
||||
U8 c0 = 'a' + ((x >> 60) & 0xf);
|
||||
U8 c1 = 'a' + ((x >> 56) & 0xf);
|
||||
U8 c2 = 'a' + ((x >> 52) & 0xf);
|
||||
U8 c3 = 'a' + ((x >> 48) & 0xf);
|
||||
U8 c4 = 'a' + ((x >> 44) & 0xf);
|
||||
U8 c5 = 'a' + ((x >> 40) & 0xf);
|
||||
U8 c6 = 'a' + ((x >> 36) & 0xf);
|
||||
U8 c7 = 'a' + ((x >> 32) & 0xf);
|
||||
U8 c8 = 'a' + ((x >> 28) & 0xf);
|
||||
U8 c9 = 'a' + ((x >> 24) & 0xf);
|
||||
U8 ca = 'a' + ((x >> 20) & 0xf);
|
||||
U8 cb = 'a' + ((x >> 16) & 0xf);
|
||||
U8 cc = 'a' + ((x >> 12) & 0xf);
|
||||
U8 cd = 'a' + ((x >> 8) & 0xf);
|
||||
U8 ce = 'a' + ((x >> 4) & 0xf);
|
||||
U8 cf = 'a' + ((x >> 0) & 0xf);
|
||||
String8 result = push_str8f(arena,
|
||||
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
|
||||
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
@@ -685,27 +841,28 @@ f64_from_str8(String8 string)
|
||||
{
|
||||
// rjf: find starting pos of numeric string, as well as sign
|
||||
F64 sign = +1.0;
|
||||
//U64 first_numeric = 0;
|
||||
if(string.str[0] == '-')
|
||||
{
|
||||
//first_numeric = 1;
|
||||
sign = -1.0;
|
||||
}
|
||||
else if(string.str[0] == '+')
|
||||
{
|
||||
//first_numeric = 1;
|
||||
sign = 1.0;
|
||||
}
|
||||
|
||||
// rjf: gather numerics
|
||||
U64 num_valid_chars = 0;
|
||||
char buffer[64];
|
||||
B32 exp = 0;
|
||||
for(U64 idx = 0; idx < string.size && num_valid_chars < sizeof(buffer)-1; idx += 1)
|
||||
{
|
||||
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.')
|
||||
if(char_is_digit(string.str[idx], 10) || string.str[idx] == '.' || string.str[idx] == 'e' ||
|
||||
(exp && (string.str[idx] == '+' || string.str[idx] == '-')))
|
||||
{
|
||||
buffer[num_valid_chars] = string.str[idx];
|
||||
num_valid_chars += 1;
|
||||
exp = 0;
|
||||
exp = (string.str[idx] == 'e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,7 +1295,9 @@ str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){
|
||||
internal String8
|
||||
str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
|
||||
StringJoin params = {0};
|
||||
switch (style){
|
||||
switch(style)
|
||||
{
|
||||
case PathStyle_Null:{}break;
|
||||
case PathStyle_Relative:
|
||||
case PathStyle_WindowsAbsolute:
|
||||
{
|
||||
@@ -1151,9 +1310,8 @@ str8_path_list_join_by_style(Arena *arena, String8List *path, PathStyle style){
|
||||
params.sep = str8_lit("/");
|
||||
}break;
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, path, ¶ms);
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8TxtPtPair
|
||||
@@ -1412,6 +1570,35 @@ str32_from_8(Arena *arena, String8 in){
|
||||
return(str32(str, size));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
read_only global struct
|
||||
{
|
||||
String8 string;
|
||||
OperatingSystem os;
|
||||
} g_os_enum_map[] =
|
||||
{
|
||||
{ str8_lit_comp(""), OperatingSystem_Null },
|
||||
{ str8_lit_comp("Windows"), OperatingSystem_Windows, },
|
||||
{ str8_lit_comp("Linux"), OperatingSystem_Linux, },
|
||||
{ str8_lit_comp("Mac"), OperatingSystem_Mac, },
|
||||
};
|
||||
StaticAssert(ArrayCount(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_count_check);
|
||||
|
||||
internal OperatingSystem
|
||||
operating_system_from_string(String8 string)
|
||||
{
|
||||
for(U64 i = 0; i < ArrayCount(g_os_enum_map); ++i)
|
||||
{
|
||||
if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
return g_os_enum_map[i].os;
|
||||
}
|
||||
}
|
||||
return OperatingSystem_Null;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
@@ -1444,18 +1631,14 @@ string_from_side(Side side){
|
||||
}
|
||||
|
||||
internal String8
|
||||
string_from_operating_system(OperatingSystem os){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Windows"),
|
||||
str8_lit_comp("Linux"),
|
||||
str8_lit_comp("Mac"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (os < OperatingSystem_COUNT){
|
||||
result = strings[os];
|
||||
string_from_operating_system(OperatingSystem os)
|
||||
{
|
||||
String8 result = g_os_enum_map[OperatingSystem_Null].string;
|
||||
if(os < ArrayCount(g_os_enum_map))
|
||||
{
|
||||
result = g_os_enum_map[os].string;
|
||||
}
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
@@ -1565,6 +1748,78 @@ string_from_elapsed_time(Arena *arena, DateTime dt){
|
||||
return(result);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally UNique Ids
|
||||
|
||||
internal String8
|
||||
string_from_guid(Arena *arena, Guid guid)
|
||||
{
|
||||
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
guid.data1,
|
||||
guid.data2,
|
||||
guid.data3,
|
||||
guid.data4[0],
|
||||
guid.data4[1],
|
||||
guid.data4[2],
|
||||
guid.data4[3],
|
||||
guid.data4[4],
|
||||
guid.data4[5],
|
||||
guid.data4[6],
|
||||
guid.data4[7]);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
try_guid_from_string(String8 string, Guid *guid_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
B32 is_parsed = 0;
|
||||
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
|
||||
if(list.node_count == 5)
|
||||
{
|
||||
String8 data1_str = list.first->string;
|
||||
String8 data2_str = list.first->next->string;
|
||||
String8 data3_str = list.first->next->next->string;
|
||||
String8 data4_hi_str = list.first->next->next->next->string;
|
||||
String8 data4_lo_str = list.first->next->next->next->next->string;
|
||||
if(str8_is_integer(data1_str, 16) &&
|
||||
str8_is_integer(data2_str, 16) &&
|
||||
str8_is_integer(data3_str, 16) &&
|
||||
str8_is_integer(data4_hi_str, 16) &&
|
||||
str8_is_integer(data4_lo_str, 16))
|
||||
{
|
||||
U64 data1 = u64_from_str8(data1_str, 16);
|
||||
U64 data2 = u64_from_str8(data2_str, 16);
|
||||
U64 data3 = u64_from_str8(data3_str, 16);
|
||||
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
|
||||
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
|
||||
if(data1 <= max_U32 &&
|
||||
data2 <= max_U16 &&
|
||||
data3 <= max_U16 &&
|
||||
data4_hi <= max_U16 &&
|
||||
data4_lo <= 0xffffffffffff)
|
||||
{
|
||||
guid_out->data1 = (U32)data1;
|
||||
guid_out->data2 = (U16)data2;
|
||||
guid_out->data3 = (U16)data3;
|
||||
U64 data4 = (data4_hi << 48) | data4_lo;
|
||||
MemoryCopy(&guid_out->data4[0], &data4, sizeof(data4));
|
||||
is_parsed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal Guid
|
||||
guid_from_string(String8 string)
|
||||
{
|
||||
Guid guid = {0};
|
||||
try_guid_from_string(string, &guid);
|
||||
return guid;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
|
||||
+20
-1
@@ -86,6 +86,7 @@ enum
|
||||
|
||||
typedef enum PathStyle
|
||||
{
|
||||
PathStyle_Null,
|
||||
PathStyle_Relative,
|
||||
PathStyle_WindowsAbsolute,
|
||||
PathStyle_UnixAbsolute,
|
||||
@@ -192,6 +193,8 @@ internal String8 str8_cstring(char *c);
|
||||
internal String16 str16_cstring(U16 *c);
|
||||
internal String32 str32_cstring(U32 *c);
|
||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||
internal String16 str16_cstring_capped(void *cstr, void *cap);
|
||||
internal String8 str8_cstring_capped_reverse(void *raw_start, void *raw_cap);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Stylization
|
||||
@@ -205,6 +208,7 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
||||
|
||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||
|
||||
////////////////////////////////
|
||||
@@ -237,7 +241,10 @@ internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||
|
||||
//- rjf: integer -> string
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||
|
||||
@@ -309,6 +316,11 @@ internal String16 str16_from_8(Arena *arena, String8 in);
|
||||
internal String8 str8_from_32(Arena *arena, String32 in);
|
||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
internal OperatingSystem operating_system_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
@@ -326,6 +338,13 @@ internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
||||
internal Guid guid_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
|
||||
+22
-10
@@ -80,6 +80,13 @@ cv_numeric_from_data_range(U8 *first, U8 *opl)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out)
|
||||
{
|
||||
*out = cv_numeric_from_data_range(data.str + offset, data.str + data.size);
|
||||
return out->encoded_size;
|
||||
}
|
||||
|
||||
internal B32
|
||||
cv_numeric_fits_in_u64(CV_NumericParsed *num)
|
||||
{
|
||||
@@ -186,7 +193,7 @@ cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value)
|
||||
}
|
||||
|
||||
// 2 bytes
|
||||
else if((header & 0xC0) == 0x80 && cursor+2 <= data.size)
|
||||
else if((header & 0xC0) == 0x80 && cursor+1 <= data.size)
|
||||
{
|
||||
U8 second_byte;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &second_byte);
|
||||
@@ -411,7 +418,7 @@ cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first)
|
||||
//~ CodeView C13 Parser Functions
|
||||
|
||||
internal CV_C13Parsed *
|
||||
cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_CoffSectionArray *sections)
|
||||
cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
@@ -483,19 +490,21 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_
|
||||
CV_C13SubSecLinesHeader *hdr = (CV_C13SubSecLinesHeader*)(first + read_off);
|
||||
read_off += sizeof(*hdr);
|
||||
|
||||
// extract top level info
|
||||
// rjf: extract section index
|
||||
U32 sec_idx = hdr->sec;
|
||||
B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns);
|
||||
U64 secrel_off = hdr->sec_off;
|
||||
U64 secrel_opl = secrel_off + hdr->len;
|
||||
U64 sec_base_off = sections->sections[sec_idx - 1].voff;
|
||||
|
||||
// rjf: bad section index -> skip
|
||||
if(sec_idx < 1 || sections->count < sec_idx)
|
||||
if(sec_idx < 1 || sections.count < sec_idx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// extract top level info
|
||||
B32 has_cols = !!(hdr->flags & CV_C13SubSecLinesFlag_HasColumns);
|
||||
U64 secrel_off = hdr->sec_off;
|
||||
U64 secrel_opl = secrel_off + hdr->len;
|
||||
U64 sec_base_off = sections.v[sec_idx - 1].voff;
|
||||
|
||||
// read files
|
||||
for(;read_off+sizeof(CV_C13File) <= read_off_opl;)
|
||||
{
|
||||
@@ -511,7 +520,8 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = pdb_strtbl_string_from_off(strtbl, name_off);
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
}
|
||||
|
||||
// array layouts
|
||||
@@ -587,7 +597,8 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = pdb_strtbl_string_from_off(strtbl, name_off);
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
}
|
||||
|
||||
// rjf: parse extra files
|
||||
@@ -608,6 +619,7 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_
|
||||
SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n);
|
||||
n->v.inlinee = hdr->inlinee;
|
||||
n->v.file_name = file_name;
|
||||
n->v.file_off = hdr->file_off;
|
||||
n->v.first_source_ln = hdr->first_source_ln;
|
||||
n->v.extra_file_count = extra_file_count;
|
||||
n->v.extra_files = extra_files;
|
||||
|
||||
+138
-34
@@ -9,9 +9,15 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: CodeView Format Shared Types
|
||||
|
||||
typedef U32 CV_TypeId;
|
||||
typedef U32 CV_ItemId;
|
||||
#define CV_TypeIndex_Max max_U32
|
||||
typedef U32 CV_TypeIndex;
|
||||
typedef CV_TypeIndex CV_TypeId;
|
||||
typedef CV_TypeIndex CV_ItemId;
|
||||
|
||||
#define CV_ModIndex_Max max_U16
|
||||
#define CV_ModIndex_Invalid CV_ModIndex_Max
|
||||
typedef U16 CV_ModIndex;
|
||||
|
||||
typedef U16 CV_SectionIndex;
|
||||
typedef U16 CV_Reg;
|
||||
|
||||
@@ -898,7 +904,95 @@ X(YMM14D3, 683, zmm14, 24, 8)\
|
||||
X(YMM15D0, 684, zmm15, 0, 8)\
|
||||
X(YMM15D1, 685, zmm15, 8, 8)\
|
||||
X(YMM15D2, 686, zmm15, 16, 8)\
|
||||
X(YMM15D3, 687, zmm15, 24, 8)
|
||||
X(YMM15D3, 687, zmm15, 24, 8)\
|
||||
X(XMM16, 694, zmm16, 0, 16)\
|
||||
X(XMM17, 695, zmm17, 0, 16)\
|
||||
X(XMM18, 696, zmm18, 0, 16)\
|
||||
X(XMM19, 697, zmm19, 0, 16)\
|
||||
X(XMM20, 698, zmm20, 0, 16)\
|
||||
X(XMM21, 699, zmm21, 0, 16)\
|
||||
X(XMM22, 700, zmm22, 0, 16)\
|
||||
X(XMM23, 701, zmm23, 0, 16)\
|
||||
X(XMM24, 702, zmm24, 0, 16)\
|
||||
X(XMM25, 703, zmm25, 0, 16)\
|
||||
X(XMM26, 704, zmm26, 0, 16)\
|
||||
X(XMM27, 705, zmm27, 0, 16)\
|
||||
X(XMM28, 706, zmm28, 0, 16)\
|
||||
X(XMM29, 707, zmm29, 0, 16)\
|
||||
X(XMM30, 708, zmm30, 0, 16)\
|
||||
X(XMM31, 709, zmm31, 0, 16)\
|
||||
X(YMM16, 710, zmm16, 0, 32)\
|
||||
X(YMM17, 711, zmm17, 0, 32)\
|
||||
X(YMM18, 712, zmm18, 0, 32)\
|
||||
X(YMM19, 713, zmm19, 0, 32)\
|
||||
X(YMM20, 714, zmm20, 0, 32)\
|
||||
X(YMM21, 715, zmm21, 0, 32)\
|
||||
X(YMM22, 716, zmm22, 0, 32)\
|
||||
X(YMM23, 717, zmm23, 0, 32)\
|
||||
X(YMM24, 718, zmm24, 0, 32)\
|
||||
X(YMM25, 719, zmm25, 0, 32)\
|
||||
X(YMM26, 720, zmm26, 0, 32)\
|
||||
X(YMM27, 721, zmm27, 0, 32)\
|
||||
X(YMM28, 722, zmm28, 0, 32)\
|
||||
X(YMM29, 723, zmm29, 0, 32)\
|
||||
X(YMM30, 724, zmm30, 0, 32)\
|
||||
X(YMM31, 725, zmm31, 0, 32)\
|
||||
X(ZMM0, 726, zmm0, 0, 64)\
|
||||
X(ZMM1, 727, zmm1, 0, 64)\
|
||||
X(ZMM2, 728, zmm2, 0, 64)\
|
||||
X(ZMM3, 729, zmm3, 0, 64)\
|
||||
X(ZMM4, 730, zmm4, 0, 64)\
|
||||
X(ZMM5, 731, zmm5, 0, 64)\
|
||||
X(ZMM6, 732, zmm6, 0, 64)\
|
||||
X(ZMM7, 733, zmm7, 0, 64)\
|
||||
X(ZMM8, 734, zmm8, 0, 64)\
|
||||
X(ZMM9, 735, zmm9, 0, 64)\
|
||||
X(ZMM10, 736, zmm10, 0, 64)\
|
||||
X(ZMM11, 737, zmm11, 0, 64)\
|
||||
X(ZMM12, 738, zmm12, 0, 64)\
|
||||
X(ZMM13, 739, zmm13, 0, 64)\
|
||||
X(ZMM14, 740, zmm14, 0, 64)\
|
||||
X(ZMM15, 741, zmm15, 0, 64)\
|
||||
X(ZMM16, 742, zmm16, 0, 64)\
|
||||
X(ZMM17, 743, zmm17, 0, 64)\
|
||||
X(ZMM18, 744, zmm18, 0, 64)\
|
||||
X(ZMM19, 745, zmm19, 0, 64)\
|
||||
X(ZMM20, 746, zmm20, 0, 64)\
|
||||
X(ZMM21, 747, zmm21, 0, 64)\
|
||||
X(ZMM22, 748, zmm22, 0, 64)\
|
||||
X(ZMM23, 749, zmm23, 0, 64)\
|
||||
X(ZMM24, 750, zmm24, 0, 64)\
|
||||
X(ZMM25, 751, zmm25, 0, 64)\
|
||||
X(ZMM26, 752, zmm26, 0, 64)\
|
||||
X(ZMM27, 753, zmm27, 0, 64)\
|
||||
X(ZMM28, 754, zmm28, 0, 64)\
|
||||
X(ZMM29, 755, zmm29, 0, 64)\
|
||||
X(ZMM30, 756, zmm30, 0, 64)\
|
||||
X(ZMM31, 757, zmm31, 0, 64)\
|
||||
X(K0, 758, k0, 0, 8)\
|
||||
X(K1, 759, k1, 0, 8)\
|
||||
X(K2, 760, k2, 0, 8)\
|
||||
X(K3, 761, k3, 0, 8)\
|
||||
X(K4, 762, k4, 0, 8)\
|
||||
X(K5, 763, k5, 0, 8)\
|
||||
X(K6, 764, k6, 0, 8)\
|
||||
X(K7, 765, k7, 0, 8)\
|
||||
X(ZMM0H, 766, zmm0, 32, 32)\
|
||||
X(ZMM1H, 767, zmm1, 32, 32)\
|
||||
X(ZMM2H, 768, zmm2, 32, 32)\
|
||||
X(ZMM3H, 769, zmm3, 32, 32)\
|
||||
X(ZMM4H, 770, zmm4, 32, 32)\
|
||||
X(ZMM5H, 771, zmm5, 32, 32)\
|
||||
X(ZMM6H, 772, zmm6, 32, 32)\
|
||||
X(ZMM7H, 773, zmm7, 32, 32)\
|
||||
X(ZMM8H, 774, zmm8, 32, 32)\
|
||||
X(ZMM9H, 775, zmm9, 32, 32)\
|
||||
X(ZMM10H, 776, zmm10, 32, 32)\
|
||||
X(ZMM11H, 777, zmm11, 32, 32)\
|
||||
X(ZMM12H, 778, zmm12, 32, 32)\
|
||||
X(ZMM13H, 779, zmm13, 32, 32)\
|
||||
X(ZMM14H, 780, zmm14, 32, 32)\
|
||||
X(ZMM15H, 781, zmm15, 32, 32)
|
||||
|
||||
typedef U16 CV_Regx64;
|
||||
typedef enum CV_Regx64Enum
|
||||
@@ -917,7 +1011,7 @@ X(C11, 2)\
|
||||
X(C13, 4)\
|
||||
X(RESERVED, 5)
|
||||
|
||||
typedef U16 CV_Signature;
|
||||
typedef U32 CV_Signature;
|
||||
typedef enum CV_SignatureEnum
|
||||
{
|
||||
#define X(N,c) CV_Signature_##N = c,
|
||||
@@ -1164,8 +1258,8 @@ struct CV_SymAnnotation
|
||||
|
||||
//- (SymKind: OBJNAME)
|
||||
|
||||
typedef struct CV_SymObjname CV_SymObjname;
|
||||
struct CV_SymObjname
|
||||
typedef struct CV_SymObjName CV_SymObjName;
|
||||
struct CV_SymObjName
|
||||
{
|
||||
U32 sig;
|
||||
// U8[] name (null terminated)
|
||||
@@ -1286,19 +1380,19 @@ struct CV_SymData32
|
||||
|
||||
//- (SymKind: PUB32)
|
||||
|
||||
typedef U32 CV_PubFlags;
|
||||
typedef U32 CV_Pub32Flags;
|
||||
enum
|
||||
{
|
||||
CV_PubFlag_Code = (1 << 0),
|
||||
CV_PubFlag_Function = (1 << 1),
|
||||
CV_PubFlag_ManagedCode = (1 << 2),
|
||||
CV_PubFlag_MSIL = (1 << 3),
|
||||
CV_Pub32Flag_Code = (1 << 0),
|
||||
CV_Pub32Flag_Function = (1 << 1),
|
||||
CV_Pub32Flag_ManagedCode = (1 << 2),
|
||||
CV_Pub32Flag_MSIL = (1 << 3),
|
||||
};
|
||||
|
||||
typedef struct CV_SymPub32 CV_SymPub32;
|
||||
struct CV_SymPub32
|
||||
{
|
||||
CV_PubFlags flags;
|
||||
CV_Pub32Flags flags;
|
||||
U32 off;
|
||||
CV_SectionIndex sec;
|
||||
// U8[] name (null terminated)
|
||||
@@ -1607,6 +1701,24 @@ struct CV_SymDiscarded
|
||||
};
|
||||
|
||||
//- (SymKind: COMPILE3)
|
||||
typedef U32 CV_Compile3Flags;
|
||||
enum
|
||||
{
|
||||
CV_Compile3Flag_EC = (1 << 8),
|
||||
CV_Compile3Flag_NoDbgInfo = (1 << 9),
|
||||
CV_Compile3Flag_LTCG = (1 << 10),
|
||||
CV_Compile3Flag_NoDataAlign = (1 << 11),
|
||||
CV_Compile3Flag_ManagedPresent = (1 << 12),
|
||||
CV_Compile3Flag_SecurityChecks = (1 << 13),
|
||||
CV_Compile3Flag_HotPatch = (1 << 14),
|
||||
CV_Compile3Flag_CVTCIL = (1 << 15),
|
||||
CV_Compile3Flag_MSILModule = (1 << 16),
|
||||
CV_Compile3Flag_SDL = (1 << 17),
|
||||
CV_Compile3Flag_PGO = (1 << 18),
|
||||
CV_Compile3Flag_EXP = (1 << 19),
|
||||
|
||||
CV_Compile3Flag_Language_Shift = 0, CV_Compile3Flag_Language_Mask = 0xff,
|
||||
};
|
||||
|
||||
typedef U32 CV_Compile3Flags;
|
||||
#define CV_Compile3Flags_ExtractLanguage(f) (((f) )&0xFF)
|
||||
@@ -1715,6 +1827,8 @@ struct CV_SymDefrangeFramepointerRel
|
||||
|
||||
//- (SymKind: DEFRANGE_SUBFIELD_REGISTER)
|
||||
|
||||
#define CV_DefrangeSubfieldRegister_ExtractParentOffset(x) ((x) & 0x1FFF)
|
||||
|
||||
typedef struct CV_SymDefrangeSubfieldRegister CV_SymDefrangeSubfieldRegister;
|
||||
struct CV_SymDefrangeSubfieldRegister
|
||||
{
|
||||
@@ -1968,24 +2082,6 @@ struct CV_SymInlinees
|
||||
// (type info)
|
||||
//
|
||||
|
||||
#define CV_LeafIDKindXList(X) \
|
||||
X(FUNC_ID, 0x1601)\
|
||||
X(MFUNC_ID, 0x1602)\
|
||||
X(BUILDINFO, 0x1603)\
|
||||
X(SUBSTR_LIST, 0x1604)\
|
||||
X(STRING_ID, 0x1605)\
|
||||
X(UDT_SRC_LINE, 0x1606)\
|
||||
X(UDT_MOD_SRC_LINE, 0x1607)
|
||||
|
||||
typedef U16 CV_LeafIDKind;
|
||||
typedef enum CV_LeafIDKindEnum
|
||||
{
|
||||
#define X(N,c) CV_LeafIDKind_##N = c,
|
||||
CV_LeafIDKindXList(X)
|
||||
#undef X
|
||||
}
|
||||
CV_LeafIDKindEnum;
|
||||
|
||||
#define CV_TypeId_Variadic 0
|
||||
|
||||
#define CV_BasicPointerKindXList(X) \
|
||||
@@ -2197,10 +2293,18 @@ struct CV_LeafPreComp
|
||||
{
|
||||
U32 start_index;
|
||||
U32 count;
|
||||
U32 signature;
|
||||
U32 sig;
|
||||
// U8[] name (null terminated)
|
||||
};
|
||||
|
||||
//- (LeafKind; END_PRECOMP)
|
||||
|
||||
typedef struct CV_LeafEndPreComp CV_LeafEndPreComp;
|
||||
struct CV_LeafEndPreComp
|
||||
{
|
||||
U32 sig;
|
||||
};
|
||||
|
||||
//- (LeafKind: TYPESERVER)
|
||||
|
||||
typedef struct CV_LeafTypeServer CV_LeafTypeServer;
|
||||
@@ -2916,6 +3020,7 @@ typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
|
||||
struct CV_C13InlineeLinesParsed
|
||||
{
|
||||
CV_ItemId inlinee;
|
||||
U32 file_off;
|
||||
String8 file_name;
|
||||
U32 first_source_ln;
|
||||
U32 extra_file_count;
|
||||
@@ -2979,6 +3084,7 @@ internal U64 cv_hash_from_string(String8 string);
|
||||
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
|
||||
|
||||
internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl);
|
||||
internal U64 cv_read_numeric(String8 data, U64 offset, CV_NumericParsed *out);
|
||||
|
||||
internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num);
|
||||
internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num);
|
||||
@@ -3010,8 +3116,6 @@ internal CV_LeafParsed *cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_Ty
|
||||
////////////////////////////////
|
||||
//~ CodeView C13 Parser Functions
|
||||
|
||||
typedef struct PDB_Strtbl PDB_Strtbl;
|
||||
typedef struct PDB_CoffSectionArray PDB_CoffSectionArray;
|
||||
internal CV_C13Parsed *cv_c13_parsed_from_data(Arena *arena, String8 c13_data, struct PDB_Strtbl *strtbl, struct PDB_CoffSectionArray *sections);
|
||||
internal CV_C13Parsed *cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
|
||||
|
||||
#endif // CODEVIEW_H
|
||||
|
||||
@@ -246,7 +246,7 @@ cv_string_from_arch:
|
||||
{MANTYPREF - 0x1028}
|
||||
{UNAMESPACE_ST - 0x1029}
|
||||
{ST_MAX - 0x1100}
|
||||
{OBJNAME Objname 0x1101}
|
||||
{OBJNAME ObjName 0x1101}
|
||||
{THUNK32 Thunk32 0x1102}
|
||||
{BLOCK32 Block32 0x1103}
|
||||
{WITH32 - 0x1104}
|
||||
@@ -462,6 +462,7 @@ CV_BasicTypeTable:
|
||||
@table(name header_type_name val)
|
||||
CV_LeafKindTable:
|
||||
{
|
||||
{NOTYPE - 0x0000}
|
||||
{MODIFIER_16t - 0x0001}
|
||||
{POINTER_16t - 0x0002}
|
||||
{ARRAY_16t - 0x0003}
|
||||
@@ -586,6 +587,13 @@ CV_LeafKindTable:
|
||||
{VECTOR - 0x151b}
|
||||
{MATRIX - 0x151c}
|
||||
{VFTABLE - 0x151d}
|
||||
{FUNC_ID FuncId 0x1601}
|
||||
{MFUNC_ID MFuncId 0x1602}
|
||||
{BUILDINFO BuildInfo 0x1603}
|
||||
{SUBSTR_LIST SubstrList 0x1604}
|
||||
{STRING_ID StringId 0x1605}
|
||||
{UDT_SRC_LINE UDTSrcLine 0x1606}
|
||||
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
|
||||
{CLASS2 Struct2 0x1608}
|
||||
{STRUCT2 Struct2 0x1609}
|
||||
}
|
||||
|
||||
@@ -408,11 +408,11 @@ cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||
|
||||
case CV_SymKind_OBJNAME:
|
||||
{
|
||||
if (sizeof(CV_SymObjname) > cap){
|
||||
if (sizeof(CV_SymObjName) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad symbol range\n"));
|
||||
}
|
||||
else{
|
||||
CV_SymObjname *objname = (CV_SymObjname*)first;
|
||||
CV_SymObjName *objname = (CV_SymObjName*)first;
|
||||
|
||||
// sig
|
||||
str8_list_pushf(arena, out, " sig=%u\n", objname->sig);
|
||||
@@ -568,22 +568,22 @@ cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||
CV_SymPub32 *pub32 = (CV_SymPub32*)first;
|
||||
|
||||
// flags
|
||||
CV_PubFlags flags = pub32->flags;
|
||||
CV_Pub32Flags flags = pub32->flags;
|
||||
str8_list_push(arena, out, str8_lit(" flags="));
|
||||
if (flags == 0){
|
||||
str8_list_push(arena, out, str8_lit("0|"));
|
||||
}
|
||||
else{
|
||||
if (flags&CV_PubFlag_Code){
|
||||
if (flags&CV_Pub32Flag_Code){
|
||||
str8_list_push(arena, out, str8_lit("Code|"));
|
||||
}
|
||||
if (flags&CV_PubFlag_Function){
|
||||
if (flags&CV_Pub32Flag_Function){
|
||||
str8_list_push(arena, out, str8_lit("Function|"));
|
||||
}
|
||||
if (flags&CV_PubFlag_ManagedCode){
|
||||
if (flags&CV_Pub32Flag_ManagedCode){
|
||||
str8_list_push(arena, out, str8_lit("ManagedCode|"));
|
||||
}
|
||||
if (flags&CV_PubFlag_MSIL){
|
||||
if (flags&CV_Pub32Flag_MSIL){
|
||||
str8_list_push(arena, out, str8_lit("MSIL|"));
|
||||
}
|
||||
}
|
||||
@@ -2004,7 +2004,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_FUNC_ID:
|
||||
case CV_LeafKind_FUNC_ID:
|
||||
{
|
||||
if (sizeof(CV_LeafFuncId) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2020,7 +2020,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_MFUNC_ID:
|
||||
case CV_LeafKind_MFUNC_ID:
|
||||
{
|
||||
if (sizeof(CV_LeafMFuncId) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2036,7 +2036,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_BUILDINFO:
|
||||
case CV_LeafKind_BUILDINFO:
|
||||
{
|
||||
if (sizeof(CV_LeafBuildInfo) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2057,7 +2057,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_SUBSTR_LIST:
|
||||
case CV_LeafKind_SUBSTR_LIST:
|
||||
{
|
||||
if (sizeof(CV_LeafSubstrList) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2078,7 +2078,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_STRING_ID:
|
||||
case CV_LeafKind_STRING_ID:
|
||||
{
|
||||
if (sizeof(CV_LeafStringId) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2093,7 +2093,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
}
|
||||
}break;
|
||||
|
||||
case CV_LeafIDKind_UDT_SRC_LINE:
|
||||
case CV_LeafKind_UDT_SRC_LINE:
|
||||
{
|
||||
if (sizeof(CV_LeafUDTSrcLine) > cap){
|
||||
str8_list_push(arena, out, str8_lit(" bad leaf range\n"));
|
||||
@@ -2243,7 +2243,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||
//case CV_LeafIDKind_SUBSTR_LIST:
|
||||
//case CV_LeafIDKind_STRING_ID:
|
||||
//case CV_LeafIDKind_UDT_SRC_LINE:
|
||||
case CV_LeafIDKind_UDT_MOD_SRC_LINE:
|
||||
case CV_LeafKind_UDT_MOD_SRC_LINE:
|
||||
|
||||
{
|
||||
str8_list_push(arena, out, str8_lit(" no stringizer path\n"));
|
||||
@@ -2328,3 +2328,15 @@ cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13){
|
||||
str8_list_push(arena, out, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
internal String8
|
||||
cv_string_from_inline_range_kind(CV_InlineRangeKind kind)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (kind) {
|
||||
case CV_InlineRangeKind_Expr: result = str8_lit("Expr"); break;
|
||||
case CV_InlineRangeKind_Stmt: result = str8_lit("Stmt"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,4 +79,6 @@ internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
|
||||
|
||||
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
|
||||
|
||||
internal String8 cv_string_from_inline_range_kind(CV_InlineRangeKind kind);
|
||||
|
||||
#endif // CODEVIEW_STRINGIZE_H
|
||||
|
||||
@@ -447,6 +447,7 @@ String8 result = str8_lit("<Unknown CV_LeafKind>");
|
||||
switch(v)
|
||||
{
|
||||
default:{}break;
|
||||
case CV_LeafKind_NOTYPE:{result = str8_lit("NOTYPE");}break;
|
||||
case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
|
||||
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
||||
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
||||
@@ -571,6 +572,13 @@ case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
|
||||
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
||||
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
||||
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break;
|
||||
case CV_LeafKind_FUNC_ID:{result = str8_lit("FUNC_ID");}break;
|
||||
case CV_LeafKind_MFUNC_ID:{result = str8_lit("MFUNC_ID");}break;
|
||||
case CV_LeafKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break;
|
||||
case CV_LeafKind_SUBSTR_LIST:{result = str8_lit("SUBSTR_LIST");}break;
|
||||
case CV_LeafKind_STRING_ID:{result = str8_lit("STRING_ID");}break;
|
||||
case CV_LeafKind_UDT_SRC_LINE:{result = str8_lit("UDT_SRC_LINE");}break;
|
||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = str8_lit("UDT_MOD_SRC_LINE");}break;
|
||||
case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break;
|
||||
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
||||
}
|
||||
@@ -592,7 +600,7 @@ case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
|
||||
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
||||
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
||||
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break;
|
||||
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjname);}break;
|
||||
case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjName);}break;
|
||||
case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break;
|
||||
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
||||
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
||||
@@ -696,6 +704,13 @@ case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
|
||||
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
||||
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
||||
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break;
|
||||
case CV_LeafKind_FUNC_ID:{result = sizeof(CV_LeafFuncId);}break;
|
||||
case CV_LeafKind_MFUNC_ID:{result = sizeof(CV_LeafMFuncId);}break;
|
||||
case CV_LeafKind_BUILDINFO:{result = sizeof(CV_LeafBuildInfo);}break;
|
||||
case CV_LeafKind_SUBSTR_LIST:{result = sizeof(CV_LeafSubstrList);}break;
|
||||
case CV_LeafKind_STRING_ID:{result = sizeof(CV_LeafStringId);}break;
|
||||
case CV_LeafKind_UDT_SRC_LINE:{result = sizeof(CV_LeafUDTSrcLine);}break;
|
||||
case CV_LeafKind_UDT_MOD_SRC_LINE:{result = sizeof(CV_LeafUDTModSrcLine);}break;
|
||||
case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
||||
}
|
||||
|
||||
@@ -381,6 +381,7 @@ CV_BasicType_PTR = 0xf0,
|
||||
typedef U16 CV_LeafKind;
|
||||
typedef enum CV_LeafKindEnum
|
||||
{
|
||||
CV_LeafKind_NOTYPE = 0x0000,
|
||||
CV_LeafKind_MODIFIER_16t = 0x0001,
|
||||
CV_LeafKind_POINTER_16t = 0x0002,
|
||||
CV_LeafKind_ARRAY_16t = 0x0003,
|
||||
@@ -505,6 +506,13 @@ CV_LeafKind_BINTERFACE = 0x151a,
|
||||
CV_LeafKind_VECTOR = 0x151b,
|
||||
CV_LeafKind_MATRIX = 0x151c,
|
||||
CV_LeafKind_VFTABLE = 0x151d,
|
||||
CV_LeafKind_FUNC_ID = 0x1601,
|
||||
CV_LeafKind_MFUNC_ID = 0x1602,
|
||||
CV_LeafKind_BUILDINFO = 0x1603,
|
||||
CV_LeafKind_SUBSTR_LIST = 0x1604,
|
||||
CV_LeafKind_STRING_ID = 0x1605,
|
||||
CV_LeafKind_UDT_SRC_LINE = 0x1606,
|
||||
CV_LeafKind_UDT_MOD_SRC_LINE = 0x1607,
|
||||
CV_LeafKind_CLASS2 = 0x1608,
|
||||
CV_LeafKind_STRUCT2 = 0x1609,
|
||||
} CV_LeafKindEnum;
|
||||
|
||||
+413
-137
@@ -97,15 +97,17 @@ coff_header_info_from_data(String8 data)
|
||||
COFF_HeaderInfo info = {0};
|
||||
if (coff_is_big_obj(data)) {
|
||||
COFF_HeaderBigObj *big_header = (COFF_HeaderBigObj*)data.str;
|
||||
info.machine = big_header->machine;
|
||||
info.section_array_off = sizeof(COFF_HeaderBigObj);
|
||||
info.section_count_no_null = big_header->section_count;
|
||||
info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols;
|
||||
info.symbol_size = sizeof(COFF_Symbol32);
|
||||
info.symbol_off = big_header->pointer_to_symbol_table;
|
||||
info.symbol_count = big_header->number_of_symbols;
|
||||
info.type = COFF_DataType_BIG_OBJ;
|
||||
info.machine = big_header->machine;
|
||||
info.section_array_off = sizeof(COFF_HeaderBigObj);
|
||||
info.section_count_no_null = big_header->section_count;
|
||||
info.string_table_off = big_header->pointer_to_symbol_table + sizeof(COFF_Symbol32) * big_header->number_of_symbols;
|
||||
info.symbol_size = sizeof(COFF_Symbol32);
|
||||
info.symbol_off = big_header->pointer_to_symbol_table;
|
||||
info.symbol_count = big_header->number_of_symbols;
|
||||
} else if (coff_is_obj(data)) {
|
||||
COFF_Header *header = (COFF_Header*)data.str;
|
||||
COFF_Header *header = (COFF_Header*)data.str;
|
||||
info.type = COFF_DataType_OBJ;
|
||||
info.machine = header->machine;
|
||||
info.section_array_off = sizeof(COFF_Header);
|
||||
info.section_count_no_null = header->section_count;
|
||||
@@ -143,6 +145,30 @@ coff_align_size_from_section_flags(COFF_SectionFlags flags)
|
||||
return align;
|
||||
}
|
||||
|
||||
internal COFF_SectionFlags
|
||||
coff_section_flag_from_align_size(U64 align)
|
||||
{
|
||||
COFF_SectionFlags flags = 0;
|
||||
switch (align) {
|
||||
case 1: flags = COFF_SectionAlign_1BYTES; break;
|
||||
case 2: flags = COFF_SectionAlign_2BYTES; break;
|
||||
case 4: flags = COFF_SectionAlign_4BYTES; break;
|
||||
case 8: flags = COFF_SectionAlign_8BYTES; break;
|
||||
case 16: flags = COFF_SectionAlign_16BYTES; break;
|
||||
case 32: flags = COFF_SectionAlign_32BYTES; break;
|
||||
case 64: flags = COFF_SectionAlign_64BYTES; break;
|
||||
case 128: flags = COFF_SectionAlign_128BYTES; break;
|
||||
case 256: flags = COFF_SectionAlign_256BYTES; break;
|
||||
case 512: flags = COFF_SectionAlign_512BYTES; break;
|
||||
case 1024: flags = COFF_SectionAlign_1024BYTES; break;
|
||||
case 2048: flags = COFF_SectionAlign_2048BYTES; break;
|
||||
case 4096: flags = COFF_SectionAlign_4096BYTES; break;
|
||||
case 8192: flags = COFF_SectionAlign_8192BYTES; break;
|
||||
}
|
||||
flags <<= COFF_SectionFlag_ALIGN_SHIFT;
|
||||
return flags;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_symbol(COFF_Symbol32 *symbol)
|
||||
{
|
||||
@@ -387,12 +413,34 @@ coff_word_size_from_machine(COFF_MachineType machine)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch (machine) {
|
||||
case COFF_MachineType_X64: result = 8; break;
|
||||
case COFF_MachineType_X86: result = 4; break;
|
||||
case COFF_MachineType_X64: result = 8; break;
|
||||
case COFF_MachineType_X86: result = 4; break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_default_exe_base_from_machine(COFF_MachineType machine)
|
||||
{
|
||||
U64 exe_base = 0;
|
||||
switch (coff_word_size_from_machine(machine)) {
|
||||
case 4: exe_base = 0x400000; break;
|
||||
case 8: exe_base = 0x140000000; break;
|
||||
}
|
||||
return exe_base;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_default_dll_base_from_machine(COFF_MachineType machine)
|
||||
{
|
||||
U64 dll_base = 0;
|
||||
switch (coff_word_size_from_machine(machine)) {
|
||||
case 4: dll_base = 0x10000000; break;
|
||||
case 8: dll_base = 0x180000000; break;
|
||||
}
|
||||
return dll_base;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_lookup(Arena *arena, U16 hint, String8 name)
|
||||
{
|
||||
@@ -421,6 +469,147 @@ coff_make_ordinal_64(U16 hint)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal String8
|
||||
coff_make_import_header_by_name(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
String8 name,
|
||||
U16 hint,
|
||||
COFF_ImportHeaderType type)
|
||||
{
|
||||
struct {
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
COFF_MachineType machine;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 sizeof_data;
|
||||
U16 hint_ordinal;
|
||||
U16 flags;
|
||||
} import_header = {
|
||||
COFF_MachineType_UNKNOWN, // sig1
|
||||
max_U16, // sig2
|
||||
0, // version
|
||||
machine,
|
||||
time_stamp,
|
||||
safe_cast_u32(name.size + dll_name.size + 2), // sizeof_data
|
||||
0, // hint_ordinal
|
||||
0, // flags
|
||||
};
|
||||
|
||||
import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT;
|
||||
import_header.flags |= COFF_ImportHeaderNameType_NAME << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT;
|
||||
import_header.hint_ordinal = hint;
|
||||
|
||||
// alloc memory
|
||||
U64 buffer_size = sizeof(import_header) + import_header.sizeof_data;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
|
||||
// copy header
|
||||
MemoryCopy(buffer, &import_header, sizeof(import_header));
|
||||
|
||||
// copy function name
|
||||
U8 *func_name = buffer + sizeof(import_header);
|
||||
MemoryCopy(func_name, name.str, name.size);
|
||||
func_name[name.size] = 0;
|
||||
|
||||
// copy dll name
|
||||
U8 *dll_name_buffer = buffer + sizeof(import_header) + name.size + 1;
|
||||
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
|
||||
dll_name_buffer[dll_name.size] = 0;
|
||||
|
||||
String8 import_data = str8(buffer, buffer_size);
|
||||
return import_data;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_make_import_header_by_ordinal(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U16 ordinal,
|
||||
COFF_ImportHeaderType type)
|
||||
{
|
||||
struct {
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
COFF_MachineType machine;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 sizeof_data;
|
||||
U16 hint_ordinal;
|
||||
U16 flags;
|
||||
} import_header = {
|
||||
COFF_MachineType_UNKNOWN, // sig1
|
||||
max_U16, // sig2
|
||||
0, // version
|
||||
machine,
|
||||
time_stamp,
|
||||
safe_cast_u32(/* name.size + */ dll_name.size + 2), // sizeof_data
|
||||
0, // hint_ordinal
|
||||
0, // flags
|
||||
};
|
||||
|
||||
import_header.flags |= (U16)(type & COFF_IMPORT_HEADER_TYPE_MASK) << COFF_IMPORT_HEADER_TYPE_SHIFT;
|
||||
import_header.flags |= COFF_ImportHeaderNameType_ORDINAL << COFF_IMPORT_HEADER_NAME_TYPE_SHIFT;
|
||||
import_header.hint_ordinal = ordinal;
|
||||
|
||||
// alloc memory
|
||||
U64 buffer_size = sizeof(import_header) + import_header.sizeof_data;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
|
||||
// copy header
|
||||
MemoryCopyStruct(buffer, &import_header);
|
||||
|
||||
// no function name write zero
|
||||
U8 *func_name = buffer + sizeof(import_header);
|
||||
func_name[0] = 0;
|
||||
|
||||
// copy dll name
|
||||
U8 *dll_name_buffer = buffer + sizeof(import_header) + /* name.size */ + 1;
|
||||
MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size);
|
||||
dll_name_buffer[dll_name.size] = 0;
|
||||
|
||||
String8 import_data = str8(buffer, buffer_size);
|
||||
return import_data;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Resources
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str16(Arena *arena, String16 string)
|
||||
{
|
||||
AssertAlways(string.size <= max_U16);
|
||||
U16 size16 = (U16)string.size;
|
||||
|
||||
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
|
||||
MemoryCopy(buffer + 0, &size16, sizeof(size16));
|
||||
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
|
||||
|
||||
return str8_array(buffer, size16 + 1);
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_string_from_str8(Arena *arena, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String16 string16 = str16_from_8(scratch.arena, string);
|
||||
String8 result = coff_resource_string_from_str16(arena, string16);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_resource_number_from_u16(Arena *arena, U16 number)
|
||||
{
|
||||
U16 *buffer = push_array_no_zero(arena, U16, 2);
|
||||
buffer[0] = max_U16;
|
||||
buffer[1] = number;
|
||||
return str8_array(buffer, 2);
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
||||
{
|
||||
@@ -437,28 +626,9 @@ coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b)
|
||||
}
|
||||
|
||||
internal COFF_ResourceID
|
||||
coff_resource_id_copy(Arena *arena, COFF_ResourceID id)
|
||||
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
{
|
||||
COFF_ResourceID result = zero_struct;
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
case COFF_ResourceIDType_NUMBER: {
|
||||
result.type = COFF_ResourceIDType_NUMBER;
|
||||
result.u.number = id.u.number;
|
||||
} break;
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
result.type = COFF_ResourceIDType_STRING;
|
||||
result.u.string = id.u.string;
|
||||
} break;
|
||||
default: Assert(!"invalid resource id type");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ResourceID
|
||||
coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
{
|
||||
COFF_ResourceID id;
|
||||
COFF_ResourceID id = {0};
|
||||
id.type = id_16->type;
|
||||
switch (id_16->type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
@@ -468,23 +638,22 @@ coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16)
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
id.u.string = str8_from_16(arena, id_16->u.string);
|
||||
} break;
|
||||
default: Assert(!"invalid resource id type");
|
||||
default: InvalidPath;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
coff_read_resource_id_utf16(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U16 flag = 0;
|
||||
str8_deserial_read_struct(data, cursor, &flag);
|
||||
|
||||
B32 is_number = flag == max_U16;
|
||||
if (is_number) {
|
||||
cursor += sizeof(flag);
|
||||
if (flag == max_U16) {
|
||||
id_out->type = COFF_ResourceIDType_NUMBER;
|
||||
cursor += sizeof(flag);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number);
|
||||
} else {
|
||||
id_out->type = COFF_ResourceIDType_STRING;
|
||||
@@ -492,72 +661,130 @@ coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out)
|
||||
}
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
read_size = AlignPow2(read_size, COFF_RES_ALIGN);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out)
|
||||
{
|
||||
// parse header
|
||||
COFF_ResourceHeaderPrefix prefix; MemoryZeroStruct(&prefix);
|
||||
U64 cursor = str8_deserial_read_struct(raw_res, off, &prefix);
|
||||
String8 header_data = str8_substr(raw_res, rng_1u64(off, off + prefix.header_size));
|
||||
String8 raw_header = str8_skip(raw_res, off);
|
||||
U64 header_cursor = 0;
|
||||
|
||||
// prefix
|
||||
COFF_ResourceHeaderPrefix prefix = {0};
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
|
||||
|
||||
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
|
||||
raw_header = str8_prefix(raw_header, prefix.header_size);
|
||||
|
||||
// header
|
||||
COFF_ResourceID_16 type_16 = {0};
|
||||
COFF_ResourceID_16 name_16 = {0};
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
|
||||
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
|
||||
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
|
||||
Assert(prefix.header_size == header_cursor);
|
||||
|
||||
// convert utf-16 resource ids to utf-8
|
||||
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
|
||||
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
|
||||
|
||||
// read data
|
||||
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
|
||||
Assert(prefix.data_size == data_read_size);
|
||||
|
||||
COFF_ResourceID_16 type_16; MemoryZeroStruct(&type_16);
|
||||
cursor += coff_read_resource_id(header_data, cursor, &type_16);
|
||||
cursor = AlignPow2(cursor, COFF_RES_ALIGN);
|
||||
|
||||
COFF_ResourceID_16 name_16; MemoryZeroStruct(&name_16);
|
||||
cursor += coff_read_resource_id(header_data, cursor, &name_16);
|
||||
cursor = AlignPow2(cursor, COFF_RES_ALIGN);
|
||||
|
||||
U32 data_version = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &data_version);
|
||||
|
||||
COFF_ResourceMemoryFlags memory_flags = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &memory_flags);
|
||||
|
||||
U16 language_id = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &language_id);
|
||||
|
||||
U32 version = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &version);
|
||||
|
||||
U32 characteristics = 0;
|
||||
cursor += str8_deserial_read_struct(header_data, cursor, &characteristics);
|
||||
|
||||
String8 data;
|
||||
cursor += str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &data);
|
||||
|
||||
// was resource parsed?
|
||||
Assert(cursor >= prefix.data_size + prefix.header_size);
|
||||
|
||||
// fill out result
|
||||
res_out->type = coff_convert_resource_id(arena, &type_16);
|
||||
res_out->name = coff_convert_resource_id(arena, &name_16);
|
||||
res_out->language_id = language_id;
|
||||
res_out->data_version = data_version;
|
||||
res_out->version = version;
|
||||
res_out->memory_flags = memory_flags;
|
||||
res_out->data = data;
|
||||
|
||||
U64 resource_size = AlignPow2(prefix.data_size + prefix.header_size, COFF_RES_ALIGN);
|
||||
return resource_size;
|
||||
// compute read size
|
||||
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_RES_ALIGN);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal COFF_ResourceList
|
||||
coff_resource_list_from_data(Arena *arena, String8 data)
|
||||
{
|
||||
COFF_ResourceList list; MemoryZeroStruct(&list);
|
||||
for (U64 cursor = 0, stride; cursor < data.size; cursor += stride) {
|
||||
COFF_ResourceList list = {0};
|
||||
U64 cursor;
|
||||
for (cursor = 0 ; cursor < data.size; ) {
|
||||
COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1);
|
||||
stride = coff_read_resource(data, cursor, arena, &node->data);
|
||||
list.count += 1;
|
||||
cursor += coff_read_resource(data, cursor, arena, &node->data);
|
||||
SLLQueuePush(list.first, list.last, node);
|
||||
++list.count;
|
||||
}
|
||||
Assert(cursor == data.size);
|
||||
return list;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
|
||||
{
|
||||
String8 result = str8_zero();
|
||||
switch (id.type) {
|
||||
case COFF_ResourceIDType_NULL: break;
|
||||
case COFF_ResourceIDType_NUMBER: {
|
||||
result = coff_resource_number_from_u16(arena, id.u.number);
|
||||
} break;
|
||||
case COFF_ResourceIDType_STRING: {
|
||||
result = coff_resource_string_from_str8(arena, id.u.string);
|
||||
} break;
|
||||
default: InvalidPath;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_write_resource(Arena *arena,
|
||||
COFF_ResourceID type,
|
||||
COFF_ResourceID name,
|
||||
U32 data_version,
|
||||
COFF_ResourceMemoryFlags memory_flags,
|
||||
U16 language_id,
|
||||
U32 version,
|
||||
U32 characteristics,
|
||||
String8 data)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List list = {0};
|
||||
|
||||
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
|
||||
String8 packed_type = coff_write_resource_id(scratch.arena, type);
|
||||
String8 packed_name = coff_write_resource_id(scratch.arena, name);
|
||||
|
||||
// prefix + header
|
||||
str8_list_push(scratch.arena, &list, str8_struct(prefix));
|
||||
str8_list_push(scratch.arena, &list, packed_type);
|
||||
str8_list_push(scratch.arena, &list, packed_name);
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&version));
|
||||
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
|
||||
|
||||
prefix->data_size = safe_cast_u32(data.size);
|
||||
prefix->header_size = safe_cast_u32(list.total_size);
|
||||
|
||||
// data
|
||||
str8_list_push(scratch.arena, &list, data);
|
||||
|
||||
// magic
|
||||
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
|
||||
|
||||
// align
|
||||
U64 align_size = AlignPow2(list.total_size, COFF_RES_ALIGN) - list.total_size;
|
||||
U8 *align = push_array(scratch.arena, U8, align_size);
|
||||
str8_list_push(scratch.arena, &list, str8(align, align_size));
|
||||
|
||||
// join
|
||||
String8 res = str8_list_join(arena, &list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_DataType
|
||||
@@ -567,12 +794,10 @@ coff_data_type_from_data(String8 data)
|
||||
if (is_big_obj) {
|
||||
return COFF_DataType_BIG_OBJ;
|
||||
}
|
||||
|
||||
B32 is_import = coff_is_import(data);
|
||||
if (is_import) {
|
||||
return COFF_DataType_IMPORT;
|
||||
}
|
||||
|
||||
return COFF_DataType_OBJ;
|
||||
}
|
||||
|
||||
@@ -591,18 +816,22 @@ coff_is_import(String8 data)
|
||||
internal B32
|
||||
coff_is_archive(String8 data)
|
||||
{
|
||||
U64 sig = 0;
|
||||
str8_deserial_read_struct(data, 0, &sig);
|
||||
B32 is_archive = sig == COFF_ARCHIVE_SIG;
|
||||
B32 is_archive = 0;
|
||||
U8 sig[sizeof(g_coff_archive_sig)];
|
||||
if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) {
|
||||
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
|
||||
}
|
||||
return is_archive;
|
||||
}
|
||||
|
||||
internal B32
|
||||
coff_is_thin_archive(String8 data)
|
||||
{
|
||||
U64 sig = 0;
|
||||
str8_deserial_read_struct(data, 0, &sig);
|
||||
B32 is_archive = sig == COFF_THIN_ARCHIVE_SIG;
|
||||
B32 is_archive = 0;
|
||||
U8 sig[sizeof(g_coff_thin_archive_sig)];
|
||||
if (str8_deserial_read_struct(data, 0, &sig) == sizeof(sig)) {
|
||||
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
|
||||
}
|
||||
return is_archive;
|
||||
}
|
||||
|
||||
@@ -751,11 +980,9 @@ coff_read_archive_long_name(String8 long_names, String8 name)
|
||||
internal U64
|
||||
coff_archive_member_iter_init(String8 data)
|
||||
{
|
||||
U64 cursor = 0;
|
||||
U64 sig = 0;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &sig);
|
||||
if (sig != COFF_ARCHIVE_SIG) {
|
||||
cursor = data.size;
|
||||
U64 cursor = data.size;
|
||||
if (coff_is_archive(data)) {
|
||||
cursor = sizeof(g_coff_archive_sig);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
@@ -915,11 +1142,9 @@ coff_archive_from_data(Arena *arena, String8 data)
|
||||
internal U64
|
||||
coff_thin_archive_member_iter_init(String8 data)
|
||||
{
|
||||
U64 cursor = 0;
|
||||
U64 sig = 0;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &sig);
|
||||
if (sig != COFF_THIN_ARCHIVE_SIG) {
|
||||
cursor = data.size;
|
||||
U64 cursor = data.size;
|
||||
if (coff_is_thin_archive(data)) {
|
||||
cursor = sizeof(g_coff_thin_archive_sig);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
@@ -990,18 +1215,59 @@ coff_archive_parse_from_data(Arena *arena, String8 data)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
read_only struct
|
||||
{
|
||||
String8 string;
|
||||
COFF_MachineType machine;
|
||||
} g_coff_machine_map[] = {
|
||||
{ str8_lit_comp(""), COFF_MachineType_UNKNOWN },
|
||||
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
|
||||
{ str8_lit_comp("AMD64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
|
||||
{ str8_lit_comp("AM33"), COFF_MachineType_AM33 },
|
||||
{ str8_lit_comp("ARM"), COFF_MachineType_ARM },
|
||||
{ str8_lit_comp("ARM64"), COFF_MachineType_ARM64 },
|
||||
{ str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT },
|
||||
{ str8_lit_comp("EBC"), COFF_MachineType_EBC },
|
||||
{ str8_lit_comp("IA64"), COFF_MachineType_IA64 },
|
||||
{ str8_lit_comp("M32R"), COFF_MachineType_M32R },
|
||||
{ str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 },
|
||||
{ str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU },
|
||||
{ str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 },
|
||||
{ str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC },
|
||||
{ str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP },
|
||||
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
|
||||
{ str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 },
|
||||
{ str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 },
|
||||
{ str8_lit_comp("SH3"), COFF_MachineType_SH3 },
|
||||
{ str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP },
|
||||
{ str8_lit_comp("SH4"), COFF_MachineType_SH4 },
|
||||
{ str8_lit_comp("SH5"), COFF_MachineType_SH5 },
|
||||
{ str8_lit_comp("THUMB"), COFF_MachineType_THUMB },
|
||||
{ str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 },
|
||||
};
|
||||
|
||||
read_only static struct {
|
||||
char * name;
|
||||
COFF_ImportHeaderType type;
|
||||
} g_coff_import_header_type_map[] = {
|
||||
{ "CODE", COFF_ImportHeaderType_CODE },
|
||||
{ "DATA", COFF_ImportHeaderType_DATA },
|
||||
{ "CONST", COFF_ImportHeaderType_CONST },
|
||||
};
|
||||
|
||||
internal String8
|
||||
coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
||||
{
|
||||
String8 result = str8(0,0);
|
||||
switch (select) {
|
||||
case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break;
|
||||
case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break;
|
||||
case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break;
|
||||
case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break;
|
||||
case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break;
|
||||
case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break;
|
||||
case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break;
|
||||
case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break;
|
||||
case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break;
|
||||
case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break;
|
||||
case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break;
|
||||
case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break;
|
||||
case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break;
|
||||
case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1009,35 +1275,12 @@ coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
|
||||
internal String8
|
||||
coff_string_from_machine_type(COFF_MachineType machine)
|
||||
{
|
||||
String8 result = str8(0,0);
|
||||
switch (machine) {
|
||||
case COFF_MachineType_UNKNOWN: result = str8_lit("UNKNOWN"); break;
|
||||
case COFF_MachineType_X86: result = str8_lit("X86"); break;
|
||||
case COFF_MachineType_X64: result = str8_lit("X64"); break;
|
||||
case COFF_MachineType_AM33: result = str8_lit("AM33"); break;
|
||||
case COFF_MachineType_ARM: result = str8_lit("ARM"); break;
|
||||
case COFF_MachineType_ARM64: result = str8_lit("ARM64"); break;
|
||||
case COFF_MachineType_ARMNT: result = str8_lit("ARMNT"); break;
|
||||
case COFF_MachineType_EBC: result = str8_lit("EBC"); break;
|
||||
case COFF_MachineType_IA64: result = str8_lit("IA64"); break;
|
||||
case COFF_MachineType_M32R: result = str8_lit("M32R"); break;
|
||||
case COFF_MachineType_MIPS16: result = str8_lit("MIPS16"); break;
|
||||
case COFF_MachineType_MIPSFPU: result = str8_lit("MIPSFPU"); break;
|
||||
case COFF_MachineType_MIPSFPU16: result = str8_lit("MIPSFPU16"); break;
|
||||
case COFF_MachineType_POWERPC: result = str8_lit("POWERPC"); break;
|
||||
case COFF_MachineType_POWERPCFP: result = str8_lit("POWERPCFP"); break;
|
||||
case COFF_MachineType_R4000: result = str8_lit("R4000"); break;
|
||||
case COFF_MachineType_RISCV32: result = str8_lit("RISCV32"); break;
|
||||
case COFF_MachineType_RISCV64: result = str8_lit("RISCV64"); break;
|
||||
case COFF_MachineType_RISCV128: result = str8_lit("RISCV128"); break;
|
||||
case COFF_MachineType_SH3: result = str8_lit("SH3"); break;
|
||||
case COFF_MachineType_SH3DSP: result = str8_lit("SH3DSP"); break;
|
||||
case COFF_MachineType_SH4: result = str8_lit("SH4"); break;
|
||||
case COFF_MachineType_SH5: result = str8_lit("SH5"); break;
|
||||
case COFF_MachineType_THUMB: result = str8_lit("THUMB"); break;
|
||||
case COFF_MachineType_WCEMIPSV2: result = str8_lit("WCEMIPSV2"); break;
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (g_coff_machine_map[i].machine == machine) {
|
||||
return g_coff_machine_map[i].string;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
@@ -1117,3 +1360,36 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
coff_string_from_import_header_type(COFF_ImportHeaderType type)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (g_coff_import_header_type_map[i].type == type) {
|
||||
return str8_cstring(g_coff_import_header_type_map[i].name);
|
||||
}
|
||||
}
|
||||
return str8(0,0);
|
||||
}
|
||||
|
||||
internal COFF_MachineType
|
||||
coff_machine_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) {
|
||||
if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_machine_map[i].machine;
|
||||
}
|
||||
}
|
||||
return COFF_MachineType_UNKNOWN;
|
||||
}
|
||||
|
||||
internal COFF_ImportHeaderType
|
||||
coff_import_header_type_from_string(String8 name)
|
||||
{
|
||||
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
|
||||
if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_coff_import_header_type_map[i].type;
|
||||
}
|
||||
}
|
||||
return COFF_ImportHeaderType_COUNT;
|
||||
}
|
||||
|
||||
|
||||
+308
-286
@@ -77,12 +77,12 @@ typedef struct COFF_Header COFF_Header;
|
||||
struct COFF_Header
|
||||
{
|
||||
COFF_MachineType machine;
|
||||
U16 section_count;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 symbol_table_foff;
|
||||
U32 symbol_count;
|
||||
U16 optional_header_size;
|
||||
COFF_Flags flags;
|
||||
U16 section_count;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 symbol_table_foff;
|
||||
U32 symbol_count;
|
||||
U16 optional_header_size;
|
||||
COFF_Flags flags;
|
||||
};
|
||||
|
||||
typedef U32 COFF_SectionAlign;
|
||||
@@ -108,35 +108,36 @@ enum
|
||||
typedef U32 COFF_SectionFlags;
|
||||
enum
|
||||
{
|
||||
COFF_SectionFlag_TYPE_NO_PAD = (1 << 3),
|
||||
COFF_SectionFlag_CNT_CODE = (1 << 5),
|
||||
COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6),
|
||||
COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7),
|
||||
COFF_SectionFlag_LNK_OTHER = (1 << 8),
|
||||
COFF_SectionFlag_LNK_INFO = (1 << 9),
|
||||
COFF_SectionFlag_LNK_REMOVE = (1 << 11),
|
||||
COFF_SectionFlag_LNK_COMDAT = (1 << 12),
|
||||
COFF_SectionFlag_GPREL = (1 << 15),
|
||||
COFF_SectionFlag_MEM_16BIT = (1 << 17),
|
||||
COFF_SectionFlag_MEM_LOCKED = (1 << 18),
|
||||
COFF_SectionFlag_MEM_PRELOAD = (1 << 19),
|
||||
COFF_SectionFlag_ALIGN_SHIFT = 20, COFF_SectionFlag_ALIGN_MASK = 0xf,
|
||||
COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24),
|
||||
COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25),
|
||||
COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26),
|
||||
COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27),
|
||||
COFF_SectionFlag_MEM_SHARED = (1 << 28),
|
||||
COFF_SectionFlag_MEM_EXECUTE = (1 << 29),
|
||||
COFF_SectionFlag_MEM_READ = (1 << 30),
|
||||
COFF_SectionFlag_MEM_WRITE = (1 << 31),
|
||||
COFF_SectionFlag_TYPE_NO_PAD = (1 << 3),
|
||||
COFF_SectionFlag_CNT_CODE = (1 << 5),
|
||||
COFF_SectionFlag_CNT_INITIALIZED_DATA = (1 << 6),
|
||||
COFF_SectionFlag_CNT_UNINITIALIZED_DATA = (1 << 7),
|
||||
COFF_SectionFlag_LNK_OTHER = (1 << 8),
|
||||
COFF_SectionFlag_LNK_INFO = (1 << 9),
|
||||
COFF_SectionFlag_LNK_REMOVE = (1 << 11),
|
||||
COFF_SectionFlag_LNK_COMDAT = (1 << 12),
|
||||
COFF_SectionFlag_GPREL = (1 << 15),
|
||||
COFF_SectionFlag_MEM_16BIT = (1 << 17),
|
||||
COFF_SectionFlag_MEM_LOCKED = (1 << 18),
|
||||
COFF_SectionFlag_MEM_PRELOAD = (1 << 19),
|
||||
COFF_SectionFlag_ALIGN_SHIFT = 20,
|
||||
COFF_SectionFlag_ALIGN_MASK = 0xf,
|
||||
COFF_SectionFlag_LNK_NRELOC_OVFL = (1 << 24),
|
||||
COFF_SectionFlag_MEM_DISCARDABLE = (1 << 25),
|
||||
COFF_SectionFlag_MEM_NOT_CACHED = (1 << 26),
|
||||
COFF_SectionFlag_MEM_NOT_PAGED = (1 << 27),
|
||||
COFF_SectionFlag_MEM_SHARED = (1 << 28),
|
||||
COFF_SectionFlag_MEM_EXECUTE = (1 << 29),
|
||||
COFF_SectionFlag_MEM_READ = (1 << 30),
|
||||
COFF_SectionFlag_MEM_WRITE = (1 << 31),
|
||||
};
|
||||
#define COFF_SectionFlags_Extract_ALIGN(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_ALIGN_SHIFT) & COFF_SectionFlag_ALIGN_MASK)
|
||||
#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL)
|
||||
#define COFF_SectionFlags_LNK_FLAGS ((COFF_SectionFlag_ALIGN_MASK << COFF_SectionFlag_ALIGN_SHIFT) | COFF_SectionFlag_LNK_COMDAT | COFF_SectionFlag_LNK_INFO | COFF_SectionFlag_LNK_OTHER | COFF_SectionFlag_LNK_REMOVE | COFF_SectionFlag_LNK_NRELOC_OVFL)
|
||||
|
||||
typedef struct COFF_SectionHeader COFF_SectionHeader;
|
||||
struct COFF_SectionHeader
|
||||
{
|
||||
U8 name[8];
|
||||
U8 name[8];
|
||||
U32 vsize;
|
||||
U32 voff;
|
||||
U32 fsize;
|
||||
@@ -151,112 +152,99 @@ struct COFF_SectionHeader
|
||||
typedef U16 COFF_RelocTypeX64;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeX64_ABS = 0x0,
|
||||
COFF_RelocTypeX64_ADDR64 = 0x1,
|
||||
COFF_RelocTypeX64_ADDR32 = 0x2,
|
||||
COFF_RelocTypeX64_ADDR32NB = 0x3,
|
||||
// NB => No Base
|
||||
COFF_RelocTypeX64_REL32 = 0x4,
|
||||
COFF_RelocTypeX64_REL32_1 = 0x5,
|
||||
COFF_RelocTypeX64_REL32_2 = 0x6,
|
||||
COFF_RelocTypeX64_REL32_3 = 0x7,
|
||||
COFF_RelocTypeX64_REL32_4 = 0x8,
|
||||
COFF_RelocTypeX64_REL32_5 = 0x9,
|
||||
COFF_RelocTypeX64_SECTION = 0xA,
|
||||
COFF_RelocTypeX64_SECREL = 0xB,
|
||||
COFF_RelocTypeX64_SECREL7 = 0xC,
|
||||
// TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_RelocTypeX64_TOKEN = 0xD,
|
||||
COFF_RelocTypeX64_SREL32 = 0xE,
|
||||
// TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_RelocTypeX64_PAIR = 0xF,
|
||||
COFF_RelocTypeX64_SSPAN32 = 0x10,
|
||||
COFF_RelocTypeX64_COUNT = 17
|
||||
COFF_RelocTypeX64_ABS = 0x0,
|
||||
COFF_RelocTypeX64_ADDR64 = 0x1,
|
||||
COFF_RelocTypeX64_ADDR32 = 0x2,
|
||||
COFF_RelocTypeX64_ADDR32NB = 0x3, // NB => No Base
|
||||
COFF_RelocTypeX64_REL32 = 0x4,
|
||||
COFF_RelocTypeX64_REL32_1 = 0x5,
|
||||
COFF_RelocTypeX64_REL32_2 = 0x6,
|
||||
COFF_RelocTypeX64_REL32_3 = 0x7,
|
||||
COFF_RelocTypeX64_REL32_4 = 0x8,
|
||||
COFF_RelocTypeX64_REL32_5 = 0x9,
|
||||
COFF_RelocTypeX64_SECTION = 0xA,
|
||||
COFF_RelocTypeX64_SECREL = 0xB,
|
||||
COFF_RelocTypeX64_SECREL7 = 0xC, // TODO(nick): MSDN doesn't specify size for CLR token
|
||||
COFF_RelocTypeX64_TOKEN = 0xD,
|
||||
COFF_RelocTypeX64_SREL32 = 0xE, // TODO(nick): MSDN doesn't specify size for PAIR
|
||||
COFF_RelocTypeX64_PAIR = 0xF,
|
||||
COFF_RelocTypeX64_SSPAN32 = 0x10,
|
||||
COFF_RelocTypeX64_COUNT = 17
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeX86;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeX86_ABS = 0x0,
|
||||
// relocation is ignored
|
||||
COFF_RelocTypeX86_DIR16 = 0x1,
|
||||
// no support
|
||||
COFF_RelocTypeX86_REL16 = 0x2,
|
||||
// no support
|
||||
COFF_RelocTypeX86_UNKNOWN0 = 0x3,
|
||||
COFF_RelocTypeX86_UNKNOWN2 = 0x4,
|
||||
COFF_RelocTypeX86_UNKNOWN3 = 0x5,
|
||||
COFF_RelocTypeX86_DIR32 = 0x6,
|
||||
// 32-bit virtual address
|
||||
COFF_RelocTypeX86_DIR32NB = 0x7,
|
||||
// 32-bit virtual offset
|
||||
COFF_RelocTypeX86_SEG12 = 0x9,
|
||||
// no support
|
||||
COFF_RelocTypeX86_SECTION = 0xA,
|
||||
// 16-bit section index, used for debug info purposes
|
||||
COFF_RelocTypeX86_SECREL = 0xB,
|
||||
// 32-bit offset from start of a section
|
||||
COFF_RelocTypeX86_TOKEN = 0xC,
|
||||
// CLR token? (for managed languages)
|
||||
COFF_RelocTypeX86_SECREL7 = 0xD,
|
||||
// 7-bit offset from the base of the section that contains the target.
|
||||
COFF_RelocTypeX86_UNKNOWN4 = 0xE,
|
||||
COFF_RelocTypeX86_UNKNOWN5 = 0xF,
|
||||
COFF_RelocTypeX86_UNKNOWN6 = 0x10,
|
||||
COFF_RelocTypeX86_UNKNOWN7 = 0x11,
|
||||
COFF_RelocTypeX86_UNKNOWN8 = 0x12,
|
||||
COFF_RelocTypeX86_UNKNOWN9 = 0x13,
|
||||
COFF_RelocTypeX86_REL32 = 0x14,
|
||||
COFF_RelocTypeX86_COUNT = 20
|
||||
COFF_RelocTypeX86_ABS = 0x0, // relocation is ignored
|
||||
COFF_RelocTypeX86_DIR16 = 0x1, // no support
|
||||
COFF_RelocTypeX86_REL16 = 0x2, // no support
|
||||
COFF_RelocTypeX86_UNKNOWN0 = 0x3,
|
||||
COFF_RelocTypeX86_UNKNOWN2 = 0x4,
|
||||
COFF_RelocTypeX86_UNKNOWN3 = 0x5,
|
||||
COFF_RelocTypeX86_DIR32 = 0x6, // 32-bit virtual address
|
||||
COFF_RelocTypeX86_DIR32NB = 0x7, // 32-bit virtual offset
|
||||
COFF_RelocTypeX86_SEG12 = 0x9, // no support
|
||||
COFF_RelocTypeX86_SECTION = 0xA, // 16-bit section index, used for debug info purposes
|
||||
COFF_RelocTypeX86_SECREL = 0xB, // 32-bit offset from start of a section
|
||||
COFF_RelocTypeX86_TOKEN = 0xC, // CLR token? (for managed languages)
|
||||
COFF_RelocTypeX86_SECREL7 = 0xD, // 7-bit offset from the base of the section that contains the target.
|
||||
COFF_RelocTypeX86_UNKNOWN4 = 0xE,
|
||||
COFF_RelocTypeX86_UNKNOWN5 = 0xF,
|
||||
COFF_RelocTypeX86_UNKNOWN6 = 0x10,
|
||||
COFF_RelocTypeX86_UNKNOWN7 = 0x11,
|
||||
COFF_RelocTypeX86_UNKNOWN8 = 0x12,
|
||||
COFF_RelocTypeX86_UNKNOWN9 = 0x13,
|
||||
COFF_RelocTypeX86_REL32 = 0x14,
|
||||
COFF_RelocTypeX86_COUNT = 20
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeARM;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeARM_ABS = 0x0,
|
||||
COFF_RelocTypeARM_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM_BRANCH24 = 0x3,
|
||||
COFF_RelocTypeARM_BRANCH11 = 0x4,
|
||||
COFF_RelocTypeARM_UNKNOWN1 = 0x5,
|
||||
COFF_RelocTypeARM_UNKNOWN2 = 0x6,
|
||||
COFF_RelocTypeARM_UNKNOWN3 = 0x7,
|
||||
COFF_RelocTypeARM_UNKNOWN4 = 0x8,
|
||||
COFF_RelocTypeARM_UNKNOWN5 = 0x9,
|
||||
COFF_RelocTypeARM_REL32 = 0xA,
|
||||
COFF_RelocTypeARM_SECTION = 0xE,
|
||||
COFF_RelocTypeARM_SECREL = 0xF,
|
||||
COFF_RelocTypeARM_MOV32 = 0x10,
|
||||
COFF_RelocTypeARM_THUMB_MOV32 = 0x11,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12,
|
||||
COFF_RelocTypeARM_UNUSED = 0x13,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14,
|
||||
COFF_RelocTypeARM_THUMB_BLX23 = 0x15,
|
||||
COFF_RelocTypeARM_PAIR = 0x16,
|
||||
COFF_RelocTypeARM_COUNT = 20
|
||||
COFF_RelocTypeARM_ABS = 0x0,
|
||||
COFF_RelocTypeARM_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM_BRANCH24 = 0x3,
|
||||
COFF_RelocTypeARM_BRANCH11 = 0x4,
|
||||
COFF_RelocTypeARM_UNKNOWN1 = 0x5,
|
||||
COFF_RelocTypeARM_UNKNOWN2 = 0x6,
|
||||
COFF_RelocTypeARM_UNKNOWN3 = 0x7,
|
||||
COFF_RelocTypeARM_UNKNOWN4 = 0x8,
|
||||
COFF_RelocTypeARM_UNKNOWN5 = 0x9,
|
||||
COFF_RelocTypeARM_REL32 = 0xA,
|
||||
COFF_RelocTypeARM_SECTION = 0xE,
|
||||
COFF_RelocTypeARM_SECREL = 0xF,
|
||||
COFF_RelocTypeARM_MOV32 = 0x10,
|
||||
COFF_RelocTypeARM_THUMB_MOV32 = 0x11,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH20 = 0x12,
|
||||
COFF_RelocTypeARM_UNUSED = 0x13,
|
||||
COFF_RelocTypeARM_THUMB_BRANCH24 = 0x14,
|
||||
COFF_RelocTypeARM_THUMB_BLX23 = 0x15,
|
||||
COFF_RelocTypeARM_PAIR = 0x16,
|
||||
COFF_RelocTypeARM_COUNT = 20
|
||||
};
|
||||
|
||||
typedef U16 COFF_RelocTypeARM64;
|
||||
enum
|
||||
{
|
||||
COFF_RelocTypeARM64_ABS = 0x0,
|
||||
COFF_RelocTypeARM64_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM64_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM64_BRANCH26 = 0x3,
|
||||
COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4,
|
||||
COFF_RelocTypeARM64_REL21 = 0x5,
|
||||
COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6,
|
||||
COFF_RelocTypeARM64_SECREL = 0x8,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12A = 0x9,
|
||||
COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12L = 0xB,
|
||||
COFF_RelocTypeARM64_TOKEN = 0xC,
|
||||
COFF_RelocTypeARM64_SECTION = 0xD,
|
||||
COFF_RelocTypeARM64_ADDR64 = 0xE,
|
||||
COFF_RelocTypeARM64_BRANCH19 = 0xF,
|
||||
COFF_RelocTypeARM64_BRANCH14 = 0x10,
|
||||
COFF_RelocTypeARM64_REL32 = 0x11,
|
||||
COFF_RelocTypeARM64_COUNT = 17
|
||||
COFF_RelocTypeARM64_ABS = 0x0,
|
||||
COFF_RelocTypeARM64_ADDR32 = 0x1,
|
||||
COFF_RelocTypeARM64_ADDR32NB = 0x2,
|
||||
COFF_RelocTypeARM64_BRANCH26 = 0x3,
|
||||
COFF_RelocTypeARM64_PAGEBASE_REL21 = 0x4,
|
||||
COFF_RelocTypeARM64_REL21 = 0x5,
|
||||
COFF_RelocTypeARM64_PAGEOFFSET_12A = 0x6,
|
||||
COFF_RelocTypeARM64_SECREL = 0x8,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12A = 0x9,
|
||||
COFF_RelocTypeARM64_SECREL_HIGH12A = 0xA,
|
||||
COFF_RelocTypeARM64_SECREL_LOW12L = 0xB,
|
||||
COFF_RelocTypeARM64_TOKEN = 0xC,
|
||||
COFF_RelocTypeARM64_SECTION = 0xD,
|
||||
COFF_RelocTypeARM64_ADDR64 = 0xE,
|
||||
COFF_RelocTypeARM64_BRANCH19 = 0xF,
|
||||
COFF_RelocTypeARM64_BRANCH14 = 0x10,
|
||||
COFF_RelocTypeARM64_REL32 = 0x11,
|
||||
COFF_RelocTypeARM64_COUNT = 17
|
||||
};
|
||||
|
||||
typedef U8 COFF_SymType;
|
||||
@@ -273,8 +261,7 @@ enum
|
||||
COFF_SymType_STRUCT,
|
||||
COFF_SymType_UNION,
|
||||
COFF_SymType_ENUM,
|
||||
COFF_SymType_MOE,
|
||||
// member of enumeration
|
||||
COFF_SymType_MOE, // member of enumeration
|
||||
COFF_SymType_BYTE,
|
||||
COFF_SymType_WORD,
|
||||
COFF_SymType_UINT,
|
||||
@@ -285,100 +272,100 @@ enum
|
||||
typedef U8 COFF_SymStorageClass;
|
||||
enum
|
||||
{
|
||||
COFF_SymStorageClass_END_OF_FUNCTION = 0xff,
|
||||
COFF_SymStorageClass_NULL = 0,
|
||||
COFF_SymStorageClass_AUTOMATIC = 1,
|
||||
COFF_SymStorageClass_EXTERNAL = 2,
|
||||
COFF_SymStorageClass_STATIC = 3,
|
||||
COFF_SymStorageClass_REGISTER = 4,
|
||||
COFF_SymStorageClass_EXTERNAL_DEF = 5,
|
||||
COFF_SymStorageClass_LABEL = 6,
|
||||
COFF_SymStorageClass_UNDEFINED_LABEL = 7,
|
||||
COFF_SymStorageClass_MEMBER_OF_STRUCT = 8,
|
||||
COFF_SymStorageClass_ARGUMENT = 9,
|
||||
COFF_SymStorageClass_STRUCT_TAG = 10,
|
||||
COFF_SymStorageClass_MEMBER_OF_UNION = 11,
|
||||
COFF_SymStorageClass_UNION_TAG = 12,
|
||||
COFF_SymStorageClass_TYPE_DEFINITION = 13,
|
||||
COFF_SymStorageClass_UNDEFINED_STATIC = 14,
|
||||
COFF_SymStorageClass_ENUM_TAG = 15,
|
||||
COFF_SymStorageClass_MEMBER_OF_ENUM = 16,
|
||||
COFF_SymStorageClass_REGISTER_PARAM = 17,
|
||||
COFF_SymStorageClass_BIT_FIELD = 18,
|
||||
COFF_SymStorageClass_BLOCK = 100,
|
||||
COFF_SymStorageClass_FUNCTION = 101,
|
||||
COFF_SymStorageClass_END_OF_STRUCT = 102,
|
||||
COFF_SymStorageClass_FILE = 103,
|
||||
COFF_SymStorageClass_SECTION = 104,
|
||||
COFF_SymStorageClass_WEAK_EXTERNAL = 105,
|
||||
COFF_SymStorageClass_CLR_TOKEN = 107,
|
||||
COFF_SymStorageClass_COUNT = 27
|
||||
COFF_SymStorageClass_END_OF_FUNCTION = 0xff,
|
||||
COFF_SymStorageClass_NULL = 0,
|
||||
COFF_SymStorageClass_AUTOMATIC = 1,
|
||||
COFF_SymStorageClass_EXTERNAL = 2,
|
||||
COFF_SymStorageClass_STATIC = 3,
|
||||
COFF_SymStorageClass_REGISTER = 4,
|
||||
COFF_SymStorageClass_EXTERNAL_DEF = 5,
|
||||
COFF_SymStorageClass_LABEL = 6,
|
||||
COFF_SymStorageClass_UNDEFINED_LABEL = 7,
|
||||
COFF_SymStorageClass_MEMBER_OF_STRUCT = 8,
|
||||
COFF_SymStorageClass_ARGUMENT = 9,
|
||||
COFF_SymStorageClass_STRUCT_TAG = 10,
|
||||
COFF_SymStorageClass_MEMBER_OF_UNION = 11,
|
||||
COFF_SymStorageClass_UNION_TAG = 12,
|
||||
COFF_SymStorageClass_TYPE_DEFINITION = 13,
|
||||
COFF_SymStorageClass_UNDEFINED_STATIC = 14,
|
||||
COFF_SymStorageClass_ENUM_TAG = 15,
|
||||
COFF_SymStorageClass_MEMBER_OF_ENUM = 16,
|
||||
COFF_SymStorageClass_REGISTER_PARAM = 17,
|
||||
COFF_SymStorageClass_BIT_FIELD = 18,
|
||||
COFF_SymStorageClass_BLOCK = 100,
|
||||
COFF_SymStorageClass_FUNCTION = 101,
|
||||
COFF_SymStorageClass_END_OF_STRUCT = 102,
|
||||
COFF_SymStorageClass_FILE = 103,
|
||||
COFF_SymStorageClass_SECTION = 104,
|
||||
COFF_SymStorageClass_WEAK_EXTERNAL = 105,
|
||||
COFF_SymStorageClass_CLR_TOKEN = 107,
|
||||
COFF_SymStorageClass_COUNT = 27
|
||||
};
|
||||
|
||||
typedef U16 COFF_SymSecNumber;
|
||||
enum
|
||||
{
|
||||
COFF_SymSecNumber_NUMBER_UNDEFINED = 0,
|
||||
COFF_SymSecNumber_ABSOLUTE = 0xffff,
|
||||
COFF_SymSecNumber_DEBUG = 0xfffe,
|
||||
COFF_SymSecNumber_COUNT = 3
|
||||
COFF_SymSecNumber_NUMBER_UNDEFINED = 0,
|
||||
COFF_SymSecNumber_ABSOLUTE = 0xffff,
|
||||
COFF_SymSecNumber_DEBUG = 0xfffe,
|
||||
COFF_SymSecNumber_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U8 COFF_SymDType;
|
||||
enum
|
||||
{
|
||||
COFF_SymDType_NULL = 0,
|
||||
COFF_SymDType_PTR = 16,
|
||||
COFF_SymDType_FUNC = 32,
|
||||
COFF_SymDType_ARRAY = 48,
|
||||
COFF_SymDType_COUNT = 4
|
||||
COFF_SymDType_NULL = 0,
|
||||
COFF_SymDType_PTR = 16,
|
||||
COFF_SymDType_FUNC = 32,
|
||||
COFF_SymDType_ARRAY = 48,
|
||||
COFF_SymDType_COUNT = 4
|
||||
};
|
||||
|
||||
typedef U32 COFF_WeakExtType;
|
||||
enum
|
||||
{
|
||||
COFF_WeakExtType_NOLIBRARY = 1,
|
||||
COFF_WeakExtType_SEARCH_LIBRARY = 2,
|
||||
COFF_WeakExtType_SEARCH_ALIAS = 3,
|
||||
COFF_WeakExtType_COUNT = 3
|
||||
COFF_WeakExtType_NOLIBRARY = 1,
|
||||
COFF_WeakExtType_SEARCH_LIBRARY = 2,
|
||||
COFF_WeakExtType_SEARCH_ALIAS = 3,
|
||||
COFF_WeakExtType_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U32 COFF_ImportHeaderType;
|
||||
enum
|
||||
{
|
||||
COFF_ImportHeaderType_CODE = 0,
|
||||
COFF_ImportHeaderType_DATA = 1,
|
||||
COFF_ImportHeaderType_CONST = 2,
|
||||
COFF_ImportHeaderType_COUNT = 3
|
||||
COFF_ImportHeaderType_CODE = 0,
|
||||
COFF_ImportHeaderType_DATA = 1,
|
||||
COFF_ImportHeaderType_CONST = 2,
|
||||
COFF_ImportHeaderType_COUNT = 3
|
||||
};
|
||||
|
||||
typedef U32 COFF_ImportHeaderNameType;
|
||||
enum
|
||||
{
|
||||
COFF_ImportHeaderNameType_ORDINAL = 0,
|
||||
COFF_ImportHeaderNameType_NAME = 1,
|
||||
COFF_ImportHeaderNameType_NAME_NOPREFIX = 2,
|
||||
COFF_ImportHeaderNameType_UNDECORATE = 3,
|
||||
COFF_ImportHeaderNameType_COUNT = 4
|
||||
COFF_ImportHeaderNameType_ORDINAL = 0,
|
||||
COFF_ImportHeaderNameType_NAME = 1,
|
||||
COFF_ImportHeaderNameType_NAME_NOPREFIX = 2,
|
||||
COFF_ImportHeaderNameType_UNDECORATE = 3,
|
||||
COFF_ImportHeaderNameType_COUNT = 4
|
||||
};
|
||||
|
||||
#define COFF_IMPORT_HEADER_TYPE_MASK 0x03
|
||||
#define COFF_IMPORT_HEADER_TYPE_SHIFT 0
|
||||
#define COFF_IMPORT_HEADER_TYPE_MASK 0x03
|
||||
#define COFF_IMPORT_HEADER_TYPE_SHIFT 0
|
||||
#define COFF_IMPORT_HEADER_NAME_TYPE_MASK 0x1c
|
||||
#define COFF_IMPORT_HEADER_NAME_TYPE_SHIFT 2
|
||||
#define COFF_IMPORT_HEADER_GET_TYPE(x) (((x) & COFF_IMPORT_HEADER_TYPE_MASK) >> COFF_IMPORT_HEADER_TYPE_SHIFT)
|
||||
#define COFF_IMPORT_HEADER_GET_NAME_TYPE(x) (((x) & COFF_IMPORT_HEADER_NAME_TYPE_MASK) >> COFF_IMPORT_HEADER_NAME_TYPE_SHIFT)
|
||||
typedef struct COFF_ImportHeader
|
||||
{
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
U16 machine;
|
||||
U16 sig1;
|
||||
U16 sig2;
|
||||
U16 version;
|
||||
U16 machine;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U32 data_size;
|
||||
U16 hint;
|
||||
U16 type;
|
||||
U16 name_type;
|
||||
U32 data_size;
|
||||
U16 hint;
|
||||
U16 type;
|
||||
U16 name_type;
|
||||
// type : 2
|
||||
// name type : 3
|
||||
// reserved : 11
|
||||
@@ -390,30 +377,18 @@ typedef struct COFF_ImportHeader
|
||||
typedef U8 COFF_ComdatSelectType;
|
||||
enum
|
||||
{
|
||||
COFF_ComdatSelectType_NULL = 0,
|
||||
// Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_NODUPLICATES = 1,
|
||||
// Select any symbol, even if there are multiple definitions. (we default to first declaration)
|
||||
COFF_ComdatSelectType_ANY = 2,
|
||||
// Sections that symbols reference must match in size, otherwise multiply definition error is thrown.
|
||||
COFF_ComdatSelectType_SAME_SIZE = 3,
|
||||
// Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_EXACT_MATCH = 4,
|
||||
// Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
|
||||
COFF_ComdatSelectType_ASSOCIATIVE = 5,
|
||||
// Linker selects section with largest size.
|
||||
COFF_ComdatSelectType_LARGEST = 6,
|
||||
COFF_ComdatSelectType_COUNT = 7
|
||||
COFF_ComdatSelectType_NULL = 0, // Only one symbol is allowed to be in global symbol table, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_NODUPLICATES = 1, // Select any symbol, even if there are multiple definitions. (we default to first declaration)
|
||||
COFF_ComdatSelectType_ANY = 2, // Sections that symbols reference must match in size, otherwise multiply definition error is thrown.
|
||||
COFF_ComdatSelectType_SAME_SIZE = 3, // Sections that symbols reference must have identical checksums, otherwise multiply defintion error is thrown.
|
||||
COFF_ComdatSelectType_EXACT_MATCH = 4, // Symbols with associative type form a chain of sections are related to each other. (next link is indicated in COFF_SecDef in 'number')
|
||||
COFF_ComdatSelectType_ASSOCIATIVE = 5, // Linker selects section with largest size.
|
||||
COFF_ComdatSelectType_LARGEST = 6,
|
||||
COFF_ComdatSelectType_COUNT = 7
|
||||
};
|
||||
|
||||
#define COFF_MIN_BIG_OBJ_VERSION 2
|
||||
|
||||
global U8 coff_big_obj_magic[] =
|
||||
{
|
||||
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
|
||||
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
|
||||
};
|
||||
|
||||
typedef struct COFF_HeaderBigObj COFF_HeaderBigObj;
|
||||
struct COFF_HeaderBigObj
|
||||
{
|
||||
@@ -422,7 +397,7 @@ struct COFF_HeaderBigObj
|
||||
U16 version;
|
||||
U16 machine;
|
||||
U32 time_stamp;
|
||||
U8 magic[16];
|
||||
U8 magic[16];
|
||||
U32 unused[4];
|
||||
U32 section_count;
|
||||
U32 pointer_to_symbol_table;
|
||||
@@ -454,8 +429,8 @@ typedef struct COFF_Symbol16 COFF_Symbol16;
|
||||
struct COFF_Symbol16
|
||||
{
|
||||
COFF_SymbolName name;
|
||||
U32 value;
|
||||
U16 section_number;
|
||||
U32 value;
|
||||
U16 section_number;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -473,8 +448,8 @@ typedef struct COFF_Symbol32 COFF_Symbol32;
|
||||
struct COFF_Symbol32
|
||||
{
|
||||
COFF_SymbolName name;
|
||||
U32 value;
|
||||
U32 section_number;
|
||||
U32 value;
|
||||
U32 section_number;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -494,11 +469,11 @@ struct COFF_Symbol32
|
||||
// storage class: FUNCTION
|
||||
typedef struct COFF_SymbolFunc
|
||||
{
|
||||
U8 unused[4];
|
||||
U8 unused[4];
|
||||
U16 ln;
|
||||
U8 unused2[2];
|
||||
U8 unused2[2];
|
||||
U32 ptr_to_next_func;
|
||||
U8 unused3[2];
|
||||
U8 unused3[2];
|
||||
} COFF_SymbolFunc;
|
||||
|
||||
// storage class: WEAK_EXTERNAL
|
||||
@@ -506,7 +481,7 @@ typedef struct COFF_SymbolWeakExt
|
||||
{
|
||||
U32 tag_index;
|
||||
U32 characteristics;
|
||||
U8 unused[10];
|
||||
U8 unused[10];
|
||||
} COFF_SymbolWeakExt;
|
||||
|
||||
typedef struct COFF_SymbolFile
|
||||
@@ -522,9 +497,10 @@ typedef struct COFF_SymbolSecDef
|
||||
U16 number_of_relocations;
|
||||
U16 number_of_ln;
|
||||
U32 check_sum;
|
||||
U16 number; // one-based section index
|
||||
U8 selection;
|
||||
U8 unused[3];
|
||||
U16 number_lo; // one-based section index
|
||||
U8 selection;
|
||||
U8 unused;
|
||||
U16 number_hi;
|
||||
} COFF_SymbolSecDef;
|
||||
|
||||
// specifies how section data should be modified when placed in the image file.
|
||||
@@ -584,7 +560,7 @@ typedef struct COFF_ResourceID_16
|
||||
COFF_ResourceIDType type;
|
||||
union
|
||||
{
|
||||
U16 number;
|
||||
U16 number;
|
||||
String16 string;
|
||||
} u;
|
||||
} COFF_ResourceID_16;
|
||||
@@ -594,20 +570,21 @@ typedef struct COFF_ResourceID
|
||||
COFF_ResourceIDType type;
|
||||
union
|
||||
{
|
||||
U16 number;
|
||||
U16 number;
|
||||
String8 string;
|
||||
} u;
|
||||
} COFF_ResourceID;
|
||||
|
||||
typedef struct COFF_Resource
|
||||
{
|
||||
COFF_ResourceID type;
|
||||
COFF_ResourceID name;
|
||||
U16 language_id;
|
||||
U32 data_version;
|
||||
U32 version;
|
||||
COFF_ResourceID type;
|
||||
COFF_ResourceID name;
|
||||
U32 data_version;
|
||||
COFF_ResourceMemoryFlags memory_flags;
|
||||
String8 data;
|
||||
U16 language_id;
|
||||
U32 version;
|
||||
U32 characteristics;
|
||||
String8 data;
|
||||
} COFF_Resource;
|
||||
|
||||
typedef struct COFF_ResourceDataEntry
|
||||
@@ -620,12 +597,12 @@ typedef struct COFF_ResourceDataEntry
|
||||
|
||||
typedef struct COFF_ResourceDirTable
|
||||
{
|
||||
U32 characteristics;
|
||||
U32 characteristics;
|
||||
COFF_TimeStamp time_stamp;
|
||||
U16 major_version;
|
||||
U16 minor_version;
|
||||
U16 name_entry_count;
|
||||
U16 id_entry_count;
|
||||
U16 major_version;
|
||||
U16 minor_version;
|
||||
U16 name_entry_count;
|
||||
U16 id_entry_count;
|
||||
} COFF_ResourceDirTable;
|
||||
|
||||
#define COFF_RESOURCE_SUB_DIR_FLAG (1u << 31u)
|
||||
@@ -643,24 +620,19 @@ typedef struct COFF_ResourceDirEntry
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
// !<arch>\n
|
||||
#define COFF_ARCHIVE_SIG 0x0A3E686372613C21ULL
|
||||
// !<thin>\n
|
||||
#define COFF_THIN_ARCHIVE_SIG 0xA3E6E6968743C21ULL
|
||||
|
||||
#define COFF_ARCHIVE_ALIGN 2
|
||||
#define COFF_ARCHIVE_MAX_SHORT_NAME_SIZE 15
|
||||
|
||||
#define COFF_ARCHIVE_ALIGN 2
|
||||
#define COFF_ARCHIVE_MEMBER_HEADER_SIZE 60
|
||||
|
||||
typedef struct COFF_ArchiveMemberHeader
|
||||
{
|
||||
String8 name; // padded to 16 bytes with spaces
|
||||
U32 date; // unix time
|
||||
U32 user_id; // unix artifact that does not have meaning on windows
|
||||
U32 group_id; // unix artifact that does not have meaning on windows
|
||||
String8 mode; // octal representation the members file mode
|
||||
U32 size; // size of the member data, not including header
|
||||
B32 is_end_correct; // set to true if found correct signature after header
|
||||
String8 name; // padded to 16 bytes with spaces
|
||||
U32 date; // unix time
|
||||
U32 user_id; // unix artifact that does not have meaning on windows
|
||||
U32 group_id; // unix artifact that does not have meaning on windows
|
||||
String8 mode; // octal representation the members file mode
|
||||
U32 size; // size of the member data, not including header
|
||||
B32 is_end_correct; // set to true if found correct signature after header
|
||||
} COFF_ArchiveMemberHeader;
|
||||
|
||||
////////////////////////////////
|
||||
@@ -678,71 +650,61 @@ typedef U32 COFF_DataType;
|
||||
typedef struct COFF_HeaderInfo
|
||||
{
|
||||
COFF_MachineType machine;
|
||||
U64 section_array_off;
|
||||
U64 section_count_no_null;
|
||||
U64 string_table_off;
|
||||
U64 symbol_size;
|
||||
U64 symbol_off;
|
||||
U64 symbol_count;
|
||||
COFF_DataType type;
|
||||
U64 section_array_off;
|
||||
U64 section_count_no_null;
|
||||
U64 string_table_off;
|
||||
U64 symbol_size;
|
||||
U64 symbol_off;
|
||||
U64 symbol_count;
|
||||
} COFF_HeaderInfo;
|
||||
|
||||
enum
|
||||
{
|
||||
// symbol has section and offset.
|
||||
COFF_SymbolValueInterp_REGULAR,
|
||||
|
||||
// symbol is overridable
|
||||
COFF_SymbolValueInterp_WEAK,
|
||||
|
||||
// symbol doesn't have a reference section.
|
||||
COFF_SymbolValueInterp_UNDEFINED,
|
||||
|
||||
// symbol has no section but still has size.
|
||||
COFF_SymbolValueInterp_COMMON,
|
||||
|
||||
// symbol has an absolute (non-relocatable) value and is not an address.
|
||||
COFF_SymbolValueInterp_ABS,
|
||||
|
||||
// symbol is used to provide general type of debugging information.
|
||||
COFF_SymbolValueInterp_DEBUG
|
||||
COFF_SymbolValueInterp_REGULAR, // symbol has section and offset.
|
||||
COFF_SymbolValueInterp_WEAK, // symbol is overridable
|
||||
COFF_SymbolValueInterp_UNDEFINED, // symbol doesn't have a reference section.
|
||||
COFF_SymbolValueInterp_COMMON, // symbol has no section but still has size.
|
||||
COFF_SymbolValueInterp_ABS, // symbol has an absolute (non-relocatable) value and is not an address.
|
||||
COFF_SymbolValueInterp_DEBUG // symbol is used to provide general type of debugging information.
|
||||
};
|
||||
typedef U32 COFF_SymbolValueInterpType;
|
||||
|
||||
typedef struct COFF_Symbol16Node
|
||||
{
|
||||
struct COFF_Symbol16Node *next;
|
||||
COFF_Symbol16 data;
|
||||
COFF_Symbol16 data;
|
||||
} COFF_Symbol16Node;
|
||||
|
||||
typedef struct COFF_Symbol16List
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Symbol16Node *first;
|
||||
COFF_Symbol16Node *last;
|
||||
} COFF_Symbol16List;
|
||||
|
||||
typedef struct COFF_Symbol32Array
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Symbol32 *v;
|
||||
} COFF_Symbol32Array;
|
||||
|
||||
typedef struct COFF_RelocNode
|
||||
{
|
||||
struct COFF_RelocNode *next;
|
||||
COFF_Reloc data;
|
||||
COFF_Reloc data;
|
||||
} COFF_RelocNode;
|
||||
|
||||
typedef struct COFF_RelocList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_RelocNode *first;
|
||||
COFF_RelocNode *last;
|
||||
} COFF_RelocList;
|
||||
|
||||
typedef struct COFF_RelocArray
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_Reloc *v;
|
||||
} COFF_RelocArray;
|
||||
|
||||
@@ -755,12 +717,12 @@ typedef struct COFF_RelocInfo
|
||||
typedef struct COFF_ResourceNode
|
||||
{
|
||||
struct COFF_ResourceNode *next;
|
||||
COFF_Resource data;
|
||||
COFF_Resource data;
|
||||
} COFF_ResourceNode;
|
||||
|
||||
typedef struct COFF_ResourceList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_ResourceNode *first;
|
||||
COFF_ResourceNode *last;
|
||||
} COFF_ResourceList;
|
||||
@@ -770,21 +732,21 @@ typedef struct COFF_ResourceList
|
||||
typedef struct COFF_ArchiveMember
|
||||
{
|
||||
COFF_ArchiveMemberHeader header;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
} COFF_ArchiveMember;
|
||||
|
||||
typedef struct COFF_ArchiveFirstMember
|
||||
{
|
||||
U32 symbol_count;
|
||||
U32 symbol_count;
|
||||
String8 member_offsets;
|
||||
String8 string_table;
|
||||
} COFF_ArchiveFirstMember;
|
||||
|
||||
typedef struct COFF_ArchiveSecondMember
|
||||
{
|
||||
U32 member_count;
|
||||
U32 symbol_count;
|
||||
U32 member_count;
|
||||
U32 symbol_count;
|
||||
String8 member_offsets;
|
||||
String8 symbol_indices;
|
||||
String8 string_table;
|
||||
@@ -793,12 +755,12 @@ typedef struct COFF_ArchiveSecondMember
|
||||
typedef struct COFF_ArchiveMemberNode
|
||||
{
|
||||
struct COFF_ArchiveMemberNode *next;
|
||||
COFF_ArchiveMember data;
|
||||
COFF_ArchiveMember data;
|
||||
} COFF_ArchiveMemberNode;
|
||||
|
||||
typedef struct COFF_ArchiveMemberList
|
||||
{
|
||||
U64 count;
|
||||
U64 count;
|
||||
COFF_ArchiveMemberNode *first;
|
||||
COFF_ArchiveMemberNode *last;
|
||||
} COFF_ArchiveMemberList;
|
||||
@@ -812,14 +774,37 @@ typedef enum
|
||||
|
||||
typedef struct COFF_ArchiveParse
|
||||
{
|
||||
COFF_ArchiveFirstMember first_member;
|
||||
COFF_ArchiveFirstMember first_member;
|
||||
COFF_ArchiveSecondMember second_member;
|
||||
String8 long_names;
|
||||
String8 long_names;
|
||||
} COFF_ArchiveParse;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct COFF_SectionHeaderArray
|
||||
{
|
||||
U64 count;
|
||||
COFF_SectionHeader *v;
|
||||
} COFF_SectionHeaderArray;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global U8 coff_big_obj_magic[] =
|
||||
{
|
||||
0xC7,0xA1,0xBA,0xD1,0xEE,0xBA,0xA9,0x4B,
|
||||
0xAF,0x20,0xFA,0xF6,0x6A,0xA4,0xDC,0xB8,
|
||||
};
|
||||
|
||||
read_only global U8 g_coff_archive_sig[8] = "!<arch>\n";
|
||||
read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
|
||||
|
||||
read_only global U8 g_coff_res_magic[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
read_only global COFF_SectionHeader coff_section_header_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -829,6 +814,7 @@ internal B32 coff_is_big_obj(String8 data);
|
||||
internal B32 coff_is_obj(String8 data);
|
||||
internal COFF_HeaderInfo coff_header_info_from_data(String8 data);
|
||||
internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags);
|
||||
internal COFF_SectionFlags coff_section_flag_from_align_size(U64 align);
|
||||
internal COFF_SymbolValueInterpType coff_interp_symbol(COFF_Symbol32 *symbol);
|
||||
|
||||
internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff);
|
||||
@@ -844,18 +830,47 @@ internal COFF_Symbol32Array coff_symbol_array_from_data(Arena *arena, String8 d
|
||||
internal COFF_Symbol16Node * coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
|
||||
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
|
||||
|
||||
internal U64 coff_word_size_from_machine(COFF_MachineType machine);
|
||||
internal U64 coff_word_size_from_machine(COFF_MachineType machine);
|
||||
internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine);
|
||||
internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine);
|
||||
|
||||
internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name);
|
||||
internal U32 coff_make_ordinal_32(U16 hint);
|
||||
internal U64 coff_make_ordinal_64(U16 hint);
|
||||
|
||||
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
||||
internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id);
|
||||
internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16);
|
||||
internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
||||
internal String8 coff_make_import_header_by_name(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
String8 name,
|
||||
U16 hint,
|
||||
COFF_ImportHeaderType type);
|
||||
internal String8 coff_make_import_header_by_ordinal(Arena *arena,
|
||||
String8 dll_name,
|
||||
COFF_MachineType machine,
|
||||
COFF_TimeStamp time_stamp,
|
||||
U16 ordinal,
|
||||
COFF_ImportHeaderType type);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Resources
|
||||
|
||||
internal String8 coff_resource_string_from_str16(Arena *arena, String16 string);
|
||||
internal String8 coff_resource_string_from_str8(Arena *arena, String8 string);
|
||||
internal String8 coff_resource_number_from_u16(Arena *arena, U16 number);
|
||||
|
||||
internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b);
|
||||
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16);
|
||||
|
||||
internal U64 coff_read_resource_id_utf16(String8 res, U64 off, COFF_ResourceID_16 *id_out);
|
||||
internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out);
|
||||
internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data);
|
||||
|
||||
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
|
||||
internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal COFF_DataType coff_data_type_from_data(String8 data);
|
||||
internal B32 coff_is_import(String8 data);
|
||||
internal B32 coff_is_archive(String8 data);
|
||||
@@ -875,8 +890,15 @@ internal COFF_ArchiveParse coff_thin_archive_from_data(Arena *arena, String8 da
|
||||
internal COFF_ArchiveType coff_archive_type_from_data(String8 data);
|
||||
internal COFF_ArchiveParse coff_archive_parse_from_data(Arena *arena, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
// String <-> Enum
|
||||
|
||||
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select);
|
||||
internal String8 coff_string_from_machine_type(COFF_MachineType machine);
|
||||
internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags);
|
||||
internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type);
|
||||
|
||||
internal COFF_MachineType coff_machine_from_string(String8 string);
|
||||
internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name);
|
||||
|
||||
#endif //COFF_H
|
||||
|
||||
+589
-284
File diff suppressed because it is too large
Load Diff
+54
-10
@@ -15,6 +15,20 @@ typedef U64 CTRL_MachineID;
|
||||
////////////////////////////////
|
||||
//~ rjf: Meta Evaluation Types
|
||||
|
||||
//- rjf: auto-checkbox b32s
|
||||
|
||||
typedef struct CTRL_CheckB32 CTRL_CheckB32;
|
||||
struct CTRL_CheckB32
|
||||
{
|
||||
B32 b32;
|
||||
};
|
||||
|
||||
struct_members(CTRL_CheckB32)
|
||||
{
|
||||
member_lit_comp(CTRL_CheckB32, type(B32), b32),
|
||||
};
|
||||
struct_type(CTRL_CheckB32);
|
||||
|
||||
//- rjf: styled string types
|
||||
|
||||
ptr_type(CTRL_PlainString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPlainText,.count_delimiter_name = str8_lit_comp("size"));
|
||||
@@ -74,18 +88,22 @@ typedef struct CTRL_MetaEval CTRL_MetaEval;
|
||||
struct CTRL_MetaEval
|
||||
{
|
||||
#define CTRL_MetaEval_MemberXList \
|
||||
X(B32, enabled, "Enabled")\
|
||||
X(B32, frozen, "Frozen")\
|
||||
X(U64, hit_count, "Hit Count")\
|
||||
X(U64, id, "ID")\
|
||||
X(Rng1U64, vaddr_range, "Address Range")\
|
||||
X(U32, color, "Color")\
|
||||
X(B32, enabled, "Enabled")\
|
||||
X(B32, frozen, "Frozen")\
|
||||
X(U64, hit_count, "Hit Count")\
|
||||
X(U64, id, "ID")\
|
||||
X(Rng1U64, vaddr_range, "Address Range")\
|
||||
X(U32, color, "Color")\
|
||||
X(CTRL_CheckB32, debug_subprocesses,"Debug Subprocesses")\
|
||||
Y(String8, type(CTRL_CodeString8), label, "Label")\
|
||||
Y(String8, type(CTRL_PathString8), exe, "Executable Path")\
|
||||
Y(String8, type(CTRL_PathString8), dbg, "Debug Info Path")\
|
||||
Y(String8, type(CTRL_PlainString8), args, "Arguments")\
|
||||
Y(String8, type(CTRL_PathString8), working_directory, "Working Directory")\
|
||||
Y(String8, type(CTRL_CodeString8), entry_point, "Custom Entry Point")\
|
||||
Y(String8, type(CTRL_PathString8), stdout_path, "Standard Output Path")\
|
||||
Y(String8, type(CTRL_PathString8), stderr_path, "Standard Error Path")\
|
||||
Y(String8, type(CTRL_PathString8), stdin_path, "Standard Input Path")\
|
||||
Y(String8, type(CTRL_PathString8), source_location, "Source Location")\
|
||||
Y(String8, type(CTRL_CodeString8), function_location, "Function Location")\
|
||||
Y(String8, type(CTRL_CodeString8), address_location, "Address Location")\
|
||||
@@ -132,6 +150,10 @@ struct_members(CTRL_TargetMetaEval)
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PlainString8),args, .pretty_name = str8_lit_comp("Arguments")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), working_directory, .pretty_name = str8_lit_comp("Working Directory")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), entry_point, .pretty_name = str8_lit_comp("Custom Entry Point")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdout_path, .pretty_name = str8_lit_comp("Standard Output Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stderr_path, .pretty_name = str8_lit_comp("Standard Error Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), stdin_path, .pretty_name = str8_lit_comp("Standard Input Path")),
|
||||
member_lit_comp(CTRL_MetaEval, type(CTRL_CheckB32), debug_subprocesses, .pretty_name = str8_lit_comp("Debug Subprocesses")),
|
||||
};
|
||||
|
||||
struct_members(CTRL_PinMetaEval)
|
||||
@@ -511,6 +533,7 @@ typedef enum CTRL_MsgKind
|
||||
CTRL_MsgKind_Launch,
|
||||
CTRL_MsgKind_Attach,
|
||||
CTRL_MsgKind_Kill,
|
||||
CTRL_MsgKind_KillAll,
|
||||
CTRL_MsgKind_Detach,
|
||||
CTRL_MsgKind_Run,
|
||||
CTRL_MsgKind_SingleStep,
|
||||
@@ -539,11 +562,15 @@ struct CTRL_Msg
|
||||
U32 entity_id;
|
||||
U32 exit_code;
|
||||
B32 env_inherit;
|
||||
B32 debug_subprocesses;
|
||||
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
|
||||
String8 path;
|
||||
String8List entry_points;
|
||||
String8List cmd_line_string_list;
|
||||
String8List env_string_list;
|
||||
String8 stdout_path;
|
||||
String8 stderr_path;
|
||||
String8 stdin_path;
|
||||
CTRL_TrapList traps;
|
||||
CTRL_UserBreakpointList user_bps;
|
||||
CTRL_MetaEvalArray meta_evals;
|
||||
@@ -813,6 +840,23 @@ struct CTRL_ModuleImageInfoCache
|
||||
CTRL_ModuleImageInfoCacheStripe *stripes;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Touched Debug Info Directory Cache
|
||||
|
||||
typedef struct CTRL_DbgDirNode CTRL_DbgDirNode;
|
||||
struct CTRL_DbgDirNode
|
||||
{
|
||||
CTRL_DbgDirNode *first;
|
||||
CTRL_DbgDirNode *last;
|
||||
CTRL_DbgDirNode *next;
|
||||
CTRL_DbgDirNode *prev;
|
||||
CTRL_DbgDirNode *parent;
|
||||
String8 name;
|
||||
U64 search_count;
|
||||
U64 child_count;
|
||||
U64 module_direct_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Wakeup Hook Function Types
|
||||
|
||||
@@ -869,6 +913,8 @@ struct CTRL_State
|
||||
CTRL_MetaEvalArray user_meta_evals;
|
||||
U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64];
|
||||
U64 process_counter;
|
||||
Arena *dbg_dir_arena;
|
||||
CTRL_DbgDirNode *dbg_dir_root;
|
||||
|
||||
// rjf: user -> memstream ring buffer
|
||||
U64 u2ms_ring_size;
|
||||
@@ -877,10 +923,6 @@ struct CTRL_State
|
||||
U64 u2ms_ring_read_pos;
|
||||
OS_Handle u2ms_ring_mutex;
|
||||
OS_Handle u2ms_ring_cv;
|
||||
|
||||
// rjf: memory stream threads
|
||||
U64 ms_thread_count;
|
||||
OS_Handle *ms_threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1132,6 +1174,7 @@ internal void ctrl_thread__end_and_flush_info_log(void);
|
||||
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
@@ -1144,6 +1187,7 @@ internal B32 ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
|
||||
|
||||
//- rjf: entry point
|
||||
ASYNC_WORK_DEF(ctrl_mem_stream_work);
|
||||
internal void ctrl_mem_stream_thread__entry_point(void *p);
|
||||
|
||||
#endif // CTRL_CORE_H
|
||||
|
||||
+281
-300
@@ -41,7 +41,14 @@ dasm_inst_from_code(Arena *arena, Arch arch, U64 vaddr, String8 code, DASM_Synta
|
||||
ZydisDecodedOperand *first_visible_op = (zinst.info.operand_count_visible > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *first_op = (zinst.info.operand_count > 0 ? &zinst.operands[0] : 0);
|
||||
ZydisDecodedOperand *second_op = (zinst.info.operand_count > 1 ? &zinst.operands[1] : 0);
|
||||
if(first_visible_op != 0)
|
||||
if(first_visible_op != 0 &&
|
||||
(first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM8 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM32_32_64 ||
|
||||
first_visible_op->encoding == ZYDIS_OPERAND_ENCODING_JIMM16_32_32))
|
||||
{
|
||||
ZydisCalcAbsoluteAddress(&zinst.info, first_visible_op, vaddr, &jump_dest_vaddr);
|
||||
}
|
||||
@@ -267,31 +274,9 @@ dasm_init(void)
|
||||
dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size);
|
||||
dasm_shared->u2p_ring_cv = os_condition_variable_alloc();
|
||||
dasm_shared->u2p_ring_mutex = os_mutex_alloc();
|
||||
dasm_shared->parse_thread_count = 1;
|
||||
dasm_shared->parse_threads = push_array(arena, OS_Handle, dasm_shared->parse_thread_count);
|
||||
for(U64 idx = 0; idx < dasm_shared->parse_thread_count; idx += 1)
|
||||
{
|
||||
dasm_shared->parse_threads[idx] = os_thread_launch(dasm_parse_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
dasm_shared->evictor_detector_thread = os_thread_launch(dasm_evictor_detector_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void
|
||||
dasm_user_clock_tick(void)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&dasm_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
dasm_user_clock_idx(void)
|
||||
{
|
||||
U64 idx = ins_atomic_u64_eval(&dasm_shared->user_clock_idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -341,7 +326,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node)
|
||||
DASM_Touch *touch = push_array(dasm_tctx->arena, DASM_Touch, 1);
|
||||
ins_atomic_u64_inc_eval(&node->scope_ref_count);
|
||||
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
|
||||
touch->hash = node->hash;
|
||||
MemoryCopyStruct(&touch->params, &node->params);
|
||||
touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key);
|
||||
@@ -423,6 +408,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
if(node_is_new)
|
||||
{
|
||||
dasm_u2p_enqueue_req(hash, params, max_U64);
|
||||
async_push_work(dasm_parse_work);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
@@ -471,8 +457,6 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_write_pos += 7;
|
||||
dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
@@ -506,8 +490,6 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp);
|
||||
dasm_shared->u2p_ring_read_pos += 7;
|
||||
dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64);
|
||||
@@ -515,284 +497,282 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
os_condition_variable_broadcast(dasm_shared->u2p_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_parse_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(dasm_parse_work)
|
||||
{
|
||||
ThreadNameF("[dasm] parse thread #%I64u", (U64)p);
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &di_rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Arch_x64:
|
||||
case Arch_x86:
|
||||
{
|
||||
// rjf: disassemble
|
||||
RDI_SourceFile *last_file = &rdi_nil_element_union.source_file;
|
||||
RDI_Line *last_line = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax);
|
||||
if(inst.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: push strings derived from voff -> line info
|
||||
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
|
||||
{
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
{
|
||||
U64 voff = (params.vaddr+off) - params.base_vaddr;
|
||||
U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff);
|
||||
if(line_info_idx < unit_line_info.count)
|
||||
{
|
||||
RDI_Line *line = &unit_line_info.lines[line_info_idx];
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
String8 file_normalized_full_path = {0};
|
||||
file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size);
|
||||
if(file != last_file)
|
||||
{
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames &&
|
||||
file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0)
|
||||
{
|
||||
String8 inst_string = str8_lit(">");
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
last_file = file;
|
||||
}
|
||||
if(line && line != last_line && file->normal_full_path_string_idx != 0 &&
|
||||
params.style_flags & DASM_StyleFlag_SourceLines &&
|
||||
file_normalized_full_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(file_normalized_full_path);
|
||||
if(props.modified != 0)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
TXT_TextInfo text_info = {0};
|
||||
for(;os_now_microseconds() <= endt_us;)
|
||||
{
|
||||
text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 < line->line_num && line->line_num < text_info.lines_count)
|
||||
{
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1]));
|
||||
if(line_text.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", line_text);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push line
|
||||
String8 addr_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_Addresses)
|
||||
{
|
||||
addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off);
|
||||
}
|
||||
String8 code_bytes_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_CodeBytes)
|
||||
{
|
||||
String8List code_bytes_strings = {0};
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{"));
|
||||
for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1)
|
||||
{
|
||||
if(byte_idx < inst.size)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : "");
|
||||
}
|
||||
else if(byte_idx < 8)
|
||||
{
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
}
|
||||
}
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0);
|
||||
}
|
||||
String8 symbol_part = {0};
|
||||
if(inst.jump_dest_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames)
|
||||
{
|
||||
RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr);
|
||||
if(scope_idx != 0)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
RDI_U32 procedure_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
String8 procedure_name = {0};
|
||||
procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size);
|
||||
if(procedure_name.size != 0)
|
||||
{
|
||||
symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part);
|
||||
DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
|
||||
// rjf: increment
|
||||
off += inst.size;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
StringJoin text_join = {0};
|
||||
text_join.sep = str8_lit("\n");
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
|
||||
//- rjf: produce value bundle
|
||||
info_arena = arena_alloc();
|
||||
info.text_key = text_key;
|
||||
info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
n->info_arena = info_arena;
|
||||
MemoryCopyStruct(&n->info, &info);
|
||||
if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames))
|
||||
{
|
||||
n->change_gen = change_gen;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt_scope_close(txt_scope);
|
||||
di_scope_close(di_scope);
|
||||
hs_scope_close(hs_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &di_rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
//- rjf: x86/x64 decoding
|
||||
case Arch_x64:
|
||||
case Arch_x86:
|
||||
{
|
||||
// rjf: disassemble
|
||||
RDI_SourceFile *last_file = &rdi_nil_element_union.source_file;
|
||||
RDI_Line *last_line = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
// rjf: disassemble one instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, params.arch, params.vaddr+off, str8_skip(data, off), params.syntax);
|
||||
if(inst.size == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: push strings derived from voff -> line info
|
||||
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
|
||||
{
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
{
|
||||
U64 voff = (params.vaddr+off) - params.base_vaddr;
|
||||
U32 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff);
|
||||
if(line_info_idx < unit_line_info.count)
|
||||
{
|
||||
RDI_Line *line = &unit_line_info.lines[line_info_idx];
|
||||
RDI_SourceFile *file = rdi_element_from_name_idx(rdi, SourceFiles, line->file_idx);
|
||||
String8 file_normalized_full_path = {0};
|
||||
file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size);
|
||||
if(file != last_file)
|
||||
{
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames &&
|
||||
file->normal_full_path_string_idx != 0 && file_normalized_full_path.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", file_normalized_full_path);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
if(params.style_flags & DASM_StyleFlag_SourceFilesNames && file->normal_full_path_string_idx == 0)
|
||||
{
|
||||
String8 inst_string = str8_lit(">");
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
last_file = file;
|
||||
}
|
||||
if(line && line != last_line && file->normal_full_path_string_idx != 0 &&
|
||||
params.style_flags & DASM_StyleFlag_SourceLines &&
|
||||
file_normalized_full_path.size != 0)
|
||||
{
|
||||
FileProperties props = os_properties_from_file_path(file_normalized_full_path);
|
||||
if(props.modified != 0)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
TXT_TextInfo text_info = {0};
|
||||
for(;os_now_microseconds() <= endt_us;)
|
||||
{
|
||||
text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(0 < line->line_num && line->line_num < text_info.lines_count)
|
||||
{
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
String8 line_text = str8_skip_chop_whitespace(str8_substr(data, text_info.lines_ranges[line->line_num-1]));
|
||||
if(line_text.size != 0)
|
||||
{
|
||||
String8 inst_string = push_str8f(scratch.arena, "> %S", line_text);
|
||||
DASM_Line inst = {u32_from_u64_saturate(off), DASM_LineFlag_Decorative, 0, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &inst);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_line = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push line
|
||||
String8 addr_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_Addresses)
|
||||
{
|
||||
addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off);
|
||||
}
|
||||
String8 code_bytes_part = {0};
|
||||
if(params.style_flags & DASM_StyleFlag_CodeBytes)
|
||||
{
|
||||
String8List code_bytes_strings = {0};
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{"));
|
||||
for(U64 byte_idx = 0; byte_idx < inst.size || byte_idx < 16; byte_idx += 1)
|
||||
{
|
||||
if(byte_idx < inst.size)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == inst.size-1 ? "}" : "");
|
||||
}
|
||||
else if(byte_idx < 8)
|
||||
{
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
}
|
||||
}
|
||||
str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" "));
|
||||
code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0);
|
||||
}
|
||||
String8 symbol_part = {0};
|
||||
if(inst.jump_dest_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames)
|
||||
{
|
||||
RDI_U32 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, inst.jump_dest_vaddr-params.base_vaddr);
|
||||
if(scope_idx != 0)
|
||||
{
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx);
|
||||
RDI_U32 procedure_idx = scope->proc_idx;
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_idx);
|
||||
String8 procedure_name = {0};
|
||||
procedure_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &procedure_name.size);
|
||||
if(procedure_name.size != 0)
|
||||
{
|
||||
symbol_part = push_str8f(scratch.arena, " (%S)", procedure_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 inst_string = push_str8f(scratch.arena, "%S%S%S%S", addr_part, code_bytes_part, inst.string, symbol_part);
|
||||
DASM_Line line = {u32_from_u64_saturate(off), 0, inst.jump_dest_vaddr, r1u64(inst_strings.total_size + inst_strings.node_count,
|
||||
inst_strings.total_size + inst_strings.node_count + inst_string.size)};
|
||||
dasm_line_chunk_list_push(scratch.arena, &line_list, 1024, &line);
|
||||
str8_list_push(scratch.arena, &inst_strings, inst_string);
|
||||
|
||||
// rjf: increment
|
||||
off += inst.size;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
StringJoin text_join = {0};
|
||||
text_join.sep = str8_lit("\n");
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
|
||||
//- rjf: produce value bundle
|
||||
info_arena = arena_alloc();
|
||||
info.text_key = text_key;
|
||||
info.lines = dasm_line_array_from_chunk_list(info_arena, &line_list);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
n->info_arena = info_arena;
|
||||
MemoryCopyStruct(&n->info, &info);
|
||||
if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames))
|
||||
{
|
||||
n->change_gen = change_gen;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
txt_scope_close(txt_scope);
|
||||
di_scope_close(di_scope);
|
||||
hs_scope_close(hs_scope);
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -806,7 +786,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
{
|
||||
U64 change_gen = fs_change_gen();
|
||||
U64 check_time_us = os_now_microseconds();
|
||||
U64 check_time_user_clocks = dasm_user_clock_idx();
|
||||
U64 check_time_user_clocks = update_tick_idx();
|
||||
U64 evict_threshold_us = 10*1000000;
|
||||
U64 retry_threshold_us = 1*1000000;
|
||||
U64 evict_threshold_user_clocks = 10;
|
||||
@@ -863,6 +843,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
{
|
||||
if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64))
|
||||
{
|
||||
async_push_work(dasm_parse_work);
|
||||
n->last_time_requested_us = os_now_microseconds();
|
||||
n->last_user_clock_idx_requested = check_time_user_clocks;
|
||||
}
|
||||
|
||||
@@ -246,9 +246,6 @@ struct DASM_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
@@ -263,10 +260,6 @@ struct DASM_Shared
|
||||
OS_Handle u2p_ring_cv;
|
||||
OS_Handle u2p_ring_mutex;
|
||||
|
||||
// rjf: parse threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
|
||||
// rjf: evictor/detector thread
|
||||
OS_Handle evictor_detector_thread;
|
||||
};
|
||||
@@ -305,12 +298,6 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
|
||||
|
||||
internal void dasm_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void dasm_user_clock_tick(void);
|
||||
internal U64 dasm_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -329,7 +316,7 @@ internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_P
|
||||
|
||||
internal B32 dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us);
|
||||
internal void dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out);
|
||||
internal void dasm_parse_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(dasm_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor/Detector Thread
|
||||
|
||||
@@ -29,9 +29,9 @@ D_CmdTable: // | | | |
|
||||
{RunToLine 0 1 Null null Nil Null 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" }
|
||||
{RunToAddress 1 1 Vaddr null Nil Null 0 0 0 0 1 1 PlayStepForward "run_to_address" "Run To Address" "Runs until a particular address is hit." "" }
|
||||
{Run 1 1 Null null Nil Null 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" }
|
||||
{Restart 1 1 Null null Nil Null 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then restarts the targets which were used to launch all current processes (if any).""restart,retry" }
|
||||
{StepInto 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" }
|
||||
{StepOver 1 1 Null null Nil Null 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" }
|
||||
{Restart 1 1 Null null Nil Null 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" }
|
||||
{StepInto 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" }
|
||||
{StepOver 1 1 Null null Nil Null 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" }
|
||||
|
||||
//- rjf: debug control context management operations
|
||||
{FreezeThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" }
|
||||
@@ -107,7 +107,6 @@ D_ViewRuleTable:
|
||||
@table(name)
|
||||
D_DevToggleTable:
|
||||
{
|
||||
{telemetry_capture}
|
||||
{simulate_lag}
|
||||
{draw_ui_text_pos}
|
||||
{draw_ui_focus_debug}
|
||||
|
||||
@@ -942,6 +942,100 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
|
||||
internal D_LineListArray
|
||||
d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range)
|
||||
{
|
||||
D_LineListArray array = {0};
|
||||
{
|
||||
array.count = dim_1s64(line_num_range)+1;
|
||||
array.v = push_array(arena, D_LineList, array.count);
|
||||
di_key_list_push(arena, &array.dbgi_keys, &dbgi_key);
|
||||
}
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
|
||||
for(String8Node *override_n = overrides.first;
|
||||
override_n != 0;
|
||||
override_n = override_n->next)
|
||||
{
|
||||
String8 file_path = override_n->string;
|
||||
String8 file_path_normalized = lower_from_str8(scratch.arena, file_path);
|
||||
|
||||
// rjf: binary -> rdi
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
U32 src_id = 0;
|
||||
if(rdi != &di_rdi_parsed_nil) ProfScope("file_path_normalized * rdi -> src_id")
|
||||
{
|
||||
RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths);
|
||||
RDI_ParsedNameMap map = {0};
|
||||
rdi_parsed_from_name_map(rdi, mapptr, &map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size);
|
||||
if(node != 0)
|
||||
{
|
||||
U32 id_count = 0;
|
||||
U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count);
|
||||
if(id_count > 0)
|
||||
{
|
||||
good_src_id = 1;
|
||||
src_id = ids[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: good src-id -> look up line info for visible range
|
||||
if(good_src_id) ProfScope("good src-id -> look up line info for visible range")
|
||||
{
|
||||
RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id);
|
||||
RDI_SourceLineMap *src_line_map = rdi_element_from_name_idx(rdi, SourceLineMaps, src->source_line_map_idx);
|
||||
RDI_ParsedSourceLineMap line_map = {0};
|
||||
rdi_parsed_from_source_line_map(rdi, src_line_map, &line_map);
|
||||
U64 line_idx = 0;
|
||||
for(S64 line_num = line_num_range.min;
|
||||
line_num <= line_num_range.max;
|
||||
line_num += 1, line_idx += 1)
|
||||
{
|
||||
D_LineList *list = &array.v[line_idx];
|
||||
U32 voff_count = 0;
|
||||
U64 *voffs = rdi_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count);
|
||||
if(lines_num_voffs[line_idx] < 8) ProfScope("iterate voffs (%i)", voff_count) for(U64 idx = 0; idx < voff_count; idx += 1)
|
||||
{
|
||||
U64 base_voff = voffs[idx];
|
||||
U64 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, base_voff);
|
||||
RDI_Unit *unit = rdi_element_from_name_idx(rdi, Units, unit_idx);
|
||||
RDI_LineTable *line_table = rdi_element_from_name_idx(rdi, LineTables, unit->line_table_idx);
|
||||
RDI_ParsedLineTable unit_line_info = {0};
|
||||
rdi_parsed_from_line_table(rdi, line_table, &unit_line_info);
|
||||
U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, base_voff);
|
||||
if(unit_line_info.voffs != 0)
|
||||
{
|
||||
Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]);
|
||||
S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num;
|
||||
D_LineNode *n = push_array(arena, D_LineNode, 1);
|
||||
n->v.voff_range = range;
|
||||
n->v.pt.line = (S64)actual_line;
|
||||
n->v.pt.column = 1;
|
||||
n->v.dbgi_key = dbgi_key;
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
lines_num_voffs[line_idx] += 1;
|
||||
if(lines_num_voffs[line_idx] >= 8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
scratch_end(scratch);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal D_LineListArray
|
||||
d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range)
|
||||
{
|
||||
@@ -951,6 +1045,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
array.v = push_array(arena, D_LineList, array.count);
|
||||
}
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
DI_KeyList dbgi_keys = d_push_active_dbgi_key_list(scratch.arena);
|
||||
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
|
||||
@@ -971,7 +1066,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
U32 src_id = 0;
|
||||
if(rdi != &di_rdi_parsed_nil)
|
||||
if(rdi != &di_rdi_parsed_nil) ProfScope("file_path_normalized * rdi -> src_id")
|
||||
{
|
||||
RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_NormalSourcePaths);
|
||||
RDI_ParsedNameMap map = {0};
|
||||
@@ -990,7 +1085,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
}
|
||||
|
||||
// rjf: good src-id -> look up line info for visible range
|
||||
if(good_src_id)
|
||||
if(good_src_id) ProfScope("good src-id -> look up line info for visible range")
|
||||
{
|
||||
RDI_SourceFile *src = rdi_element_from_name_idx(rdi, SourceFiles, src_id);
|
||||
RDI_SourceLineMap *src_line_map = rdi_element_from_name_idx(rdi, SourceLineMaps, src->source_line_map_idx);
|
||||
@@ -1004,7 +1099,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
D_LineList *list = &array.v[line_idx];
|
||||
U32 voff_count = 0;
|
||||
U64 *voffs = rdi_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count);
|
||||
for(U64 idx = 0; idx < voff_count; idx += 1)
|
||||
if(lines_num_voffs[line_idx] < 8) ProfScope("iterate voffs (%i)", voff_count) for(U64 idx = 0; idx < voff_count; idx += 1)
|
||||
{
|
||||
U64 base_voff = voffs[idx];
|
||||
U64 unit_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_UnitVMap, base_voff);
|
||||
@@ -1024,6 +1119,11 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
n->v.dbgi_key = key;
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
lines_num_voffs[line_idx] += 1;
|
||||
if(lines_num_voffs[line_idx] >= 8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1041,6 +1141,18 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
return array;
|
||||
}
|
||||
|
||||
internal D_LineList
|
||||
d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num)
|
||||
{
|
||||
D_LineListArray array = d_lines_array_from_dbgi_key_file_path_line_range(arena, dbgi_key, file_path, r1s64(line_num, line_num+1));
|
||||
D_LineList list = {0};
|
||||
if(array.count != 0)
|
||||
{
|
||||
list = array.v[0];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal D_LineList
|
||||
d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num)
|
||||
{
|
||||
@@ -1968,21 +2080,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: start/stop telemetry captures
|
||||
//
|
||||
ProfScope("start/stop telemetry captures")
|
||||
{
|
||||
if(!ProfIsCapturing() && DEV_telemetry_capture)
|
||||
{
|
||||
ProfBeginCapture("raddbg");
|
||||
}
|
||||
if(ProfIsCapturing() && !DEV_telemetry_capture)
|
||||
{
|
||||
ProfEndCapture();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: process top-level commands
|
||||
//
|
||||
@@ -2031,6 +2128,9 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
String8 args = str8_skip_chop_whitespace(target->args);
|
||||
String8 working_directory = str8_skip_chop_whitespace(target->working_directory);
|
||||
String8 custom_entry_point_name = str8_skip_chop_whitespace(target->custom_entry_point_name);
|
||||
String8 stdout_path = str8_skip_chop_whitespace(target->stdout_path);
|
||||
String8 stderr_path = str8_skip_chop_whitespace(target->stderr_path);
|
||||
String8 stdin_path = str8_skip_chop_whitespace(target->stdin_path);
|
||||
String8List env = target->env;
|
||||
if(working_directory.size == 0)
|
||||
{
|
||||
@@ -2071,6 +2171,10 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
msg->kind = CTRL_MsgKind_Launch;
|
||||
msg->path = working_directory;
|
||||
msg->cmd_line_string_list = cmdln_strings;
|
||||
msg->stdout_path = stdout_path;
|
||||
msg->stderr_path = stderr_path;
|
||||
msg->stdin_path = stdin_path;
|
||||
msg->debug_subprocesses = target->debug_subprocesses;
|
||||
msg->env_inherit = 1;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
@@ -2089,7 +2193,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
// rjf: no targets -> error
|
||||
if(targets_to_launch->count == 0)
|
||||
{
|
||||
log_user_error(str8_lit("No active targets exist; cannot launch. You must select target first."));
|
||||
log_user_error(str8_lit("No active targets exist; cannot launch. You must select a target first."));
|
||||
}
|
||||
}break;
|
||||
case D_CmdKind_Kill:
|
||||
@@ -2111,16 +2215,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_KillAll:
|
||||
{
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
for(CTRL_EntityNode *n = processes.first; n != 0; n = n->next)
|
||||
{
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_Kill;
|
||||
msg->exit_code = 1;
|
||||
msg->entity = n->v->handle;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_KillAll;
|
||||
msg->exit_code = 1;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}break;
|
||||
case D_CmdKind_Detach:
|
||||
{
|
||||
@@ -2308,8 +2407,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_Restart:
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
if(processes.count != 0)
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
}
|
||||
}break;
|
||||
case D_CmdKind_StepInto:
|
||||
case D_CmdKind_StepOver:
|
||||
@@ -2375,6 +2478,14 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
msg->entity = e->handle;
|
||||
}
|
||||
}
|
||||
if(d_ctrl_targets_running())
|
||||
{
|
||||
need_run = 1;
|
||||
run_kind = d_state->ctrl_last_run_kind;
|
||||
run_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, d_state->ctrl_last_run_thread_handle);
|
||||
run_flags = d_state->ctrl_last_run_flags;
|
||||
run_traps = d_state->ctrl_last_run_traps;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: entity decoration
|
||||
|
||||
@@ -14,6 +14,10 @@ struct D_Target
|
||||
String8 args;
|
||||
String8 working_directory;
|
||||
String8 custom_entry_point_name;
|
||||
String8 stdout_path;
|
||||
String8 stderr_path;
|
||||
String8 stdin_path;
|
||||
B32 debug_subprocesses;
|
||||
String8List env;
|
||||
};
|
||||
|
||||
@@ -440,7 +444,10 @@ internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U
|
||||
|
||||
//- rjf: file:line -> line info
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
// TODO(rjf): need to clean this up & dedup
|
||||
internal D_LineListArray d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineListArray d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 line_num_range);
|
||||
internal D_LineList d_lines_from_dbgi_key_file_path_line_num(Arena *arena, DI_Key dbgi_key, String8 file_path, S64 line_num);
|
||||
internal D_LineList d_lines_from_file_path_line_num(Arena *arena, String8 file_path, S64 line_num);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -71,7 +71,6 @@ D_ViewRuleKind_Geo3D,
|
||||
D_ViewRuleKind_COUNT,
|
||||
} D_ViewRuleKind;
|
||||
|
||||
global B32 DEV_telemetry_capture = 0;
|
||||
global B32 DEV_simulate_lag = 0;
|
||||
global B32 DEV_draw_ui_text_pos = 0;
|
||||
global B32 DEV_draw_ui_focus_debug = 0;
|
||||
@@ -83,7 +82,6 @@ global B32 DEV_scratch_mouse_draw = 0;
|
||||
global B32 DEV_updating_indicator = 0;
|
||||
struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =
|
||||
{
|
||||
{&DEV_telemetry_capture, str8_lit_comp("telemetry_capture")},
|
||||
{&DEV_simulate_lag, str8_lit_comp("simulate_lag")},
|
||||
{&DEV_draw_ui_text_pos, str8_lit_comp("draw_ui_text_pos")},
|
||||
{&DEV_draw_ui_focus_debug, str8_lit_comp("draw_ui_focus_debug")},
|
||||
|
||||
+1199
-290
File diff suppressed because it is too large
Load Diff
+226
-9
@@ -72,7 +72,7 @@ struct DI_EventList
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
@@ -92,7 +92,6 @@ struct DI_Node
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
U64 last_time_requested_us;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
@@ -126,6 +125,91 @@ struct DI_Stripe
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Cache Types
|
||||
|
||||
typedef struct DI_SearchItem DI_SearchItem;
|
||||
struct DI_SearchItem
|
||||
{
|
||||
U64 idx;
|
||||
U64 dbgi_idx;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunk DI_SearchItemChunk;
|
||||
struct DI_SearchItemChunk
|
||||
{
|
||||
DI_SearchItemChunk *next;
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunkList DI_SearchItemChunkList;
|
||||
struct DI_SearchItemChunkList
|
||||
{
|
||||
DI_SearchItemChunk *first;
|
||||
DI_SearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemArray DI_SearchItemArray;
|
||||
struct DI_SearchItemArray
|
||||
{
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchParams DI_SearchParams;
|
||||
struct DI_SearchParams
|
||||
{
|
||||
RDI_SectionKind target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchBucket DI_SearchBucket;
|
||||
struct DI_SearchBucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
U64 params_hash;
|
||||
DI_SearchParams params;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchNode DI_SearchNode;
|
||||
struct DI_SearchNode
|
||||
{
|
||||
DI_SearchNode *next;
|
||||
DI_SearchNode *prev;
|
||||
U128 key;
|
||||
U64 scope_refcount;
|
||||
U64 work_refcount;
|
||||
U64 last_update_tick_idx;
|
||||
U64 bucket_read_gen;
|
||||
U64 bucket_write_gen;
|
||||
U64 bucket_items_gen;
|
||||
DI_SearchBucket buckets[6];
|
||||
DI_SearchItemArray items;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchSlot DI_SearchSlot;
|
||||
struct DI_SearchSlot
|
||||
{
|
||||
DI_SearchNode *first;
|
||||
DI_SearchNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchStripe DI_SearchStripe;
|
||||
struct DI_SearchStripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_SearchNode *free_node;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
@@ -134,6 +218,7 @@ struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
DI_SearchNode *search_node;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
@@ -152,6 +237,98 @@ struct DI_TCTX
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Thread State Types
|
||||
|
||||
typedef struct DI_SearchThread DI_SearchThread;
|
||||
struct DI_SearchThread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle ring_mutex;
|
||||
OS_Handle ring_cv;
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Cache State Types
|
||||
|
||||
typedef struct DI_Match DI_Match;
|
||||
struct DI_Match
|
||||
{
|
||||
DI_Match *next;
|
||||
DI_Match *prev;
|
||||
U64 dbgi_idx;
|
||||
RDI_SectionKind section;
|
||||
U32 idx;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameNode DI_MatchNameNode;
|
||||
struct DI_MatchNameNode
|
||||
{
|
||||
// rjf: synchronously written by usage code
|
||||
DI_MatchNameNode *next;
|
||||
DI_MatchNameNode *prev;
|
||||
DI_MatchNameNode *lru_next;
|
||||
DI_MatchNameNode *lru_prev;
|
||||
U64 alloc_gen;
|
||||
U64 first_gen_touched;
|
||||
U64 last_gen_touched;
|
||||
U64 req_params_hash;
|
||||
U64 req_count;
|
||||
String8 name;
|
||||
U64 hash;
|
||||
|
||||
// rjf: atomically written by match work
|
||||
U64 cmp_count;
|
||||
U64 cmp_params_hash;
|
||||
RDI_SectionKind section_kind;
|
||||
// DI_Match *first_match;
|
||||
// DI_Match *last_match;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameSlot DI_MatchNameSlot;
|
||||
struct DI_MatchNameSlot
|
||||
{
|
||||
DI_MatchNameNode *first;
|
||||
DI_MatchNameNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchStore DI_MatchStore;
|
||||
struct DI_MatchStore
|
||||
{
|
||||
Arena *arena;
|
||||
U64 gen;
|
||||
Arena *gen_arenas[2];
|
||||
|
||||
// rjf: parameters
|
||||
Arena *params_arena;
|
||||
OS_Handle params_rw_mutex;
|
||||
U64 params_hash;
|
||||
DI_KeyArray params_keys;
|
||||
|
||||
// rjf: match cache
|
||||
U64 match_name_slots_count;
|
||||
DI_MatchNameSlot *match_name_slots;
|
||||
DI_MatchNameNode *first_free_match_name;
|
||||
DI_Match *first_free_match;
|
||||
DI_MatchNameNode *first_lru_match_name;
|
||||
DI_MatchNameNode *last_lru_match_name;
|
||||
U64 active_match_name_nodes_count;
|
||||
OS_Handle match_rw_mutex;
|
||||
OS_Handle match_cv;
|
||||
|
||||
// rjf: user -> match work ring buffer
|
||||
OS_Handle u2m_ring_cv;
|
||||
OS_Handle u2m_ring_mutex;
|
||||
U64 u2m_ring_size;
|
||||
U8 *u2m_ring_base;
|
||||
U64 u2m_ring_write_pos;
|
||||
U64 u2m_ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
@@ -160,12 +337,18 @@ struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: node cache
|
||||
// rjf: debug info cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
|
||||
// rjf: search cache
|
||||
U64 search_slots_count;
|
||||
DI_SearchSlot *search_slots;
|
||||
U64 search_stripes_count;
|
||||
DI_SearchStripe *search_stripes;
|
||||
|
||||
// rjf: user -> parse ring
|
||||
OS_Handle u2p_ring_mutex;
|
||||
OS_Handle u2p_ring_cv;
|
||||
@@ -182,9 +365,10 @@ struct DI_Shared
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
|
||||
// rjf: threads
|
||||
U64 parse_thread_count;
|
||||
OS_Handle *parse_threads;
|
||||
// rjf: search threads
|
||||
U64 search_threads_count;
|
||||
DI_SearchThread *search_threads;
|
||||
OS_Handle search_evictor_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -197,6 +381,7 @@ global RDI_Parsed di_rdi_parsed_nil = {0};
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
@@ -205,6 +390,12 @@ internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
internal DI_KeyArray di_key_array_copy(Arena *arena, DI_KeyArray *src);
|
||||
internal DI_SearchParams di_search_params_copy(Arena *arena, DI_SearchParams *src);
|
||||
internal U64 di_hash_from_search_params(DI_SearchParams *params);
|
||||
internal void di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push);
|
||||
internal U64 di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx);
|
||||
internal String8 di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
@@ -217,6 +408,7 @@ internal void di_init(void);
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node);
|
||||
internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchNode *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
@@ -237,12 +429,17 @@ internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
//~ rjf: Debug Info Cache Lookups
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
//~ rjf: Search Cache Lookups
|
||||
|
||||
internal DI_SearchItemArray di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Parse Work
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
@@ -250,6 +447,26 @@ internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
internal void di_parse_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(di_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Threads
|
||||
|
||||
internal B32 di_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal U128 di_u2s_dequeue_req(U64 thread_idx);
|
||||
|
||||
ASYNC_WORK_DEF(di_search_work);
|
||||
internal int di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b);
|
||||
internal void di_search_thread__entry_point(void *p);
|
||||
|
||||
internal void di_search_evictor_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Store
|
||||
|
||||
internal DI_MatchStore *di_match_store_alloc(void);
|
||||
internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys);
|
||||
internal RDI_SectionKind di_match_store_section_kind_from_name(DI_MatchStore *store, String8 name, U64 endt_us);
|
||||
ASYNC_WORK_DEF(di_match_work);
|
||||
|
||||
#endif // DBGI_H
|
||||
|
||||
@@ -156,3 +156,33 @@ dmn_rsp_from_thread(DMN_Handle thread)
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Memory Helpers
|
||||
|
||||
internal String8
|
||||
dmn_process_read_cstring(Arena *arena, DMN_Handle process, U64 addr)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List block_list = {0};
|
||||
|
||||
for(U64 cursor = addr, stride = 256; ; cursor += stride)
|
||||
{
|
||||
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
|
||||
U64 read_size = dmn_process_read(process, r1u64(cursor, cursor + stride), raw_block);
|
||||
String8 block = str8_cstring_capped(raw_block, raw_block + read_size);
|
||||
|
||||
str8_list_push(scratch.arena, &block_list, block);
|
||||
|
||||
if(read_size != stride || (block.size+1 <= read_size && block.str[block.size] == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &block_list, 0);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -226,6 +226,7 @@ internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
|
||||
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
|
||||
#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
|
||||
internal String8 dmn_process_read_cstring(Arena *arena, DMN_Handle process, U64 addr);
|
||||
|
||||
//- rjf: threads
|
||||
internal Arch dmn_arch_from_thread(DMN_Handle handle);
|
||||
|
||||
@@ -1217,6 +1217,8 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
{
|
||||
String8List args = {0};
|
||||
String8 exe_path = params->cmd_line.first->string;
|
||||
String8List exe_path_parts = str8_split_path(scratch.arena, exe_path);
|
||||
exe_path = str8_list_join(scratch.arena, &exe_path_parts, &(StringJoin){.sep = str8_lit("\\")});
|
||||
str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path);
|
||||
for(String8Node *n = params->cmd_line.first->next; n != 0; n = n->next)
|
||||
{
|
||||
@@ -1256,11 +1258,41 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params)
|
||||
String16 env16 = str16_from_8(scratch.arena, env);
|
||||
|
||||
//- rjf: launch
|
||||
DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS;
|
||||
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
if(params->debug_subprocesses)
|
||||
{
|
||||
creation_flags |= DEBUG_PROCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
creation_flags |= DEBUG_ONLY_THIS_PROCESS;
|
||||
}
|
||||
BOOL inherit_handles = 0;
|
||||
STARTUPINFOW startup_info = {sizeof(startup_info)};
|
||||
if(!os_handle_match(params->stdout_file, os_handle_zero()))
|
||||
{
|
||||
HANDLE stdout_handle = (HANDLE)params->stdout_file.u64[0];
|
||||
startup_info.hStdOutput = stdout_handle;
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
inherit_handles = 1;
|
||||
}
|
||||
if(!os_handle_match(params->stderr_file, os_handle_zero()))
|
||||
{
|
||||
HANDLE stderr_handle = (HANDLE)params->stderr_file.u64[0];
|
||||
startup_info.hStdError = stderr_handle;
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
inherit_handles = 1;
|
||||
}
|
||||
if(!os_handle_match(params->stdin_file, os_handle_zero()))
|
||||
{
|
||||
HANDLE stdin_handle = (HANDLE)params->stdin_file.u64[0];
|
||||
startup_info.hStdInput = stdin_handle;
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
inherit_handles = 1;
|
||||
}
|
||||
PROCESS_INFORMATION process_info = {0};
|
||||
AllocConsole();
|
||||
if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info))
|
||||
if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, creation_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info))
|
||||
{
|
||||
// check if we are 32-bit app, and just close it immediately
|
||||
BOOL is_wow = 0;
|
||||
|
||||
@@ -609,6 +609,7 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x
|
||||
internal void
|
||||
dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
F32 advance = 0;
|
||||
FNT_Piece *piece_first = run.pieces.v;
|
||||
FNT_Piece *piece_opl = piece_first + run.pieces.count;
|
||||
@@ -629,6 +630,7 @@ dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run)
|
||||
}
|
||||
advance += piece->advance;
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ internal DR_Bucket *dr_bucket_make(void);
|
||||
internal void dr_push_bucket(DR_Bucket *bucket);
|
||||
internal void dr_pop_bucket(void);
|
||||
internal DR_Bucket *dr_top_bucket(void);
|
||||
#define D_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket())
|
||||
#define DR_BucketScope(b) DeferLoop(dr_push_bucket(b), dr_pop_bucket())
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bucket Stacks
|
||||
|
||||
@@ -90,6 +90,7 @@ E_ExprKindTable:
|
||||
{ Typeof UnaryPrefix 1 "typeof" "typeof" "(" ")"}
|
||||
{ ByteSwap UnaryPrefix 1 "bswap" "bswap" "(" ")"}
|
||||
|
||||
{ Pos UnaryPrefix 2 "+" "+" "" "" }
|
||||
{ Neg UnaryPrefix 2 "-" "-" "" "" }
|
||||
{ LogNot UnaryPrefix 2 "!" "!" "" "" }
|
||||
{ BitNot UnaryPrefix 2 "~" "~" "" "" }
|
||||
|
||||
@@ -170,7 +170,7 @@ e_value_eval_from_eval(E_Eval eval)
|
||||
U64 valid_bits_mask = 0;
|
||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
||||
{
|
||||
valid_bits_mask |= (1<<idx);
|
||||
valid_bits_mask |= (1ull<<idx);
|
||||
}
|
||||
eval.value.u64 = eval.value.u64 >> type->off;
|
||||
eval.value.u64 = eval.value.u64 & valid_bits_mask;
|
||||
|
||||
@@ -846,6 +846,10 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr)
|
||||
}break;
|
||||
|
||||
//- rjf: unary operations
|
||||
case E_ExprKind_Pos:
|
||||
{
|
||||
result = e_irtree_and_type_from_expr(arena, expr->first);
|
||||
}break;
|
||||
case E_ExprKind_Neg:
|
||||
case E_ExprKind_LogNot:
|
||||
case E_ExprKind_BitNot:
|
||||
@@ -1050,6 +1054,7 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr)
|
||||
ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->space, ptr_tree->mode, ptr_root, ptr_tree->type_key);
|
||||
}
|
||||
E_IRNode *int_root = int_tree->root;
|
||||
int_root = e_irtree_resolve_to_value(arena, int_tree->space, int_tree->mode, int_root, int_tree->type_key);
|
||||
if(direct_type_size > 1)
|
||||
{
|
||||
E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size);
|
||||
|
||||
+25
-10
@@ -389,6 +389,7 @@ e_token_array_from_text(Arena *arena, String8 text)
|
||||
E_TokenKind active_token_kind = E_TokenKind_Null;
|
||||
B32 active_token_kind_started_with_tick = 0;
|
||||
B32 escaped = 0;
|
||||
B32 exp = 0;
|
||||
for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance)
|
||||
{
|
||||
U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0;
|
||||
@@ -486,11 +487,17 @@ e_token_array_from_text(Arena *arena, String8 text)
|
||||
}break;
|
||||
case E_TokenKind_Numeric:
|
||||
{
|
||||
if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':')
|
||||
if(exp && (byte == '+' || byte == '-')){}
|
||||
else if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.' && byte != ':')
|
||||
{
|
||||
advance = 0;
|
||||
token_formed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp = 0;
|
||||
exp = (byte == 'e');
|
||||
}
|
||||
}break;
|
||||
case E_TokenKind_StringLiteral:
|
||||
{
|
||||
@@ -1018,6 +1025,12 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens)
|
||||
if(token.kind == E_TokenKind_Identifier)
|
||||
{
|
||||
String8 token_string = str8_substr(text, token.range);
|
||||
if(token_string.size >= 2 &&
|
||||
token_string.str[0] == '`' &&
|
||||
token_string.str[token_string.size-1] == '`')
|
||||
{
|
||||
token_string = str8_substr(token_string, r1u64(1, token_string.size-1));
|
||||
}
|
||||
E_TypeKey type_key = e_leaf_type_from_name(token_string);
|
||||
if(!e_type_key_match(e_type_key_zero(), type_key))
|
||||
{
|
||||
@@ -1351,7 +1364,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try members
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("member"), 0))) ProfScope("try to map name as member")
|
||||
{
|
||||
U64 data_member_num = e_num_from_string(e_parse_ctx->member_map, token_string);
|
||||
if(data_member_num != 0)
|
||||
@@ -1362,7 +1375,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try locals
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("local"), 0))) ProfScope("try to map name as local")
|
||||
{
|
||||
E_Module *module = e_parse_ctx->primary_module;
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
@@ -1426,7 +1439,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try registers
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register")
|
||||
{
|
||||
U64 reg_num = e_num_from_string(e_parse_ctx->regs_map, token_string);
|
||||
if(reg_num != 0)
|
||||
@@ -1440,7 +1453,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try register aliases
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("reg"), 0))) ProfScope("try to map name as register alias")
|
||||
{
|
||||
U64 alias_num = e_num_from_string(e_parse_ctx->reg_alias_map, token_string);
|
||||
if(alias_num != 0)
|
||||
@@ -1454,7 +1467,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try global variables
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("global"), 0))) ProfScope("try to map name as global variable")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1498,7 +1511,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try thread variables
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("thread_variable"), 0))) ProfScope("try to map name as thread variable")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1538,7 +1551,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try procedures
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("procedure"), 0))) ProfScope("try to map name as procedure")
|
||||
{
|
||||
for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1)
|
||||
{
|
||||
@@ -1580,7 +1593,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: try types
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0)))
|
||||
if(mapped_identifier == 0 && (resolution_qualifier.size == 0 || str8_match(resolution_qualifier, str8_lit("type"), 0))) ProfScope("try to map name as type")
|
||||
{
|
||||
type_key = e_leaf_type_from_name(token_string);
|
||||
if(!e_type_key_match(e_type_key_zero(), type_key))
|
||||
@@ -1609,7 +1622,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
}
|
||||
|
||||
//- rjf: attach on map
|
||||
if(mapped_identifier != 0)
|
||||
if(mapped_identifier != 0) ProfScope("attach on map")
|
||||
{
|
||||
it += 1;
|
||||
|
||||
@@ -2100,7 +2113,9 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to
|
||||
internal E_Parse
|
||||
e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens)
|
||||
{
|
||||
ProfBegin("parse '%.*s'", str8_varg(text));
|
||||
E_Parse parse = e_parse_expr_from_text_tokens__prec(arena, text, tokens, e_max_precedence);
|
||||
ProfEnd();
|
||||
return parse;
|
||||
}
|
||||
|
||||
|
||||
+44
-17
@@ -403,6 +403,8 @@ e_type_key_cons_(E_ConsTypeParams *params)
|
||||
{
|
||||
node->params.members[idx].name = push_str8_copy(e_type_state->arena, node->params.members[idx].name);
|
||||
node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_type_state->arena, &node->params.members[idx].inheritance_key_chain);
|
||||
U64 opl_off = (node->params.members[idx].off + e_type_byte_size_from_key(node->params.members[idx].type_key));
|
||||
node->byte_size = Max(node->byte_size, opl_off);
|
||||
}
|
||||
}
|
||||
else if(params->enum_vals != 0)
|
||||
@@ -413,6 +415,23 @@ e_type_key_cons_(E_ConsTypeParams *params)
|
||||
{
|
||||
node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name);
|
||||
}
|
||||
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
}
|
||||
else switch(params->kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
node->byte_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
}break;
|
||||
case E_TypeKind_Ptr:
|
||||
{
|
||||
node->byte_size = bit_size_from_arch(node->params.arch)/8;
|
||||
}break;
|
||||
case E_TypeKind_Array:
|
||||
{
|
||||
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
node->byte_size = ptee_size * node->params.count;
|
||||
}break;
|
||||
}
|
||||
result = key;
|
||||
}
|
||||
@@ -565,6 +584,7 @@ e_type_kind_from_key(E_TypeKey key)
|
||||
internal E_Type *
|
||||
e_type_from_key(Arena *arena, E_TypeKey key)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
E_Type *type = &e_type_nil;
|
||||
U64 reg_byte_count = 0;
|
||||
{
|
||||
@@ -603,21 +623,9 @@ e_type_from_key(Arena *arena, E_TypeKey key)
|
||||
type->name = push_str8_copy(arena, node->params.name);
|
||||
type->direct_type_key = node->params.direct_key;
|
||||
type->count = node->params.count;
|
||||
type->byte_size = node->byte_size;
|
||||
switch(type->kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
type->byte_size = e_type_byte_size_from_key(type->direct_type_key);
|
||||
}break;
|
||||
case E_TypeKind_Ptr:
|
||||
{
|
||||
type->byte_size = bit_size_from_arch(node->params.arch)/8;
|
||||
}break;
|
||||
case E_TypeKind_Array:
|
||||
{
|
||||
U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key);
|
||||
type->byte_size = ptee_size * type->count;
|
||||
}break;
|
||||
case E_TypeKind_Struct:
|
||||
case E_TypeKind_Union:
|
||||
case E_TypeKind_Class:
|
||||
@@ -1115,12 +1123,14 @@ e_type_from_key(Arena *arena, E_TypeKey key)
|
||||
}break;
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
return type;
|
||||
}
|
||||
|
||||
internal U64
|
||||
e_type_byte_size_from_key(E_TypeKey key)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
U64 result = 0;
|
||||
switch(key.kind)
|
||||
{
|
||||
@@ -1131,14 +1141,31 @@ e_type_byte_size_from_key(E_TypeKey key)
|
||||
result = e_kind_basic_byte_size_table[kind];
|
||||
}break;
|
||||
case E_TypeKeyKind_Ext:
|
||||
{
|
||||
U64 type_node_idx = key.u32[1];
|
||||
U32 rdi_idx = key.u32[2];
|
||||
RDI_Parsed *rdi = e_type_state->ctx->modules[rdi_idx].rdi;
|
||||
RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx);
|
||||
result = rdi_type->byte_size;
|
||||
}break;
|
||||
case E_TypeKeyKind_Cons:
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
E_Type *type = e_type_from_key(scratch.arena, key);
|
||||
result = type->byte_size;
|
||||
scratch_end(scratch);
|
||||
U64 key_hash = e_hash_from_string(5381, str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%e_type_state->cons_key_slots_count;
|
||||
E_ConsTypeSlot *key_slot = &e_type_state->cons_key_slots[key_slot_idx];
|
||||
for(E_ConsTypeNode *node = key_slot->first;
|
||||
node != 0;
|
||||
node = node->key_next)
|
||||
{
|
||||
if(e_type_key_match(node->key, key))
|
||||
{
|
||||
result = node->byte_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
}
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,6 +162,7 @@ struct E_ConsTypeNode
|
||||
E_ConsTypeNode *content_next;
|
||||
E_TypeKey key;
|
||||
E_ConsTypeParams params;
|
||||
U64 byte_size;
|
||||
};
|
||||
|
||||
typedef struct E_ConsTypeSlot E_ConsTypeSlot;
|
||||
|
||||
@@ -14,7 +14,7 @@ str8_lit_comp("CharLiteral"),
|
||||
str8_lit_comp("Symbol"),
|
||||
};
|
||||
|
||||
String8 e_expr_kind_strings[47] =
|
||||
String8 e_expr_kind_strings[48] =
|
||||
{
|
||||
str8_lit_comp("Nil"),
|
||||
str8_lit_comp("Ref"),
|
||||
@@ -26,6 +26,7 @@ str8_lit_comp("Cast"),
|
||||
str8_lit_comp("Sizeof"),
|
||||
str8_lit_comp("Typeof"),
|
||||
str8_lit_comp("ByteSwap"),
|
||||
str8_lit_comp("Pos"),
|
||||
str8_lit_comp("Neg"),
|
||||
str8_lit_comp("LogNot"),
|
||||
str8_lit_comp("BitNot"),
|
||||
@@ -80,7 +81,7 @@ str8_lit_comp("Insufficient evaluation machine stack space."),
|
||||
str8_lit_comp("Malformed bytecode."),
|
||||
};
|
||||
|
||||
E_OpInfo e_expr_kind_op_info_table[47] =
|
||||
E_OpInfo e_expr_kind_op_info_table[48] =
|
||||
{
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") },
|
||||
@@ -92,6 +93,7 @@ E_OpInfo e_expr_kind_op_info_table[47] =
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap"), str8_lit_comp("("), str8_lit_comp(")") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp("") },
|
||||
|
||||
@@ -101,6 +101,7 @@ E_ExprKind_Cast,
|
||||
E_ExprKind_Sizeof,
|
||||
E_ExprKind_Typeof,
|
||||
E_ExprKind_ByteSwap,
|
||||
E_ExprKind_Pos,
|
||||
E_ExprKind_Neg,
|
||||
E_ExprKind_LogNot,
|
||||
E_ExprKind_BitNot,
|
||||
@@ -159,9 +160,9 @@ E_InterpretationCode_COUNT,
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern String8 e_token_kind_strings[6];
|
||||
extern String8 e_expr_kind_strings[47];
|
||||
extern String8 e_expr_kind_strings[48];
|
||||
extern String8 e_interpretation_code_display_strings[11];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[47];
|
||||
extern E_OpInfo e_expr_kind_op_info_table[48];
|
||||
extern U8 e_kind_basic_byte_size_table[56];
|
||||
extern String8 e_kind_basic_string_table[56];
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ EV_ViewRuleTable:
|
||||
{x Oct oct "oct" x - - - "Display In Octal" x "" "Specifies that all numeric values should be shown in base 8 (octal)." }
|
||||
{x Dec dec "dec" x - - - "Display In Decimal" x "" "Specifies that all numeric values should be shown in base 10 (decimal)." }
|
||||
{x Hex hex "hex" x - - - "Display In Hexadecimal" x "" "Specifies that all numeric values should be shown in base 16 (hexadecimal)." }
|
||||
{x NoAddress no_addr "no_addr" x - - - "Omit Addresses" x "" "Specifies that addresses should be omitted from visualizations, if possible." }
|
||||
}
|
||||
|
||||
@enum EV_ViewRuleKind:
|
||||
|
||||
@@ -39,6 +39,12 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity)
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Functions
|
||||
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "linker/third_party_ext/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal EV_Key
|
||||
ev_key_make(U64 parent_hash, U64 child_id)
|
||||
{
|
||||
@@ -74,11 +80,7 @@ ev_key_match(EV_Key a, EV_Key b)
|
||||
internal U64
|
||||
ev_hash_from_seed_string(U64 seed, String8 string)
|
||||
{
|
||||
U64 result = seed;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
U64 result = XXH3_64bits_withSeed(string.str, string.size, seed);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -671,6 +673,7 @@ ev_resolved_from_expr(Arena *arena, E_Expr *expr, EV_ViewRuleList *view_rules)
|
||||
internal EV_BlockTree
|
||||
ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 string, E_Expr *expr, EV_ViewRuleList *view_rules)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
EV_BlockTree tree = {&ev_nil_block};
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
@@ -818,7 +821,7 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str
|
||||
}
|
||||
|
||||
// rjf: gather children expansions from inverse of expansion state
|
||||
if(!child_count && (expand_info.rows_default_expanded || expand_node == 0 && !expand_info.rows_default_expanded))
|
||||
if(!child_count && (expand_info.rows_default_expanded || (expand_node == 0 && !expand_info.rows_default_expanded)))
|
||||
{
|
||||
child_count = expand_info.row_count;
|
||||
child_keys = push_array(scratch.arena, EV_Key, child_count);
|
||||
@@ -840,46 +843,51 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str
|
||||
{
|
||||
continue;
|
||||
}
|
||||
EV_ExpandRangeInfo child_expand = expand_view_rule_info->expr_expand_range_info(arena, view, filter, t->expr, expand_params, r1u64(split_relative_idx, split_relative_idx+1), expand_info.user_data);
|
||||
if(child_expand.row_exprs_count > 0)
|
||||
if(expand_info.rows_default_expanded || ev_expansion_from_key(view, child_keys[idx]))
|
||||
{
|
||||
EV_Key child_key = child_keys[idx];
|
||||
E_Expr *child_expr = child_expand.row_exprs[0];
|
||||
EV_ViewRuleList *child_view_rules = ev_view_rule_list_from_inheritance(arena, t->view_rules);
|
||||
String8 child_view_rule_string = ev_view_rule_from_key(view, child_key);
|
||||
ev_view_rule_list_push_string(arena, child_view_rules, child_view_rule_string);
|
||||
if(child_expand.row_strings[0].size != 0)
|
||||
EV_ExpandRangeInfo child_expand = expand_view_rule_info->expr_expand_range_info(arena, view, filter, t->expr, expand_params, r1u64(split_relative_idx, split_relative_idx+1), expand_info.user_data);
|
||||
if(child_expand.row_exprs_count > 0)
|
||||
{
|
||||
EV_ViewRuleList *fastpath_view_rules = ev_view_rule_list_from_expr_fastpaths(arena, child_expand.row_strings[0]);
|
||||
ev_view_rule_list_concat_in_place(child_view_rules, &fastpath_view_rules);
|
||||
EV_Key child_key = child_keys[idx];
|
||||
E_Expr *child_expr = child_expand.row_exprs[0];
|
||||
EV_ViewRuleList *child_view_rules = ev_view_rule_list_from_inheritance(arena, t->view_rules);
|
||||
String8 child_view_rule_string = ev_view_rule_from_key(view, child_key);
|
||||
ev_view_rule_list_push_string(arena, child_view_rules, child_view_rule_string);
|
||||
if(child_expand.row_strings[0].size != 0)
|
||||
{
|
||||
EV_ViewRuleList *fastpath_view_rules = ev_view_rule_list_from_expr_fastpaths(arena, child_expand.row_strings[0]);
|
||||
ev_view_rule_list_concat_in_place(child_view_rules, &fastpath_view_rules);
|
||||
}
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
E_IRTreeAndType child_irtree = e_irtree_and_type_from_expr(scratch.arena, child_expr);
|
||||
EV_ViewRuleList *child_auto_view_rules = ev_auto_view_rules_from_type_key(arena, child_irtree.type_key, 1, child_view_rule_string.size == 0);
|
||||
ev_view_rule_list_concat_in_place(child_view_rules, &child_auto_view_rules);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
E_Expr *child_expr__resolved = ev_resolved_from_expr(arena, child_expr, child_view_rules);
|
||||
Task *task = push_array(scratch.arena, Task, 1);
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
task->parent_block = expansion_block;
|
||||
task->expr = child_expr__resolved;
|
||||
task->child_id = child_key.child_id;
|
||||
task->view_rules = child_view_rules;
|
||||
task->split_relative_idx = split_relative_idx;
|
||||
task->default_expanded = expand_info.rows_default_expanded;
|
||||
}
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
E_IRTreeAndType child_irtree = e_irtree_and_type_from_expr(scratch.arena, child_expr);
|
||||
EV_ViewRuleList *child_auto_view_rules = ev_auto_view_rules_from_type_key(arena, child_irtree.type_key, 1, child_view_rule_string.size == 0);
|
||||
ev_view_rule_list_concat_in_place(child_view_rules, &child_auto_view_rules);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
E_Expr *child_expr__resolved = ev_resolved_from_expr(arena, child_expr, child_view_rules);
|
||||
Task *task = push_array(scratch.arena, Task, 1);
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
task->parent_block = expansion_block;
|
||||
task->expr = child_expr__resolved;
|
||||
task->child_id = child_key.child_id;
|
||||
task->view_rules = child_view_rules;
|
||||
task->split_relative_idx = split_relative_idx;
|
||||
task->default_expanded = expand_info.rows_default_expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
ProfEnd();
|
||||
return tree;
|
||||
}
|
||||
|
||||
internal EV_BlockTree
|
||||
ev_block_tree_from_string(Arena *arena, EV_View *view, String8 filter, String8 string, EV_ViewRuleList *view_rules)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
EV_BlockTree tree = {0};
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
{
|
||||
@@ -891,6 +899,7 @@ ev_block_tree_from_string(Arena *arena, EV_View *view, String8 filter, String8 s
|
||||
tree = ev_block_tree_from_expr(arena, view, filter, string, parse.expr, all_view_rules);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return tree;
|
||||
}
|
||||
|
||||
@@ -1526,12 +1535,15 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
case E_TypeKind_UChar16:
|
||||
case E_TypeKind_UChar32:
|
||||
{
|
||||
B32 type_is_unsigned = (E_TypeKind_UChar8 <= type_kind && type_kind <= E_TypeKind_UChar32);
|
||||
String8 char_str = ev_string_from_ascii_value(arena, eval.value.s64);
|
||||
if(char_str.size != 0)
|
||||
{
|
||||
if(flags & EV_StringFlag_ReadOnlyDisplayRules)
|
||||
{
|
||||
String8 imm_string = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator);
|
||||
String8 imm_string = (type_is_unsigned
|
||||
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
|
||||
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
|
||||
result = push_str8f(arena, "'%S' (%S)", char_str, imm_string);
|
||||
}
|
||||
else
|
||||
@@ -1541,7 +1553,9 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
}
|
||||
else
|
||||
{
|
||||
result = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator);
|
||||
result = (type_is_unsigned
|
||||
? str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator)
|
||||
: str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator));
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -1591,15 +1605,16 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
break;
|
||||
}
|
||||
}
|
||||
String8 numeric_value_string = str8_from_u64(scratch.arena, eval.value.u64, radix, min_digits, digit_group_separator);
|
||||
if(flags & EV_StringFlag_ReadOnlyDisplayRules)
|
||||
{
|
||||
if(constant_name.size != 0)
|
||||
{
|
||||
result = push_str8f(arena, "0x%I64x (%S)", eval.value.u64, constant_name);
|
||||
result = push_str8f(arena, "%S (%S)", numeric_value_string, constant_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "0x%I64x (%I64u)", eval.value.u64, eval.value.u64);
|
||||
result = push_str8_copy(arena, numeric_value_string);
|
||||
}
|
||||
}
|
||||
else if(constant_name.size != 0)
|
||||
@@ -1608,7 +1623,7 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix,
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_str8f(arena, "0x%I64x (%I64u)", eval.value.u64, eval.value.u64);
|
||||
result = push_str8_copy(arena, numeric_value_string);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}break;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
EV_ViewRuleInfo ev_builtin_view_rule_info_table[13] =
|
||||
EV_ViewRuleInfo ev_builtin_view_rule_info_table[14] =
|
||||
{
|
||||
{str8_lit_comp("default"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(default) , EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(default) , EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
{str8_lit_comp("array"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(array) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
@@ -19,6 +19,7 @@ EV_ViewRuleInfo ev_builtin_view_rule_info_table[13] =
|
||||
{str8_lit_comp("oct"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
{str8_lit_comp("dec"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
{str8_lit_comp("hex"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
{str8_lit_comp("no_addr"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) },
|
||||
};
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -21,6 +21,7 @@ EV_ViewRuleKind_Bin,
|
||||
EV_ViewRuleKind_Oct,
|
||||
EV_ViewRuleKind_Dec,
|
||||
EV_ViewRuleKind_Hex,
|
||||
EV_ViewRuleKind_NoAddress,
|
||||
EV_ViewRuleKind_COUNT,
|
||||
} EV_ViewRuleKind;
|
||||
|
||||
|
||||
+114
-140
@@ -53,12 +53,6 @@ fs_init(void)
|
||||
fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size);
|
||||
fs_shared->u2s_ring_cv = os_condition_variable_alloc();
|
||||
fs_shared->u2s_ring_mutex = os_mutex_alloc();
|
||||
fs_shared->streamer_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
|
||||
fs_shared->streamers = push_array(arena, OS_Handle, 1);
|
||||
for(U64 idx = 0; idx < fs_shared->streamer_count; idx += 1)
|
||||
{
|
||||
fs_shared->streamers[idx] = os_thread_launch(fs_streamer_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
@@ -106,7 +100,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
// rjf: loop: request, check for results, return until we can't
|
||||
OS_MutexScopeR(path_stripe->rw_mutex) for(;;)
|
||||
OS_MutexScopeW(path_stripe->rw_mutex) for(;;)
|
||||
{
|
||||
// rjf: path -> node
|
||||
FS_Node *node = 0;
|
||||
@@ -119,25 +113,14 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: node does not exist? -> create & store (we must re-search after promoting r -> w)
|
||||
if(node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex)
|
||||
// rjf: node does not exist? -> create & store
|
||||
if(node == 0)
|
||||
{
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(path, n->path, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
}
|
||||
node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
}
|
||||
|
||||
// rjf: range -> node
|
||||
@@ -154,30 +137,25 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: range node does not exist? create & store (we must re-search after promoting r -> w)
|
||||
if(range_node == 0) OS_MutexScopeRWPromote(path_stripe->rw_mutex)
|
||||
// rjf: range node does not exist? create & store
|
||||
if(range_node == 0)
|
||||
{
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(range_node == 0)
|
||||
{
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->range = range;
|
||||
}
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->range = range;
|
||||
}
|
||||
|
||||
// rjf: try to send stream request
|
||||
if(!ins_atomic_u32_eval_cond_assign(&range_node->is_working, 1, 0) &&
|
||||
!fs_u2s_enqueue_req(range, path, endt_us))
|
||||
if((ins_atomic_u64_eval(&range_node->request_count) == ins_atomic_u64_eval(&range_node->completion_count) ||
|
||||
ins_atomic_u64_eval(&range_node->last_time_requested_us)+100000 < os_now_microseconds()) &&
|
||||
fs_u2s_enqueue_req(range, path, endt_us))
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&range_node->is_working, 0);
|
||||
ins_atomic_u64_eval_assign(&range_node->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_node->request_count);
|
||||
DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex))
|
||||
{
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_node->completion_count);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: try to reobtain results
|
||||
@@ -186,7 +164,7 @@ fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
// rjf: have time to wait? -> wait on this stripe; otherwise exit
|
||||
if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us)
|
||||
{
|
||||
os_condition_variable_wait_rw_r(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -275,15 +253,14 @@ fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
|
||||
{
|
||||
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
|
||||
U64 available_size = fs_shared->u2s_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(U64) + path.size)
|
||||
U64 needed_size = sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size;
|
||||
if(available_size >= needed_size)
|
||||
{
|
||||
result = 1;
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size);
|
||||
fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size);
|
||||
fs_shared->u2s_ring_write_pos += 7;
|
||||
fs_shared->u2s_ring_write_pos -= fs_shared->u2s_ring_write_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us);
|
||||
@@ -308,8 +285,6 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size);
|
||||
path_out->str = push_array(arena, U8, path_out->size);
|
||||
fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path_out->str, path_out->size);
|
||||
fs_shared->u2s_ring_read_pos += 7;
|
||||
fs_shared->u2s_ring_read_pos -= fs_shared->u2s_ring_read_pos%8;
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64);
|
||||
@@ -317,108 +292,105 @@ fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
|
||||
os_condition_variable_broadcast(fs_shared->u2s_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
fs_streamer_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(fs_stream_work)
|
||||
{
|
||||
ThreadNameF("[fs] streamer #%I64u", (U64)p);
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request
|
||||
Rng1U64 range = {0};
|
||||
String8 path = {0};
|
||||
fs_u2s_dequeue_req(scratch.arena, &range, &path);
|
||||
|
||||
//- rjf: unpack request
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
//- rjf: load
|
||||
ProfBegin("load \"%.*s\"", str8_varg(path));
|
||||
FileProperties pre_props = os_properties_from_file_path(path);
|
||||
U64 range_size = dim_1u64(range);
|
||||
U64 read_size = Min(pre_props.size, range_size);
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
|
||||
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
|
||||
data_arena_size += KB(4)-1;
|
||||
data_arena_size -= data_arena_size%KB(4);
|
||||
ProfBegin("allocate");
|
||||
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
|
||||
ProfEnd();
|
||||
ProfBegin("read");
|
||||
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
|
||||
ProfEnd();
|
||||
os_file_close(file);
|
||||
FileProperties post_props = os_properties_from_file_path(path);
|
||||
|
||||
//- rjf: abort if modification timestamps differ - we did not successfully read the file
|
||||
if(pre_props.modified != post_props.modified)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request
|
||||
Rng1U64 range = {0};
|
||||
String8 path = {0};
|
||||
fs_u2s_dequeue_req(scratch.arena, &range, &path);
|
||||
|
||||
//- rjf: unpack request
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
//- rjf: load
|
||||
ProfBegin("load \"%.*s\"", str8_varg(path));
|
||||
FileProperties pre_props = os_properties_from_file_path(path);
|
||||
U64 range_size = dim_1u64(range);
|
||||
U64 read_size = Min(pre_props.size, range_size);
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
|
||||
U64 data_arena_size = read_size+ARENA_HEADER_SIZE;
|
||||
data_arena_size += KB(4)-1;
|
||||
data_arena_size -= data_arena_size%KB(4);
|
||||
ProfBegin("allocate");
|
||||
Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
|
||||
ProfEnd();
|
||||
ProfBegin("read");
|
||||
String8 data = os_string_from_file_range(data_arena, file, r1u64(range.min, range.min+read_size));
|
||||
ProfEnd();
|
||||
os_file_close(file);
|
||||
FileProperties post_props = os_properties_from_file_path(path);
|
||||
|
||||
//- rjf: abort if modification timestamps differ - we did not successfully read the file
|
||||
if(pre_props.modified != post_props.modified)
|
||||
ProfScope("abort")
|
||||
{
|
||||
ProfScope("abort")
|
||||
arena_release(data_arena);
|
||||
MemoryZeroStruct(&data);
|
||||
data_arena = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: submit
|
||||
else
|
||||
{
|
||||
ProfScope("submit")
|
||||
{
|
||||
hs_submit_data(key, &data_arena, data);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit info to cache
|
||||
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
|
||||
{
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->path, path, 0))
|
||||
{
|
||||
arena_release(data_arena);
|
||||
MemoryZeroStruct(&data);
|
||||
data_arena = 0;
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: submit
|
||||
else
|
||||
if(node != 0)
|
||||
{
|
||||
ProfScope("submit")
|
||||
if(node->timestamp != 0)
|
||||
{
|
||||
hs_submit_data(key, &data_arena, data);
|
||||
ins_atomic_u64_inc_eval(&fs_shared->change_gen);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit info to cache
|
||||
ProfScope("commit to cache") OS_MutexScopeW(path_stripe->rw_mutex)
|
||||
{
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
if(post_props.modified == pre_props.modified)
|
||||
{
|
||||
if(str8_match(n->path, path, 0))
|
||||
node->timestamp = post_props.modified;
|
||||
node->size = post_props.size;
|
||||
}
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
node = n;
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node != 0)
|
||||
{
|
||||
if(node->timestamp != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&fs_shared->change_gen);
|
||||
}
|
||||
if(post_props.modified == pre_props.modified)
|
||||
{
|
||||
node->timestamp = post_props.modified;
|
||||
node->size = post_props.size;
|
||||
}
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&range_node->is_working, 0);
|
||||
}
|
||||
}
|
||||
os_condition_variable_broadcast(path_stripe->cv);
|
||||
|
||||
ProfEnd();
|
||||
scratch_end(scratch);
|
||||
}
|
||||
os_condition_variable_broadcast(path_stripe->cv);
|
||||
|
||||
ProfEnd();
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -427,7 +399,7 @@ fs_streamer_thread__entry_point(void *p)
|
||||
internal void
|
||||
fs_detector_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[fs] detector");
|
||||
ThreadNameF("[fs] detector thread");
|
||||
for(;;)
|
||||
{
|
||||
U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count;
|
||||
@@ -449,10 +421,12 @@ fs_detector_thread__entry_point(void *p)
|
||||
range_n != 0;
|
||||
range_n = range_n->next)
|
||||
{
|
||||
if(!ins_atomic_u32_eval_cond_assign(&range_n->is_working, 1, 0) &&
|
||||
!fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
|
||||
if(ins_atomic_u64_eval(&range_n->request_count) == ins_atomic_u64_eval(&range_n->completion_count) &&
|
||||
fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&range_n->is_working, 0);
|
||||
ins_atomic_u64_eval_assign(&range_n->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_n->request_count);
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_n->completion_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ struct FS_RangeNode
|
||||
{
|
||||
FS_RangeNode *next;
|
||||
Rng1U64 range;
|
||||
B32 is_working;
|
||||
U64 request_count;
|
||||
U64 completion_count;
|
||||
U64 last_time_requested_us;
|
||||
};
|
||||
|
||||
typedef struct FS_RangeSlot FS_RangeSlot;
|
||||
@@ -75,10 +77,6 @@ struct FS_Shared
|
||||
OS_Handle u2s_ring_cv;
|
||||
OS_Handle u2s_ring_mutex;
|
||||
|
||||
// rjf: streamer threads
|
||||
U64 streamer_count;
|
||||
OS_Handle *streamers;
|
||||
|
||||
// rjf: change detector threads
|
||||
OS_Handle detector_thread;
|
||||
};
|
||||
@@ -114,12 +112,11 @@ internal U64 fs_timestamp_from_path(String8 path);
|
||||
internal U64 fs_size_from_path(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Streamer Threads
|
||||
//~ rjf: Streaming Work
|
||||
|
||||
internal B32 fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us);
|
||||
internal void fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out);
|
||||
|
||||
internal void fs_streamer_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(fs_stream_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Change Detector Thread
|
||||
|
||||
+31
-28
@@ -4,28 +4,29 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Functions
|
||||
|
||||
#if !defined(BLAKE2_H)
|
||||
#define HAVE_SSE2
|
||||
#include "third_party/blake2/blake2.h"
|
||||
#include "third_party/blake2/blake2b.c"
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "linker/third_party_ext/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal U128
|
||||
fnt_hash_from_string(String8 string)
|
||||
{
|
||||
U128 result = {0};
|
||||
blake2b((U8 *)&result.u64[0], sizeof(result), string.str, string.size, 0, 0);
|
||||
return result;
|
||||
union
|
||||
{
|
||||
XXH128_hash_t xxhash;
|
||||
U128 u128;
|
||||
}
|
||||
hash;
|
||||
hash.xxhash = XXH3_128bits(string.str, string.size);
|
||||
return hash.u128;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fnt_little_hash_from_string(String8 string)
|
||||
{
|
||||
U64 result = 5381;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
U64 result = XXH3_64bits(string.str, string.size);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -575,46 +576,48 @@ fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px,
|
||||
FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags);
|
||||
|
||||
//- rjf: decode string & produce run pieces
|
||||
B32 first = 1;
|
||||
FNT_PieceChunkList piece_chunks = {0};
|
||||
Vec2F32 dim = {0};
|
||||
B32 font_handle_mapped_on_miss = 0;
|
||||
FP_Handle font_handle = {0};
|
||||
U64 piece_substring_start_idx = 0;
|
||||
for(U64 idx = 0; idx < string.size; first = 0)
|
||||
U64 piece_substring_end_idx = 0;
|
||||
for(U64 idx = 0; idx <= string.size;)
|
||||
{
|
||||
//- rjf: decode next codepoint & get piece substring, or continuation rule
|
||||
String8 piece_substring;
|
||||
U8 byte = (idx < string.size ? string.str[idx] : 0);
|
||||
B32 need_another_codepoint = 0;
|
||||
switch(utf8_class[string.str[idx]>>3])
|
||||
if(byte == 0)
|
||||
{
|
||||
idx += 1;
|
||||
}
|
||||
else switch(utf8_class[byte>>3])
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
piece_substring.str = &string.str[idx];
|
||||
piece_substring.size = 1;
|
||||
idx += 1;
|
||||
piece_substring_end_idx += 1;
|
||||
need_another_codepoint = 0;
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx);
|
||||
idx += decode.inc;
|
||||
if(decode.inc == 0) { break; }
|
||||
piece_substring.str = string.str + piece_substring_start_idx;
|
||||
piece_substring.size = decode.inc;
|
||||
// NOTE(rjf): assuming 1 codepoint per piece for now.
|
||||
piece_substring_end_idx += decode.inc;
|
||||
need_another_codepoint = 0;
|
||||
}break;
|
||||
}
|
||||
|
||||
//- rjf: need another codepoint? -> continue
|
||||
if(need_another_codepoint)
|
||||
//- rjf: need another codepoint, or have no substring? -> continue
|
||||
if(need_another_codepoint || piece_substring_end_idx == piece_substring_start_idx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//- rjf: do not need another codepoint? -> bump piece start idx
|
||||
{
|
||||
piece_substring_start_idx = idx;
|
||||
}
|
||||
//- rjf: do not need another codepoint? -> grab substring, bump piece start idx
|
||||
String8 piece_substring = str8_substr(string, r1u64(piece_substring_start_idx, piece_substring_end_idx));
|
||||
piece_substring_start_idx = idx;
|
||||
piece_substring_end_idx = idx;
|
||||
|
||||
//- rjf: determine if this piece is a tab - if so, use space info to draw
|
||||
B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t');
|
||||
|
||||
@@ -1,547 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64
|
||||
fzy_hash_from_string(U64 seed, String8 string)
|
||||
{
|
||||
U64 result = seed;
|
||||
for(U64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fzy_hash_from_params(FZY_Params *params)
|
||||
{
|
||||
U64 hash = 5381;
|
||||
hash = fzy_hash_from_string(hash, str8_struct(¶ms->target));
|
||||
for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1)
|
||||
{
|
||||
hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].min_timestamp));
|
||||
hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
internal U64
|
||||
fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx)
|
||||
{
|
||||
U64 fuzzy_item_num = 0;
|
||||
for(U64 idx = 0; idx < array->count; idx += 1)
|
||||
{
|
||||
if(array->v[idx].idx == element_idx)
|
||||
{
|
||||
fuzzy_item_num = idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fuzzy_item_num;
|
||||
}
|
||||
|
||||
internal String8
|
||||
fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx)
|
||||
{
|
||||
String8 result = {0};
|
||||
switch(target)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
RDI_Procedure *proc = rdi_element_from_name_idx(rdi, Procedures, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size);
|
||||
result = str8(name_base, name_size);
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal FZY_Params
|
||||
fzy_params_copy(Arena *arena, FZY_Params *src)
|
||||
{
|
||||
FZY_Params dst = zero_struct;
|
||||
MemoryCopyStruct(&dst, src);
|
||||
dst.dbgi_keys.v = push_array(arena, DI_Key, dst.dbgi_keys.count);
|
||||
MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(DI_Key)*src->dbgi_keys.count);
|
||||
for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1)
|
||||
{
|
||||
dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void
|
||||
fzy_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
fzy_shared = push_array(arena, FZY_Shared, 1);
|
||||
fzy_shared->arena = arena;
|
||||
fzy_shared->slots_count = 256;
|
||||
fzy_shared->stripes_count = os_get_system_info()->logical_processor_count;
|
||||
fzy_shared->slots = push_array(arena, FZY_Slot, fzy_shared->slots_count);
|
||||
fzy_shared->stripes = push_array(arena, FZY_Stripe, fzy_shared->stripes_count);
|
||||
for(U64 idx = 0; idx < fzy_shared->stripes_count; idx += 1)
|
||||
{
|
||||
fzy_shared->stripes[idx].arena = arena_alloc();
|
||||
fzy_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
|
||||
fzy_shared->stripes[idx].cv = os_condition_variable_alloc();
|
||||
}
|
||||
fzy_shared->thread_count = Min(os_get_system_info()->logical_processor_count, 2);
|
||||
fzy_shared->threads = push_array(arena, FZY_Thread, fzy_shared->thread_count);
|
||||
for(U64 idx = 0; idx < fzy_shared->thread_count; idx += 1)
|
||||
{
|
||||
fzy_shared->threads[idx].u2f_ring_mutex = os_mutex_alloc();
|
||||
fzy_shared->threads[idx].u2f_ring_cv = os_condition_variable_alloc();
|
||||
fzy_shared->threads[idx].u2f_ring_size = KB(64);
|
||||
fzy_shared->threads[idx].u2f_ring_base = push_array_no_zero(arena, U8, fzy_shared->threads[idx].u2f_ring_size);
|
||||
fzy_shared->threads[idx].thread = os_thread_launch(fzy_search_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *
|
||||
fzy_scope_open(void)
|
||||
{
|
||||
if(fzy_tctx == 0)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
fzy_tctx = push_array(arena, FZY_TCTX, 1);
|
||||
fzy_tctx->arena = arena;
|
||||
}
|
||||
FZY_Scope *scope = fzy_tctx->free_scope;
|
||||
if(scope != 0)
|
||||
{
|
||||
SLLStackPop(fzy_tctx->free_scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
scope = push_array_no_zero(fzy_tctx->arena, FZY_Scope, 1);
|
||||
}
|
||||
MemoryZeroStruct(scope);
|
||||
return scope;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_scope_close(FZY_Scope *scope)
|
||||
{
|
||||
for(FZY_Touch *t = scope->first_touch, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
SLLStackPush(fzy_tctx->free_touch, t);
|
||||
if(t->node != 0)
|
||||
{
|
||||
ins_atomic_u64_dec_eval(&t->node->touch_count);
|
||||
}
|
||||
}
|
||||
SLLStackPush(fzy_tctx->free_scope, scope);
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node)
|
||||
{
|
||||
if(node != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&node->touch_count);
|
||||
}
|
||||
FZY_Touch *touch = fzy_tctx->free_touch;
|
||||
if(touch != 0)
|
||||
{
|
||||
SLLStackPop(fzy_tctx->free_touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
touch = push_array_no_zero(fzy_tctx->arena, FZY_Touch, 1);
|
||||
}
|
||||
MemoryZeroStruct(touch);
|
||||
SLLQueuePush(scope->first_touch, scope->last_touch, touch);
|
||||
touch->node = node;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray
|
||||
fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
FZY_ItemArray items = {0};
|
||||
|
||||
//- rjf: hash parameters
|
||||
U64 params_hash = fzy_hash_from_params(params);
|
||||
|
||||
//- rjf: unpack key
|
||||
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
|
||||
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
|
||||
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: query and/or request
|
||||
OS_MutexScopeR(stripe->rw_mutex) for(;;)
|
||||
{
|
||||
// rjf: map key -> node
|
||||
FZY_Node *node = 0;
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: no node? -> allocate
|
||||
if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
node = push_array(stripe->arena, FZY_Node, 1);
|
||||
SLLQueuePush(slot->first, slot->last, node);
|
||||
node->key = key;
|
||||
for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1)
|
||||
{
|
||||
node->buckets[idx].arena = arena_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: try to grab last valid results for this key/query; determine if stale
|
||||
B32 stale = 1;
|
||||
if(params_hash == node->buckets[node->gen%ArrayCount(node->buckets)].params_hash &&
|
||||
node->gen != 0)
|
||||
{
|
||||
fzy_scope_touch_node__stripe_mutex_r_guarded(scope, node);
|
||||
items = node->gen_items;
|
||||
stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0);
|
||||
if(stale_out != 0)
|
||||
{
|
||||
*stale_out = stale;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if stale -> request again
|
||||
if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex)
|
||||
{
|
||||
if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1)
|
||||
{
|
||||
node->submit_gen += 1;
|
||||
arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params = fzy_params_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, params);
|
||||
node->buckets[node->submit_gen%ArrayCount(node->buckets)].params_hash = params_hash;
|
||||
}
|
||||
if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) &&
|
||||
fzy_u2s_enqueue_req(key, endt_us))
|
||||
{
|
||||
node->last_time_submitted_us = os_now_microseconds();
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: not stale, or timeout -> break
|
||||
if(!stale || os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: no results, but have time to wait -> wait
|
||||
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return items;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32
|
||||
fzy_u2s_enqueue_req(U128 key, U64 endt_us)
|
||||
{
|
||||
B32 sent = 0;
|
||||
FZY_Thread *thread = &fzy_shared->threads[key.u64[1]%fzy_shared->thread_count];
|
||||
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
|
||||
U64 available_size = thread->u2f_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(U128))
|
||||
{
|
||||
sent = 1;
|
||||
thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key);
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us);
|
||||
}
|
||||
if(sent)
|
||||
{
|
||||
os_condition_variable_broadcast(thread->u2f_ring_cv);
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out)
|
||||
{
|
||||
OS_MutexScope(thread->u2f_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(U128))
|
||||
{
|
||||
thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out);
|
||||
break;
|
||||
}
|
||||
os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64);
|
||||
}
|
||||
os_condition_variable_broadcast(thread->u2f_ring_cv);
|
||||
}
|
||||
|
||||
internal int
|
||||
fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b)
|
||||
{
|
||||
int result = 0;
|
||||
if(a->match_ranges.count > b->match_ranges.count)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a->match_ranges.count < b->match_ranges.count)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
else if(a->missed_size < b->missed_size)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if(a->missed_size > b->missed_size)
|
||||
{
|
||||
result = +1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
fzy_search_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[fzy] searcher #%I64u", (U64)p);
|
||||
FZY_Thread *thread = &fzy_shared->threads[(U64)p];
|
||||
for(;;)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: dequeue next request
|
||||
//
|
||||
U128 key = {0};
|
||||
fzy_u2s_dequeue_req(scratch.arena, thread, &key);
|
||||
U64 slot_idx = key.u64[1]%fzy_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%fzy_shared->stripes_count;
|
||||
FZY_Slot *slot = &fzy_shared->slots[slot_idx];
|
||||
FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx];
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: grab next exe_path/query for this key
|
||||
//
|
||||
B32 task_is_good = 0;
|
||||
Arena *task_arena = 0;
|
||||
String8 query = {0};
|
||||
FZY_Params params = {RDI_SectionKind_Procedures};
|
||||
U64 initial_submit_gen = 0;
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
FZY_Bucket *bucket = &n->buckets[n->submit_gen%ArrayCount(n->buckets)];
|
||||
task_is_good = 1;
|
||||
initial_submit_gen = n->submit_gen;
|
||||
task_arena = bucket->arena;
|
||||
query = bucket->query;
|
||||
params = bucket->params;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: params -> look up all rdis
|
||||
//
|
||||
U64 rdis_count = params.dbgi_keys.count;
|
||||
RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count);
|
||||
if(task_is_good)
|
||||
{
|
||||
for(U64 idx = 0; idx < rdis_count; idx += 1)
|
||||
{
|
||||
rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], max_U64);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: search target -> info about search space
|
||||
//
|
||||
U64 element_name_idx_off = 0;
|
||||
if(task_is_good)
|
||||
{
|
||||
switch(params.target)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx);
|
||||
}break;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
// NOTE(rjf): name must be determined from self_type_idx
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: rdis * query * params -> item list
|
||||
//
|
||||
FZY_ItemChunkList items_list = {0};
|
||||
if(task_is_good)
|
||||
{
|
||||
U64 base_idx = 0;
|
||||
for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1)
|
||||
{
|
||||
RDI_Parsed *rdi = rdis[rdi_idx];
|
||||
U64 element_count = 0;
|
||||
void *table_base = rdi_section_raw_table_from_kind(rdi, params.target, &element_count);
|
||||
U64 element_size = rdi_section_element_size_table[params.target];
|
||||
for(U64 idx = 1; task_is_good && idx < element_count; idx += 1)
|
||||
{
|
||||
void *element = (U8 *)table_base + element_size*idx;
|
||||
U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off);
|
||||
if(params.target == RDI_SectionKind_UDTs)
|
||||
{
|
||||
RDI_UDT *udt = (RDI_UDT *)element;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
|
||||
name_idx_ptr = &type_node->user_defined.name_string_idx;
|
||||
}
|
||||
U32 name_idx = *name_idx_ptr;
|
||||
U64 name_size = 0;
|
||||
U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size);
|
||||
String8 name = str8(name_base, name_size);
|
||||
if(name.size == 0) { continue; }
|
||||
FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name);
|
||||
if(matches.count == matches.needle_part_count)
|
||||
{
|
||||
FZY_ItemChunk *chunk = items_list.last;
|
||||
if(chunk == 0 || chunk->count >= chunk->cap)
|
||||
{
|
||||
chunk = push_array(scratch.arena, FZY_ItemChunk, 1);
|
||||
chunk->cap = 1024;
|
||||
chunk->count = 0;
|
||||
chunk->v = push_array_no_zero(scratch.arena, FZY_Item, chunk->cap);
|
||||
SLLQueuePush(items_list.first, items_list.last, chunk);
|
||||
items_list.chunk_count += 1;
|
||||
}
|
||||
chunk->v[chunk->count].idx = base_idx + idx;
|
||||
chunk->v[chunk->count].match_ranges = matches;
|
||||
chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0;
|
||||
chunk->count += 1;
|
||||
items_list.total_count += 1;
|
||||
}
|
||||
if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen)
|
||||
{
|
||||
task_is_good = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
base_idx += element_count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: item list -> item array
|
||||
FZY_ItemArray items = {0};
|
||||
if(task_is_good)
|
||||
{
|
||||
items.count = items_list.total_count;
|
||||
items.v = push_array_no_zero(task_arena, FZY_Item, items.count);
|
||||
U64 idx = 0;
|
||||
for(FZY_ItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next)
|
||||
{
|
||||
MemoryCopy(items.v+idx, chunk->v, sizeof(FZY_Item)*chunk->count);
|
||||
idx += chunk->count;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: sort item array
|
||||
if(items.count != 0 && query.size != 0)
|
||||
{
|
||||
quick_sort(items.v, items.count, sizeof(FZY_Item), fzy_qsort_compare_items);
|
||||
}
|
||||
|
||||
//- rjf: commit to cache - busyloop on scope touches
|
||||
if(task_is_good)
|
||||
{
|
||||
for(B32 done = 0; !done;)
|
||||
{
|
||||
B32 found = 0;
|
||||
OS_MutexScopeW(stripe->rw_mutex) for(FZY_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
{
|
||||
if(n->touch_count == 0)
|
||||
{
|
||||
n->gen = initial_submit_gen;
|
||||
n->gen_items = items;
|
||||
done = 1;
|
||||
}
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
di_scope_close(di_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef FUZZY_SEARCH_H
|
||||
#define FUZZY_SEARCH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Result Types
|
||||
|
||||
typedef struct FZY_Item FZY_Item;
|
||||
struct FZY_Item
|
||||
{
|
||||
U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count)
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunk FZY_ItemChunk;
|
||||
struct FZY_ItemChunk
|
||||
{
|
||||
FZY_ItemChunk *next;
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemChunkList FZY_ItemChunkList;
|
||||
struct FZY_ItemChunkList
|
||||
{
|
||||
FZY_ItemChunk *first;
|
||||
FZY_ItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct FZY_ItemArray FZY_ItemArray;
|
||||
struct FZY_ItemArray
|
||||
{
|
||||
FZY_Item *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Parameter Types
|
||||
|
||||
typedef struct FZY_Params FZY_Params;
|
||||
struct FZY_Params
|
||||
{
|
||||
RDI_SectionKind target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct FZY_Bucket FZY_Bucket;
|
||||
struct FZY_Bucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
FZY_Params params;
|
||||
U64 params_hash;
|
||||
};
|
||||
|
||||
typedef struct FZY_Node FZY_Node;
|
||||
struct FZY_Node
|
||||
{
|
||||
FZY_Node *next;
|
||||
U128 key;
|
||||
U64 touch_count;
|
||||
U64 last_time_submitted_us;
|
||||
FZY_Bucket buckets[3];
|
||||
U64 gen;
|
||||
U64 submit_gen;
|
||||
FZY_ItemArray gen_items;
|
||||
};
|
||||
|
||||
typedef struct FZY_Slot FZY_Slot;
|
||||
struct FZY_Slot
|
||||
{
|
||||
FZY_Node *first;
|
||||
FZY_Node *last;
|
||||
};
|
||||
|
||||
typedef struct FZY_Stripe FZY_Stripe;
|
||||
struct FZY_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
OS_Handle rw_mutex;
|
||||
OS_Handle cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct FZY_Touch FZY_Touch;
|
||||
struct FZY_Touch
|
||||
{
|
||||
FZY_Touch *next;
|
||||
FZY_Node *node;
|
||||
};
|
||||
|
||||
typedef struct FZY_Scope FZY_Scope;
|
||||
struct FZY_Scope
|
||||
{
|
||||
FZY_Scope *next;
|
||||
FZY_Touch *first_touch;
|
||||
FZY_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct FZY_TCTX FZY_TCTX;
|
||||
struct FZY_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
FZY_Scope *free_scope;
|
||||
FZY_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
|
||||
typedef struct FZY_Thread FZY_Thread;
|
||||
struct FZY_Thread
|
||||
{
|
||||
OS_Handle thread;
|
||||
OS_Handle u2f_ring_mutex;
|
||||
OS_Handle u2f_ring_cv;
|
||||
U64 u2f_ring_size;
|
||||
U8 *u2f_ring_base;
|
||||
U64 u2f_ring_write_pos;
|
||||
U64 u2f_ring_read_pos;
|
||||
};
|
||||
|
||||
typedef struct FZY_Shared FZY_Shared;
|
||||
struct FZY_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: search artifact cache table
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
FZY_Slot *slots;
|
||||
FZY_Stripe *stripes;
|
||||
|
||||
// rjf: threads
|
||||
U64 thread_count;
|
||||
FZY_Thread *threads;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global FZY_Shared *fzy_shared = 0;
|
||||
thread_static FZY_TCTX *fzy_tctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 fzy_hash_from_string(U64 seed, String8 string);
|
||||
internal U64 fzy_hash_from_params(FZY_Params *params);
|
||||
internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx);
|
||||
internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
|
||||
internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void fzy_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
|
||||
internal FZY_Scope *fzy_scope_open(void);
|
||||
internal void fzy_scope_close(FZY_Scope *scope);
|
||||
internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookup Functions
|
||||
|
||||
internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Searcher Threads
|
||||
|
||||
internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out);
|
||||
|
||||
internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b);
|
||||
|
||||
internal void fzy_search_thread__entry_point(void *p);
|
||||
|
||||
#endif // FUZZY_SEARCH_H
|
||||
+58
-78
@@ -25,12 +25,6 @@ geo_init(void)
|
||||
geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size);
|
||||
geo_shared->u2x_ring_cv = os_condition_variable_alloc();
|
||||
geo_shared->u2x_ring_mutex = os_mutex_alloc();
|
||||
geo_shared->xfer_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
|
||||
geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count);
|
||||
for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1)
|
||||
{
|
||||
geo_shared->xfer_threads[idx] = os_thread_launch(geo_xfer_thread__entry_point, (void *)idx, 0);
|
||||
}
|
||||
geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0);
|
||||
}
|
||||
|
||||
@@ -48,21 +42,6 @@ geo_tctx_ensure_inited(void)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void
|
||||
geo_user_clock_tick(void)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
internal U64
|
||||
geo_user_clock_idx(void)
|
||||
{
|
||||
return ins_atomic_u64_eval(&geo_shared->user_clock_idx);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -116,7 +95,7 @@ geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node)
|
||||
GEO_Touch *touch = geo_tctx->free_touch;
|
||||
ins_atomic_u64_inc_eval(&node->scope_ref_count);
|
||||
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx());
|
||||
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, update_tick_idx());
|
||||
if(touch != 0)
|
||||
{
|
||||
SLLStackPop(geo_tctx->free_touch);
|
||||
@@ -192,6 +171,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash)
|
||||
if(node_is_new)
|
||||
{
|
||||
geo_u2x_enqueue_req(hash, max_U64);
|
||||
async_push_work(geo_xfer_work);
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
@@ -259,68 +239,67 @@ geo_u2x_dequeue_req(U128 *hash_out)
|
||||
os_condition_variable_broadcast(geo_shared->u2x_ring_cv);
|
||||
}
|
||||
|
||||
internal void
|
||||
geo_xfer_thread__entry_point(void *p)
|
||||
ASYNC_WORK_DEF(geo_xfer_work)
|
||||
{
|
||||
for(;;)
|
||||
ProfBeginFunction();
|
||||
HS_Scope *scope = hs_scope_open();
|
||||
|
||||
//- rjf: decode
|
||||
U128 hash = {0};
|
||||
geo_u2x_dequeue_req(&hash);
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
|
||||
GEO_Slot *slot = &geo_shared->slots[slot_idx];
|
||||
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
HS_Scope *scope = hs_scope_open();
|
||||
|
||||
//- rjf: decode
|
||||
U128 hash = {0};
|
||||
geo_u2x_dequeue_req(&hash);
|
||||
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%geo_shared->stripes_count;
|
||||
GEO_Slot *slot = &geo_shared->slots[slot_idx];
|
||||
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data -> buffer
|
||||
R_Handle buffer = {0};
|
||||
if(got_task && data.size != 0)
|
||||
{
|
||||
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
n->buffer = buffer;
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hs_scope_close(scope);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(scope, hash);
|
||||
}
|
||||
|
||||
//- rjf: data -> buffer
|
||||
R_Handle buffer = {0};
|
||||
if(got_task && data.size != 0)
|
||||
{
|
||||
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(GEO_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
n->buffer = buffer;
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hs_scope_close(scope);
|
||||
ProfEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -329,10 +308,11 @@ geo_xfer_thread__entry_point(void *p)
|
||||
internal void
|
||||
geo_evictor_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[geo] evictor thread");
|
||||
for(;;)
|
||||
{
|
||||
U64 check_time_us = os_now_microseconds();
|
||||
U64 check_time_user_clocks = geo_user_clock_idx();
|
||||
U64 check_time_user_clocks = update_tick_idx();
|
||||
U64 evict_threshold_us = 10*1000000;
|
||||
U64 evict_threshold_user_clocks = 10;
|
||||
for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1)
|
||||
|
||||
@@ -72,9 +72,6 @@ struct GEO_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user clock
|
||||
U64 user_clock_idx;
|
||||
|
||||
// rjf: cache
|
||||
U64 slots_count;
|
||||
U64 stripes_count;
|
||||
@@ -90,10 +87,6 @@ struct GEO_Shared
|
||||
OS_Handle u2x_ring_cv;
|
||||
OS_Handle u2x_ring_mutex;
|
||||
|
||||
// rjf: transfer threads
|
||||
U64 xfer_thread_count;
|
||||
OS_Handle *xfer_threads;
|
||||
|
||||
// rjf: evictor thread
|
||||
OS_Handle evictor_thread;
|
||||
};
|
||||
@@ -114,12 +107,6 @@ internal void geo_init(void);
|
||||
|
||||
internal void geo_tctx_ensure_inited(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: User Clock
|
||||
|
||||
internal void geo_user_clock_tick(void);
|
||||
internal U64 geo_user_clock_idx(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
|
||||
@@ -138,7 +125,7 @@ internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
|
||||
|
||||
internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us);
|
||||
internal void geo_u2x_dequeue_req(U128 *hash_out);
|
||||
internal void geo_xfer_thread__entry_point(void *p);
|
||||
ASYNC_WORK_DEF(geo_xfer_work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evictor Threads
|
||||
|
||||
@@ -14,10 +14,7 @@ internal U128
|
||||
hs_hash_from_data(String8 data)
|
||||
{
|
||||
U128 u128 = {0};
|
||||
if(data.size != 0)
|
||||
{
|
||||
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
|
||||
}
|
||||
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
|
||||
return u128;
|
||||
}
|
||||
|
||||
@@ -299,6 +296,7 @@ hs_data_from_hash(HS_Scope *scope, U128 hash)
|
||||
internal void
|
||||
hs_evictor_thread__entry_point(void *p)
|
||||
{
|
||||
ThreadNameF("[hs] evictor thread");
|
||||
for(;;)
|
||||
{
|
||||
for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1)
|
||||
|
||||
@@ -306,7 +306,8 @@ typedef enum RDI_LanguageEnum
|
||||
RDI_Language_NULL = 0,
|
||||
RDI_Language_C = 1,
|
||||
RDI_Language_CPlusPlus = 2,
|
||||
RDI_Language_COUNT = 3,
|
||||
RDI_Language_Masm = 3,
|
||||
RDI_Language_COUNT = 4,
|
||||
} RDI_LanguageEnum;
|
||||
|
||||
typedef RDI_U16 RDI_TypeKind;
|
||||
@@ -367,6 +368,7 @@ RDI_TypeKind_IncompleteClass = 0x2007,
|
||||
RDI_TypeKind_IncompleteEnum = 0x2008,
|
||||
RDI_TypeKind_Bitfield = 0xF000,
|
||||
RDI_TypeKind_Variadic = 0xF001,
|
||||
RDI_TypeKind_Count = 0xF002,
|
||||
RDI_TypeKind_FirstBuiltIn = RDI_TypeKind_Void,
|
||||
RDI_TypeKind_LastBuiltIn = RDI_TypeKind_ComplexF128,
|
||||
RDI_TypeKind_FirstConstructed = RDI_TypeKind_Modifier,
|
||||
@@ -587,6 +589,172 @@ X(NULL)\
|
||||
X(X86)\
|
||||
X(X64)\
|
||||
|
||||
#define RDI_RegCodeX86_XList \
|
||||
X(nil, 0)\
|
||||
X(eax, 1)\
|
||||
X(ecx, 2)\
|
||||
X(edx, 3)\
|
||||
X(ebx, 4)\
|
||||
X(esp, 5)\
|
||||
X(ebp, 6)\
|
||||
X(esi, 7)\
|
||||
X(edi, 8)\
|
||||
X(fsbase, 9)\
|
||||
X(gsbase, 10)\
|
||||
X(eflags, 11)\
|
||||
X(eip, 12)\
|
||||
X(dr0, 13)\
|
||||
X(dr1, 14)\
|
||||
X(dr2, 15)\
|
||||
X(dr3, 16)\
|
||||
X(dr4, 17)\
|
||||
X(dr5, 18)\
|
||||
X(dr6, 19)\
|
||||
X(dr7, 20)\
|
||||
X(fpr0, 21)\
|
||||
X(fpr1, 22)\
|
||||
X(fpr2, 23)\
|
||||
X(fpr3, 24)\
|
||||
X(fpr4, 25)\
|
||||
X(fpr5, 26)\
|
||||
X(fpr6, 27)\
|
||||
X(fpr7, 28)\
|
||||
X(st0, 29)\
|
||||
X(st1, 30)\
|
||||
X(st2, 31)\
|
||||
X(st3, 32)\
|
||||
X(st4, 33)\
|
||||
X(st5, 34)\
|
||||
X(st6, 35)\
|
||||
X(st7, 36)\
|
||||
X(fcw, 37)\
|
||||
X(fsw, 38)\
|
||||
X(ftw, 39)\
|
||||
X(fop, 40)\
|
||||
X(fcs, 41)\
|
||||
X(fds, 42)\
|
||||
X(fip, 43)\
|
||||
X(fdp, 44)\
|
||||
X(mxcsr, 45)\
|
||||
X(mxcsr_mask, 46)\
|
||||
X(ss, 47)\
|
||||
X(cs, 48)\
|
||||
X(ds, 49)\
|
||||
X(es, 50)\
|
||||
X(fs, 51)\
|
||||
X(gs, 52)\
|
||||
X(ymm0, 53)\
|
||||
X(ymm1, 54)\
|
||||
X(ymm2, 55)\
|
||||
X(ymm3, 56)\
|
||||
X(ymm4, 57)\
|
||||
X(ymm5, 58)\
|
||||
X(ymm6, 59)\
|
||||
X(ymm7, 60)\
|
||||
|
||||
#define RDI_RegCodeX64_XList \
|
||||
X(nil, 0)\
|
||||
X(rax, 1)\
|
||||
X(rcx, 2)\
|
||||
X(rdx, 3)\
|
||||
X(rbx, 4)\
|
||||
X(rsp, 5)\
|
||||
X(rbp, 6)\
|
||||
X(rsi, 7)\
|
||||
X(rdi, 8)\
|
||||
X(r8, 9)\
|
||||
X(r9, 10)\
|
||||
X(r10, 11)\
|
||||
X(r11, 12)\
|
||||
X(r12, 13)\
|
||||
X(r13, 14)\
|
||||
X(r14, 15)\
|
||||
X(r15, 16)\
|
||||
X(es, 17)\
|
||||
X(cs, 18)\
|
||||
X(ss, 19)\
|
||||
X(ds, 20)\
|
||||
X(fs, 21)\
|
||||
X(gs, 22)\
|
||||
X(rip, 23)\
|
||||
X(rflags, 24)\
|
||||
X(dr0, 25)\
|
||||
X(dr1, 26)\
|
||||
X(dr2, 27)\
|
||||
X(dr3, 28)\
|
||||
X(dr4, 29)\
|
||||
X(dr5, 30)\
|
||||
X(dr6, 31)\
|
||||
X(dr7, 32)\
|
||||
X(st0, 33)\
|
||||
X(st1, 34)\
|
||||
X(st2, 35)\
|
||||
X(st3, 36)\
|
||||
X(st4, 37)\
|
||||
X(st5, 38)\
|
||||
X(st6, 39)\
|
||||
X(st7, 40)\
|
||||
X(fpr0, 41)\
|
||||
X(fpr1, 42)\
|
||||
X(fpr2, 43)\
|
||||
X(fpr3, 44)\
|
||||
X(fpr4, 45)\
|
||||
X(fpr5, 46)\
|
||||
X(fpr6, 47)\
|
||||
X(fpr7, 48)\
|
||||
X(zmm0, 49)\
|
||||
X(zmm1, 50)\
|
||||
X(zmm2, 51)\
|
||||
X(zmm3, 52)\
|
||||
X(zmm4, 53)\
|
||||
X(zmm5, 54)\
|
||||
X(zmm6, 55)\
|
||||
X(zmm7, 56)\
|
||||
X(zmm8, 57)\
|
||||
X(zmm9, 58)\
|
||||
X(zmm10, 59)\
|
||||
X(zmm11, 60)\
|
||||
X(zmm12, 61)\
|
||||
X(zmm13, 62)\
|
||||
X(zmm14, 63)\
|
||||
X(zmm15, 64)\
|
||||
X(zmm16, 65)\
|
||||
X(zmm17, 66)\
|
||||
X(zmm18, 67)\
|
||||
X(zmm19, 68)\
|
||||
X(zmm20, 69)\
|
||||
X(zmm21, 70)\
|
||||
X(zmm22, 71)\
|
||||
X(zmm23, 72)\
|
||||
X(zmm24, 73)\
|
||||
X(zmm25, 74)\
|
||||
X(zmm26, 75)\
|
||||
X(zmm27, 76)\
|
||||
X(zmm28, 77)\
|
||||
X(zmm29, 78)\
|
||||
X(zmm30, 79)\
|
||||
X(zmm31, 80)\
|
||||
X(k0, 81)\
|
||||
X(k1, 82)\
|
||||
X(k2, 83)\
|
||||
X(k3, 84)\
|
||||
X(k4, 85)\
|
||||
X(k5, 86)\
|
||||
X(k6, 87)\
|
||||
X(k7, 88)\
|
||||
X(mxcsr, 89)\
|
||||
X(fsbase, 90)\
|
||||
X(gsbase, 91)\
|
||||
X(fcw, 92)\
|
||||
X(fsw, 93)\
|
||||
X(ftw, 94)\
|
||||
X(fop, 95)\
|
||||
X(fcs, 96)\
|
||||
X(fds, 97)\
|
||||
X(fip, 98)\
|
||||
X(fdp, 99)\
|
||||
X(mxcsr_mask, 100)\
|
||||
|
||||
#define RDI_TopLevelInfo_XList \
|
||||
X(RDI_Arch, arch)\
|
||||
X(RDI_U32, exe_name_string_idx)\
|
||||
@@ -655,6 +823,7 @@ X(RDI_U32, line_map_voff_base_idx)\
|
||||
X(NULL)\
|
||||
X(C)\
|
||||
X(CPlusPlus)\
|
||||
X(Masm)\
|
||||
X(COUNT)\
|
||||
|
||||
#define RDI_TypeKind_XList \
|
||||
@@ -713,6 +882,7 @@ X(IncompleteClass)\
|
||||
X(IncompleteEnum)\
|
||||
X(Bitfield)\
|
||||
X(Variadic)\
|
||||
X(Count)\
|
||||
|
||||
#define RDI_TypeModifierFlags_XList \
|
||||
X(Const)\
|
||||
|
||||
@@ -303,9 +303,9 @@ rdi_line_info_idx_from_voff(RDI_ParsedLineTable *line_info, RDI_U64 voff)
|
||||
{
|
||||
RDI_U64 count = 0;
|
||||
RDI_U64 result = rdi_line_info_idx_range_from_voff(line_info, voff, &count);
|
||||
for(RDI_U64 idx = 0; idx < count && result+idx < line_info->count; idx += 1)
|
||||
for(RDI_S64 idx = count-1; idx >= 0; idx -= 1)
|
||||
{
|
||||
if(line_info->lines[result+idx].file_idx != 0)
|
||||
if(result + idx < line_info->count && line_info->lines[result+idx].file_idx != 0)
|
||||
{
|
||||
result += idx;
|
||||
break;
|
||||
|
||||
+82
-29
@@ -1129,7 +1129,7 @@ rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_So
|
||||
|
||||
//- rjf: fill output vmap entries
|
||||
RDI_U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry;
|
||||
RDI_VMapEntry *vmap = rdim_push_array_no_zero(arena, RDI_VMapEntry, vmap_count_raw + 1);
|
||||
RDI_VMapEntry *vmap = rdim_push_array(arena, RDI_VMapEntry, vmap_count_raw + 1);
|
||||
RDI_U32 vmap_entry_count_pass_1 = 0;
|
||||
{
|
||||
typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker;
|
||||
@@ -1345,11 +1345,11 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr
|
||||
// build new sort tasks for buckets with many elements
|
||||
{
|
||||
RDI_U64 write_idx = 0;
|
||||
for(U64 bucket_idx = 0; bucket_idx < 256; bucket_idx += 1)
|
||||
for(RDI_U64 bucket_idx = 0; bucket_idx < 256; bucket_idx += 1)
|
||||
{
|
||||
// rjf: write each chunk node's array into original array, detect if there is size left to sort
|
||||
RDI_U64 bucket_base_idx = write_idx;
|
||||
RDI_U64 max_size_left_to_sort = 0;
|
||||
RDI_U64 need_next_char_sort = 0;
|
||||
for(RDIM_BakeStringChunkNode *n = buckets[bucket_idx].first; n != 0; n = n->next)
|
||||
{
|
||||
rdim_memcpy(t->v+write_idx, n->v, sizeof(n->v[0])*n->count);
|
||||
@@ -1358,14 +1358,14 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr
|
||||
{
|
||||
if(n->v[idx].string.size > t->string_off+1)
|
||||
{
|
||||
max_size_left_to_sort = Max(max_size_left_to_sort, (n->v[idx].string.size - t->string_off+1));
|
||||
need_next_char_sort = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if any bucket has >1 element & has some amount of size left to sort, push new task for this
|
||||
// bucket's region in the array, and for remainder of keys
|
||||
if(buckets[bucket_idx].total_count > 1 && max_size_left_to_sort > 0)
|
||||
if(buckets[bucket_idx].total_count > 1 && need_next_char_sort)
|
||||
{
|
||||
SortTask *new_task = rdim_push_array(scratch.arena, SortTask, 1);
|
||||
RDIM_SLLQueuePush(first_task, last_task, new_task);
|
||||
@@ -1376,9 +1376,60 @@ rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStr
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
rdim_scratch_end(scratch);
|
||||
}
|
||||
|
||||
//- rjf: iterate sorted chunk node, remove duplicates, count # of duplicates
|
||||
RDI_U64 num_duplicates = 0;
|
||||
if(dst.first != 0)
|
||||
{
|
||||
RDI_U64 last_idx = 0;
|
||||
for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1)
|
||||
{
|
||||
if(rdim_str8_match(dst.first->v[last_idx].string, dst.first->v[idx].string, 0))
|
||||
{
|
||||
rdim_memzero_struct(&dst.first->v[idx]);
|
||||
num_duplicates += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_idx = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: iterate sorted chunk node, make non-empty elements contiguous
|
||||
if(num_duplicates != 0)
|
||||
{
|
||||
RDI_U64 last_idx = 0;
|
||||
for(RDI_U64 idx = 1; idx < dst.first->count; idx += 1)
|
||||
{
|
||||
if(last_idx == 0 &&
|
||||
dst.first->v[idx].string.RDIM_String8_SizeMember == 0 &&
|
||||
dst.first->v[idx].hash == 0)
|
||||
{
|
||||
last_idx = idx;
|
||||
}
|
||||
if(last_idx != 0 && dst.first->v[idx].string.RDIM_String8_SizeMember != 0)
|
||||
{
|
||||
rdim_memcpy_struct(&dst.first->v[last_idx], &dst.first->v[idx]);
|
||||
rdim_memzero_struct(&dst.first->v[idx]);
|
||||
last_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: pop extras
|
||||
if(num_duplicates != 0)
|
||||
{
|
||||
RDI_U64 arena_pos_pre_pop = rdim_arena_pos(arena);
|
||||
rdim_arena_pop_to(arena, arena_pos_pre_pop - num_duplicates*sizeof(dst.first->v[0]));
|
||||
dst.first->count -= num_duplicates;
|
||||
dst.first->cap -= num_duplicates;
|
||||
dst.total_count -= num_duplicates;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -1395,31 +1446,34 @@ rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *t
|
||||
RDI_PROC void
|
||||
rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map, RDI_U64 chunk_cap, RDIM_String8 string)
|
||||
{
|
||||
RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember);
|
||||
RDI_U64 slot_idx = hash%map_topology->slots_count;
|
||||
RDIM_BakeStringChunkList *slot = map->slots[slot_idx];
|
||||
if(slot == 0)
|
||||
if(string.RDIM_String8_SizeMember != 0)
|
||||
{
|
||||
slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeStringChunkList, 1);
|
||||
}
|
||||
RDI_S32 is_duplicate = 0;
|
||||
for(RDIM_BakeStringChunkNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < n->count; idx += 1)
|
||||
RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember);
|
||||
RDI_U64 slot_idx = hash%map_topology->slots_count;
|
||||
RDIM_BakeStringChunkList *slot = map->slots[slot_idx];
|
||||
if(slot == 0)
|
||||
{
|
||||
if(rdim_str8_match(n->v[idx].string, string, 0))
|
||||
slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeStringChunkList, 1);
|
||||
}
|
||||
RDI_S32 is_duplicate = 0;
|
||||
for(RDIM_BakeStringChunkNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
for(RDI_U64 idx = 0; idx < n->count; idx += 1)
|
||||
{
|
||||
is_duplicate = 1;
|
||||
goto break_all;
|
||||
if(rdim_str8_match(n->v[idx].string, string, 0))
|
||||
{
|
||||
is_duplicate = 1;
|
||||
goto break_all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break_all:;
|
||||
if(!is_duplicate)
|
||||
{
|
||||
RDIM_BakeString *bstr = rdim_bake_string_chunk_list_push(arena, slot, chunk_cap);
|
||||
bstr->string = string;
|
||||
bstr->hash = hash;
|
||||
break_all:;
|
||||
if(!is_duplicate)
|
||||
{
|
||||
RDIM_BakeString *bstr = rdim_bake_string_chunk_list_push(arena, slot, chunk_cap);
|
||||
bstr->string = string;
|
||||
bstr->hash = hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3057,7 +3111,7 @@ rdim_bake_global_vmap(RDIM_Arena *arena, RDIM_SymbolChunkList *src)
|
||||
RDIM_Temp scratch = rdim_scratch_begin(&arena, 1);
|
||||
|
||||
//- rjf: allocate keys/markers
|
||||
RDI_U64 marker_count = src->total_count*2;
|
||||
RDI_U64 marker_count = src->total_count*2 + 2;
|
||||
RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count);
|
||||
RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count);
|
||||
|
||||
@@ -3427,7 +3481,7 @@ rdim_bake_inline_sites(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM
|
||||
{
|
||||
RDIM_InlineSiteBakeResult result = {0};
|
||||
{
|
||||
result.inline_sites_count = src->total_count;
|
||||
result.inline_sites_count = src->total_count+1;
|
||||
result.inline_sites = rdim_push_array(arena, RDI_InlineSite, result.inline_sites_count+1);
|
||||
RDI_U64 dst_idx = 1;
|
||||
for(RDIM_InlineSiteChunkNode *n = src->first; n != 0; n = n->next)
|
||||
@@ -3510,7 +3564,6 @@ rdim_bake_file_paths(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_B
|
||||
RDI_PROC RDIM_StringBakeResult
|
||||
rdim_bake_strings(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings)
|
||||
{
|
||||
RDIM_BakeSectionList sections = {0};
|
||||
RDI_U32 *str_offs = rdim_push_array_no_zero(arena, RDI_U32, strings->total_count + 1);
|
||||
RDI_U32 off_cursor = 0;
|
||||
{
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
push_cstr(Arena *arena, String8 str)
|
||||
{
|
||||
U64 buffer_size = str.size + 1;
|
||||
U8 *buffer = push_array_no_zero(arena, U8, buffer_size);
|
||||
MemoryCopy(buffer, str.str, str.size);
|
||||
buffer[str.size] = 0;
|
||||
String8 result = str8(buffer, buffer_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32 *
|
||||
push_u32(Arena *arena, U32 value)
|
||||
{
|
||||
U32 *result = push_array_no_zero(arena, U32, 1);
|
||||
*result = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64 *
|
||||
push_u64(Arena *arena, U64 value)
|
||||
{
|
||||
U64 *result = push_array_no_zero(arena, U64, 1);
|
||||
*result = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U32 *
|
||||
push_array_copy_u32(Arena *arena, U32 *v, U64 count)
|
||||
{
|
||||
U32 *result = push_array_no_zero(arena, U32, count);
|
||||
MemoryCopyTyped(result, v, count);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64 *
|
||||
push_array_copy_u64(Arena *arena, U64 *v, U64 count)
|
||||
{
|
||||
U64 *result = push_array_no_zero(arena, U64, count);
|
||||
MemoryCopyTyped(result, v, count);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64 **
|
||||
push_matrix_u64(Arena *arena, U64 rows, U64 columns)
|
||||
{
|
||||
U64 **result = push_array_no_zero(arena, U64 *, rows);
|
||||
for (U64 row_idx = 0; row_idx < rows; row_idx += 1) {
|
||||
result[row_idx] = push_array(arena, U64, columns);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Arena **
|
||||
alloc_fixed_size_arena_array(Arena *arena, U64 count, U64 res, U64 cmt)
|
||||
{
|
||||
U64 data_size = sizeof(count) + sizeof(Arena *) * count;
|
||||
U8 *data = push_array_no_zero(arena, U8, data_size);
|
||||
U64 *count_ptr = (U64 *)data;
|
||||
Arena **arr = (Arena **)(count_ptr + 1);
|
||||
*count_ptr = count;
|
||||
|
||||
ArenaParams params = {0};
|
||||
params.reserve_size = res;
|
||||
params.commit_size = cmt;
|
||||
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
Arena *fixed_arena = arena_alloc_(¶ms);
|
||||
arr[i] = fixed_arena;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal void
|
||||
release_arena_array(Arena **arr)
|
||||
{
|
||||
U64 *count_ptr = (U64 *)arr - 1;
|
||||
U64 count = *count_ptr;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
arena_release(arr[i]);
|
||||
arr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
internal U32 * push_u32(Arena *arena, U32 value);
|
||||
internal U64 * push_u64(Arena *arena, U64 value);
|
||||
internal U32 * push_array_copy_u32(Arena *arena, U32 *v, U64 count);
|
||||
internal U64 * push_array_copy_u64(Arena *arena, U64 *v, U64 count);
|
||||
internal U64 ** push_matrix_u64(Arena *arena, U64 rows, U64 columns);
|
||||
internal String8 push_cstr(Arena *arena, String8 str);
|
||||
|
||||
internal Arena ** alloc_fixed_size_arena_array(Arena *arena, U64 count, U64 res, U64 cmt);
|
||||
internal void release_arena_array(Arena **arr);
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
void_list_count_nodes(VoidNode *head)
|
||||
{
|
||||
U64 node_count = 0;
|
||||
for (VoidNode *curr = head; curr != 0; curr = curr->next) {
|
||||
++node_count;
|
||||
}
|
||||
return node_count;
|
||||
}
|
||||
|
||||
internal void
|
||||
void_node_concat(VoidNode **head, VoidNode *node)
|
||||
{
|
||||
Assert(*head != node);
|
||||
node->next = *head;
|
||||
*head = node;
|
||||
}
|
||||
|
||||
internal void
|
||||
void_node_concat_atomic(VoidNode **head, VoidNode *node)
|
||||
{
|
||||
Assert(*head != node);
|
||||
node->next = ins_atomic_ptr_eval_assign(head, node);
|
||||
}
|
||||
|
||||
internal U64Node *
|
||||
u64_list_push(Arena *arena, U64List *list, U64 data)
|
||||
{
|
||||
U64Node *n = push_array(arena, U64Node, 1);
|
||||
n->next = 0;
|
||||
n->data = data;
|
||||
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
++list->count;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
internal void
|
||||
u64_list_concat_in_place(U64List *list, U64List *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal U64Array
|
||||
u64_array_from_list(Arena *arena, U64List *list)
|
||||
{
|
||||
U64Array result;
|
||||
result.count = 0;
|
||||
result.v = push_array(arena, U64, list->count);
|
||||
for (U64Node *n = list->first; n != NULL; n = n->next) {
|
||||
result.v[result.count++] = n->data;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
u32_array_sort(U64 count, U32 *v)
|
||||
{
|
||||
radsort(v, count, u32_is_before);
|
||||
}
|
||||
|
||||
internal void
|
||||
u32_pair_radix_sort(U64 count, PairU32 *arr)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
PairU32 *temp = push_array(scratch.arena, PairU32, count);
|
||||
|
||||
const U64 bit_count0 = 11;
|
||||
const U64 bit_count1 = 11;
|
||||
const U64 bit_count2 = 10;
|
||||
|
||||
U32 *count0 = push_array(scratch.arena, U32, (1 << bit_count0));
|
||||
U32 *count1 = push_array(scratch.arena, U32, (1 << bit_count1));
|
||||
U32 *count2 = push_array(scratch.arena, U32, (1 << bit_count2));
|
||||
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
U32 digit0 = (arr[i].v0 >> 0 ) % (1 << bit_count0);
|
||||
U32 digit1 = (arr[i].v0 >> bit_count0) % (1 << bit_count1);
|
||||
U32 digit2 = (arr[i].v0 >> bit_count1) % (1 << bit_count2);
|
||||
|
||||
++count0[digit0];
|
||||
++count1[digit1];
|
||||
++count2[digit2];
|
||||
}
|
||||
|
||||
counts_to_offsets_array_u32((1 << bit_count0), count0);
|
||||
counts_to_offsets_array_u32((1 << bit_count1), count1);
|
||||
counts_to_offsets_array_u32((1 << bit_count2), count2);
|
||||
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
U32 digit0 = (arr[i].v0 >> 0) % (1 << bit_count0);
|
||||
temp[count0[digit0]++] = arr[i];
|
||||
}
|
||||
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
U32 digit1 = (temp[i].v0 >> bit_count0) % (1 << bit_count1);
|
||||
arr[count1[digit1]++] = temp[i];
|
||||
}
|
||||
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
U32 digit2 = (arr[i].v0 >> bit_count1) % (1 << bit_count2);
|
||||
temp[count2[digit2]++] = arr[i];
|
||||
}
|
||||
|
||||
MemoryCopyTyped(arr, temp, count);
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal B32
|
||||
u32_array_compare(U32Array a, U32Array b)
|
||||
{
|
||||
B32 are_equal = 0;
|
||||
if (a.count == b.count) {
|
||||
int cmp = MemoryCompare(a.v, b.v, sizeof(a.v[0]) * a.count);
|
||||
are_equal = (cmp == 0);
|
||||
}
|
||||
return are_equal;
|
||||
}
|
||||
|
||||
internal U64Array
|
||||
u64_array_remove_duplicates(Arena *arena, U64Array in)
|
||||
{
|
||||
U64Array result;
|
||||
result.count = 0;
|
||||
result.v = push_array(arena, U64, in.count);
|
||||
|
||||
for (U64 i = 1; i < in.count; ++i) {
|
||||
B32 is_unique = in.v[i - 1] != in.v[i];
|
||||
if (is_unique) {
|
||||
result.v[result.count++] = in.v[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (in.count > 0 && result.count > 0) {
|
||||
B32 is_unique = result.v[result.count - 1] != in.v[in.count - 1];
|
||||
if (is_unique) {
|
||||
result.v[result.count++] = in.v[in.count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
U64 slack_size = (in.count - result.count) * sizeof(result.v[0]);
|
||||
arena_pop(arena, slack_size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
sum_array_u64(U64 count, U64 *v)
|
||||
{
|
||||
U64 result = 0;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
result += v[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
sum_matrix_u64(U64 rows, U64 cols, U64 **v)
|
||||
{
|
||||
U64 result = 0;
|
||||
for (U64 i = 0; i < rows; ++i) {
|
||||
result += sum_array_u64(cols, v[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
max_array_u64(U64 count, U64 *v)
|
||||
{
|
||||
U64 result = 0;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
result = Max(v[i], result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
min_array_u64(U64 count, U64 *v)
|
||||
{
|
||||
U64 result = max_U64;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
result = Min(v[i], result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
counts_to_offsets_array_u32(U64 count, U32 *arr)
|
||||
{
|
||||
U32 next_offset = 0;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
U32 current_offset = next_offset;
|
||||
next_offset += arr[i];
|
||||
arr[i] = current_offset;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
counts_to_offsets_array_u64(U64 count, U64 *arr)
|
||||
{
|
||||
U64 next_offset = 0;
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
U64 current_offset = next_offset;
|
||||
next_offset += arr[i];
|
||||
arr[i] = current_offset;
|
||||
}
|
||||
}
|
||||
|
||||
internal U32 *
|
||||
offsets_from_counts_array_u32(Arena *arena, U32 *v, U64 count)
|
||||
{
|
||||
U32 *result = push_array_copy_u32(arena, v, count);
|
||||
counts_to_offsets_array_u32(count, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64 *
|
||||
offsets_from_counts_array_u64(Arena *arena, U64 *v, U64 count)
|
||||
{
|
||||
U64 *result = push_array_copy_u64(arena, v, count);
|
||||
counts_to_offsets_array_u64(count, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct U32Array
|
||||
{
|
||||
U64 count;
|
||||
U32 *v;
|
||||
} U32Array;
|
||||
|
||||
typedef struct U64Array
|
||||
{
|
||||
U64 count;
|
||||
U64 *v;
|
||||
} U64Array;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 count;
|
||||
U128 *v;
|
||||
} U128Array;
|
||||
|
||||
typedef struct U64Node
|
||||
{
|
||||
struct U64Node *next;
|
||||
U64 data;
|
||||
} U64Node;
|
||||
|
||||
typedef struct U64List
|
||||
{
|
||||
U64 count;
|
||||
U64Node *first;
|
||||
U64Node *last;
|
||||
} U64List;
|
||||
|
||||
typedef struct VoidNode
|
||||
{
|
||||
struct VoidNode *next;
|
||||
void *v;
|
||||
} VoidNode;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64Node * u64_list_push(Arena *arena, U64List *list, U64 data);
|
||||
internal void u64_list_concat_in_place(U64List *list, U64List *to_concat);
|
||||
internal U64Array u64_array_from_list(Arena *arena, U64List *list);
|
||||
|
||||
internal U64Array u64_array_remove_duplicates(Arena *arena, U64Array in);
|
||||
|
||||
internal void u32_array_sort(U64 count, U32 *v);
|
||||
internal B32 u32_array_compare(U32Array a, U32Array b);
|
||||
|
||||
internal U64 sum_array_u64(U64 count, U64 *v);
|
||||
internal U64 max_array_u64(U64 count, U64 *v);
|
||||
internal U64 min_array_u64(U64 count, U64 *v);
|
||||
|
||||
internal void counts_to_offsets_array_u32(U64 count, U32 *arr);
|
||||
internal void counts_to_offsets_array_u64(U64 count, U64 *arr);
|
||||
|
||||
internal U32 * offsets_from_counts_array_u32(Arena *arena, U32 *v, U64 count);
|
||||
internal U64 * offsets_from_counts_array_u64(Arena *arena, U64 *v, U64 count);
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32Array
|
||||
bit_array_init32(Arena *arena, U64 word_count)
|
||||
{
|
||||
U32Array result;
|
||||
result.count = CeilIntegerDiv(word_count, 32);
|
||||
result.v = push_array(arena, U32, word_count);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
bit_array_scan_left_to_right32(U32Array bit_array, U64 lo, U64 hi, B32 state)
|
||||
{
|
||||
Assert(lo < bit_array.count*32);
|
||||
Assert(hi <= bit_array.count*32);
|
||||
Assert(lo <= hi);
|
||||
Assert(state == 0 || state == 1);
|
||||
|
||||
U64 word_lo = lo / 32;
|
||||
U64 word_hi = CeilIntegerDiv(hi, 32) - 1;
|
||||
|
||||
U64 word_idx = word_lo;
|
||||
U64 bit_idx = 0;
|
||||
|
||||
U64 scan_count = hi - lo;
|
||||
if (scan_count < 32) {
|
||||
U64 bit_lo = lo % 32;
|
||||
U64 bit_hi = hi % 32;
|
||||
U64 word = bit_array.v[word_idx];
|
||||
word ^= state - 1;
|
||||
word &= (1U << bit_hi) - (1U << bit_lo);
|
||||
if (word) {
|
||||
bit_idx = ctz32(word);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
U32 first_word = bit_array.v[word_idx];
|
||||
first_word ^= state - 1;
|
||||
first_word &= ~0u << (lo % 32);
|
||||
if (first_word) {
|
||||
bit_idx = ctz32(first_word);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (word_idx += 1; word_idx < word_hi; word_idx += 1) {
|
||||
U32 word = bit_array.v[word_idx];
|
||||
word ^= state - 1;
|
||||
if (word != 0) {
|
||||
bit_idx = ctz32(word);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
U64 bit_hi = hi - (word_idx * 32);
|
||||
U32 last_word = bit_array.v[word_idx];
|
||||
last_word ^= state - 1;
|
||||
last_word &= (1 << bit_hi) - 1;
|
||||
if (last_word) {
|
||||
bit_idx = ctz32(last_word);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
word_idx = 0;
|
||||
bit_idx = max_U32;
|
||||
|
||||
exit:;
|
||||
|
||||
U64 result = word_idx * 32 + bit_idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
bit_array_scan_right_to_left32(U32Array bit_array, U64 lo, U64 hi, B32 state)
|
||||
{
|
||||
Assert(lo <= hi);
|
||||
Assert(state == 0 || state == 1);
|
||||
|
||||
S64 word_lo = lo / 32;
|
||||
S64 word_hi = CeilIntegerDiv(hi, 32) - 1;
|
||||
|
||||
S64 word_idx = word_hi;
|
||||
S64 bit_idx = -1;
|
||||
|
||||
U64 scan_count = hi - lo;
|
||||
if (scan_count < 32) {
|
||||
S64 bit_lo = lo % 32;
|
||||
S64 bit_hi = bit_lo + scan_count;
|
||||
U32 word = bit_array.v[word_idx];
|
||||
for (bit_idx = bit_hi; bit_idx >= bit_lo; bit_idx -= 1) {
|
||||
U32 bit = ExtractBit(word, bit_idx);
|
||||
if (bit == state) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
U32 last_word = bit_array.v[word_idx];
|
||||
S64 bit_hi = hi % 32;
|
||||
for (bit_idx = bit_hi; bit_idx >= 0; bit_idx -= 1) {
|
||||
U32 bit = ExtractBit(last_word, bit_idx);
|
||||
if (bit == state) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
for (word_idx -= 1; word_idx > word_lo; word_idx -= 1) {
|
||||
U32 word = bit_array.v[word_idx];
|
||||
for (bit_idx = 32 - 1; bit_idx >= 0; bit_idx -= 1) {
|
||||
U32 bit = ExtractBit(word, bit_idx);
|
||||
if (bit == state) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U32 first_word = bit_array.v[word_idx];
|
||||
S64 bit_lo = lo % 32;
|
||||
for (bit_idx = 32 - 1; bit_idx >= bit_lo; bit_idx -= 1) {
|
||||
U32 bit = ExtractBit(first_word, bit_idx);
|
||||
if (bit == state) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
word_idx = 0;
|
||||
bit_idx = max_U32;
|
||||
|
||||
exit:;
|
||||
|
||||
S64 result_s64 = word_idx * 32 + bit_idx;
|
||||
U64 result_u64 = (U64)result_s64;
|
||||
return result_u64;
|
||||
}
|
||||
|
||||
internal Rng1U64
|
||||
bit_array_scan_left_to_right32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count)
|
||||
{
|
||||
Rng1U64 result = rng_1u64(max_U64, max_U64);
|
||||
|
||||
U64 curr_count = 0, rover = lo;
|
||||
while (curr_count < in_row_count) {
|
||||
rover = bit_array_scan_left_to_right32(bit_array, rover, hi, state);
|
||||
|
||||
// no more bits in range
|
||||
if (rover >= hi) {
|
||||
break;
|
||||
}
|
||||
|
||||
// set first match
|
||||
if (result.v[0] == max_U64) {
|
||||
result = rng_1u64(rover, rover);
|
||||
continue;
|
||||
}
|
||||
|
||||
// reset on non-contiguous range
|
||||
B32 is_bit_index_not_adjoined = (result.v[0] + 1 < rover);
|
||||
if (is_bit_index_not_adjoined) {
|
||||
curr_count = 0;
|
||||
result = rng_1u64(max_U64, max_U64);
|
||||
continue;
|
||||
}
|
||||
|
||||
// advance
|
||||
result.v[1] = rover;
|
||||
curr_count -= 1;
|
||||
}
|
||||
|
||||
// did we allocate enough bits?
|
||||
if (curr_count != in_row_count) {
|
||||
result = rng_1u64(max_U64, max_U64);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Rng1U64
|
||||
bit_array_scan_right_to_left32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count)
|
||||
{
|
||||
Rng1U64 result = rng_1u64(max_U64, max_U64);
|
||||
|
||||
U64 curr_count = 0, rover = lo;
|
||||
while (curr_count < in_row_count) {
|
||||
rover = bit_array_scan_right_to_left32(bit_array, lo, rover, state);
|
||||
|
||||
// no more bits in range
|
||||
if (rover >= hi) {
|
||||
break;
|
||||
}
|
||||
|
||||
// set first match
|
||||
if (result.v[0] == max_U64) {
|
||||
result = rng_1u64(rover, rover);
|
||||
continue;
|
||||
}
|
||||
|
||||
// reset on non-contiguous range
|
||||
B32 is_bit_index_not_adjoined = (result.v[0] + 1 < rover);
|
||||
if (is_bit_index_not_adjoined) {
|
||||
curr_count = 0;
|
||||
result = rng_1u64(max_U64, max_U64);
|
||||
continue;
|
||||
}
|
||||
|
||||
// advance
|
||||
result.v[0] = rover;
|
||||
curr_count -= 1;
|
||||
}
|
||||
|
||||
// did we allocate enough bits?
|
||||
if (curr_count != in_row_count) {
|
||||
result = rng_1u64(max_U64, max_U64);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
bit_array_find_next_unset_bit32(U32Array bit_array)
|
||||
{
|
||||
U64 result = bit_array_scan_left_to_right32(bit_array, 0, bit_array.count*32, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
bit_array_find_next_set_bit32(U32Array bit_array)
|
||||
{
|
||||
U64 result = bit_array_scan_left_to_right32(bit_array, 0, bit_array.count*32, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
bit_array_set_bit32(U32Array bit_array, U64 idx, B32 state)
|
||||
{
|
||||
Assert(idx < bit_array.count*32);
|
||||
U64 word_idx = idx / 32;
|
||||
U64 bit_idx = idx % 32;
|
||||
if (state) {
|
||||
bit_array.v[word_idx] |= (1 << bit_idx);
|
||||
} else {
|
||||
bit_array.v[word_idx] &= ~(1 << bit_idx);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
bit_array_set_bit_range32(U32Array bit_array, Rng1U64 range, B32 state)
|
||||
{
|
||||
for (U64 idx = range.min ; idx < range.max; idx += 1) {
|
||||
bit_array_set_bit32(bit_array, idx, state);
|
||||
}
|
||||
}
|
||||
|
||||
internal U32
|
||||
bit_array_get_bit32(U32Array bit_array, U64 idx)
|
||||
{
|
||||
Assert(idx < bit_array.count*32);
|
||||
U64 word_idx = idx / 32;
|
||||
U64 bit_idx = idx % 32;
|
||||
U32 bit = (bit_array.v[word_idx] & (1 << bit_idx)) >> bit_idx;
|
||||
return bit;
|
||||
}
|
||||
|
||||
internal B32
|
||||
bit_array_is_bit_set(U32Array bit_arr, U64 bit_pos)
|
||||
{
|
||||
U64 word_idx = bit_pos / 32;
|
||||
Assert(word_idx < bit_arr.count);
|
||||
U32 word = bit_arr.v[word_idx];
|
||||
U64 bit_idx = bit_pos % 32;
|
||||
B32 is_set = !!(word & (1 << bit_idx));
|
||||
return is_set;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
internal U32Array bit_array_init32(Arena *arena, U64 word_count);
|
||||
internal U64 bit_array_scan_left_to_right32(U32Array bit_array, U64 lo, U64 hi, B32 state);
|
||||
internal U64 bit_array_scan_right_to_left32(U32Array bit_array, U64 lo, U64 hi, B32 state);
|
||||
internal Rng1U64 bit_array_scan_left_to_right32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count);
|
||||
internal Rng1U64 bit_array_scan_right_to_left32_contiguous(U32Array bit_array, U64 lo, U64 hi, B32 state, U64 in_row_count);
|
||||
internal B32 byte_scan_right_to_left(U8 *start, U8 *opl, U8 byte, U64 *offset_out);
|
||||
internal U64 bit_array_find_next_unset_bit32(U32Array bit_array);
|
||||
internal U64 bit_array_find_next_set_bit32(U32Array bit_array);
|
||||
internal void bit_array_set_bit32(U32Array bit_array, U64 idx, B32 state);
|
||||
internal void bit_array_set_bit_range32(U32Array bit_array, Rng1U64 range, B32 state);
|
||||
internal U32 bit_array_get_bit32(U32Array bit_array, U64 idx);
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmacro-redefined"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (push, 0)
|
||||
#endif
|
||||
|
||||
#include "../third_party_ext/blake3/c/blake3_portable.c"
|
||||
|
||||
#if defined(_M_AMD64) || defined(__x86_64__)
|
||||
|
||||
#define round_fn sse2_round_fn
|
||||
#define compress_pre sse2_compress_pre
|
||||
|
||||
#include "../third_party_ext/blake3/c/blake3_sse2.c"
|
||||
|
||||
#define loadu sse41_loadu
|
||||
#define storeu sse41_storeu
|
||||
#define addv sse41_addv
|
||||
#define xorv sse41_xorv
|
||||
#define set1 sse41_set1
|
||||
#define set4 sse41_set4
|
||||
#define rot16 sse41_rot16
|
||||
#define rot12 sse41_rot12
|
||||
#define rot8 sse41_rot8
|
||||
#define rot7 sse41_rot7
|
||||
#define g1 sse41_g1
|
||||
#define g2 sse41_g2
|
||||
#define diagonalize sse41_diagonalize
|
||||
#define undiagonalize sse41_undiagonalize
|
||||
#define compress_pre sse41_compress_pre
|
||||
#define round_fn sse41_round_fn
|
||||
#define transpose_vecs sse41_transpose_vecs
|
||||
#define transpose_msg_vecs sse41_transpose_msg_vecs
|
||||
#define load_counters sse41_load_counters
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute push(__attribute__((target("sse4.1"))), apply_to=function)
|
||||
#endif
|
||||
#include "../third_party_ext/blake3/c/blake3_sse41.c"
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute pop
|
||||
#endif
|
||||
|
||||
#define loadu avx2_loadu
|
||||
#define storeu avx2_storeu
|
||||
#define addv avx2_addv
|
||||
#define xorv avx2_xorv
|
||||
#define set1 avx2_set1
|
||||
#define rot7 avx2_rot7
|
||||
#define rot8 avx2_rot8
|
||||
#define rot12 avx2_rot12
|
||||
#define rot16 avx2_rot16
|
||||
#define round_fn avx2_round_fn
|
||||
#define transpose_vecs avx2_transpose_vecs
|
||||
#define transpose_msg_vecs avx2_transpose_msg_vecs
|
||||
#define load_counters avx2_load_counters
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute push(__attribute__((target("avx2"))), apply_to=function)
|
||||
#endif
|
||||
#include "../third_party_ext/blake3/c/blake3_avx2.c"
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute pop
|
||||
#endif
|
||||
|
||||
#define set4 avx512_set4
|
||||
#define g1 avx512_g1
|
||||
#define g2 avx512_g2
|
||||
#define diagonalize avx512_diagonalize
|
||||
#define undiagonalize avx512_undiagonalize
|
||||
#define compress_pre avx512_compress_pre
|
||||
#define transpose_vecs avx512_transpose_vecs
|
||||
#define transpose_msg_vecs avx512_transpose_msg_vecs
|
||||
#define load_counters avx512_load_counters
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute push(__attribute__((target("avx512f,avx512vl"))), apply_to=function)
|
||||
#endif
|
||||
#include "../third_party_ext/blake3/c/blake3_avx512.c"
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) || defined(_M_ARM64)
|
||||
#include "../third_party_ext/blake3/c/blake3_neon.c"
|
||||
#endif
|
||||
|
||||
#include "../third_party_ext/blake3/c/blake3_dispatch.c"
|
||||
#include "../third_party_ext/blake3/c/blake3.c"
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning (pop, 0)
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__) && defined(__x86_64__)
|
||||
# if defined(__IMMINTRIN_H)
|
||||
# error "include this header before immintrin.h / x86intrin.h / intrin.h"
|
||||
# endif
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wreserved-macro-identifier"
|
||||
# pragma push_macro("__AVX__")
|
||||
# pragma push_macro("__AVX2__")
|
||||
# pragma push_macro("__SSE4_1__")
|
||||
# pragma push_macro("__AVX512F__")
|
||||
# pragma push_macro("__AVX512VL__")
|
||||
# define __AVX__ 1
|
||||
# define __AVX2__ 1
|
||||
# define __SSE4_1__ 1
|
||||
# define __AVX512F__ 1
|
||||
# define __AVX512VL__ 1
|
||||
# include <immintrin.h>
|
||||
# pragma pop_macro("__AVX512VL__")
|
||||
# pragma pop_macro("__AVX512F__")
|
||||
# pragma pop_macro("__SSE4_1__")
|
||||
# pragma pop_macro("__AVX2__")
|
||||
# pragma pop_macro("__AVX__")
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "../third_party_ext/blake3/c/blake3.h"
|
||||
|
||||
static void
|
||||
blake3(void* out, size_t outlen, void* in, size_t inlen)
|
||||
{
|
||||
blake3_hasher hasher;
|
||||
blake3_hasher_init(&hasher);
|
||||
blake3_hasher_update(&hasher, in, inlen);
|
||||
blake3_hasher_finalize(&hasher, (uint8_t*)out, outlen);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "../third_party_ext/blake3/blake3_portable.c"
|
||||
|
||||
#if defined(__aarch64__) || defined(_M_ARM64)
|
||||
#include "../third_party_ext/blake3/blake3_neon.c"
|
||||
#endif
|
||||
|
||||
#include "../third_party_ext/blake3/blake3_dispatch.c"
|
||||
#include "../third_party_ext/blake3/blake3.c"
|
||||
|
||||
#pragma comment (lib, "blake3")
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_BLAKE3_H
|
||||
#define BASE_BLAKE3_H
|
||||
|
||||
#include "../third_party_ext/blake3/blake3.h"
|
||||
|
||||
static void
|
||||
blake3(void* out, size_t outlen, void* in, size_t inlen)
|
||||
{
|
||||
blake3_hasher hasher;
|
||||
blake3_hasher_init(&hasher);
|
||||
blake3_hasher_update(&hasher, in, inlen);
|
||||
blake3_hasher_finalize(&hasher, (uint8_t*)out, outlen);
|
||||
}
|
||||
|
||||
#endif // BASE_BLAKE3_H
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U16
|
||||
safe_cast_u16x(U64 x)
|
||||
{
|
||||
AssertAlways(x <= max_U16);
|
||||
return (U16)x;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64
|
||||
u128_mod64(U128 a, U64 b)
|
||||
{
|
||||
return a.u64[1] % b;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal Version
|
||||
make_version(U64 major, U64 minor)
|
||||
{
|
||||
Version version;
|
||||
version.major = major;
|
||||
version.minor = minor;
|
||||
return version;
|
||||
}
|
||||
|
||||
internal int
|
||||
version_compar(Version a, Version b)
|
||||
{
|
||||
int cmp = 0;
|
||||
if (a.major < b.major) {
|
||||
cmp = -1;
|
||||
} else if (a.major > b.major) {
|
||||
cmp = +1;
|
||||
} else if (a.major == b.major) {
|
||||
if (a.minor < b.minor) {
|
||||
cmp = -1;
|
||||
} else if (a.minor > b.minor) {
|
||||
cmp = +1;
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ISectOff
|
||||
isect_off(U32 isect, U32 off)
|
||||
{
|
||||
ISectOff result = { isect, off };
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal int
|
||||
u16_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
U16 a = *(U16*)raw_a;
|
||||
U16 b = *(U16*)raw_b;
|
||||
int result = a < b ? -1 :
|
||||
a > b ? +1 :
|
||||
0;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
u32_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
U32 a = *(U32*)raw_a;
|
||||
U32 b = *(U32*)raw_b;
|
||||
int result = a < b ? -1 :
|
||||
a > b ? +1 :
|
||||
0;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
u64_compar(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
U64 a = *(const U64*)raw_a;
|
||||
U64 b = *(const U64*)raw_b;
|
||||
int result = a < b ? -1 : a > b ? +1 : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
u64_compar_inv(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
U64 a = *(const U64*)raw_a;
|
||||
U64 b = *(const U64*)raw_b;
|
||||
int result = a < b ? +1 : a > b ? -1 : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int
|
||||
u16_compar_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U16 *a = (U16 *)raw_a;
|
||||
U16 *b = (U16 *)raw_b;
|
||||
int is_before = *a < *b;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal int
|
||||
u32_compar_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U32 *a = (U32 *)raw_a;
|
||||
U32 *b = (U32 *)raw_b;
|
||||
int is_before = *a < *b;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal int
|
||||
u64_compar_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U64 *a = (U64 *)raw_a;
|
||||
U64 *b = (U64 *)raw_b;
|
||||
int is_before = *a < *b;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
|
||||
internal int
|
||||
u8_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U8 *a = (U8 *) raw_a;
|
||||
U8 *b = (U8 *) raw_b;
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
internal int
|
||||
u16_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U16 *a = (U16 *) raw_a;
|
||||
U16 *b = (U16 *) raw_b;
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
internal int
|
||||
u32_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U32 *a = (U32 *) raw_a;
|
||||
U32 *b = (U32 *) raw_b;
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
internal int
|
||||
u64_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
U64 *a = (U64 *) raw_a;
|
||||
U64 *b = (U64 *) raw_b;
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u32_is_before_v0(void *raw_a, void *raw_b)
|
||||
{
|
||||
PairU32 *a = raw_a;
|
||||
PairU32 *b = raw_b;
|
||||
return a->v0 < b->v0;
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u32_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
PairU32 *a = raw_a;
|
||||
PairU32 *b = raw_b;
|
||||
return a->v1 < b->v1;
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u64_is_before_v0(void *raw_a, void *raw_b)
|
||||
{
|
||||
PairU64 *a = raw_a;
|
||||
PairU64 *b = raw_b;
|
||||
return a->v0 < b->v0;
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u64_is_before_v1(void *raw_a, void *raw_b)
|
||||
{
|
||||
PairU64 *a = raw_a;
|
||||
PairU64 *b = raw_b;
|
||||
return a->v1 < b->v1;
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u32_compar_v0(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const PairU32 *a = raw_a;
|
||||
const PairU32 *b = raw_b;
|
||||
return u32_compar(&a->v0, &b->v0);
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u64_compar_v0(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const PairU64 *a = raw_a;
|
||||
const PairU64 *b = raw_b;
|
||||
return u64_compar(&a->v0, &b->v0);
|
||||
}
|
||||
|
||||
internal int
|
||||
pair_u64_compar_v1(const void *raw_a, const void *raw_b)
|
||||
{
|
||||
const PairU64 *a = raw_a;
|
||||
const PairU64 *b = raw_b;
|
||||
return u64_compar(&a->v1, &b->v1);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void
|
||||
str8_list_concat_in_place_array(String8List *list, String8List *arr, U64 count)
|
||||
{
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
str8_list_concat_in_place(list, &arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define COMPILER_STRING "MSVC"
|
||||
#elif COMPILER_CLANG
|
||||
# define COMPILER_STRING "Clang"
|
||||
#elif COMPILER_GCC
|
||||
# define COMPILER_STRING "GCC"
|
||||
#else
|
||||
# error "undefined compiler string"
|
||||
#endif
|
||||
|
||||
#if BUILD_DEBUG
|
||||
# define BUILD_MODE_STRING "Debug"
|
||||
#else
|
||||
# define BUILD_MODE_STRING "Release"
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define BitExtract(x, count, shift) (((x) >> (shift)) & ((1 << (count)) - 1))
|
||||
|
||||
////////////////////////////////
|
||||
// Linked List Helpers
|
||||
|
||||
#define DLLConcatInPlace(list, to_concat) do { \
|
||||
if ((to_concat)->count) { \
|
||||
if ((list)->count) { \
|
||||
(list)->last->next = (to_concat)->first; \
|
||||
(to_concat)->first->prev = (list)->last; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} else { \
|
||||
(list)->first = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} \
|
||||
(list)->count += (to_concat)->count; \
|
||||
MemoryZeroStruct(to_concat); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLConcatInPlaceArray(list, to_concat_arr, count) for (U64 i = 0; i < (count); i += 1) { DLLConcatInPlace(list, &(to_concat_arr)[i]); }
|
||||
|
||||
#define SLLQueuePushCount(list, node) do { \
|
||||
SLLQueuePush((list)->first, (list)->last, node); \
|
||||
++(list)->count; \
|
||||
} while (0)
|
||||
|
||||
#define SLLConcatInPlaceNoCount(list, to_concat) do { \
|
||||
if ((to_concat)->first) { \
|
||||
if ((list)->first) { \
|
||||
(list)->last->next = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} else { \
|
||||
(list)->first = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} \
|
||||
MemoryZeroStruct(to_concat); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SLLConcatInPlace(list, to_concat) do { \
|
||||
if ((to_concat)->count) { \
|
||||
if ((list)->count) { \
|
||||
(list)->last->next = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} else { \
|
||||
(list)->first = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} \
|
||||
(list)->count += (to_concat)->count; \
|
||||
MemoryZeroStruct(to_concat); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLConcatInPlaceArray(list, to_concat_arr, count) for (U64 i = 0; i < (count); ++i) { SLLConcatInPlace(list, &(to_concat_arr)[i]); }
|
||||
|
||||
#define SLLConcatInPlaceChunkList(list, to_concat, chunk_type) do { \
|
||||
if ((list)->last != 0) { \
|
||||
U64 base_cursor = (list)->last->base + (list)->last->count; \
|
||||
for (chunk_type *c = (to_concat)->first; c != 0; c = c->next) { \
|
||||
c->base = base_cursor; \
|
||||
base_cursor += c->count; \
|
||||
} \
|
||||
} \
|
||||
SLLConcatInPlace(list, to_concat); \
|
||||
} while (0)
|
||||
|
||||
#define SLLConcatInPlaceChunkListArray(list, to_concat_arr, type, count) for (U64 i = 0; i < (count); ++i) { SLLConcatInPlaceChunkList(list, &(to_concat_arr)[i], type); }
|
||||
|
||||
#define SLLChunkListPush(_arena, _list, _cap, _value_type) do { \
|
||||
if ((_list)->last == 0 || (_list)->last->count >= (_list)->last->cap) { \
|
||||
_value_type##Chunk *new_chunk = push_array(_arena, _value_type##Chunk, 1); \
|
||||
new_chunk->v = push_array(_arena, _value_type, _cap); \
|
||||
new_chunk->cap = _cap; \
|
||||
new_chunk->base = (_list)->last ? (_list)->last->base + (_list)->last->cap : 0; \
|
||||
SLLQueuePushCount(_list, new_chunk); \
|
||||
} \
|
||||
_value_type *v = &(_list)->last->v[(_list)->last->count++]; \
|
||||
v->chunk = (_list)->last; \
|
||||
} while (0)
|
||||
|
||||
#define SLLChunkListPushZero(_arena, _list, _cap, _value_type) do { \
|
||||
SLLChunkListPush(_arena, _list, _cap, _value_type); \
|
||||
MemoryZeroStruct(SLLChunkListLastItem(_list)); \
|
||||
SLLChunkListLastItem(_list)->chunk = (_list)->last; \
|
||||
} while(0)
|
||||
|
||||
#define SLLChunkListLastItem(_list) (&(_list)->last->v[(_list)->last->count - 1])
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define MemoryIsZeroStruct(p) memory_is_zero(p, sizeof(*p))
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#if ARCH_LITTLE_ENDIAN
|
||||
# define BE_U32(x) bswap_u32(x)
|
||||
#else
|
||||
# define BE_U32(x) (x)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 major;
|
||||
U64 minor;
|
||||
} Version;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct ISectOff
|
||||
{
|
||||
U32 isect;
|
||||
U32 off;
|
||||
} ISectOff;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct PairU32
|
||||
{
|
||||
U32 v0;
|
||||
U32 v1;
|
||||
} PairU32;
|
||||
|
||||
typedef struct PairU64
|
||||
{
|
||||
U64 v0;
|
||||
U64 v1;
|
||||
} PairU64;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U16 safe_cast_u16x(U64 x);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 u128_mod64(U128 a, U64 b);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal Version make_version(U64 major, U64 minor);
|
||||
internal int version_compar(Version a, Version b);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal ISectOff isect_off(U32 isect, U32 off);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal int u16_compar(const void *raw_a, const void *raw_b);
|
||||
internal int u32_compar(const void *raw_a, const void *raw_b);
|
||||
internal int u64_compar(const void *raw_a, const void *raw_b);
|
||||
|
||||
internal int u8_is_before(void *raw_a, void *raw_b);
|
||||
internal int u16_is_before(void *raw_a, void *raw_b);
|
||||
internal int u32_is_before(void *raw_a, void *raw_b);
|
||||
internal int u64_is_before(void *raw_a, void *raw_b);
|
||||
|
||||
internal int pair_u32_is_before_v0(void *raw_a, void *raw_b);
|
||||
internal int pair_u32_is_before_v1(void *raw_a, void *raw_b);
|
||||
internal int pair_u64_is_before_v0(void *raw_a, void *raw_b);
|
||||
internal int pair_u64_is_before_v1(void *raw_a, void *raw_b);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void str8_list_concat_in_place_array(String8List *list, String8List *arr, U64 count);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U32
|
||||
update_crc32(U32 crc, U8 *ptr, U64 size)
|
||||
{
|
||||
// CRC-32 algo borrowed from stb.h
|
||||
|
||||
local_persist U32 crc_table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
|
||||
0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
|
||||
0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
|
||||
0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
|
||||
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
|
||||
0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
|
||||
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
|
||||
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
|
||||
0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
|
||||
0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
|
||||
0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
|
||||
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
|
||||
0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
|
||||
0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
|
||||
0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
|
||||
0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
|
||||
0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
|
||||
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
|
||||
0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
|
||||
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
|
||||
0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
|
||||
0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
|
||||
0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
|
||||
0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
|
||||
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
#if 0
|
||||
for (U32 i = 0; i < 256; ++i) {
|
||||
U32 s = i;
|
||||
for (U32 j = 0; j < 8; ++j) {
|
||||
s = (s >> 1) ^ (s & 1 ? 0xedb88320 : 0);
|
||||
}
|
||||
crc_table[i] = s;
|
||||
}
|
||||
#endif
|
||||
|
||||
crc = ~crc;
|
||||
for (U32 i = 0; i < size; ++i) {
|
||||
crc = (crc >> 8) ^ crc_table[(ptr[i] ^ crc) & 0xff];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
internal U32
|
||||
crc32_from_string(String8 string)
|
||||
{
|
||||
return update_crc32(0, string.str, string.size);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
internal U32 update_crc32(U32 crc, U8 *ptr, U64 size);
|
||||
internal U32 crc32_from_string(String8 string);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "base_core.c"
|
||||
#include "base_strings.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_arrays.c"
|
||||
#include "base_bit_array.c"
|
||||
#include "base_crc32.c"
|
||||
#include "base_md5.c"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base_core.h"
|
||||
#include "base_strings.h"
|
||||
#include "base_arena.h"
|
||||
#include "base_math.h"
|
||||
#include "base_arrays.h"
|
||||
#include "base_blake3.h"
|
||||
#include "base_bit_array.h"
|
||||
#include "base_crc32.h"
|
||||
#include "base_md5.h"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
rng_1u64_list_push_node(Rng1U64List *list, Rng1U64Node *node)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
}
|
||||
|
||||
internal Rng1U64Node *
|
||||
rng_1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 range)
|
||||
{
|
||||
Rng1U64Node *node = push_array(arena, Rng1U64Node, 1);
|
||||
node->v = range;
|
||||
rng_1u64_list_push_node(list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct Rng1U64Node
|
||||
{
|
||||
struct Rng1U64Node *next;
|
||||
Rng1U64 v;
|
||||
} Rng1U64Node;
|
||||
|
||||
typedef struct Rng1U64List
|
||||
{
|
||||
U64 count;
|
||||
Rng1U64Node *first;
|
||||
Rng1U64Node *last;
|
||||
} Rng1U64List;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void rng_1u64_list_push_node(Rng1U64List *list, Rng1U64Node *node);
|
||||
internal Rng1U64Node * rng_1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 range);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal MD5Hash
|
||||
md5_hash_from_string(String8 data)
|
||||
{
|
||||
MD5_CTX ctx; MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, (void*)data.str, safe_cast_u32(data.size));
|
||||
MD5Hash hash; MD5_Final((unsigned char*)&hash, &ctx);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct MD5Hash
|
||||
{
|
||||
U8 value[16];
|
||||
} MD5Hash;
|
||||
|
||||
internal MD5Hash md5_hash_from_string(String8 data);
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal int
|
||||
str8_compar(String8 a, String8 b, B32 ignore_case)
|
||||
{
|
||||
int cmp = 0;
|
||||
U64 size = Min(a.size, b.size);
|
||||
if (ignore_case) {
|
||||
for (U64 i = 0; i < size; ++i) {
|
||||
U8 la = char_to_lower(a.str[i]);
|
||||
U8 lb = char_to_lower(b.str[i]);
|
||||
if (la < lb) {
|
||||
cmp = -1;
|
||||
break;
|
||||
} else if (la > lb) {
|
||||
cmp = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (U64 i = 0; i < size; ++i) {
|
||||
if (a.str[i] < b.str[i]) {
|
||||
cmp = -1;
|
||||
break;
|
||||
} else if (a.str[i] > b.str[i]) {
|
||||
cmp = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp == 0) {
|
||||
// shorter prefix must precede longer prefixes
|
||||
if (a.size > b.size) {
|
||||
cmp = +1;
|
||||
} else if (b.size > a.size) {
|
||||
cmp = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar_ignore_case(const void *a, const void *b)
|
||||
{
|
||||
return str8_compar(*(String8*)a, *(String8*)b, 1);
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_compar_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
return str8_compar(*(String8*)a, *(String8*)b, 0);
|
||||
}
|
||||
|
||||
internal int
|
||||
str8_is_before_case_sensitive(const void *a, const void *b)
|
||||
{
|
||||
int cmp = str8_compar_case_sensitive(a, b);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
internal String8Node *
|
||||
str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size)
|
||||
{
|
||||
String8 data = str8((U8 *)data_ptr, data_size);
|
||||
String8Node *node = str8_list_push(arena, list, data);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal U64
|
||||
str8_list_push_pad(Arena *arena, String8List *list, U64 offset, U64 align)
|
||||
{
|
||||
U64 pad_size = AlignPow2(offset, align) - offset;
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
MemorySet(pad, 0, pad_size);
|
||||
str8_list_push(arena, list, str8(pad, pad_size));
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
str8_list_push_pad_front(Arena *arena, String8List *list, U64 offset, U64 align)
|
||||
{
|
||||
U64 pad_size = AlignPow2(offset, align) - offset;
|
||||
U8 *pad = push_array(arena, U8, pad_size);
|
||||
MemorySet(pad, 0, pad_size);
|
||||
str8_list_push_front(arena, list, str8(pad, pad_size));
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
internal String8List
|
||||
str8_list_arr_concat(String8List *v, U64 count)
|
||||
{
|
||||
String8List result = {0};
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
str8_list_concat_in_place(&result, &v[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8Node *
|
||||
str8_list_push_many(Arena *arena, String8List *list, U64 count)
|
||||
{
|
||||
String8Node *arr = push_array(arena, String8Node, count);
|
||||
for (U64 i = 0; i < count; ++i) {
|
||||
str8_list_push_node(list, arr + i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8Node *
|
||||
str8_list_pop_front(String8List *list)
|
||||
{
|
||||
String8Node *node = 0;
|
||||
if (list->node_count) {
|
||||
node = list->first;
|
||||
Assert(list->total_size >= list->first->string.size);
|
||||
list->node_count -= 1;
|
||||
list->total_size -= list->first->string.size;
|
||||
SLLQueuePop(list->first, list->last);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
internal U64
|
||||
hash_from_str8(String8 string)
|
||||
{
|
||||
XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size);
|
||||
return hash64;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size)
|
||||
|
||||
internal int str8_compar(String8 a, String8 b, B32 ignore_case);
|
||||
internal int str8_compar_ignore_case(const void *a, const void *b);
|
||||
internal int str8_compar_case_sensitive(const void *a, const void *b);
|
||||
|
||||
#define str8_list_push_struct(a,l,d) str8_list_push_raw(a, l, d, sizeof(*d))
|
||||
internal String8Node * str8_list_push_raw(Arena *arena, String8List *list, void *data_ptr, U64 data_size);
|
||||
internal U64 str8_list_push_pad(Arena *arena, String8List *list, U64 offset, U64 align);
|
||||
internal U64 str8_list_push_pad_front(Arena *arena, String8List *list, U64 offset, U64 align);
|
||||
internal String8List str8_list_arr_concat(String8List *v, U64 count);
|
||||
internal String8Node * str8_list_push_many(Arena *arena, String8List *list, U64 count);
|
||||
|
||||
// TODO: remove
|
||||
internal String8Node * str8_list_pop_front(String8List *list);
|
||||
|
||||
internal U64 hash_from_str8(String8 string);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CV_MinComplexTypeIndex 0x1000
|
||||
|
||||
////////////////////////////////
|
||||
// Aligns
|
||||
|
||||
#define CV_LeafAlign 4
|
||||
#define CV_SymbolAlign 1
|
||||
#define CV_C13SubSectionAlign 4
|
||||
#define CV_FileCheckSumsAlign 4
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
//- Symbol and Leaf Headers
|
||||
|
||||
#define CV_LeafSize_Max max_U16
|
||||
typedef U16 CV_LeafSize;
|
||||
|
||||
#define CV_SymSize_Max max_U16
|
||||
typedef U16 CV_SymSize;
|
||||
|
||||
typedef struct CV_LeafHeader
|
||||
{
|
||||
CV_LeafSize size;
|
||||
CV_LeafKind kind;
|
||||
} CV_LeafHeader;
|
||||
|
||||
typedef struct CV_SymbolHeader
|
||||
{
|
||||
CV_SymSize size;
|
||||
CV_SymKind kind;
|
||||
} CV_SymbolHeader;
|
||||
|
||||
////////////////////////////////
|
||||
// Type Index Helpers
|
||||
|
||||
typedef enum CV_TypeIndexSource
|
||||
{
|
||||
CV_TypeIndexSource_NULL,
|
||||
CV_TypeIndexSource_TPI,
|
||||
CV_TypeIndexSource_IPI,
|
||||
CV_TypeIndexSource_COUNT
|
||||
} CV_TypeIndexSource;
|
||||
|
||||
typedef struct CV_TypeIndexInfo
|
||||
{
|
||||
struct CV_TypeIndexInfo *next;
|
||||
U64 offset;
|
||||
CV_TypeIndexSource source;
|
||||
} CV_TypeIndexInfo;
|
||||
|
||||
typedef struct CV_TypeIndexInfoList
|
||||
{
|
||||
U64 count;
|
||||
CV_TypeIndexInfo *first;
|
||||
CV_TypeIndexInfo *last;
|
||||
} CV_TypeIndexInfoList;
|
||||
|
||||
typedef struct CV_TypeIndexArray
|
||||
{
|
||||
U32 count;
|
||||
CV_TypeIndex *v;
|
||||
} CV_TypeIndexArray;
|
||||
|
||||
//- $$Symbols
|
||||
|
||||
typedef struct CV_Symbol
|
||||
{
|
||||
CV_SymKind kind;
|
||||
U64 offset;
|
||||
String8 data;
|
||||
} CV_Symbol;
|
||||
|
||||
typedef struct CV_SymbolNode
|
||||
{
|
||||
struct CV_SymbolNode *next;
|
||||
struct CV_SymbolNode *prev;
|
||||
CV_Symbol data;
|
||||
} CV_SymbolNode;
|
||||
|
||||
typedef struct CV_SymbolPtrNode
|
||||
{
|
||||
struct CV_SymbolPtrNode *next;
|
||||
CV_Symbol *data;
|
||||
} CV_SymbolPtrNode;
|
||||
|
||||
typedef struct CV_SymbolList
|
||||
{
|
||||
U64 count;
|
||||
CV_Signature signature;
|
||||
CV_SymbolNode *first;
|
||||
CV_SymbolNode *last;
|
||||
} CV_SymbolList;
|
||||
|
||||
typedef struct CV_SymbolListArray
|
||||
{
|
||||
U64 count;
|
||||
CV_SymbolList *v;
|
||||
} CV_SymbolListArray;
|
||||
|
||||
typedef struct CV_SymbolPtrArray
|
||||
{
|
||||
U64 count;
|
||||
CV_SymbolNode **v;
|
||||
} CV_SymbolPtrArray;
|
||||
|
||||
typedef struct CV_Scope
|
||||
{
|
||||
struct CV_ScopeList *children;
|
||||
struct CV_Scope *next;
|
||||
struct CV_Scope *prev;
|
||||
CV_Symbol symbol;
|
||||
} CV_Scope;
|
||||
|
||||
typedef struct CV_ScopeList
|
||||
{
|
||||
CV_Scope *first;
|
||||
CV_Scope *last;
|
||||
} CV_ScopeList;
|
||||
|
||||
typedef struct CV_ScopeFrame
|
||||
{
|
||||
struct CV_ScopeFrame *next;
|
||||
CV_ScopeList *list;
|
||||
CV_Scope *curr;
|
||||
U64 symbol_off;
|
||||
U32 *parent_off_ptr;
|
||||
U32 *end_off_ptr;
|
||||
} CV_ScopeFrame;
|
||||
|
||||
//- $$FileChksms
|
||||
|
||||
typedef struct CV_Checksum
|
||||
{
|
||||
CV_C13Checksum *header;
|
||||
String8 value;
|
||||
} CV_Checksum;
|
||||
|
||||
typedef struct CV_ChecksumNode
|
||||
{
|
||||
struct CV_ChecksumNode *next;
|
||||
CV_Checksum data;
|
||||
} CV_ChecksumNode;
|
||||
|
||||
typedef struct CV_ChecksumList
|
||||
{
|
||||
U64 count;
|
||||
CV_ChecksumNode *first;
|
||||
CV_ChecksumNode *last;
|
||||
} CV_ChecksumList;
|
||||
|
||||
//- $$Lines
|
||||
|
||||
typedef struct CV_LineArray
|
||||
{
|
||||
U32 file_off;
|
||||
U64 line_count;
|
||||
U64 col_count;
|
||||
U64 *voffs; // [line_count + 1]
|
||||
U32 *line_nums; // [line_count]
|
||||
U16 *col_nums; // [line_count * 2]
|
||||
} CV_LineArray;
|
||||
|
||||
typedef struct CV_File
|
||||
{
|
||||
U32 file_off;
|
||||
CV_LineArray lines;
|
||||
} CV_File;
|
||||
|
||||
typedef struct CV_C13LinesHeader
|
||||
{
|
||||
U64 sec_idx;
|
||||
U64 sec_off_lo;
|
||||
U64 sec_off_hi;
|
||||
U64 file_off;
|
||||
U64 line_count;
|
||||
U64 col_count;
|
||||
U64 line_array_off;
|
||||
U64 col_array_off;
|
||||
} CV_C13LinesHeader;
|
||||
|
||||
typedef struct CV_C13LinesHeaderNode
|
||||
{
|
||||
struct CV_C13LinesHeaderNode *next;
|
||||
CV_C13LinesHeader v;
|
||||
} CV_C13LinesHeaderNode;
|
||||
|
||||
typedef struct CV_C13LinesHeaderList
|
||||
{
|
||||
CV_C13LinesHeaderNode *first;
|
||||
CV_C13LinesHeaderNode *last;
|
||||
U64 count;
|
||||
} CV_C13LinesHeaderList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct CV_UDTInfo
|
||||
{
|
||||
String8 name;
|
||||
String8 unique_name;
|
||||
CV_TypeProps props;
|
||||
} CV_UDTInfo;
|
||||
|
||||
typedef struct CV_TypeServerInfo
|
||||
{
|
||||
String8 name;
|
||||
Guid sig;
|
||||
U32 age;
|
||||
} CV_TypeServerInfo;
|
||||
|
||||
typedef struct CV_TypeServerInfoNode
|
||||
{
|
||||
struct CV_TypeServerInfoNode *next;
|
||||
CV_TypeServerInfo data;
|
||||
} CV_TypeServerInfoNode;
|
||||
|
||||
typedef struct CV_TypeServerInfoList
|
||||
{
|
||||
CV_TypeServerInfoNode *first;
|
||||
CV_TypeServerInfoNode *last;
|
||||
U64 count;
|
||||
} CV_TypeServerInfoList;
|
||||
|
||||
typedef struct CV_PrecompInfo
|
||||
{
|
||||
CV_TypeIndex start_index;
|
||||
U32 sig;
|
||||
U32 leaf_count;
|
||||
String8 obj_name;
|
||||
} CV_PrecompInfo;
|
||||
|
||||
typedef struct CV_ObjInfo
|
||||
{
|
||||
U32 sig;
|
||||
String8 name;
|
||||
} CV_ObjInfo;
|
||||
|
||||
////////////////////////////////
|
||||
// Accels
|
||||
|
||||
typedef struct CV_Line
|
||||
{
|
||||
U64 voff;
|
||||
U32 file_off;
|
||||
U32 line_num;
|
||||
U16 col_num;
|
||||
} CV_Line;
|
||||
|
||||
typedef struct CV_LinesAccel
|
||||
{
|
||||
U64 map_count;
|
||||
CV_Line *map;
|
||||
} CV_LinesAccel;
|
||||
|
||||
typedef struct CV_InlineeLinesAccel
|
||||
{
|
||||
U64 bucket_count;
|
||||
U64 bucket_max;
|
||||
CV_C13InlineeLinesParsed **buckets;
|
||||
} CV_InlineeLinesAccel;
|
||||
|
||||
typedef struct CV_InlineBinaryAnnotsParsed
|
||||
{
|
||||
U64 lines_count;
|
||||
CV_LineArray *lines;
|
||||
Rng1U64List code_ranges;
|
||||
} CV_InlineBinaryAnnotsParsed;
|
||||
|
||||
typedef struct CV_C13InlineeLinesParsedList
|
||||
{
|
||||
CV_C13InlineeLinesParsedNode *first;
|
||||
CV_C13InlineeLinesParsedNode *last;
|
||||
U64 count;
|
||||
} CV_C13InlineeLinesParsedList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef U32 CV_C13SubSectionIdxKind;
|
||||
enum
|
||||
{
|
||||
CV_C13SubSectionIdxKind_NULL,
|
||||
#define X(N,c) CV_C13SubSectionIdxKind_##N,
|
||||
CV_C13SubSectionKindXList(X)
|
||||
#undef X
|
||||
CV_C13SubSectionIdxKind_COUNT
|
||||
};
|
||||
|
||||
typedef struct CV_C13SubSectionList
|
||||
{
|
||||
CV_C13SubSectionNode *first;
|
||||
CV_C13SubSectionNode *last;
|
||||
U64 count;
|
||||
} CV_C13SubSectionList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct CV_DebugS
|
||||
{
|
||||
String8List data_list[CV_C13SubSectionIdxKind_COUNT];
|
||||
} CV_DebugS;
|
||||
|
||||
typedef struct CV_DebugT
|
||||
{
|
||||
U64 size;
|
||||
U64 count;
|
||||
U8 **v;
|
||||
} CV_DebugT;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Leaf Helpers
|
||||
|
||||
typedef struct CV_Leaf
|
||||
{
|
||||
CV_LeafKind kind;
|
||||
String8 data;
|
||||
} CV_Leaf;
|
||||
|
||||
typedef struct CV_LeafNode
|
||||
{
|
||||
struct CV_LeafNode *next;
|
||||
CV_Leaf data;
|
||||
} CV_LeafNode;
|
||||
|
||||
typedef struct CV_LeafList
|
||||
{
|
||||
U64 count;
|
||||
CV_LeafNode *first;
|
||||
CV_LeafNode *last;
|
||||
} CV_LeafList;
|
||||
|
||||
////////////////////////////////
|
||||
//~ String Hash Table
|
||||
|
||||
typedef struct CV_StringTableRange
|
||||
{
|
||||
struct CV_StringTableRange *next;
|
||||
Rng1U64 range;
|
||||
U64 debug_s_idx;
|
||||
} CV_StringTableRange;
|
||||
|
||||
typedef struct CV_StringBucket
|
||||
{
|
||||
String8 string;
|
||||
union {
|
||||
struct {
|
||||
U32 idx0;
|
||||
U32 idx1;
|
||||
};
|
||||
U64 offset;
|
||||
} u;
|
||||
} CV_StringBucket;
|
||||
|
||||
typedef struct CV_StringHashTable
|
||||
{
|
||||
U64 total_string_size;
|
||||
U64 total_insert_count;
|
||||
U64 bucket_cap;
|
||||
CV_StringBucket **buckets;
|
||||
} CV_StringHashTable;
|
||||
|
||||
typedef struct CV_StringHashTableResult
|
||||
{
|
||||
U64 string_count;
|
||||
CV_StringBucket **buckets;
|
||||
} CV_StringHashTableResult;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Task Contexts
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 cap;
|
||||
union {
|
||||
CV_SymbolNode ***buckets;
|
||||
CV_SymbolNode **deref_buckets;
|
||||
} u;
|
||||
Rng1U64 *ranges;
|
||||
CV_SymbolNode **symbols;
|
||||
} CV_SymbolDeduperTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CV_SymbolList *list_arr;
|
||||
Rng1U64 *list_range_arr;
|
||||
U64 *symbol_base_arr;
|
||||
CV_SymbolNode **symbol_arr;
|
||||
} CV_SymbolListSyncer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CV_DebugS *arr;
|
||||
CV_StringTableRange **range_lists;
|
||||
U64 *string_counts;
|
||||
U64 bucket_cap;
|
||||
CV_StringBucket **buckets;
|
||||
U64 total_string_size;
|
||||
U64 total_insert_count;
|
||||
} CV_DedupStringTablesTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U8 *buffer;
|
||||
Rng1U64 *ranges;
|
||||
CV_StringBucket **buckets;
|
||||
} CV_PackStringHashTableTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CV_DebugT debug_t;
|
||||
Rng1U64 *ranges;
|
||||
String8List *lists;
|
||||
String8Node *nodes;
|
||||
} CV_Str8ListFromDebugT;
|
||||
|
||||
////////////////////////////////
|
||||
// Type Index Helpers
|
||||
|
||||
internal CV_TypeIndexInfo * cv_symbol_type_index_info_push(Arena *arena, CV_TypeIndexInfoList *list, CV_TypeIndexSource source, U64 offset);
|
||||
internal CV_TypeIndexInfoList cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data);
|
||||
internal CV_TypeIndexInfoList cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data);
|
||||
internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data);
|
||||
internal String8Array cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, String8 data);
|
||||
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
|
||||
internal String8 cv_name_from_symbol (CV_SymKind kind, String8 data);
|
||||
internal String8 cv_name_from_udt_info (CV_UDTInfo udt_info);
|
||||
|
||||
internal B32 cv_is_udt_name_anon (String8 name);
|
||||
internal B32 cv_is_udt (CV_LeafKind kind);
|
||||
internal B32 cv_is_global_symbol (CV_SymKind kind);
|
||||
internal B32 cv_is_typedef (CV_SymKind kind);
|
||||
internal B32 cv_is_scope_symbol (CV_SymKind kind);
|
||||
internal B32 cv_is_end_symbol (CV_SymKind kind);
|
||||
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
|
||||
internal B32 cv_is_leaf_pch (CV_LeafKind kind);
|
||||
|
||||
internal CV_ObjInfo cv_obj_info_from_symbol(CV_Symbol symbol);
|
||||
internal CV_TypeServerInfo cv_type_server_info_from_leaf(CV_Leaf leaf);
|
||||
internal CV_PrecompInfo cv_precomp_info_from_leaf(CV_Leaf leaf);
|
||||
|
||||
internal B32 cv_is_reg_sp(CV_Arch arch, CV_Reg reg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Leaf Helpers
|
||||
|
||||
internal U64 cv_compute_leaf_record_size(String8 data, U64 align);
|
||||
internal U64 cv_serialize_leaf_to_buffer(U8 *buffer, U64 buffer_cursor, U64 buffer_size, CV_LeafKind kind, String8 data, U64 align);
|
||||
internal String8 cv_serialize_leaf_ex(Arena *arena, CV_LeafKind kind, String8 data, U64 align);
|
||||
internal String8 cv_serialize_leaf(Arena *arena, CV_Leaf *leaf, U64 align);
|
||||
internal CV_Leaf cv_make_leaf(Arena *arena, CV_LeafKind kind, String8 data);
|
||||
internal U64 cv_deserial_leaf(String8 raw_data, U64 off, U64 align, CV_Leaf *leaf_out);
|
||||
internal CV_Leaf cv_leaf_from_string(String8 raw_data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Symbol Helpers
|
||||
|
||||
internal U64 cv_compute_symbol_record_size(CV_Symbol *symbol, U64 align);
|
||||
internal U64 cv_serialize_symbol_to_buffer(U8 *buffer, U64 buffer_cursor, U64 buffer_size, CV_Symbol *symbol, U64 align);
|
||||
internal String8 cv_serialize_symbol(Arena *arena, CV_Symbol *symbol, U64 align);
|
||||
|
||||
internal String8 cv_make_symbol(Arena *arena, CV_SymKind kind, String8 data);
|
||||
internal String8 cv_make_obj_name(Arena *arena, String8 obj_path, U32 sig);
|
||||
internal String8 cv_make_comp3(Arena *arena,
|
||||
CV_Compile3Flags flags, CV_Language lang, CV_Arch arch,
|
||||
U16 ver_fe_major, U16 ver_fe_minor, U16 ver_fe_build, U16 ver_feqfe,
|
||||
U16 ver_major, U16 ver_minor, U16 ver_build, U16 ver_qfe,
|
||||
String8 version_string);
|
||||
internal String8 cv_make_envblock(Arena *arena, String8List string_list);
|
||||
internal CV_Symbol cv_make_proc_ref(Arena *arena, CV_ModIndex imod, U32 stream_offset, String8 name, B32 is_local);
|
||||
internal CV_Symbol cv_make_pub32(Arena *arena, CV_Pub32Flags flags, U32 off, U16 isect, String8 name);
|
||||
internal CV_SymbolList cv_make_proc_refs(Arena *arena, CV_ModIndex imod, CV_SymbolList symbol_list);
|
||||
|
||||
////////////////////////////////
|
||||
// .debug$S Helpers
|
||||
|
||||
internal CV_DebugS cv_parse_debug_s_c13(Arena *arena, String8 raw_debug_s);
|
||||
internal CV_DebugS cv_parse_debug_s_c13_list(Arena *arena, String8List raw_debug_s);
|
||||
internal CV_DebugS cv_parse_debug_s(Arena *arena, String8 raw_debug_s);
|
||||
internal void cv_debug_s_concat_in_place(CV_DebugS *dst, CV_DebugS *src);
|
||||
internal String8List cv_data_c13_from_debug_s(Arena *arena, CV_DebugS *debug_s, B32 write_sig);
|
||||
|
||||
internal CV_C13SubSectionIdxKind cv_c13_sub_section_idx_from_kind(CV_C13SubSectionKind kind);
|
||||
internal String8List * cv_sub_section_ptr_from_debug_s(CV_DebugS *debug_s, CV_C13SubSectionKind kind);
|
||||
internal String8List cv_sub_section_from_debug_s(CV_DebugS debug_s, CV_C13SubSectionKind kind);
|
||||
internal String8 cv_string_table_from_debug_s(CV_DebugS debug_s);
|
||||
internal String8 cv_file_chksms_from_debug_s(CV_DebugS debug_s);
|
||||
|
||||
////////////////////////////////
|
||||
//~ .debug$T helpers
|
||||
|
||||
internal CV_DebugT cv_debug_t_from_data_arr(Arena *arena, String8Array data_arr, U64 align);
|
||||
internal CV_DebugT cv_debug_t_from_data(Arena *arena, String8 data, U64 align);
|
||||
internal CV_Leaf cv_debug_t_get_leaf(CV_DebugT debug_t, U64 leaf_idx);
|
||||
internal String8 cv_debug_t_get_raw_leaf(CV_DebugT debug_t, U64 leaf_idx);
|
||||
internal CV_LeafHeader * cv_debug_t_get_leaf_header(CV_DebugT debug_t, U64 leaf_idx);
|
||||
internal B32 cv_debug_t_is_pch(CV_DebugT debug_t);
|
||||
internal B32 cv_debug_t_is_type_server(CV_DebugT debug_t);
|
||||
internal U64 cv_debug_t_array_count_leaves(U64 count, CV_DebugT *arr);
|
||||
|
||||
internal String8List cv_str8_list_from_debug_t_parallel(TP_Context *tp, Arena *arena, CV_DebugT types);
|
||||
|
||||
// $$Symbols
|
||||
internal void cv_parse_symbol_sub_section(Arena *arena, CV_SymbolList *list, U64 offset_base, String8 data, U64 align);
|
||||
internal void cv_symbol_list_push_node(CV_SymbolList *list, CV_SymbolNode *node);
|
||||
internal CV_SymbolNode * cv_symbol_list_push(Arena *arena, CV_SymbolList *list);
|
||||
internal CV_SymbolNode * cv_symbol_list_push_data(Arena *arena, CV_SymbolList *list, CV_SymKind kind, String8 data);
|
||||
internal CV_SymbolNode * cv_symbol_list_push_many(Arena *arena, CV_SymbolList *list, U64 count);
|
||||
internal void cv_symbol_list_remove_node(CV_SymbolList *list, CV_SymbolNode *node);
|
||||
internal void cv_symbol_list_concat_in_place(CV_SymbolList *list, CV_SymbolList *to_concat);
|
||||
internal void cv_symbol_list_concat_in_place_arr(CV_SymbolList *list, U64 count, CV_SymbolList *to_concat);
|
||||
internal U64 cv_symbol_list_arr_get_count(U64 count, CV_SymbolList *list_arr);
|
||||
internal String8List cv_data_from_symbol_list(Arena *arena, CV_SymbolList symbol_list, U64 align);
|
||||
internal CV_SymbolList cv_global_scope_symbols_from_list(Arena *arena, CV_SymbolList list);
|
||||
internal CV_ScopeList cv_symbol_tree_from_symbol_list(Arena *arena, CV_SymbolList list);
|
||||
internal CV_SymbolList cv_build_symbol_tree(Arena *arena, CV_ScopeList symbol_tree, U64 symbol_base, U64 align);
|
||||
internal CV_SymbolPtrArray cv_symbol_ptr_array_from_list(Arena *arena, TP_Context *tp, U64 count, CV_SymbolList *symbol_list_arr);
|
||||
|
||||
// $$FileChksms
|
||||
#define CV_MAP_STRING_TO_OFFSET_FUNC(name) U64 name(void *ud, String8 string)
|
||||
typedef CV_MAP_STRING_TO_OFFSET_FUNC(CV_MapStringToOffsetFunc);
|
||||
|
||||
//internal String8 cv_c13_file_chksms_from_sub_sections(String8 c13_data, CV_C13Parsed *ss);
|
||||
internal void cv_c13_patch_string_offsets_in_checksum_list(CV_ChecksumList checksum_list, String8 string_data, U64 string_data_base_offset, CV_StringHashTable string_ht);
|
||||
internal String8List cv_c13_collect_source_file_names(Arena *arena, CV_ChecksumList checksum_list, String8 string_data);
|
||||
|
||||
// $$Lines
|
||||
internal CV_C13LinesHeaderList cv_c13_lines_from_sub_sections(Arena *arena, String8 c13_data, Rng1U64 ss_range);
|
||||
internal CV_LineArray cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13LinesHeader parsed_lines);
|
||||
|
||||
// $$InlineeLines
|
||||
internal CV_C13InlineeLinesParsedList cv_c13_inlinee_lines_from_sub_sections(Arena *arena, String8List raw_inlinee_lines);
|
||||
internal CV_InlineBinaryAnnotsParsed cv_c13_parse_inline_binary_annots(Arena *arena, U64 parent_voff, CV_C13InlineeLinesParsed *inlinee_parsed, String8 binary_annots);
|
||||
|
||||
// $$FrameData
|
||||
internal void cv_c13_patch_checksum_offsets_in_frame_data_list(String8List frame_data, U32 checksum_rebase);
|
||||
|
||||
////////////////////////////////
|
||||
// $$Lines Accel
|
||||
|
||||
internal void cv_make_c13_files(Arena *arena, String8 c13_data, CV_C13SubSectionList lines, U64 *file_count_out, CV_C13File **files_out);
|
||||
internal CV_LinesAccel * cv_make_lines_accel(Arena *arena, U64 lines_count, CV_LineArray *lines);
|
||||
internal CV_Line * cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count);
|
||||
|
||||
////////////////////////////////
|
||||
// $$InlineeLines Accel
|
||||
|
||||
internal U64 cv_c13_inlinee_lines_accel_hash(void *buffer, U64 size);
|
||||
internal B32 cv_c13_inlinee_lines_accel_push(CV_InlineeLinesAccel *accel, CV_C13InlineeLinesParsed *parsed);
|
||||
internal CV_C13InlineeLinesParsed * cv_c13_inlinee_lines_accel_find(CV_InlineeLinesAccel *accel, CV_ItemId inlinee);
|
||||
internal CV_InlineeLinesAccel * cv_c13_make_inlinee_lines_accel(Arena *arena, CV_C13InlineeLinesParsedList sub_sects);
|
||||
|
||||
////////////////////////////////
|
||||
// String Hash Table
|
||||
|
||||
internal U64 cv_string_hash_table_hash(String8 string);
|
||||
internal CV_StringHashTable cv_dedup_string_tables(TP_Arena *arena, TP_Context *tp, U64 count, CV_DebugS *arr);
|
||||
internal CV_StringHashTableResult cv_serialize_string_hash_table(Arena *arena, TP_Context *tp, CV_StringHashTable string_ht);
|
||||
internal String8 cv_pack_string_hash_table(Arena *arena, TP_Context *tp, CV_StringHashTable string_ht);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal CV_EncodedFramePtrReg cv_pick_fp_encoding(CV_SymFrameproc *frameproc, B32 is_local_param);
|
||||
internal CV_Reg cv_decode_fp_reg(CV_Arch arch, CV_EncodedFramePtrReg encoded_reg);
|
||||
internal Rng1U64List cv_make_defined_range_list_from_gaps(Arena *arena, Rng1U64 defrange, CV_LvarAddrGap *gaps, U64 gap_count);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 cv_size_from_reg_x86(CV_Reg reg);
|
||||
internal U64 cv_size_from_reg_x64(CV_Reg reg);
|
||||
internal U64 cv_size_from_reg(CV_Arch arch, CV_Reg reg);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal CV_Arch cv_arch_from_coff_machine(COFF_MachineType machine);
|
||||
internal String8 cv_string_from_type_index_source(CV_TypeIndexSource ti_source);
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal void
|
||||
bucket_list_concat_in_place(BucketList *list, BucketList *to_concat)
|
||||
{
|
||||
SLLConcatInPlaceNoCount(list, to_concat);
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
bucket_list_pop(BucketList *list)
|
||||
{
|
||||
BucketNode *result = list->first;
|
||||
SLLQueuePop(list->first, list->last);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64
|
||||
hash_table_hasher(String8 string)
|
||||
{
|
||||
XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size);
|
||||
return hash64;
|
||||
}
|
||||
|
||||
internal HashTable *
|
||||
hash_table_init(Arena *arena, U64 cap)
|
||||
{
|
||||
HashTable *ht = push_array(arena, HashTable, 1);
|
||||
ht->cap = cap;
|
||||
ht->buckets = push_array(arena, BucketList, cap);
|
||||
return ht;
|
||||
}
|
||||
|
||||
internal void
|
||||
hash_table_purge(HashTable *ht)
|
||||
{
|
||||
// reset key count
|
||||
ht->count = 0;
|
||||
|
||||
// concat buckets
|
||||
for (U64 ibucket = 0; ibucket < ht->cap; ++ibucket) {
|
||||
bucket_list_concat_in_place(&ht->free_buckets, &ht->buckets[ibucket]);
|
||||
}
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push(Arena *arena, HashTable *ht, U64 hash, KeyValuePair v)
|
||||
{
|
||||
BucketNode *node;
|
||||
if (ht->free_buckets.first != 0) {
|
||||
node = bucket_list_pop(&ht->free_buckets);
|
||||
} else {
|
||||
node = push_array(arena, BucketNode, 1);
|
||||
}
|
||||
node->next = 0;
|
||||
node->v = v;
|
||||
|
||||
U64 ibucket = hash % ht->cap;
|
||||
SLLQueuePush(ht->buckets[ibucket].first, ht->buckets[ibucket].last, node);
|
||||
++ht->count;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_string_string(Arena *arena, HashTable *ht, String8 key, String8 value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(key);
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = key, .value_string = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_string_raw(Arena *arena, HashTable *ht, String8 key, void *value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(key);
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = key, .value_raw = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_string_u64(Arena *arena, HashTable *ht, String8 key, U64 value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(key);
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){.key_string = key, .value_u64 = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_u32_raw(Arena *arena, HashTable *ht, U32 key, void *value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key));
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u32 = key, .value_raw = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_u32_string(Arena *arena, HashTable *ht, U32 key, String8 value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key));
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u32 = key, .value_string = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_u64_raw(Arena *arena, HashTable *ht, U64 key, void *value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key));
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_raw = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_u64_string(Arena *arena, HashTable *ht, U64 key, String8 value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key));
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_string = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_u64_u64(Arena *arena, HashTable *ht, U64 key, U64 value)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key));
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_path_string(Arena *arena, HashTable *ht, String8 path, String8 value)
|
||||
{
|
||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
||||
return hash_table_push_string_string(arena, ht, path_canon, value);
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value)
|
||||
{
|
||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
||||
U64 hash = hash_table_hasher(path_canon);
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_u64 = value });
|
||||
}
|
||||
|
||||
internal BucketNode *
|
||||
hash_table_push_path_raw(Arena *arena, HashTable *ht, String8 path, void *value)
|
||||
{
|
||||
String8 path_canon = path_canon_from_regular_path(arena, path);
|
||||
U64 hash = hash_table_hasher(path_canon);
|
||||
return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_raw = value });
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal KeyValuePair *
|
||||
hash_table_search_string(HashTable *ht, String8 key_string)
|
||||
{
|
||||
U64 hash = hash_table_hasher(key_string);
|
||||
U64 ibucket = hash % ht->cap;
|
||||
BucketList *bucket = ht->buckets + ibucket;
|
||||
for (BucketNode *n = bucket->first; n != 0; n = n->next) {
|
||||
if (str8_match(n->v.key_string, key_string, 0)) {
|
||||
return &n->v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal KeyValuePair *
|
||||
hash_table_search_u32(HashTable *ht, U32 key_u32)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key_u32));
|
||||
U64 ibucket = hash % ht->cap;
|
||||
BucketList *bucket = ht->buckets + ibucket;
|
||||
for (BucketNode *n = bucket->first; n != 0; n = n->next) {
|
||||
if (n->v.key_u32 == key_u32) {
|
||||
return &n->v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal KeyValuePair *
|
||||
hash_table_search_u64(HashTable *ht, U64 key_u64)
|
||||
{
|
||||
U64 hash = hash_table_hasher(str8_struct(&key_u64));
|
||||
U64 ibucket = hash % ht->cap;
|
||||
BucketList *bucket = ht->buckets + ibucket;
|
||||
for (BucketNode *n = bucket->first; n != 0; n = n->next) {
|
||||
if (n->v.key_u64 == key_u64) {
|
||||
return &n->v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal KeyValuePair *
|
||||
hash_table_search_path(HashTable *ht, String8 path)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
String8 path_canon = path;
|
||||
path_canon = lower_from_str8(scratch.arena, path_canon);
|
||||
path_canon = path_convert_slashes(scratch.arena, path_canon, PathStyle_UnixAbsolute);
|
||||
KeyValuePair *result = hash_table_search_string(ht, path_canon);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out)
|
||||
{
|
||||
KeyValuePair *result = hash_table_search_path(ht, key);
|
||||
if (result != 0) {
|
||||
if (value_out != 0) {
|
||||
*value_out = result->value_u64;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out)
|
||||
{
|
||||
KeyValuePair *result = hash_table_search_string(ht, key);
|
||||
if (result != 0) {
|
||||
if (value_out != 0) {
|
||||
*value_out = result->value_u64;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal int
|
||||
key_value_pair_is_before_u32(void *raw_a, void *raw_b)
|
||||
{
|
||||
KeyValuePair *a = raw_a;
|
||||
KeyValuePair *b = raw_b;
|
||||
return a->key_u32 < b->key_u32;
|
||||
}
|
||||
|
||||
internal int
|
||||
key_value_pair_is_before_u64(void *raw_a, void *raw_b)
|
||||
{
|
||||
KeyValuePair *a = raw_a;
|
||||
KeyValuePair *b = raw_b;
|
||||
return a->key_u64 < b->key_u64;
|
||||
}
|
||||
|
||||
internal KeyValuePair *
|
||||
key_value_pairs_from_hash_table(Arena *arena, HashTable *ht)
|
||||
{
|
||||
KeyValuePair *pairs = push_array_no_zero(arena, KeyValuePair, ht->count);
|
||||
for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) {
|
||||
for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) {
|
||||
Assert(cursor < ht->count);
|
||||
pairs[cursor++] = n->v;
|
||||
}
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
internal void
|
||||
sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count)
|
||||
{
|
||||
radsort(pairs, count, key_value_pair_is_before_u32);
|
||||
}
|
||||
|
||||
internal void
|
||||
sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count)
|
||||
{
|
||||
radsort(pairs, count, key_value_pair_is_before_u64);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct KeyValuePair
|
||||
{
|
||||
union {
|
||||
String8 key_string;
|
||||
U32 key_u32;
|
||||
U64 key_u64;
|
||||
};
|
||||
union {
|
||||
String8 value_string;
|
||||
void *value_raw;
|
||||
U32 value_u32;
|
||||
U64 value_u64;
|
||||
};
|
||||
} KeyValuePair;
|
||||
|
||||
typedef struct BucketNode
|
||||
{
|
||||
struct BucketNode *next;
|
||||
KeyValuePair v;
|
||||
} BucketNode;
|
||||
|
||||
typedef struct BucketList
|
||||
{
|
||||
BucketNode *first;
|
||||
BucketNode *last;
|
||||
} BucketList;
|
||||
|
||||
typedef struct HashTable
|
||||
{
|
||||
U64 count;
|
||||
U64 cap;
|
||||
BucketList *buckets;
|
||||
BucketList free_buckets;
|
||||
} HashTable;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
//- bucket list helpers
|
||||
|
||||
internal void bucket_list_concat_in_place(BucketList *list, BucketList *to_concat);
|
||||
internal BucketNode * bucket_list_pop(BucketList *list);
|
||||
|
||||
//- main
|
||||
|
||||
internal U64 hash_table_hasher(String8 string);
|
||||
internal HashTable * hash_table_init(Arena *arena, U64 cap);
|
||||
internal void hash_table_purge(HashTable *ht);
|
||||
|
||||
//- push
|
||||
|
||||
internal BucketNode * hash_table_push (Arena *arena, HashTable *ht, U64 hash, KeyValuePair v);
|
||||
internal BucketNode * hash_table_push_u32_string (Arena *arena, HashTable *ht, U32 key, String8 value);
|
||||
internal BucketNode * hash_table_push_u64_string (Arena *arena, HashTable *ht, U64 key, String8 value);
|
||||
internal BucketNode * hash_table_push_string_string(Arena *arena, HashTable *ht, String8 key, String8 value);
|
||||
internal BucketNode * hash_table_push_path_string (Arena *arena, HashTable *ht, String8 key, String8 value);
|
||||
internal BucketNode * hash_table_push_u32_raw (Arena *arena, HashTable *ht, U32 key, void *value);
|
||||
internal BucketNode * hash_table_push_u64_raw (Arena *arena, HashTable *ht, U64 key, void *value);
|
||||
internal BucketNode * hash_table_push_path_raw (Arena *arena, HashTable *ht, String8 path, void *value);
|
||||
internal BucketNode * hash_table_push_path_u64 (Arena *arena, HashTable *ht, String8 path, U64 value);
|
||||
internal BucketNode * hash_table_push_u64_u64 (Arena *arena, HashTable *ht, U64 key, U64 value);
|
||||
|
||||
//- search
|
||||
|
||||
internal KeyValuePair * hash_table_search_string (HashTable *ht, String8 string);
|
||||
internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key);
|
||||
internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key);
|
||||
internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 path);
|
||||
|
||||
internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out);
|
||||
|
||||
//- key-value helpers
|
||||
|
||||
internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht);
|
||||
internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count);
|
||||
internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="LNK_Section">
|
||||
<DisplayString>{{ name={name} flags={flags} id={id} sort_index={sort_index} }}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="U32Array">
|
||||
<AlternativeType Name="U64Array"/>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>v</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="LNK_SymbolList">
|
||||
<AlternativeType Name="LNK_SectionList"/>
|
||||
<AlternativeType Name="LNK_ChunkList"/>
|
||||
<AlternativeType Name="CV_SymbolList"/>
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>data</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="Rng1U64List">
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>v</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_LineTable">
|
||||
<DisplayString>{{count={count} first={first} last={last} }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[count]">count</Item>
|
||||
<LinkedListItems>
|
||||
<Size>count</Size>
|
||||
<HeadPointer>first</HeadPointer>
|
||||
<NextPointer>next_line_table</NextPointer>
|
||||
<ValueNode>this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_VariableChunkList">
|
||||
<AlternativeType Name="RDIB_UnitChunkList"/>
|
||||
<AlternativeType Name="RDIB_LineTableChunkList"/>
|
||||
<AlternativeType Name="RDIB_SourceFileChunkList"/>
|
||||
<AlternativeType Name="RDIB_ProcedureChunkList"/>
|
||||
<AlternativeType Name="RDIB_ScopeChunkList"/>
|
||||
<AlternativeType Name="RDIB_InlineSiteChunkList"/>
|
||||
<AlternativeType Name="RDIB_UDTMemberChunkList"/>
|
||||
<AlternativeType Name="RDIB_TypeChunkList"/>
|
||||
<Expand>
|
||||
<Item Name="[chunk count]">count</Item>
|
||||
<CustomListItems MaxItemsPerView="5000">
|
||||
<Variable Name="node" InitialValue="first"/>
|
||||
<Variable Name="idx" InitialValue="0"/>
|
||||
<Loop>
|
||||
<Break Condition="node == 0"/>
|
||||
<Exec>idx = 0</Exec>
|
||||
<Loop>
|
||||
<Break Condition="idx >= node->count"/>
|
||||
<Item>node->v[idx]</Item>
|
||||
<Exec>idx += 1</Exec>
|
||||
</Loop>
|
||||
<Exec>node = node->next</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="RDIB_VariableChunk">
|
||||
<AlternativeType Name="RDIB_UnitChunk"/>
|
||||
<AlternativeType Name="RDIB_LineTableChunk"/>
|
||||
<AlternativeType Name="RDIB_SourceFileChunk"/>
|
||||
<AlternativeType Name="RDIB_ProcedureChunk"/>
|
||||
<AlternativeType Name="RDIB_ScopeChunk"/>
|
||||
<AlternativeType Name="RDIB_InlineSiteChunk"/>
|
||||
<AlternativeType Name="RDIB_UDTMemberChunk"/>
|
||||
<AlternativeType Name="RDIB_TypeChunk"/>
|
||||
<DisplayString>{count,cap,v}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[base]">base</Item>
|
||||
<Item Name="[count]">count</Item>
|
||||
<Item Name="[cap]">cap</Item>
|
||||
<ArrayItems>
|
||||
<Size>count</Size>
|
||||
<ValuePointer>v</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
|
||||
+4321
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LNK_NULL_SYMBOL_NAME "NULL"
|
||||
#define LNK_TEXT_SYMBOL_NAME "TEXT"
|
||||
#define LNK_DATA_SYMBOL_NAME "DATA"
|
||||
#define LNK_RDATA_SYMBOL_NAME "RDATA"
|
||||
#define LNK_BSS_SYMBOL_NAME "BSS"
|
||||
#define LNK_XDATA_SYMBOL_NAME "XDATA"
|
||||
#define LNK_PDATA_SYMBOL_NAME "PDATA"
|
||||
#define LNK_BASE_RELOC_SYMBOL_NAME "BASE_RELOC"
|
||||
#define LNK_EDATA_SYMBOL_NAME "EDATA"
|
||||
#define LNK_DEBUG_DIR_SYMBOL_NAME "DEDIR"
|
||||
#define LNK_DEBUG_DATA_SYMBOL_NAME "DEDAT"
|
||||
#define LNK_CV_DIR_SYMBOL_NAME "CV_DIR"
|
||||
#define LNK_CV_HEADER_PDB70_SYMBOL_NAME "CV_HEADER_PDB70"
|
||||
#define LNK_CV_HEADER_RDI_SYMBOL_NAME "CV_HEADER_RDI"
|
||||
#define LNK_CV_HEADER_GUID_SYMBOL_NAME "CV_HEADER_GUID"
|
||||
#define LNK_RSRC_SYMBOL_NAME "RSRC"
|
||||
#define LNK_DEBUG_SYMBOL_NAME "DEBUG"
|
||||
#define LNK_GFIDS_SYMBOL_NAME "GFIDS"
|
||||
#define LNK_GIATS_SYMBOL_NAME "GIATS"
|
||||
#define LNK_GLJMP_SYMBOL_NAME "GLJMP"
|
||||
#define LNK_GEHCONT_SYMBOL_NAME "GEHCONT"
|
||||
#define LNK_IMPORT_NAME_TABLE_SYMBOL_NAME "IMPORT_STR"
|
||||
#define LNK_IMPORT_DLL_TABLE_SYMBOL_NAME "IDATA"
|
||||
#define LNK_IMPORT_ILT_SYMBOL_NAME "ILT"
|
||||
#define LNK_IMPORT_IAT_SYMBOL_NAME "IAT"
|
||||
#define LNK_IMPORT_JMP_SYMBOL_NAME "IMPORT_THUNKS"
|
||||
#define LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME "DELAYED_IMPORT_DLL_TABLE"
|
||||
#define LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME "DELAYED_IMPORT_HANDLE_TABLE"
|
||||
#define LNK_DELAYED_IMPORT_INT_SYMBOL_NAME "DELAYED_IMPORT_INT"
|
||||
#define LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME "DELAYED_IMPORT_IAT"
|
||||
#define LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME "DELAYED_IMPORT_ILT"
|
||||
#define LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME "DELAYED_IMPORT_BIAT"
|
||||
#define LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME "DELAYED_IMPORT_UIAT"
|
||||
#define LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME "DELAYED_IMPORT_CODE"
|
||||
|
||||
#define LNK_WIN32_HEADER_SYMBOL_NAME "WIN32_HEADER"
|
||||
#define LNK_DOS_SYMBOL_NAME "DOS"
|
||||
#define LNK_NT_HEADERS_SYMBOL_NAME "NT_HEADERS"
|
||||
#define LNK_PE_MAGIC_CONTAINER_SYMBOL_NAME "PE_MAGIC_CONTAINER"
|
||||
#define LNK_COFF_FILE_HEADER_CONTAINER_SYMBOL_NAME "COFF_FILE_HEADER_CONTAINER"
|
||||
#define LNK_PE_OPT_HEADER_CONTAINER_SYMBOL_NAME "PE_OPTIONAL_HEADER_CONTAINER"
|
||||
#define LNK_COFF_SECTION_HEADER_CONTAINER_SYMBOL_NAME "COFF_SECTION_HEADER_CONTAINER"
|
||||
|
||||
#define LNK_DOS_HEADER_SYMBOL_NAME "DOS_HEADER"
|
||||
#define LNK_DOS_PROGRAM_SYMBOL_NAME "DOS_PROGRAM"
|
||||
#define LNK_PE_MAGIC_SYMBOL_NAME "PE_MAGIC"
|
||||
#define LNK_COFF_HEADER_SYMBOL_NAME "COFF_HEADER"
|
||||
#define LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME "PE_DIRECTORY_ARRAY"
|
||||
#define LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME "PE_DIRECTORY_COUNT"
|
||||
#define LNK_PE_OPT_HEADER_SYMBOL_NAME "PE_OPTIONAL_HEADER"
|
||||
#define LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME "COFF_SECT_HEADER_ARRAY"
|
||||
#define LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME "COFF_SECT_HEADER_COUNT"
|
||||
#define LNK_PE_CHECKSUM_SYMBOL_NAME "PE_CHECKSUM"
|
||||
|
||||
// _tls_used is a special section in CRT which has format of
|
||||
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
|
||||
#define LNK_TLS_SYMBOL_NAME "_tls_used"
|
||||
|
||||
// _load_config_used points to SYMS_PeLoadConfig32/SYMS_PeLoadConfig64
|
||||
// and symbols below are used to patch patricual fields of the struct.
|
||||
#define LNK_LOAD_CONFIG_SYMBOL_NAME "_load_config_used"
|
||||
#define LNK_ENCLAVE_CONFIG_SYMBOL_NAME "__enclave_config"
|
||||
#define LNK_GUARD_FLAGS_SYMBOL_NAME "__guard_flags"
|
||||
#define LNK_GUARD_FIDS_TABLE_SYMBOL_NAME "__guard_fids_table"
|
||||
#define LNK_GUARD_FIDS_COUNT_SYMBOL_NAME "__guard_fids_count"
|
||||
#define LNK_GUARD_IAT_TABLE_SYMBOL_NAME "__guard_iat_table"
|
||||
#define LNK_GUARD_IAT_COUNT_SYMBOL_NAME "__guard_iat_count"
|
||||
#define LNK_GUARD_LONGJMP_TABLE_SYMBOL_NAME "__guard_longjmp_table"
|
||||
#define LNK_GUARD_LONGJMP_COUNT_SYMBOL_NAME "__guard_longjmp_count"
|
||||
#define LNK_GUARD_EHCONT_TABLE_SYMBOL_NAME "__guard_eh_cont_table"
|
||||
#define LNK_GUARD_EHCONT_COUNT_SYMBOL_NAME "__guard_eh_cont_count"
|
||||
// x86 load config fields
|
||||
#define LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME "__safe_se_handler_table"
|
||||
#define LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME "__safe_se_handler_count"
|
||||
|
||||
// load symbols from delayimp.lib
|
||||
#define LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME "__delayLoadHelper2"
|
||||
#define LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME "___delayLoadHelper2@8"
|
||||
|
||||
#define LNK_TEXT_SECTION_FLAGS (COFF_SectionFlag_CNT_CODE|COFF_SectionFlag_MEM_EXECUTE|COFF_SectionFlag_MEM_READ)
|
||||
#define LNK_DATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE)
|
||||
#define LNK_RDATA_SECTION_FLAGS (COFF_SectionFlag_CNT_INITIALIZED_DATA|COFF_SectionFlag_MEM_READ)
|
||||
#define LNK_BSS_SECTION_FLAGS (COFF_SectionFlag_CNT_UNINITIALIZED_DATA|COFF_SectionFlag_MEM_READ|COFF_SectionFlag_MEM_WRITE)
|
||||
#define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
|
||||
#define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
|
||||
#define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
|
||||
#define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_GFIDS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_GIATS_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_GLJMP_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_GEHCONT_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
|
||||
#define LNK_RELOC_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE)
|
||||
#define LNK_DEBUG_SECTION_FLAGS (LNK_RDATA_SECTION_FLAGS | COFF_SectionFlag_MEM_DISCARDABLE)
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_InputSource_CmdLine, // specified on command line
|
||||
LNK_InputSource_Default, // specified through defaultlib switch
|
||||
LNK_InputSource_Obj, // refrenced from objects
|
||||
LNK_InputSource_Count
|
||||
} LNK_InputSourceType;
|
||||
|
||||
typedef String8Node LNK_InputLib;
|
||||
typedef String8List LNK_InputLibList;
|
||||
|
||||
typedef struct LNK_InputImport
|
||||
{
|
||||
COFF_ImportHeader import_header;
|
||||
struct LNK_InputImport *next;
|
||||
} LNK_InputImport;
|
||||
|
||||
typedef struct LNK_InputImportList
|
||||
{
|
||||
U64 count;
|
||||
LNK_InputImport *first;
|
||||
LNK_InputImport *last;
|
||||
} LNK_InputImportList;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_BaseRelocPage
|
||||
{
|
||||
U64 voff;
|
||||
U64List entries;
|
||||
} LNK_BaseRelocPage;
|
||||
|
||||
typedef struct LNK_BaseRelocPageNode
|
||||
{
|
||||
struct LNK_BaseRelocPageNode *next;
|
||||
LNK_BaseRelocPage v;
|
||||
} LNK_BaseRelocPageNode;
|
||||
|
||||
typedef struct LNK_BaseRelocPageList
|
||||
{
|
||||
U64 count;
|
||||
LNK_BaseRelocPageNode *first;
|
||||
LNK_BaseRelocPageNode *last;
|
||||
} LNK_BaseRelocPageList;
|
||||
|
||||
typedef struct LNK_BaseRelocPageArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_BaseRelocPage *v;
|
||||
} LNK_BaseRelocPageArray;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 page_size;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_Reloc **reloc_arr;
|
||||
Rng1U64 *range_arr;
|
||||
LNK_BaseRelocPageList *list_arr;
|
||||
HashTable **page_ht_arr;
|
||||
} LNK_BaseRelocTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Rng1U64 *ranges;
|
||||
U64 page_size;
|
||||
LNK_Section **sect_id_map;
|
||||
LNK_BaseRelocPageList *list_arr;
|
||||
LNK_Obj **obj_arr;
|
||||
HashTable **page_ht_arr;
|
||||
} LNK_ObjBaseRelocTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_InputObjList input_obj_list;
|
||||
LNK_InputImportList input_import_list;
|
||||
LNK_SymbolList unresolved_symbol_list;
|
||||
} LNK_SymbolFinderResult;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PathStyle path_style;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SymbolNodeArray lookup_node_arr;
|
||||
LNK_SymbolFinderResult *result_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SymbolFinder;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
union {
|
||||
LNK_ObjNodeArray objs;
|
||||
LNK_LibNodeArray libs;
|
||||
} u;
|
||||
} LNK_SymbolPusher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *st;
|
||||
LNK_Section **sect_id_map;
|
||||
U64 base_addr;
|
||||
LNK_Section **sect_arr;
|
||||
Rng1U64 *range_arr;
|
||||
} LNK_SectionRelocPatcher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 image_data;
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SectionTable *st;
|
||||
LNK_Section **sect_id_map;
|
||||
U64 base_addr;
|
||||
LNK_Obj **obj_arr;
|
||||
} LNK_ObjRelocPatcher;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 path;
|
||||
String8 data;
|
||||
} LNK_WriteThreadContext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
String8 data;
|
||||
Rng1U64 *ranges;
|
||||
U128 *hashes;
|
||||
} LNK_Blake3Hasher;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_InputImport * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list);
|
||||
internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat);
|
||||
internal LNK_InputImport ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list);
|
||||
internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count);
|
||||
|
||||
////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
internal String8 lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, String8 path);
|
||||
|
||||
internal String8 lnk_get_lib_name(String8 path);
|
||||
internal B32 lnk_is_lib_disallowed(HashTable *disallow_lib_ht, String8 path);
|
||||
internal B32 lnk_is_lib_loaded(HashTable *loaded_lib_ht, String8 lib_path);
|
||||
internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, String8 path);
|
||||
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
// Manifest
|
||||
|
||||
internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list);
|
||||
internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list);
|
||||
|
||||
////////////////////////////////
|
||||
// Resources
|
||||
|
||||
internal void lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir);
|
||||
internal void lnk_add_resource_debug_s(LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array);
|
||||
internal String8 lnk_make_res_obj(TP_Context *tp, Arena *arena, PE_ResourceDir *root_dir, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array);
|
||||
internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name);
|
||||
|
||||
////////////////////////////////
|
||||
// Debug
|
||||
|
||||
internal String8 lnk_make_linker_coff_obj(TP_Context *tp, Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 cwd_path, String8 exe_path, String8 pdb_path, String8 cmd_line, String8 obj_name);
|
||||
|
||||
////////////////////////////////
|
||||
// Win32 Image Helpers
|
||||
|
||||
internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, U32 age, String8 pdb_path);
|
||||
internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, String8 rdi_path);
|
||||
internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
|
||||
internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, LNK_ObjList obj_list);
|
||||
internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk);
|
||||
internal LNK_Chunk * lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent);
|
||||
internal LNK_Chunk * lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics);
|
||||
internal LNK_Chunk * lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, U64 base_addr, U64 sect_align, U64 file_align, Version linker_ver, Version os_ver, Version image_ver, Version subsystem_ver, PE_WindowsSubsystem subsystem, PE_DllCharacteristics dll_characteristics, U64 stack_reserve, U64 stack_commit, U64 heap_reserve, U64 heap_commit, String8 entry_point_name, LNK_SectionArray sect_arr);
|
||||
internal LNK_Chunk * lnk_build_pe_directories(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent);
|
||||
internal LNK_Chunk * lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk, LNK_SectionArray sect_arr);
|
||||
internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk, LNK_Config *config, LNK_SectionArray sect_arr);
|
||||
|
||||
////////////////////////////////
|
||||
// Relocs
|
||||
|
||||
internal void lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
internal void lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *st, LNK_Section **sect_id_map, String8 image_data, U64 base_addr);
|
||||
|
||||
internal void lnk_apply_reloc(U64 base_addr, U64 virt_align, U64 file_align, LNK_Section **sect_id_map, LNK_SymbolTable *symtab, String8 chunk_data, LNK_Reloc *reloc);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal void lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab);
|
||||
internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st);
|
||||
internal void lnk_log_timers(void);
|
||||
|
||||
////////////////////////////////
|
||||
// Enum <-> String
|
||||
|
||||
internal String8 lnk_string_from_input_source(LNK_InputSourceType input_source);
|
||||
|
||||
@@ -0,0 +1,726 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal LNK_ChunkRef
|
||||
lnk_chunk_ref(U64 sect_id, U64 chunk_id)
|
||||
{
|
||||
LNK_ChunkRef ref = {0};
|
||||
ref.sect_id = sect_id;
|
||||
ref.chunk_id = chunk_id;
|
||||
return ref;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b)
|
||||
{
|
||||
B32 is_equal = a.sect_id == b.sect_id && a.chunk_id == b.chunk_id;
|
||||
return is_equal;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_list_push(Arena *arena, LNK_ChunkList *list, LNK_Chunk *chunk)
|
||||
{
|
||||
LNK_ChunkNode *node = push_array_no_zero(arena, LNK_ChunkNode, 1);
|
||||
node->next = 0;
|
||||
node->data = chunk;
|
||||
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_list_concat_in_place(LNK_ChunkList *list, LNK_ChunkList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_list_concat_in_place_arr(LNK_ChunkList *list, LNK_ChunkList *arr, U64 count)
|
||||
{
|
||||
SLLConcatInPlaceArray(list, arr, count);
|
||||
}
|
||||
|
||||
internal LNK_ChunkList **
|
||||
lnk_make_chunk_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count)
|
||||
{
|
||||
LNK_ChunkList **arr_arr = push_array_no_zero(arena, LNK_ChunkList *, slot_count);
|
||||
for (U64 i = 0; i < slot_count; i += 1) {
|
||||
arr_arr[i] = push_array(arena, LNK_ChunkList, per_count);
|
||||
}
|
||||
return arr_arr;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_chunk_sort_index_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
// Grouped Sections (PE Format)
|
||||
// "All contributions with the same object-section name are allocated contiguously in the image,
|
||||
// and the blocks of contributions are sorted in lexical order by object-section name."
|
||||
LNK_ChunkPtr *a = raw_a;
|
||||
LNK_ChunkPtr *b = raw_b;
|
||||
|
||||
// sort on section postfix
|
||||
int cmp = str8_compar_case_sensitive(&(*a)->sort_idx, &(*b)->sort_idx);
|
||||
|
||||
// sort on obj position on command line
|
||||
if (cmp == 0) {
|
||||
cmp = u64_compar(&(*a)->input_idx, &(*b)->input_idx);
|
||||
}
|
||||
|
||||
int is_before = cmp < 0;
|
||||
return is_before;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_array_sort(LNK_ChunkArray arr)
|
||||
{
|
||||
radsort(arr.v, arr.count, lnk_chunk_sort_index_is_before);
|
||||
}
|
||||
|
||||
internal LNK_ChunkManager *
|
||||
lnk_chunk_manager_alloc(Arena *arena, U64 id, U64 align)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkList temp_list = {0};
|
||||
|
||||
LNK_Chunk temp_chunk = {0};
|
||||
temp_chunk.ref = lnk_chunk_ref(id, 0);
|
||||
temp_chunk.align = align;
|
||||
temp_chunk.type = LNK_Chunk_List;
|
||||
temp_chunk.u.list = &temp_list;
|
||||
|
||||
LNK_ChunkManager *cman = push_array_no_zero(arena, LNK_ChunkManager, 1);
|
||||
cman->total_chunk_count = 1; // null chunk
|
||||
cman->root = 0;
|
||||
cman->root = lnk_chunk_push_list(arena, cman, &temp_chunk, str8(0,0));
|
||||
cman->root->align = align;
|
||||
|
||||
ProfEnd();
|
||||
return cman;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_(Arena *arena, LNK_Chunk *parent, U64 chunk_id, String8 sort_index)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
Assert(parent->type == LNK_Chunk_List);
|
||||
LNK_ChunkList *list = parent->u.list;
|
||||
|
||||
LNK_Chunk *chunk = push_array_no_zero(arena, LNK_Chunk, 1);
|
||||
chunk->ref = lnk_chunk_ref(parent->ref.sect_id, chunk_id);
|
||||
chunk->align = 1;
|
||||
chunk->is_discarded = 0;
|
||||
chunk->sort_chunk = 1;
|
||||
chunk->type = LNK_Chunk_Null;
|
||||
chunk->sort_idx = push_str8_copy(arena, sort_index);
|
||||
chunk->input_idx = list->count;
|
||||
chunk->flags = 0;
|
||||
chunk->associate = 0;
|
||||
|
||||
lnk_chunk_list_push(arena, list, chunk);
|
||||
|
||||
ProfEnd();
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index)
|
||||
{
|
||||
U64 chunk_id = cman->total_chunk_count;
|
||||
++cman->total_chunk_count;
|
||||
LNK_Chunk *chunk = lnk_chunk_push_(arena, parent, chunk_id, sort_index);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index, void *raw_ptr, U64 raw_size)
|
||||
{
|
||||
LNK_Chunk *chunk = lnk_chunk_push(arena, cman, parent, sort_index);
|
||||
chunk->type = LNK_Chunk_Leaf;
|
||||
chunk->u.leaf = str8((U8 *)raw_ptr, raw_size);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_Chunk *
|
||||
lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index)
|
||||
{
|
||||
LNK_Chunk *chunk = lnk_chunk_push(arena, cman, parent, sort_index);
|
||||
chunk->type = LNK_Chunk_List;
|
||||
chunk->u.list = push_array(arena, LNK_ChunkList, 1);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_ChunkNode *dst_root_node = push_array_no_zero(arena, LNK_ChunkNode, 1);
|
||||
LNK_ChunkNode *src_root_node = push_array_no_zero(scratch.arena, LNK_ChunkNode, 1);
|
||||
src_root_node->next = 0;
|
||||
src_root_node->data = chunk;
|
||||
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkNode *src_node;
|
||||
LNK_ChunkNode *dst_node;
|
||||
};
|
||||
struct Stack *stack = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
stack->next = 0;
|
||||
stack->src_node = src_root_node;
|
||||
stack->dst_node = dst_root_node;
|
||||
|
||||
while (stack) {
|
||||
while (stack->src_node) {
|
||||
LNK_Chunk *src = stack->src_node->data;
|
||||
LNK_Chunk *dst = stack->dst_node->data;
|
||||
|
||||
stack->src_node = stack->src_node->next;
|
||||
stack->dst_node = stack->dst_node->next;
|
||||
|
||||
dst->ref = src->ref;
|
||||
dst->align = src->align;
|
||||
dst->sort_idx = push_str8_copy(arena, src->sort_idx);
|
||||
dst->type = src->type;
|
||||
dst->flags = src->flags;
|
||||
lnk_chunk_set_debugf(arena, dst, "%S", src->debug);
|
||||
|
||||
switch (src->type) {
|
||||
case LNK_Chunk_Null: break;
|
||||
case LNK_Chunk_Leaf: {
|
||||
B32 is_bss = src->u.leaf.str == 0;
|
||||
if (is_bss) {
|
||||
dst->u.leaf = src->u.leaf;
|
||||
} else {
|
||||
dst->u.leaf = push_str8_copy(arena, src->u.leaf);
|
||||
}
|
||||
} break;
|
||||
case LNK_Chunk_List: {
|
||||
LNK_ChunkNode *chain = 0;
|
||||
LNK_ChunkNode *curr = 0;
|
||||
if (src->u.list->count > 0) {
|
||||
chain = push_array(arena, LNK_ChunkNode, src->u.list->count);
|
||||
curr = chain;
|
||||
for (U64 i = 1; i < src->u.list->count; ++i) {
|
||||
curr->next = &chain[i];
|
||||
curr = curr->next;
|
||||
}
|
||||
curr->next = 0;
|
||||
}
|
||||
|
||||
dst->u.list = push_array_no_zero(arena, LNK_ChunkList, 1);
|
||||
dst->u.list->count = src->u.list->count;
|
||||
dst->u.list->first = chain;
|
||||
dst->u.list->last = curr;
|
||||
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
frame->src_node = src->u.list->first;
|
||||
frame->dst_node = dst->u.list->first;
|
||||
SLLStackPush(stack, frame);
|
||||
} break;
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
}
|
||||
|
||||
SLLStackPop(stack);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return dst_root_node;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 0);
|
||||
|
||||
Assert(src->ref.sect_id != dst->ref.sect_id);
|
||||
Assert(dst->type == LNK_Chunk_List);
|
||||
Assert(src->type != LNK_Chunk_Null);
|
||||
|
||||
LNK_ChunkNode *src_node = push_array(arena, LNK_ChunkNode, 1);
|
||||
src_node->data = src;
|
||||
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkNode *node;
|
||||
};
|
||||
struct Stack *stack = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
stack->next = 0;
|
||||
stack->node = src_node;
|
||||
|
||||
while (stack) {
|
||||
while (stack->node) {
|
||||
LNK_Chunk *chunk = stack->node->data;
|
||||
|
||||
// advance node
|
||||
stack->node = stack->node->next;
|
||||
|
||||
// allocate id
|
||||
U64 new_id = dst_cman->total_chunk_count++;
|
||||
|
||||
// write id map
|
||||
Assert(chunk->ref.chunk_id < id_map_max);
|
||||
id_map_out[chunk->ref.chunk_id] = new_id;
|
||||
|
||||
// update id
|
||||
chunk->ref = lnk_chunk_ref(dst->ref.sect_id, new_id);
|
||||
|
||||
// recurse down on lists
|
||||
if (chunk->type == LNK_Chunk_List) {
|
||||
struct Stack *frame = push_array_no_zero(scratch.arena, struct Stack, 1);
|
||||
frame->next = 0;
|
||||
frame->node = chunk->u.list->first;
|
||||
SLLStackPush(stack, frame);
|
||||
}
|
||||
}
|
||||
|
||||
// reached end of chunk list, pop frame
|
||||
SLLStackPop(stack);
|
||||
}
|
||||
|
||||
// move source root copy to destination section
|
||||
LNK_ChunkList *list = dst->u.list;
|
||||
++list->count;
|
||||
SLLQueuePush(list->first, list->last, src_node);
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return src_node;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *chunk)
|
||||
{
|
||||
// for simplicity we don't support multiple associations,
|
||||
// but it's possible to craft symbol table with multiple associations
|
||||
Assert(!chunk->associate);
|
||||
chunk->associate = head;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_chunk_is_discarded(LNK_Chunk *chunk)
|
||||
{
|
||||
B32 is_discarded = chunk->is_discarded;
|
||||
LNK_Chunk *curr = chunk->associate;
|
||||
while (!is_discarded && curr) {
|
||||
is_discarded = curr->is_discarded;
|
||||
curr = curr->associate;
|
||||
}
|
||||
return is_discarded;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_chunk_get_size(LNK_Chunk *chunk)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Null: break;
|
||||
case LNK_Chunk_Leaf: {
|
||||
result = chunk->u.leaf.size;
|
||||
} break;
|
||||
case LNK_Chunk_LeafArray:
|
||||
case LNK_Chunk_List: {
|
||||
Assert(!"TODO: list size");
|
||||
} break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_chunk_list_get_node_count(LNK_Chunk *chunk)
|
||||
{
|
||||
Assert(chunk->type == LNK_Chunk_List);
|
||||
return chunk->u.list->count;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_chunk_align_array_list_push(Arena *arena, Arena *scratch, LNK_ChunkAlignArrayList *list, U64 cap, U64 align_off, U64 align_size)
|
||||
{
|
||||
if (align_size > 0) {
|
||||
if (list->last == 0 || list->last->data.count >= list->last->cap) {
|
||||
LNK_ChunkAlignArrayNode *node = push_array(scratch, LNK_ChunkAlignArrayNode, 1);
|
||||
node->cap = cap;
|
||||
node->data.v = push_array_no_zero(arena, LNK_ChunkAlign, cap);
|
||||
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
}
|
||||
|
||||
LNK_ChunkAlignArray *last_array = &list->last->data;
|
||||
LNK_ChunkAlign *align = &last_array->v[last_array->count++];
|
||||
align->off = align_off;
|
||||
align->size = align_size;
|
||||
}
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count)
|
||||
{
|
||||
ProfBeginV("lnk_layout_from_chunk [total_chunk_count = %llu]", total_chunk_count);
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_ChunkLayout layout = {0};
|
||||
layout.total_count = total_chunk_count;
|
||||
layout.chunk_ptr_array = push_array_no_zero(arena, LNK_ChunkPtr, total_chunk_count);
|
||||
layout.chunk_off_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_file_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
layout.chunk_virt_size_array = push_array_no_zero(arena, U64, total_chunk_count);
|
||||
|
||||
ProfBegin("Init Arrays");
|
||||
for (U64 i = 0; i < total_chunk_count; ++i) {
|
||||
layout.chunk_ptr_array[i] = &g_null_chunk;
|
||||
}
|
||||
#if BUILD_DEBUG
|
||||
MemorySet(layout.chunk_off_array, 0xff, total_chunk_count * sizeof(layout.chunk_off_array));
|
||||
MemorySet(layout.chunk_file_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_file_size_array));
|
||||
MemorySet(layout.chunk_virt_size_array, 0xff, total_chunk_count * sizeof(layout.chunk_virt_size_array));
|
||||
#endif
|
||||
ProfEnd();
|
||||
|
||||
// handle null chunk
|
||||
layout.chunk_off_array[0] = 0;
|
||||
layout.chunk_file_size_array[0] = 0;
|
||||
layout.chunk_virt_size_array[0] = 0;
|
||||
|
||||
// setup stack
|
||||
struct Stack {
|
||||
struct Stack *next;
|
||||
LNK_ChunkArray chunk_array;
|
||||
U64 ichunk;
|
||||
};
|
||||
struct Stack *stack = push_array(scratch.arena, struct Stack, 1);
|
||||
stack->chunk_array.count = 1;
|
||||
stack->chunk_array.v = &root;
|
||||
|
||||
U64 align_cap = 4096;
|
||||
LNK_ChunkAlignArrayList align_list = {0};
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
ProfBegin("Traverse chunks from root");
|
||||
for (; stack != 0; ) {
|
||||
for (; stack->ichunk < stack->chunk_array.count; ) {
|
||||
LNK_Chunk *chunk = stack->chunk_array.v[stack->ichunk++];
|
||||
|
||||
// skip discarded chunk
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// push align
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> chunk
|
||||
Assert(chunk->ref.chunk_id < total_chunk_count);
|
||||
Assert(layout.chunk_ptr_array[chunk->ref.chunk_id] == &g_null_chunk);
|
||||
layout.chunk_ptr_array[chunk->ref.chunk_id] = chunk;
|
||||
|
||||
// store id -> offset
|
||||
Assert(layout.chunk_off_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_off_array[chunk->ref.chunk_id] = cursor;
|
||||
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Leaf: {
|
||||
// store id -> file size
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// store id -> virt size
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = chunk->u.leaf.size;
|
||||
|
||||
// advance
|
||||
cursor += chunk->u.leaf.size;
|
||||
} break;
|
||||
|
||||
case LNK_Chunk_LeafArray: {
|
||||
#if BUILD_DEBUG
|
||||
for (U64 i = 0; i < chunk->u.arr->count; ++i) {
|
||||
Assert(chunk->u.arr->v[i]->type == LNK_Chunk_Leaf);
|
||||
}
|
||||
#endif
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(*chunk->u.arr);
|
||||
}
|
||||
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = *chunk->u.arr;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_List: {
|
||||
// list -> array
|
||||
LNK_ChunkArray chunk_array = {0};
|
||||
chunk_array.v = push_array_no_zero(scratch.arena, LNK_ChunkPtr, chunk->u.list->count);
|
||||
for (LNK_ChunkNode *cptr = chunk->u.list->first; cptr != 0; cptr = cptr->next) {
|
||||
chunk_array.v[chunk_array.count++] = cptr->data;
|
||||
}
|
||||
|
||||
// apply sort
|
||||
if (chunk->sort_chunk) {
|
||||
lnk_chunk_array_sort(chunk_array);
|
||||
}
|
||||
|
||||
// recurse into sub chunks
|
||||
struct Stack *frame = push_array(scratch.arena, struct Stack, 1);
|
||||
frame->chunk_array = chunk_array;
|
||||
SLLStackPush(stack, frame);
|
||||
} goto _continue;
|
||||
|
||||
case LNK_Chunk_Null: break;
|
||||
}
|
||||
}
|
||||
|
||||
// terminate series
|
||||
if (stack->next) {
|
||||
// pop node chunk from stack
|
||||
struct Stack *prev = stack->next;
|
||||
Assert(prev->ichunk > 0);
|
||||
|
||||
// align chunk end
|
||||
LNK_Chunk *chunk = prev->chunk_array.v[prev->ichunk-1];
|
||||
U64 align_size = AlignPadPow2(cursor, chunk->align);
|
||||
lnk_chunk_align_array_list_push(arena, scratch.arena, &align_list, align_cap, cursor, align_size);
|
||||
|
||||
U64 chunk_start_off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(chunk_start_off != max_U64);
|
||||
Assert(chunk_start_off <= cursor);
|
||||
|
||||
// store id -> virt size
|
||||
Assert(layout.chunk_virt_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
U64 virt_chunk_size = cursor - chunk_start_off;
|
||||
layout.chunk_virt_size_array[chunk->ref.chunk_id] = virt_chunk_size;
|
||||
|
||||
// advance cursor
|
||||
cursor += align_size;
|
||||
|
||||
// store id -> file size
|
||||
Assert(layout.chunk_file_size_array[chunk->ref.chunk_id] == max_U64);
|
||||
U64 file_chunk_size = cursor - chunk_start_off;
|
||||
layout.chunk_file_size_array[chunk->ref.chunk_id] = file_chunk_size;
|
||||
}
|
||||
|
||||
// move to next frame
|
||||
SLLStackPop(stack);
|
||||
|
||||
_continue:;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Build Aligns Array");
|
||||
layout.align_array_count = 0;
|
||||
layout.align_array = push_array(arena, LNK_ChunkAlignArray, align_list.count);
|
||||
for (LNK_ChunkAlignArrayNode *node = align_list.first; node != 0; node = node->next) {
|
||||
layout.align_array[layout.align_array_count++] = node->data;
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal LNK_ChunkLayout
|
||||
lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
LNK_ChunkLayout layout = lnk_layout_from_chunk(arena, cman->root, cman->total_chunk_count);
|
||||
ProfEnd();
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_chunks_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
|
||||
for (U64 chunk_idx = range.min; chunk_idx < range.max; ++chunk_idx) {
|
||||
LNK_Chunk *chunk = layout.chunk_ptr_array[chunk_idx];
|
||||
|
||||
if (lnk_chunk_is_discarded(chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunk->type == LNK_Chunk_Leaf) {
|
||||
U64 off = layout.chunk_off_array[chunk->ref.chunk_id];
|
||||
Assert(off + chunk->u.leaf.size <= buffer.size);
|
||||
U8 *buffer_ptr = buffer.str + off;
|
||||
|
||||
if (chunk->u.leaf.str == 0) {
|
||||
// zero out chunk bytes
|
||||
MemorySet(buffer_ptr, 0, chunk->u.leaf.size);
|
||||
} else {
|
||||
// copy chunk bytes
|
||||
MemoryCopy(buffer_ptr, chunk->u.leaf.str, chunk->u.leaf.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_fill_aligns_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_ChunkLayoutSerializer *task = raw_task;
|
||||
Rng1U64 range = task->ranges[task_id];
|
||||
LNK_ChunkLayout layout = task->layout;
|
||||
String8 buffer = task->buffer;
|
||||
U8 fill_byte = task->fill_byte;
|
||||
|
||||
for (U64 align_array_idx = range.min; align_array_idx < range.max; ++align_array_idx) {
|
||||
LNK_ChunkAlignArray align_array = layout.align_array[align_array_idx];
|
||||
for (U64 align_idx = 0; align_idx < align_array.count; ++align_idx) {
|
||||
LNK_ChunkAlign align = align_array.v[align_idx];
|
||||
Assert(align.off + align.size <= buffer.size);
|
||||
MemorySet(buffer.str + align.off, fill_byte, align.size);
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_serialize_chunk_layout(TP_Context *tp, LNK_ChunkLayout layout, String8 buffer, U8 fill_byte)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
LNK_ChunkLayoutSerializer task;
|
||||
task.layout = layout;
|
||||
task.buffer = buffer;
|
||||
task.fill_byte = fill_byte;
|
||||
|
||||
ProfBeginV("Fill Chunks [Chunk Count %llu]", layout.total_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.total_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_chunks_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
ProfBeginV("Fill Aligns [Array Count %llu]", layout.align_array_count);
|
||||
task.ranges = tp_divide_work(scratch.arena, layout.align_array_count, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_fill_aligns_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_visit_chunks_(U64 sect_id, LNK_Chunk *chunk, LNK_ChunkVisitorSig *cb, void *ud)
|
||||
{
|
||||
// visit chunk
|
||||
B32 is_done = cb(sect_id, chunk, ud);
|
||||
if (is_done) {
|
||||
return is_done;
|
||||
}
|
||||
|
||||
switch (chunk->type) {
|
||||
case LNK_Chunk_Null:
|
||||
case LNK_Chunk_Leaf: {
|
||||
// reached leaf
|
||||
} break;
|
||||
case LNK_Chunk_LeafArray: {
|
||||
for (U64 idx = 0; idx < chunk->u.arr->count; idx += 1) {
|
||||
is_done = lnk_visit_chunks_(sect_id, chunk->u.arr->v[idx], cb, ud);
|
||||
if (is_done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case LNK_Chunk_List: {
|
||||
for (LNK_ChunkNode *i = chunk->u.list->first; i != 0; i = i->next) {
|
||||
is_done = lnk_visit_chunks_(sect_id, i->data, cb, ud);
|
||||
if (is_done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return is_done;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_visit_chunks(U64 sect_id, LNK_Chunk *chunk, LNK_ChunkVisitorSig *cb, void *ud)
|
||||
{
|
||||
lnk_visit_chunks_(sect_id, chunk, cb, ud);
|
||||
}
|
||||
|
||||
LNK_CHUNK_VISITOR_SIG(lnk_save_chunk_ptr)
|
||||
{
|
||||
LNK_Chunk **id_map = (LNK_Chunk **)ud;
|
||||
if (!chunk->is_discarded) {
|
||||
id_map[chunk->ref.chunk_id] = chunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal LNK_ChunkPtr *
|
||||
lnk_make_chunk_id_map(Arena *arena, LNK_ChunkManager *cman)
|
||||
{
|
||||
LNK_ChunkPtr *map = push_array_no_zero(arena, LNK_ChunkPtr, cman->total_chunk_count);
|
||||
lnk_visit_chunks(0, cman->root, lnk_save_chunk_ptr, map);
|
||||
map[0] = &g_null_chunk;
|
||||
return map;
|
||||
}
|
||||
|
||||
internal LNK_ChunkNode *
|
||||
lnk_chunk_ptr_list_reserve(Arena *arena, LNK_ChunkList *list, U64 count)
|
||||
{
|
||||
LNK_ChunkNode *arr = 0;
|
||||
if (count) {
|
||||
arr = push_array(arena, LNK_ChunkNode, count);
|
||||
LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, count);
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
arr[i].data = &chunk_arr[i];
|
||||
SLLQueuePush(list->first, list->last, &arr[i]);
|
||||
}
|
||||
list->count += count;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8Array
|
||||
lnk_data_arr_from_chunk_ptr_list(Arena *arena, LNK_ChunkList list)
|
||||
{
|
||||
String8Array arr = {0};
|
||||
arr.v = push_array(arena, String8, list.count);
|
||||
for (LNK_ChunkNode *n = list.first; n != 0; n = n->next) {
|
||||
LNK_ChunkPtr c = n->data;
|
||||
Assert(c->type == LNK_Chunk_Leaf);
|
||||
arr.v[arr.count] = c->u.leaf;
|
||||
arr.count += 1;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
internal String8Array *
|
||||
lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 count)
|
||||
{
|
||||
String8Array *result = push_array(arena, String8Array, count);
|
||||
for (U64 i = 0; i < count; i += 1) {
|
||||
result[i] = lnk_data_arr_from_chunk_ptr_list(arena, list_arr[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
#define LNK_DEBUG_CHUNKS 0
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef struct LNK_ChunkRef
|
||||
{
|
||||
U64 sect_id;
|
||||
U64 chunk_id;
|
||||
} LNK_ChunkRef;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LNK_Chunk_Null,
|
||||
LNK_Chunk_Leaf,
|
||||
LNK_Chunk_LeafArray,
|
||||
LNK_Chunk_List,
|
||||
} LNK_ChunkType;
|
||||
|
||||
typedef struct LNK_Chunk
|
||||
{
|
||||
LNK_ChunkRef ref;
|
||||
LNK_ChunkType type;
|
||||
U64 align;
|
||||
B32 is_discarded;
|
||||
B32 sort_chunk;
|
||||
String8 sort_idx;
|
||||
U64 input_idx;
|
||||
COFF_SectionFlags flags;
|
||||
struct LNK_Chunk *associate;
|
||||
union {
|
||||
String8 leaf;
|
||||
struct LNK_ChunkList *list;
|
||||
struct LNK_ChunkArray *arr;
|
||||
} u;
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
String8 debug;
|
||||
#endif
|
||||
} LNK_Chunk, * LNK_ChunkPtr;
|
||||
|
||||
typedef struct LNK_ChunkNode
|
||||
{
|
||||
struct LNK_ChunkNode *next;
|
||||
LNK_ChunkPtr data;
|
||||
} LNK_ChunkNode;
|
||||
|
||||
typedef struct LNK_ChunkArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkPtr *v;
|
||||
} LNK_ChunkArray;
|
||||
|
||||
typedef struct LNK_ChunkList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkNode *first;
|
||||
LNK_ChunkNode *last;
|
||||
} LNK_ChunkList;
|
||||
|
||||
typedef enum LNK_ChunkOpType
|
||||
{
|
||||
LNK_ChunkOp_Null,
|
||||
LNK_ChunkOp_WriteString,
|
||||
LNK_ChunkOp_Align,
|
||||
LNK_ChunkOp_Begin,
|
||||
LNK_ChunkOp_End,
|
||||
LNK_ChunkOp_EndVirt,
|
||||
} LNK_ChunkOpType;
|
||||
|
||||
typedef struct LNK_ChunkOp
|
||||
{
|
||||
struct LNK_ChunkOp *next;
|
||||
LNK_ChunkOpType type;
|
||||
union {
|
||||
String8 string;
|
||||
LNK_Chunk *chunk;
|
||||
struct {
|
||||
U64 val;
|
||||
U64 x;
|
||||
} align;
|
||||
LNK_Chunk *leaf;
|
||||
} u;
|
||||
} LNK_ChunkOp;
|
||||
|
||||
typedef struct LNK_ChunkOpList
|
||||
{
|
||||
U64 total_chunk_count;
|
||||
LNK_ChunkOp *first;
|
||||
LNK_ChunkOp *last;
|
||||
} LNK_ChunkOpList;
|
||||
|
||||
typedef struct LNK_ChunkAlign
|
||||
{
|
||||
U64 off;
|
||||
U64 size;
|
||||
} LNK_ChunkAlign;
|
||||
|
||||
typedef struct LNK_ChunkAlignArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkAlign *v;
|
||||
} LNK_ChunkAlignArray;
|
||||
typedef struct LNK_ChunkAlignArrayNode
|
||||
{
|
||||
struct LNK_ChunkAlignArrayNode *next;
|
||||
U64 cap;
|
||||
LNK_ChunkAlignArray data;
|
||||
} LNK_ChunkAlignArrayNode;
|
||||
typedef struct LNK_ChunkAlignArrayList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ChunkAlignArrayNode *first;
|
||||
LNK_ChunkAlignArrayNode *last;
|
||||
} LNK_ChunkAlignArrayList;
|
||||
|
||||
typedef struct LNK_ChunkLayout
|
||||
{
|
||||
U64 total_count;
|
||||
LNK_Chunk **chunk_ptr_array; // discarded chunks point to g_null_chunk
|
||||
U64 *chunk_off_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_file_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 *chunk_virt_size_array; // discarded chunks have offset set to max_U64
|
||||
U64 align_array_count;
|
||||
LNK_ChunkAlignArray *align_array;
|
||||
} LNK_ChunkLayout;
|
||||
|
||||
typedef struct LNK_ChunkManager
|
||||
{
|
||||
LNK_Chunk *root;
|
||||
U64 total_chunk_count;
|
||||
} LNK_ChunkManager;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_ChunkLayout layout;
|
||||
String8 buffer;
|
||||
U8 fill_byte;
|
||||
Rng1U64 *ranges;
|
||||
} LNK_ChunkLayoutSerializer;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
read_only global LNK_Chunk g_null_chunk = { 0, 0, /* is_discarded: */ 1 };
|
||||
read_only global LNK_Chunk *g_null_chunk_ptr = &g_null_chunk;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal LNK_ChunkRef lnk_chunk_ref(U64 sect_id, U64 chunk_id);
|
||||
internal B32 lnk_chunk_ref_is_equal(LNK_ChunkRef a, LNK_ChunkRef b);
|
||||
|
||||
internal LNK_ChunkNode * lnk_chunk_list_push(Arena *arena, LNK_ChunkList *list, LNK_Chunk *chunk);
|
||||
internal void lnk_chunk_list_concat_in_place(LNK_ChunkList *list, LNK_ChunkList *to_concat);
|
||||
internal void lnk_chunk_list_concat_in_place_arr(LNK_ChunkList *list, LNK_ChunkList *arr, U64 count);
|
||||
internal LNK_ChunkList ** lnk_make_chunk_list_arr_arr(Arena *arena, U64 slot_count, U64 per_count);
|
||||
internal void lnk_chunk_array_sort(LNK_ChunkArray arr);
|
||||
|
||||
internal LNK_ChunkManager * lnk_chunk_manager_alloc(Arena *arena, U64 id, U64 align);
|
||||
internal LNK_Chunk * lnk_chunk_push(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index);
|
||||
internal LNK_Chunk * lnk_chunk_push_leaf(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index, void *raw_ptr, U64 raw_size);
|
||||
internal LNK_Chunk * lnk_chunk_push_list(Arena *arena, LNK_ChunkManager *cman, LNK_Chunk *parent, String8 sort_index);
|
||||
internal LNK_ChunkNode * lnk_chunk_deep_copy(Arena *arena, LNK_Chunk *chunk);
|
||||
internal LNK_ChunkNode * lnk_merge_chunks(Arena *arena, LNK_ChunkManager *dst_cman, LNK_Chunk *dst, LNK_Chunk *src, U64 *id_map_out, U64 id_map_max);
|
||||
internal void lnk_chunk_associate(Arena *arena, LNK_Chunk *head, LNK_Chunk *associate);
|
||||
internal B32 lnk_chunk_is_discarded(LNK_Chunk *chunk);
|
||||
internal U64 lnk_chunk_get_size(LNK_Chunk *chunk);
|
||||
internal U64 lnk_chunk_list_get_node_count(LNK_Chunk *chunk);
|
||||
|
||||
internal void lnk_chunk_op_list_push_node(LNK_ChunkOpList *list, LNK_ChunkOp *op);
|
||||
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_begin(Arena *arena, U64 chunk_id);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_end_virt(Arena *arena);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_end_file(Arena *arena);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_align(Arena *arena, U64 align, U64 val);
|
||||
internal LNK_ChunkOp * lnk_push_chunk_op_write(Arena *arena, String8 string);
|
||||
|
||||
internal LNK_ChunkLayout lnk_layout_from_chunk(Arena *arena, LNK_Chunk *root, U64 total_chunk_count);
|
||||
internal LNK_ChunkLayout lnk_build_chunk_layout(Arena *arena, LNK_ChunkManager *cman);
|
||||
|
||||
#define LNK_CHUNK_VISITOR_SIG(name) B32 name(U64 sect_id, LNK_Chunk *chunk, void *ud)
|
||||
typedef LNK_CHUNK_VISITOR_SIG(LNK_ChunkVisitorSig);
|
||||
internal void lnk_visit_chunks(U64 sect_id, LNK_Chunk *root, LNK_ChunkVisitorSig *cb, void *ud);
|
||||
|
||||
internal LNK_ChunkNode * lnk_chunk_ptr_list_reserve(Arena *arena, LNK_ChunkList *list, U64 count);
|
||||
internal String8Array lnk_data_arr_from_chunk_ptr_list(Arena *arena, LNK_ChunkList list);
|
||||
internal String8Array * lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 count);
|
||||
|
||||
#if LNK_DEBUG_CHUNKS
|
||||
#define lnk_chunk_set_debugf(a, c, f, ...) do { (c)->debug = push_str8f((a), f, __VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define lnk_chunk_set_debugf(a, c, f, ...) (void)(c)
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user