mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9086233d89 | ||
|
|
ad1b2fa23d | ||
|
|
f67098f54b | ||
|
|
ea4e671a44 | ||
|
|
0c4c18c64f | ||
|
|
ba9d68951d | ||
|
|
340d504f10 | ||
|
|
e8f03562bf | ||
|
|
c946f88b2a | ||
|
|
56e7bae038 | ||
|
|
c1741b4f39 | ||
|
|
ba41543543 | ||
|
|
5ae60aedc5 | ||
|
|
f23979e20a | ||
|
|
57fb0eb833 | ||
|
|
5d2d13d9d9 | ||
|
|
8342cfbd53 | ||
|
|
2721adf088 | ||
|
|
ffcecd659e | ||
|
|
0ccfb51102 | ||
|
|
f41f8dd719 | ||
|
|
fa6b04ab24 | ||
|
|
156615a3ba | ||
|
|
57a35c6b28 | ||
|
|
76ce8a79c2 | ||
|
|
932db741fa | ||
|
|
0add3ef72c | ||
|
|
e417a96ce4 | ||
|
|
b2262532a7 | ||
|
|
b24326f502 | ||
|
|
66c1fa337c |
@@ -1,8 +0,0 @@
|
|||||||
*.sh text=auto eol=lf
|
|
||||||
src/lib_rdi/rdi.h text=auto eol=lf
|
|
||||||
src/lib_rdi/rdi.c text=auto eol=lf
|
|
||||||
*.meta.* text=auto eol=lf
|
|
||||||
*.exe filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.pdb filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.elf filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.rdi filter=lfs diff=lfs merge=lfs -text
|
|
||||||
+11
-132
@@ -8,144 +8,23 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
env:
|
|
||||||
TORTURE_FLAGS: "--gen_crash_dump"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-ubuntu-24-04:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- raddbg
|
|
||||||
- raddbg_non_graphical
|
|
||||||
- radlink
|
|
||||||
- radbin
|
|
||||||
- torture
|
|
||||||
compiler:
|
|
||||||
- clang-22
|
|
||||||
# TODO: - gcc
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Install Dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
|
|
||||||
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
|
|
||||||
- name: build
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
CC="${{ matrix.compiler }}" ./build.sh "${{ matrix.target }}" "${{ matrix.mode }}"
|
|
||||||
|
|
||||||
build-windows-2022:
|
build-windows-2022:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- raddbg
|
|
||||||
- radlink
|
|
||||||
- radbin
|
|
||||||
- mule_main
|
|
||||||
compiler:
|
|
||||||
- msvc
|
|
||||||
- clang
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: build (vs 2022)
|
- name: build (vs 2022)
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
call build raddbg msvc debug || exit /b 1
|
||||||
call build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
|
call build raddbgi_from_pdb msvc debug || exit /b 1
|
||||||
|
call build raddbgi_from_dwarf msvc debug || exit /b 1
|
||||||
run-ubuntu-24-04:
|
call build raddbgi_dump msvc debug || exit /b 1
|
||||||
runs-on: ubuntu-24.04
|
call build raddbg clang debug || exit /b 1
|
||||||
strategy:
|
call build raddbgi_from_pdb clang debug || exit /b 1
|
||||||
fail-fast: false
|
call build raddbgi_from_dwarf clang debug || exit /b 1
|
||||||
matrix:
|
call build raddbgi_dump clang debug || exit /b 1
|
||||||
compiler:
|
|
||||||
- clang-22
|
|
||||||
# TODO: - gcc
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
# TODO: - release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Install Dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
|
|
||||||
# crash callstack symbolizer depends on LLVM
|
|
||||||
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
|
|
||||||
- name: Run
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
CC="${{ matrix.compiler }}" ./run_tests.sh clang "${{ matrix.mode }}" -- \* $TORTURE_FLAGS
|
|
||||||
- name: Upload Artifacts
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
|
|
||||||
path: |
|
|
||||||
build/*.core
|
|
||||||
build/*.exe
|
|
||||||
build/*.pdb
|
|
||||||
build/torture_artifacts/**
|
|
||||||
if-no-files-found: ignore
|
|
||||||
|
|
||||||
run-windows-2022:
|
|
||||||
runs-on: windows-2022
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
compiler:
|
|
||||||
- msvc
|
|
||||||
- clang
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Run
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
|
|
||||||
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
|
||||||
call run_tests.bat ${{ matrix.compiler }} ${{ matrix.mode }} -- * %TORTURE_FLAGS% || exit /b 1
|
|
||||||
- name: Upload Artifacts
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
|
|
||||||
path: |
|
|
||||||
build/*.dmp
|
|
||||||
build/*.exe
|
|
||||||
build/*.pdb
|
|
||||||
build/torture_artifacts/**
|
|
||||||
if-no-files-found: ignore
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
/build/
|
/build/
|
||||||
/local/
|
/local/
|
||||||
*~
|
*~
|
||||||
.vs
|
|
||||||
tags
|
|
||||||
-399
@@ -1,399 +0,0 @@
|
|||||||
# v0.9.28-alpha
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
- Implemented `/OPT:ICF` identical COMDAT folding.
|
|
||||||
- Added DEF, and SECTION configuration support.
|
|
||||||
- Improved COMDAT handling for weak symbols, ICF, and zero-sized COMDAT
|
|
||||||
anchors, and stopped emitting empty marker sections that could produce invalid
|
|
||||||
PE images.
|
|
||||||
- Fixed import/export edge cases, including import data-directory bounds and
|
|
||||||
archive member handling for `__imp_*` symbols.
|
|
||||||
- Accepted duplicate identical weak search aliases without reporting multiply
|
|
||||||
defined symbols.
|
|
||||||
- Add support for UTF-16 encoded response files.
|
|
||||||
- Fixed DBI section-contribution image-section range mapping.
|
|
||||||
- Improved debug logging for `/OPT:REF` liveness stats and unresolved symbols
|
|
||||||
referenced by `.llvm_addrsig`.
|
|
||||||
|
|
||||||
# v0.9.27-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Fixed an issue which would rarely cause steps to take a long time.
|
|
||||||
- Drastically improved memory usage of PDB -> RDI conversion for some
|
|
||||||
workloads, notably PDBs with many small compilation units.
|
|
||||||
- Added the ability to disambiguate symbol names by module name, debug info
|
|
||||||
name, or compilation unit name in expressions. This can be done using the
|
|
||||||
usual syntax, e.g. `my_module.dll!foo`, or `my_unit.obj!foo`. `:` can also be
|
|
||||||
used instead of `!`.
|
|
||||||
- Added the ability to redirect debug string output to any label on a
|
|
||||||
per-target basis. Those labels can then be evaluated in any watch window or
|
|
||||||
text visualizer. By default, all targets write to `output`, which is
|
|
||||||
automatically visualized by an `Output` tab. But if you want different
|
|
||||||
targets to route their debug output to different buffers, you can name the
|
|
||||||
buffers differently, and then view those in separate text views.
|
|
||||||
- Added a `Run To Name` command.
|
|
||||||
- Added an `Auto Load Last Project` setting, which will automatically load the
|
|
||||||
most recently loaded project on startup (the old behavior pre-0.9.26). This
|
|
||||||
setting is off by default.
|
|
||||||
- Added right-click menus for watch expressions, to easily find them in a
|
|
||||||
memory view, or to break when their value changes.
|
|
||||||
- Added preliminary support for symbol servers. First, the debugger can attempt
|
|
||||||
to download debug info for any module via the `Download Module Debug Info`
|
|
||||||
command (also accessible by right-clicking a module). Second, the debugger
|
|
||||||
can be configured to automatically do this for all modules which don't have
|
|
||||||
debug info via the `Auto Download Debug Info` setting. The local cache path
|
|
||||||
and server URLs used by the debugger for downloading symbols are parsed from
|
|
||||||
the `_NT_SYMBOL_PATH` environment variable. If that environment variable is
|
|
||||||
not configured, then it falls back to the defaults of `C:/SymbolCache` and
|
|
||||||
`https://msdl.microsoft.com/download/symbols`.
|
|
||||||
- Adjusted the default dark theme.
|
|
||||||
- Made several UI visual improvements.
|
|
||||||
- Fixed a few issues relating to offline symbol evaluation (evaluation of
|
|
||||||
symbols in debug info when not debugging); this was sometimes preventing
|
|
||||||
function listers (e.g. used in `Go To Name`) from working when not debugging.
|
|
||||||
- Fixed the debugger's snap-to-code-location rule when a `Disassembly` tab is
|
|
||||||
occupying the same panel as source code tabs. Previously, the debugger would
|
|
||||||
overly aggressively switch back to source code tabs. Now, it should respect
|
|
||||||
the preference of disassembly correctly.
|
|
||||||
- Improved the stability of the step-over-line operation. Our stepping
|
|
||||||
algorithm would sometimes cause spurious (and rarely, non-spurious)
|
|
||||||
access violation exceptions when a thread would try to execute at address
|
|
||||||
`0x38f`. This most regularly surfaced when an exception on one thread (like a
|
|
||||||
breakpoint being hit) would interrupt stepping on another thread. This has
|
|
||||||
been resolved, and stepping in such scenarios should be much more reliable.
|
|
||||||
- Fixed some crashes in the PDB -> RDI converter. (#792, #803)
|
|
||||||
- Fixed a bug which was sometimes causing a step-over operation to resume the
|
|
||||||
process without catching the target thread after its step completed. (#804)
|
|
||||||
- Adjusted evaluation visualizations to include fully qualified symbol names.
|
|
||||||
(#809)
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
- /OPT:REF Fixed a race in the dead-code-elimination pass where the linker
|
|
||||||
sometimes erroneously removed live sections.
|
|
||||||
- Fixed a bug where the linker emitted relocations for empty COFF resource entries,
|
|
||||||
which lead to "relocating against symbol that is in a removed section" errors.
|
|
||||||
- Added the /RAD_TYPE_SERVER switch to run the type-dedup pass on object files,
|
|
||||||
producing RRT files that can be passed back on the next link to improve
|
|
||||||
linking speed.
|
|
||||||
|
|
||||||
# v0.9.26-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added scope ending visualizations to the text view, to display the header of
|
|
||||||
a scope at the closing position of the scope. This can be turned off via the
|
|
||||||
`Cursor Scope End Annotations` setting.
|
|
||||||
- Added the ability to evaluate `autos`, which is a collection of expressions
|
|
||||||
that the debugger determines refer to symbols which are being (or about to
|
|
||||||
be) changed by the selected thread.
|
|
||||||
- Added source-inline and disassembly-inline visualization of auto expressions.
|
|
||||||
This can be turned off via the `Show Auto Watches In Source / Disassembly`
|
|
||||||
setting.
|
|
||||||
- Added the ability to evaluate local static variables unambiguously, when the
|
|
||||||
same name is used for multiple local static variables, even when outside the
|
|
||||||
function containing the local static. This can be done by namespacing the
|
|
||||||
variable name with the containing function, either using a `::` or `.`
|
|
||||||
operator. (#359)
|
|
||||||
- Added a setting, `Transient Tabs`, to disable transient tabs being opened,
|
|
||||||
when the debugger automatically snaps to new code locations.
|
|
||||||
- Added a setting, `Display Pointer Addresses Before Contents`, to always
|
|
||||||
force the debugger to show pointer addresses before attempting to visualize
|
|
||||||
to what the pointer points.
|
|
||||||
- Adjusted the `Step Out` command to perform scope-granularity stepping, rather
|
|
||||||
than only being function-frame-granularity. This uses scope information found
|
|
||||||
in debug info to step out of scopes when possible, rather than always exiting
|
|
||||||
the current function frame. This makes the command much more useful for
|
|
||||||
stepping through larger functions with several scopes of larger work, or for
|
|
||||||
stepping out of loops. (#746)
|
|
||||||
- Adjusted the debugger's user & project configuration file behavior to be less
|
|
||||||
idiosyncratic with other programs. Project files are no longer auto-loaded
|
|
||||||
based on the project last loaded during the previous debugger runtime.
|
|
||||||
Creating a new user or project also does not immediately require choosing a
|
|
||||||
path for the file; these can later be specified using the respective `Save`
|
|
||||||
commands. (#743)
|
|
||||||
- Adjusted the debugger to automatically set the current path when loading a
|
|
||||||
project file. (#743)
|
|
||||||
- Added syntax highlighting and tab-completion for view identifiers in
|
|
||||||
watch expressions.
|
|
||||||
- Added more in-debugger documentation for views and their arguments, when
|
|
||||||
written in a watch expression.
|
|
||||||
- Moved configuration data previously treated as project data to being user
|
|
||||||
data, tagged with the associated project. This includes loaded debug info and
|
|
||||||
breakpoints. The effect of this is that project files are much easier to
|
|
||||||
check into source control (they do not change in spurious ways for other
|
|
||||||
users on a project), but project-related user configuration will still be
|
|
||||||
correctly filtered based on whatever project is loaded.
|
|
||||||
- Improved the debugger's behavior with respect to keeping previously-loaded
|
|
||||||
debug info around. Now, when the debugger begins a new debugging session, it
|
|
||||||
will unload all loaded debug info, and it will only reload debug info that is
|
|
||||||
actively found to be needed by debuggees. This preserves the debugger's
|
|
||||||
ability to use debug info without debugging for features like
|
|
||||||
go-to-definition and type evaluation, but it stops the debugger from keeping
|
|
||||||
old and unneeded debug info loaded indefinitely (until it is manually
|
|
||||||
unloaded). (#711)
|
|
||||||
- Adjusted recent project visualization to include the name of the project,
|
|
||||||
specified with the `Project Name` setting.
|
|
||||||
- Renamed `Switch` to `Open Source File From Debug Info`, to better represent
|
|
||||||
the command's functionality.
|
|
||||||
- Adjusted file path evaluation visualization to include the full path to the
|
|
||||||
containing folder, when it is not obvious from context (for instance, if the
|
|
||||||
file evaluation is a child evaluation of a folder evaluation, the containing
|
|
||||||
folder path is not shown; if the file path is evaluated standalone, as it is
|
|
||||||
in the lister generated for the `Open Source File From Debug Info` command,
|
|
||||||
then the containing folder path is shown).
|
|
||||||
- Improved visualization of unmapped addresses in the memory view. Now, instead
|
|
||||||
of bytes at these addresses being displayed as `0` with a special background,
|
|
||||||
they are displayed as `x`, and the annotations for these addresses (displayed
|
|
||||||
at the bottom of the memory view, for the cursor's cell) explicitly label
|
|
||||||
them as being unmapped.
|
|
||||||
- Improved visualization of unmapped addresses in watch expressions. Now,
|
|
||||||
instead of only being colored differently with evaluations reading as zeroed
|
|
||||||
memory, the value will explicitly label addresses as unmapped when possible.
|
|
||||||
- Fixed a leak which most notably manifested during rapid creation/destruction
|
|
||||||
of new threads. (#780)
|
|
||||||
- Fixed a leak related to debugger's config state. This was difficult to
|
|
||||||
reproduce, but it may fix leaks experienced after running the debugger for an
|
|
||||||
extended period of time.
|
|
||||||
- Fixed a bug where cross-module evaluations would resolve to incorrect
|
|
||||||
addresses, due to using the incorrect module's base virtual address. This was
|
|
||||||
also causing broken behavior sometimes in the `Go To Name` lister, and
|
|
||||||
other similar UIs.
|
|
||||||
- Fixed a bug where panels without tabs were unnecessarily keeping the debugger
|
|
||||||
UI awake in some cases.
|
|
||||||
- Fixed a bug preventing hover evaluation from working on indexing expressions.
|
|
||||||
(#707)
|
|
||||||
- Replaced the DWARF -> RDI converter with a new multithreaded version, which
|
|
||||||
should execute much faster on larger DWARF debug info, and produce much
|
|
||||||
smaller RDI output, due to the addition of type deduplication.
|
|
||||||
- Introduced structured namespaces to RDI, which structurally encode namespace
|
|
||||||
hierarchies for debug info symbols, instead of this information being
|
|
||||||
implicitly baked using language-specific conventions into symbol names. This
|
|
||||||
is used to deduplicate repeated namespace prefixes from symbol names, leading
|
|
||||||
to a smaller string footprint for generated RDIs. Symbols now only store
|
|
||||||
their partially-qualified name. For example, for a C++ symbol `A::B::C`, the
|
|
||||||
symbol itself will store its name as `C`, but it will also record its
|
|
||||||
container as being `B`. `B`, then, will record its container as being `A`.
|
|
||||||
This allows users of RDI to dynamically construct the fully-qualified name as
|
|
||||||
needed, and it allows for more reliable and language-agnostic usage of
|
|
||||||
partially-qualified symbol names.
|
|
||||||
- Adjusted the debugger to not rely on `SynchronizationBarrier` functions on
|
|
||||||
Windows when they're not available (pre-Windows-8). (#739)
|
|
||||||
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Implemented /DEBUG:GHASH
|
|
||||||
- Fixed an issue where an import thunk or import address could be linked from
|
|
||||||
the currently searched library instead of the library where the first import
|
|
||||||
reference was found. For example, if the first pass finds the import thunk in
|
|
||||||
foo.lib and the second pass resolves symbol to the import address in bar.lib,
|
|
||||||
the linker now always linkes the import thunk and import address members from
|
|
||||||
the library where the first reference was found.
|
|
||||||
- /OPT:REF: Fixed an issue with garbage collection of associated sections and
|
|
||||||
weak symbols that led linker to remove live sections.
|
|
||||||
- /OPT:REF Added relocation batching to reduce contention on the global
|
|
||||||
reference list during garbage collection.
|
|
||||||
|
|
||||||
# v0.9.25-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added a dedicated cursor address bar to the memory view. This can be focused
|
|
||||||
with the keyboard with the `Focus Menu` command. By default, this command is
|
|
||||||
bound to `Alt + D`, but if you have existing configuration, you may need to
|
|
||||||
bind it yourself manually (this can be done in the palette). This address bar
|
|
||||||
accepts any expression, and controls the cursor's address. All other
|
|
||||||
configuration options are still available in the memory view settings.
|
|
||||||
- Added "Peek Types" to the memory view. These control the set of types which
|
|
||||||
are used to interpret bytes at the cursor. Options exist for basic cases,
|
|
||||||
like integers and floats, but the view also supports entering a list of
|
|
||||||
full type expressions, which can include user-defined types like structures.
|
|
||||||
- Added annotations for members of structure variables to the memory view.
|
|
||||||
- Added a dedicated zoom setting for the memory view.
|
|
||||||
- Added a setting for automatically determining the number of columns in the
|
|
||||||
memory view based on the available space.
|
|
||||||
- Fixed many bugs and improved visuals in the memory view. (#690)
|
|
||||||
- Fixed the debugger incorrectly evaluating pointer casts of registers in
|
|
||||||
register space, rather than promoting them to process address space
|
|
||||||
evaluations. This fixes cases where expressions like `(int *)rax` were not
|
|
||||||
evaluating correctly. (#659)
|
|
||||||
- Fixed the debugger incorrectly requiring multiple step operations when source
|
|
||||||
lines mapped to multiple discontiguous ranges of instructions. This most
|
|
||||||
notably showed up with certain styles of `for`-loops, especially with Clang
|
|
||||||
and other non-C/C++ languages, and function prologues in non-C/C++ languages.
|
|
||||||
- Fixed the debugger treating the `foo, x` fastpath for `hex(foo)` differently
|
|
||||||
than `hex(foo)`, in that the hexadecimal setting was not being inherited.
|
|
||||||
- Fixed the debugger leaking debug info conversion process handles. This
|
|
||||||
addresses cases where the debugger was preventing stale debug info from being
|
|
||||||
updated, after a rebuild. (#736)
|
|
||||||
- Fixed the debugger not correctly using target-embedded markup data. (#702)
|
|
||||||
- Fixed the debugger not showing full call stacks when the top instruction
|
|
||||||
pointer is located at a 0 address.
|
|
||||||
- Fixed integer casts producing incorrect values. (#754)
|
|
||||||
- Fixed the PDB -> RDI converter's interpretation of certain empty argument
|
|
||||||
lists in function types in PDB. This fixes some cases where local variables
|
|
||||||
were being interpreted as parameters, which resulted in incorrect evaluation
|
|
||||||
results. (#751)
|
|
||||||
- Fixed several crashes and instabilities. (#735)
|
|
||||||
- Added a dedicated settings button to the focused tab. This opens the same
|
|
||||||
menu as right-clicking the tab, but this makes this menu (and thus all
|
|
||||||
options for all tabs and views) more discoverable.
|
|
||||||
- Added optional cursor trails, to visualize cursor motion. Can be turned off
|
|
||||||
by toggling the `Cursor Trail` setting.
|
|
||||||
- Added project names. When set, this name is used for displaying the project
|
|
||||||
instead of the project filename in the UI and window titles.
|
|
||||||
- Adjusted the rules for explicit file location finding commands (like
|
|
||||||
`Switch`, or `Switch To Partner File`), such that they prefer creating new
|
|
||||||
non-transient tabs, even if the target file is found within an existing
|
|
||||||
transient tab.
|
|
||||||
- Adjusted the source code context menu to activate commands with a single
|
|
||||||
press, rather than the usual double click behavior from general palettes.
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Optimized debug info generation to reduce memory usage in large links by 25%.
|
|
||||||
- Fixed a determinism issue that caused linker to write unreliable debug info.
|
|
||||||
- Fixed over-reservetaion of PDB pages, reducing the PDB size.
|
|
||||||
- Implemented /INFERASANLIBS
|
|
||||||
- Implemented /WHOLEARCHIVE
|
|
||||||
- Implemented /PDBSTRIPPED
|
|
||||||
- Set correct defaults for unload and bind import tables.
|
|
||||||
|
|
||||||
# v0.9.24-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added the ability for the debugger to load, use, and evaluate using debug
|
|
||||||
info, even when not actively debugging. The debugger will now keep a process'
|
|
||||||
debug info loaded, even after the process ends. It stores the set of loaded
|
|
||||||
debug info files in the project configuration file, meaning it will also
|
|
||||||
automatically load the same debug info across many runs. Debug info can also
|
|
||||||
be loaded manually (without ever launching a process) with the
|
|
||||||
`Load Debug Info` command. There is also a new tab, `Debug Info`, which allows
|
|
||||||
viewing and managing the set of loaded debug info files.
|
|
||||||
- Improved the debugger's behavior when used as a drag & drop target, to allow
|
|
||||||
for debug info loading as an option (when relevant), and to better handle the
|
|
||||||
case where many files (potentially of different types) are dropped together.
|
|
||||||
- Improved debug info searching performance and reponsiveness in large projects.
|
|
||||||
- Fixed some crashes and incorrect results with the new `list` view.
|
|
||||||
- Fixed some cases where RDIs did not contain some basic types from their
|
|
||||||
originating PDBs.
|
|
||||||
- Allowed `.` and `->` operators to be used with array types.
|
|
||||||
- Fixed the debugger's treatment of quoted command line arguments when building
|
|
||||||
targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would
|
|
||||||
create a target `main.exe` with arguments `foo bar baz` (dropping the quotes).
|
|
||||||
This is now fixed, such that the target's arguments string will also contain
|
|
||||||
the quotes, and pass them to the target when launched.
|
|
||||||
- Fixed the debugger not correctly responding (through font and UI scale) to DPI
|
|
||||||
changes.
|
|
||||||
- Fixed the debugger incorrectly generating conflicting source line info records
|
|
||||||
in PDB -> RDI conversion, which in some scenarios was preventing source line
|
|
||||||
maps from working (leading to breakpoint resolution failing).
|
|
||||||
- Other small fixes, improvements, and tweaks.
|
|
||||||
|
|
||||||
# v0.9.23-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance & memory usage.
|
|
||||||
- Adjusted limits for the amount of PDB -> RDI conversion work that the
|
|
||||||
debugger will kick off, to prevent PDB -> RDI conversion interfering with
|
|
||||||
debuggee performance.
|
|
||||||
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
|
|
||||||
visualizes them as a flat list of pointers (the same as how an array of
|
|
||||||
pointers is visualized).
|
|
||||||
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
|
|
||||||
- Fixed the debugger not visualizing `enum` types when evaluated through a
|
|
||||||
bitfield type. (#655)
|
|
||||||
- Fixed the PDB -> RDI conversion not correctly generating location information
|
|
||||||
for function parameters, when the EXE/PDB were built to include support for
|
|
||||||
Edit and Continue (`-ZI` switch). (#656)
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- Fixed a crash when using the `--compress` option, when generating RDI files.
|
|
||||||
|
|
||||||
# v0.9.22-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance.
|
|
||||||
- Capped the number of additional threads / processes spawned for PDB -> RDI
|
|
||||||
conversion.
|
|
||||||
- Prioritize PDB -> RDI conversion based on what is actually found to be
|
|
||||||
necessary by the debugger, rather than converting all PDBs in the order in
|
|
||||||
which they're discovered.
|
|
||||||
- Added preliminary support for DWARF -> RDI conversion on Windows.
|
|
||||||
- The debugger now relies on source file checksums to determine whether or not
|
|
||||||
a source file is out-of-date with respect to what was compiled when debug info
|
|
||||||
was produced, rather than just the modification timestamp.
|
|
||||||
- The debugger now will rely on debug info to detect the language of source code
|
|
||||||
files, if it cannot infer from the source file's extension, or view settings.
|
|
||||||
This will enable features like syntax highlighting and hover evaluation in
|
|
||||||
cases like `.inl` files being included in C++ projects.
|
|
||||||
- The debugger now will restore the last focused window when continuing
|
|
||||||
automatically. (#245, #596)
|
|
||||||
- Watch tables have been simplified in that they no longer have a separate
|
|
||||||
column for evaluation types, since this was usually taking a lot more space
|
|
||||||
than it deserved. The type of evaluations is still displayed in watch table
|
|
||||||
cells, and it can always be evaluated directly via `typeof`.
|
|
||||||
- Type evaluations have been simplified in watch tables as well; they no longer
|
|
||||||
have untitled columns for sizes and offsets, this is instead displayed as
|
|
||||||
an extra note by default. Similar behavior to the original behavior can still
|
|
||||||
be obtained using the `columns` view, if needed.
|
|
||||||
- The debugger no longer uses complex `union` types for most registers, and
|
|
||||||
instead just displays the register value plainly.
|
|
||||||
- The hover evaluation UI has been made larger when needed.
|
|
||||||
- The debugger now prefers matching global, function, and type identifiers to
|
|
||||||
the most relevant debug info and module in context; this fixes evaluation in
|
|
||||||
some multi-process debugging contexts. (#581)
|
|
||||||
- Fixed the debugger unnecessarily stripping `enum` type information when
|
|
||||||
accessed through array operators. (#634)
|
|
||||||
- The debugger now understands a standalone `unsigned` keyword as an
|
|
||||||
`unsigned int` type, to match C rules.
|
|
||||||
- The debugger now uses the current working directory to form the working
|
|
||||||
directory for targets specified on the command line, to match behavior when
|
|
||||||
running a command from the command line without the debugger.
|
|
||||||
- Improved call stack computation performance.
|
|
||||||
- Improved debugger memory usage over long periods of time.
|
|
||||||
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
|
|
||||||
- Fixed a bug which was causing bad debuggee performance on some threads after
|
|
||||||
some interactions with the debugger controller.
|
|
||||||
- Fixed incorrect results when adding two register values. (#642)
|
|
||||||
- Fixed the interpretation of register expressions in visualizers. (#649)
|
|
||||||
- Fixed "forever loading" states in disassembly views in some cases. (#643)
|
|
||||||
- Fixed jittering on window resizing. (#636)
|
|
||||||
- Fixed the bitmap visualizer crashing in some circumstances relating to
|
|
||||||
unsupported bitmap sizes. (#444, #563)
|
|
||||||
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
|
|
||||||
- Fixed a crash when an invalid expression would be visualized using the `text`
|
|
||||||
view. (#647)
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Changed symbol resolution in libaries to match MSVC behavior.
|
|
||||||
- Optimized image building step to reduce memory usage.
|
|
||||||
- Linker memory maps all input files by default to lower memory usage.
|
|
||||||
(`/RAD_MEMORY_MAP_FILES`)
|
|
||||||
- If debug info is available, linker uses it to show file and line number for
|
|
||||||
unresolved relocations.
|
|
||||||
- Improved base relocation build performance for large images, cutting build
|
|
||||||
time by 70%.
|
|
||||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
|
|
||||||
with existing response files
|
|
||||||
- Implemented section garbage collection (`/OPT:REF`)
|
|
||||||
- Fixed bug where thread local variables pointed to incorrect types.
|
|
||||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
|
|
||||||
to replace an undefined symbol.
|
|
||||||
- Linker no longer creates thunks for imports that don't require them.
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- The binary utility, like the debugger, now can convert DWARF debug info to
|
|
||||||
RDI files. When both DWARF and PDB info is present, it can now convert both,
|
|
||||||
and produce a single final RDI file with all information.
|
|
||||||
- Textual dumping of RDI files is now done in parallel, massively improving
|
|
||||||
dumping performance.
|
|
||||||
- PDB -> Breakpad conversion performance has now been parallelized to a greater
|
|
||||||
degree, improving performance.
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) Epic Games Tools
|
Copyright (c) 2024 Epic Games Tools
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the “Software”), to deal in
|
this software and associated documentation files (the “Software”), to deal in
|
||||||
|
|||||||
@@ -1,93 +1,45 @@
|
|||||||
# The RAD Debugger Project
|
# The RAD Debugger Project
|
||||||
|
|
||||||
_**NOTE:** This README does not document usage instructions and tips for the
|
_**Note:** This README does not document usage instructions and tips for the
|
||||||
debugger itself, and is intended as a technical overview of the project. The
|
debugger itself, and is intended as a technical overview of the project. The
|
||||||
debugger's README, which includes usage instructions and tips, can be found
|
debugger's README, which includes usage instructions and tips, can be found
|
||||||
packaged along with debugger releases, or within the `build` folder after a
|
packaged along with debugger releases, or within the `build` folder after a
|
||||||
local copy has been built. You can find pre-built release binaries
|
local copy has been built._
|
||||||
[here](https://github.com/EpicGames/raddebugger/releases)._
|
|
||||||
|
|
||||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||||
plans to expand and port in the future. In the future we'll expand to also
|
plans to expand and port in the future. In the future we'll expand to also
|
||||||
support native Linux debugging and DWARF debug info.
|
support native Linux debugging and DWARF debug info.
|
||||||
|
|
||||||
The debugger is currently in *ALPHA*. In order to get the debugger
|
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
|
||||||
bullet-proof, it'd greatly help out if you submitted the issues you find
|
proof, it'd greatly help out if you submitted the issues you find here, along
|
||||||
[here](https://github.com/EpicGames/raddebugger/issues), along with any
|
with any information you can gather, like dump files (along with the build you
|
||||||
information you can gather, like dump files (along with the build you used),
|
used), instructions to reproduce, test executables, and so on.
|
||||||
instructions to reproduce, test executables, and so on.
|
|
||||||
|
|
||||||
In addition to the debugger, we aim to further improve the toolchain with two
|
You can download pre-built binaries for the debugger
|
||||||
additional related technologies: **(1)** the RAD Debug Info (RDI) format, and
|
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||||
**(2)** the RAD Linker.
|
|
||||||
|
|
||||||
## The RAD Debug Info (RDI) Format
|
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||||
|
unifying the underlying debug info format. In that pursuit we've built the RAD
|
||||||
The RAD Debug Info (RDI) format is our custom debug information format, which
|
Debug Info (RDI) format, which is what the debugger parses and uses. To work
|
||||||
the debugger parses and uses, rather than the debug information natively
|
with existing toolchains, we convert PDB (and eventually PE/ELF files with
|
||||||
produced by toolchains, like PDB or DWARF. To work with these existing
|
embedded DWARF) into the RDI format on-demand.
|
||||||
toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF)
|
|
||||||
into the RDI format on-demand.
|
|
||||||
|
|
||||||
The RDI format is currently specified in code, in the files within the
|
The RDI format is currently specified in code, in the files within the
|
||||||
`src/lib_rdi` folder. In [`rdi.h`](src/lib_rdi/rdi.h) and
|
`src/lib_rdi_format` folder. The other relevant folders for working with the
|
||||||
[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format
|
format are:
|
||||||
itself are specified. In [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) and
|
|
||||||
[`rdi_parse.c`](src/lib_rdi/rdi_parse.c), helpers for parsing the format are
|
|
||||||
included.
|
|
||||||
|
|
||||||
We also have an in-progress library for constructing and serializing RDI data,
|
- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info.
|
||||||
located within the `src/lib_rdi_make` folder.
|
- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase
|
||||||
|
layer, or built as an executable with a command line interface frontend.
|
||||||
|
- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter.
|
||||||
|
- `rdi_dump`: Our RDI textual dumping utility.
|
||||||
|
|
||||||
Our `radbin` utility (accessible through the debugger too, via the `--bin`
|
## Development Setup Instructions
|
||||||
command line argument) is capable of converting native debug information formats
|
|
||||||
to RDI, and of producing textual dumps of contents stored within RDI files.
|
|
||||||
|
|
||||||
## The RAD Linker
|
**Note: Currently, only x64 Windows development is supported.**
|
||||||
|
|
||||||
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries.
|
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||||
It is designed to be very fast when creating gigantic executables. It generates
|
|
||||||
standard PDB files for debugging, but it can also (optionally) natively create
|
|
||||||
RAD Debug Info too, which is useful both to eliminate on-demand conversion time
|
|
||||||
when debugging, but also 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; 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
|
|
||||||
link-time-optimizations, but this feature is on the road map.
|
|
||||||
|
|
||||||
By default, the 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.
|
|
||||||
|
|
||||||
A benchmark of the linker's performance is below:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Project Development Setup Instructions
|
|
||||||
|
|
||||||
**NOTE: Currently, only x64 Windows development is supported for the project.**
|
|
||||||
|
|
||||||
## 1. Installing the Required Tools (MSVC & Windows SDK)
|
|
||||||
|
|
||||||
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
||||||
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
||||||
@@ -96,7 +48,7 @@ the Windows SDK and the MSVC compiler and linker.
|
|||||||
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
||||||
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
||||||
|
|
||||||
## 2. Build Environment Setup
|
### 2. Build Environment Setup
|
||||||
|
|
||||||
Building the codebase can be done in a terminal which is equipped with the
|
Building the codebase can be done in a terminal which is equipped with the
|
||||||
ability to call either MSVC or Clang from command line.
|
ability to call either MSVC or Clang from command line.
|
||||||
@@ -140,63 +92,33 @@ You should see the following output:
|
|||||||
[msvc compile]
|
[msvc compile]
|
||||||
[default mode, assuming `raddbg` build]
|
[default mode, assuming `raddbg` build]
|
||||||
metagen_main.c
|
metagen_main.c
|
||||||
searching C:\devel\raddebugger/src... 458 files found
|
searching C:\devel\raddebugger/src... 299 files found
|
||||||
parsing metadesk... 16 metadesk files parsed
|
parsing metadesk... 12 metadesk files parsed
|
||||||
gathering tables... 97 tables found
|
gathering tables... 37 tables found
|
||||||
generating layer code...
|
generating layer code...
|
||||||
raddbg_main.c
|
raddbg.cpp
|
||||||
```
|
```
|
||||||
|
|
||||||
If everything worked correctly, there will be a `build` folder in the root
|
If everything worked correctly, there will be a `build` folder in the root
|
||||||
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
||||||
|
|
||||||
This `raddbg.exe` will have been built in **debug mode**, which is not built
|
## Short-To-Medium-Term Roadmap
|
||||||
with optimizations, and may perform worse. To produce a
|
|
||||||
**release mode executable**, run `build.bat` with a `release` argument:
|
|
||||||
|
|
||||||
```
|
|
||||||
build release
|
|
||||||
```
|
|
||||||
|
|
||||||
This build will take significantly longer.
|
|
||||||
|
|
||||||
By default, `build.bat` only builds the debugger if no arguments (or just
|
|
||||||
`release`) are passed, but additional arguments can be passed to build the RAD
|
|
||||||
Linker, or the `radbin` CLI binary file utility:
|
|
||||||
|
|
||||||
```
|
|
||||||
build radlink release
|
|
||||||
build radbin release
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Project Roadmap
|
|
||||||
|
|
||||||
### The Initial Alpha Battle-Testing Phase
|
### The Initial Alpha Battle-Testing Phase
|
||||||
|
|
||||||
The first priority for the project is to ensure that the most crucial components
|
The first priority for the project is to ensure that the most crucial debugger
|
||||||
are functioning extremely reliably for local, x64, Windows development.
|
components are functioning extremely reliably for local, x64, Windows
|
||||||
For the debugger, this would include parts like debug info conversion, debug
|
debugging. This would include parts like debug info conversion, debug info
|
||||||
info loading, process control, stepping, evaluation (correct usage of both
|
loading, process control, stepping, evaluation (correct usage of both location
|
||||||
location info and type info), and a robust frontend which ensures the lower
|
info and type info), and a robust frontend which ensures the lower level parts
|
||||||
level parts are usable. For the linker, this is a matter of reliability and
|
are usable.
|
||||||
convergence with existing linker behavior.
|
|
||||||
|
|
||||||
We feel that we've already come a long way in all of these respects, but given
|
We feel that the debugger has already come a long way in all of these respects,
|
||||||
the massive set of possible combinations of languages, build settings,
|
but given the massive set of possible combinations of languages, build
|
||||||
toolchains, used language features, and patterns of generated code, we still
|
settings, toolchains, used language features, and patterns of generated code,
|
||||||
expect some issues, and are prioritizing these issues being resolved first.
|
there are still cases where the debugger has not been tested, and so there are
|
||||||
|
still issues. So, we feel that the top priority is eliminating these issues,
|
||||||
We also hope to continue to improve performance in this phase. For the debugger,
|
such that the debugging experience is rock solid.
|
||||||
this primarily includes frontend performance, introducing caches when economical
|
|
||||||
to do so, and tightening existing systems up. For the linker, it has been mostly
|
|
||||||
tuned thus far for giant projects, and so we'd like to improve linking speed for
|
|
||||||
small-to-mid sized projects as well.
|
|
||||||
|
|
||||||
For the linker, there are also a number of features to come, like
|
|
||||||
dead-code-elimination (`/opt:ref`), and link-time-optimizations with the help
|
|
||||||
of `clang` (we won't support LTCG from MSVC, since it is undocumented).
|
|
||||||
|
|
||||||
### Local x64 Linux Debugging Phase
|
### Local x64 Linux Debugging Phase
|
||||||
|
|
||||||
@@ -237,10 +159,6 @@ like remote debugging, porting to different architectures, further improving
|
|||||||
the debugger's features (like improving the visualization engine), and so on.
|
the debugger's features (like improving the visualization engine), and so on.
|
||||||
But for now, we're mostly focused on those first two phases.
|
But for now, we're mostly focused on those first two phases.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Codebase Introduction
|
|
||||||
|
|
||||||
## Top-Level Directory Descriptions
|
## Top-Level Directory Descriptions
|
||||||
|
|
||||||
- `data`: Small binary files which are used when building, either to embed
|
- `data`: Small binary files which are used when building, either to embed
|
||||||
@@ -251,10 +169,9 @@ After setting up the codebase and building, the following directories will
|
|||||||
also exist:
|
also exist:
|
||||||
|
|
||||||
- `build`: All build artifacts. Not checked in to version control.
|
- `build`: All build artifacts. Not checked in to version control.
|
||||||
- `local`: Local files, used for local build configuration input files. Not
|
- `local`: Local files, used for local build configuration input files.
|
||||||
checked in to version control.
|
|
||||||
|
|
||||||
## Layer Descriptions
|
## Codebase Introduction
|
||||||
|
|
||||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||||
certain problems, and to allow inclusion into various builds without needing to
|
certain problems, and to allow inclusion into various builds without needing to
|
||||||
@@ -282,85 +199,69 @@ so in other words, layers are arranged into a directed acyclic graph.
|
|||||||
A few layers are built to be used completely independently from the rest of the
|
A few layers are built to be used completely independently from the rest of the
|
||||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
codebase, as libraries in other codebases and projects. As such, these layers do
|
||||||
not depend on any other layers in the codebase. The folders which contain these
|
not depend on any other layers in the codebase. The folders which contain these
|
||||||
layers are prefixed with `lib_`, like `lib_rdi`.
|
layers are prefixed with `lib_`, like `lib_rdi_format`.
|
||||||
|
|
||||||
A list of the layers in the codebase and their associated namespaces is below:
|
A list of the layers in the codebase and their associated namespaces is below:
|
||||||
- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of
|
|
||||||
computation artifacts, which are automatically evicted when not accessed. Used
|
|
||||||
for asynchronously streaming and caching process memory and file system
|
|
||||||
contents, as well as asynchronously preparing visualizer data.
|
|
||||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||||
memory allocators, helper macros, command-line parsing, and so on. Requires
|
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||||
no other codebase layers.
|
on no other codebase layers.
|
||||||
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
|
- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format.
|
||||||
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
|
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||||
Format) file format.
|
Format) file format.
|
||||||
- `content` (`C_`): Implements a cache for general data blobs, keyed by a
|
|
||||||
128-bit hash of the data. Also implements a keying system on top, where keys
|
|
||||||
refer to a unique identity which corresponds to a history of 128-bit hashes.
|
|
||||||
Used as a general data store by other layers.
|
|
||||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||||
asynchronous process control, stepping, and breakpoints for all attached
|
asynchronous process control, stepping, and breakpoints for all attached
|
||||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||||
processes are halted. When attached processes are running, it is halted.
|
processes are halted. When attached processes are running, it is halted.
|
||||||
Driven by a debugger frontend on another thread.
|
Driven by a debugger frontend on another thread.
|
||||||
- `dbg_engine` (`D_`): Implements the core debugger system, without any
|
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||||
graphical components. This contains top-level logic for things like stepping,
|
disassembly for a particular virtual address range in a process, and threads
|
||||||
launching, freezing threads, mid-run breakpoint addition, some caches, and so
|
implemented in this layer decode and cache the disassembly for that range.
|
||||||
on.
|
- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info
|
||||||
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
|
stored in the RDI format. Users ask for debug info for a particular path, and
|
||||||
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
|
on separate threads, this layer loads the associated debug info file. If
|
||||||
Launches separate processes for on-demand conversion to the RDI format if
|
necessary, it will launch a separate conversion process to convert original
|
||||||
necessary. Also provides various asynchronous operations for using debug info,
|
debug info into the RDI format.
|
||||||
like fuzzy searching across all records in loaded debug info.
|
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||||
- `demon` (`DMN_`): An abstraction layer for local-machine, low-level process
|
|
||||||
control. The abstraction is used to provide a common interface for process
|
control. The abstraction is used to provide a common interface for process
|
||||||
control on target platforms. Used to implement part of `ctrl`.
|
control on target platforms. Used to implement part of `ctrl`.
|
||||||
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
|
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||||
ability to compute and cache disassembly asynchronously.
|
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||||
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
|
breakpoints, source files, targets, and so on). Implements a command loop
|
||||||
debugger's purposes, using the underlying `render` abstraction layer. Provides
|
for driving process control, which is used to implement stepping commands and
|
||||||
high-level APIs for various draw commands, but takes care of batching them,
|
user breakpoints. Implements extractors and caches for various entity-related
|
||||||
and so on.
|
data, like full thread unwinds and local variable maps. Also implements core
|
||||||
- `dwarf` (`DW_`): Code for parsing the DWARF format.
|
building blocks for evaluation and evaluation visualization.
|
||||||
- `eh` (`EH_`): Code for parsing the EH frame format.
|
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
|
||||||
- `elf` (`ELF_`): Code for parsing the ELF format.
|
`df/core` to provide all graphical features, including windows, panels, all
|
||||||
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
|
of the various debugger interfaces, and evaluation visualization.
|
||||||
variables, registers, types, and more, from debugger-attached processes,
|
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
|
||||||
debug info, debugger state, and files. Broken into several phases mostly
|
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||||
corresponding to traditional compiler phases: lexer, parser, type-checker, IR
|
APIs for various draw commands, but takes care of batching them, and so on.
|
||||||
generation, and IR evaluation.
|
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||||
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
|
evaluation of variables, registers, and so on from debugger-attached processes
|
||||||
visualization engine, which can be used to visualize evaluations (provided by
|
and/or debug info. Broken into several phases mostly corresponding to
|
||||||
the `eval` layer) in a number of ways. Implements core data structures and
|
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||||
transforms for watch tables.
|
IR evaluation.
|
||||||
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
|
- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU-
|
||||||
artifacts inside of the cache implemented by the `content` and
|
side data for text shaping, and in GPU texture atlases for rasterized glyphs.
|
||||||
`artifact_cache` layers, hot-reloading the contents of files when they change.
|
All cache information is sourced from the `font_provider` abstraction layer.
|
||||||
Allows callers to map file paths to data hashes, which can then be used to
|
|
||||||
obtain the file's data.
|
|
||||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
|
||||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
|
||||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
|
||||||
layer.
|
|
||||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||||
and font rasterization backends.
|
and font rasterization backends.
|
||||||
|
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||||
|
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
|
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||||
|
128-bit hash of the data. Used as a general data store by other layers.
|
||||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
||||||
programs to work with various features in the debugger. Does not depend on
|
programs to work with various features in the `raddbg` debugger. Does not
|
||||||
`base`, and can be independently relocated to other codebases.
|
depend on `base`, and can be independently relocated to other codebases.
|
||||||
- `lib_rdi` (`RDI_`): Standalone library which defines the core RDI types
|
|
||||||
and helper functions for reading and writing the RDI debug info file format.
|
|
||||||
Does not depend on `base`, and can be independently relocated to other
|
|
||||||
codebases.
|
|
||||||
- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info
|
- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info
|
||||||
data. Does not depend on `base`, and can be independently relocated
|
data. Does not depend on `base`, and can be independently relocated
|
||||||
to other codebases.
|
to other codebases.
|
||||||
- `linker` (`LNK_`): The layer which implements the RAD Linker executable
|
- `lib_rdi_format` (`RDI_`): Standalone library which defines the core RDI types
|
||||||
itself.
|
and helper functions for reading and writing the RDI debug info file format.
|
||||||
- `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which
|
Does not depend on `base`, and can be independently relocated to other
|
||||||
is the JSON-like (technically a JSON superset) text format used for the
|
codebases.
|
||||||
debugger's user and project configuration files and metacode, which is parsed
|
|
||||||
and used to generate code with the `metagen` layer.
|
|
||||||
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
||||||
generates C code which is then included by hand-written C code. Currently, it
|
generates C code which is then included by hand-written C code. Currently, it
|
||||||
@@ -369,13 +270,15 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
tables, which are then used to produce e.g. C `enum`s and a number of
|
tables, which are then used to produce e.g. C `enum`s and a number of
|
||||||
associated data tables. There are also a number of other generation features,
|
associated data tables. There are also a number of other generation features,
|
||||||
like embedding binary files or complex multi-line strings into source code.
|
like embedding binary files or complex multi-line strings into source code.
|
||||||
- `msf` (`MSF_`): Code for parsing and writing the MSF file format.
|
This layer cannot depend on any other layer in the codebase directly,
|
||||||
- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT.
|
including `base`, because it may be used to generate code for those layers. To
|
||||||
|
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||||
|
duplicate version of `base` and `os` are included in this layer. They are
|
||||||
|
updated manually, as needed. This is to ensure the stability of the
|
||||||
|
metaprogram.
|
||||||
|
- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format.
|
||||||
- `mule` (no namespace): Test executables for battle testing debugger
|
- `mule` (no namespace): Test executables for battle testing debugger
|
||||||
functionality.
|
functionality.
|
||||||
- `mutable_text` (`MTX_`): Implements an asynchronously-filled-and-mutated
|
|
||||||
cache for text buffers which are mutated across time. In the debugger, this is
|
|
||||||
used to implement the `Output` log.
|
|
||||||
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||||
types in other debuggers.
|
types in other debuggers.
|
||||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||||
@@ -384,29 +287,20 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
graphical operating system features under an abstract API, which is
|
graphical operating system features under an abstract API, which is
|
||||||
implemented per-target-operating-system.
|
implemented per-target-operating-system.
|
||||||
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
|
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
|
networking operating system features under an abstract API, which is
|
||||||
format.
|
implemented per-target-operating-system.
|
||||||
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
|
- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format.
|
||||||
executable.
|
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
file format.
|
||||||
graphical debugger executable. Implements the debugger's graphical frontend,
|
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||||
all of the debugger-specific UI, the debugger executable's command line
|
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||||
interface, and all of the built-in visualizers.
|
options, and so on.
|
||||||
- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with
|
- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion.
|
||||||
codebase-specific helpers, to easily include the library in codebase programs,
|
- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI
|
||||||
and have it be integrated with codebase constructs.
|
conversion.
|
||||||
- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the
|
- `rdi_dump` (no namespace): A dumper utility program for dumping
|
||||||
equivalent RDI data.
|
textualizations of RDI debug info files.
|
||||||
- `rdi_from_dwarf` (`D2R_`): In-progress code for converting DWARF to the
|
|
||||||
equivalent RDI data.
|
|
||||||
- `rdi_from_elf` (`E2R_`)): Code for converting ELF data to the equivalent RDI
|
|
||||||
data.
|
|
||||||
- `rdi_from_pdb` (`P2R_`): Code for converting PDB data to the equivalent RDI
|
|
||||||
data.
|
|
||||||
- `rdi_make` (`RDIM_`): A layer which includes the `lib_rdi_make` layer and
|
|
||||||
bundles it with codebase-specific helpers, to easily include the library in
|
|
||||||
codebase programs, and have it be integrated with codebase constructs.
|
|
||||||
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
||||||
supported architectures. Used in reading/writing registers in `demon`, or in
|
supported architectures. Used in reading/writing registers in `demon`, or in
|
||||||
looking up register metadata.
|
looking up register metadata.
|
||||||
@@ -415,14 +309,19 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
level drawing API - this layer is strictly for minimally abstracting on an
|
level drawing API - this layer is strictly for minimally abstracting on an
|
||||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||||
layer.
|
layer.
|
||||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
- `scratch` (no namespace): Scratch space for small and transient test or sample
|
||||||
- `tester` (no namespace): A program used for automated testing.
|
programs.
|
||||||
- `text` (`TXT_`): Implements text processing functions, like parsing line
|
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||||
breaks, and lexing and parsing source code. Also offers an API to do this
|
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
asynchronously.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
- `third_party` (no namespace): External code from other projects, which some
|
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||||
layers in the codebase depend on. All external code is included and built
|
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||||
directly within the codebase.
|
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||||
|
tokens, and metadata, and it is prepared on background threads.
|
||||||
|
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||||
|
RDI debug info files, with the additional capability of constructing
|
||||||
|
synthetic types *not* found in debug info. Used in `eval` and for various
|
||||||
|
visualization features.
|
||||||
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
||||||
core immediate mode hierarchical user interface data structure building
|
core immediate mode hierarchical user interface data structure building
|
||||||
API, and has helper layers for building some higher-level widgets.
|
API, and has helper layers for building some higher-level widgets.
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal enabledelayedexpansion
|
setlocal
|
||||||
cd /D "%~dp0"
|
cd /D "%~dp0"
|
||||||
:restart
|
|
||||||
|
|
||||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||||
::
|
::
|
||||||
:: This is a central build script for the RAD Debugger project, for use in
|
:: This is a central build script for the RAD Debugger project. It takes a list
|
||||||
:: Windows development environments. It takes a list of simple alphanumeric-
|
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
|
||||||
:: only arguments which control (a) what is built, (b) which compiler & linker
|
:: which compiler & linker are used, and (c) extra high-level build options. By
|
||||||
:: are used, and (c) extra high-level build options. By default, if no options
|
:: default, if no options are passed, then the main "raddbg" graphical debugger
|
||||||
:: are passed, then the main "raddbg" graphical debugger is built.
|
:: is built.
|
||||||
::
|
::
|
||||||
:: Below is a non-exhaustive list of possible ways to use the script:
|
:: Below is a non-exhaustive list of possible ways to use the script:
|
||||||
:: `build raddbg`
|
:: `build raddbg`
|
||||||
@@ -24,91 +23,55 @@ cd /D "%~dp0"
|
|||||||
:: Below is a list of all possible non-target command line options:
|
:: Below is a list of all possible non-target command line options:
|
||||||
::
|
::
|
||||||
:: - `asan`: enable address sanitizer
|
:: - `asan`: enable address sanitizer
|
||||||
:: - `ubsan`: enable undefined-behavior sanitizer
|
|
||||||
:: - `telemetry`: enable RAD telemetry profiling support
|
:: - `telemetry`: enable RAD telemetry profiling support
|
||||||
:: - `spall`: enable spall profiling support
|
|
||||||
|
|
||||||
:: --- Unpack Arguments -------------------------------------------------------
|
:: --- Unpack Arguments -------------------------------------------------------
|
||||||
for %%a in (%*) do set "%%~a=1"
|
for %%a in (%*) do set "%%a=1"
|
||||||
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
||||||
if not "%release%"=="1" set debug=1
|
if not "%release%"=="1" set debug=1
|
||||||
if "%debug%"=="1" set release=0 && echo [debug mode]
|
if "%debug%"=="1" set release=0 && echo [debug mode]
|
||||||
if "%release%"=="1" set debug=0 && echo [release mode]
|
if "%release%"=="1" set debug=0 && echo [release mode]
|
||||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||||
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
|
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
||||||
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
|
|
||||||
|
|
||||||
:: --- Unpack Command Line Build Arguments ------------------------------------
|
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||||
set auto_compile_flags=
|
set auto_compile_flags=
|
||||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||||
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
|
|
||||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||||
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
|
|
||||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
|
||||||
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
|
|
||||||
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
|
|
||||||
if "%pgo%"=="1" (
|
|
||||||
where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1
|
|
||||||
if "%clang%"=="1" (
|
|
||||||
if "%pgo_run%" == "1" (
|
|
||||||
call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1
|
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-use=%~dp0build\build.profdata
|
|
||||||
set pgo_run=0
|
|
||||||
) else (
|
|
||||||
echo [pgo enabled]
|
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-generate -mllvm -vp-counters-per-site=5
|
|
||||||
set LLVM_PROFILE_FILE=%~dp0build\build.profraw
|
|
||||||
set pgo_run=1
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
echo ERROR: PGO build is not supported with current compiler
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
|
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||||
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -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 -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
|
||||||
|
set cl_debug= call cl /Od /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
||||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
||||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
|
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" logo.res
|
||||||
|
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
set cl_out= /out:
|
set cl_out= /out:
|
||||||
set cl_obj_out= /Fo:
|
|
||||||
set cl_linker=
|
|
||||||
set clang_common= -mcx16 -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -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 -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
|
|
||||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 -D_DEBUG %clang_common% %auto_compile_flags%
|
|
||||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 -DNDEBUG %clang_common% %auto_compile_flags%
|
|
||||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:noicf
|
|
||||||
set clang_out= -o
|
set clang_out= -o
|
||||||
set clang_obj_out= -o
|
|
||||||
set clang_linker= -Xlinker
|
|
||||||
|
|
||||||
:: --- Per-Build Settings -----------------------------------------------------
|
:: --- Per-Build Settings -----------------------------------------------------
|
||||||
set link_icon=logo.res
|
set link_dll=-DLL
|
||||||
if "%msvc%"=="1" set linker=%cl_linker%
|
|
||||||
if "%clang%"=="1" set linker=%clang_linker%
|
|
||||||
if "%msvc%"=="1" set only_compile=/c
|
if "%msvc%"=="1" set only_compile=/c
|
||||||
if "%clang%"=="1" set only_compile=-c
|
if "%clang%"=="1" set only_compile=-c
|
||||||
if "%msvc%"=="1" set EHsc=/EHsc
|
if "%msvc%"=="1" set EHsc=/EHsc
|
||||||
if "%clang%"=="1" set EHsc=
|
if "%clang%"=="1" set EHsc=
|
||||||
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
|
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
|
||||||
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
|
if "%clang%"=="1" set no_aslr=
|
||||||
if "%msvc%"=="1" set rc=call rc
|
if "%msvc%"=="1" set rc=rc.exe
|
||||||
if "%clang%"=="1" set rc=call llvm-rc
|
if "%clang%"=="1" set rc=llvm-rc.exe
|
||||||
if "%msvc%"=="1" set link_dll=/link /DLL
|
|
||||||
if "%clang%"=="1" set link_dll=-Xlinker -DLL
|
|
||||||
|
|
||||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||||
if "%msvc%"=="1" set out=%cl_out%
|
if "%msvc%"=="1" set out=%cl_out%
|
||||||
if "%msvc%"=="1" set obj_out=%cl_obj_out%
|
|
||||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||||
if "%clang%"=="1" set compile_release=%clang_release%
|
if "%clang%"=="1" set compile_release=%clang_release%
|
||||||
if "%clang%"=="1" set compile_link=%clang_link%
|
if "%clang%"=="1" set compile_link=%clang_link%
|
||||||
if "%clang%"=="1" set out=%clang_out%
|
if "%clang%"=="1" set out=%clang_out%
|
||||||
if "%clang%"=="1" set obj_out=%clang_obj_out%
|
|
||||||
if "%debug%"=="1" set compile=%compile_debug%
|
if "%debug%"=="1" set compile=%compile_debug%
|
||||||
if "%release%"=="1" set compile=%compile_release%
|
if "%release%"=="1" set compile=%compile_release%
|
||||||
|
|
||||||
@@ -123,42 +86,30 @@ popd
|
|||||||
|
|
||||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
:: --- 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 ------------------------------------------------
|
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||||
pushd build
|
if "%no_meta%"=="1" echo [skipping metagen]
|
||||||
if "%meta%"=="1" (
|
if not "%no_meta%"=="1" (
|
||||||
echo [building metagen]
|
pushd build
|
||||||
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
||||||
)
|
|
||||||
if "%no_meta%"=="" if exist metagen.exe (
|
|
||||||
echo [running metagen]
|
|
||||||
metagen.exe || exit /b 1
|
metagen.exe || exit /b 1
|
||||||
|
popd
|
||||||
)
|
)
|
||||||
popd
|
|
||||||
|
|
||||||
:: --- Build Everything (@build_targets) --------------------------------------
|
:: --- Build Everything (@build_targets) --------------------------------------
|
||||||
pushd build
|
pushd build
|
||||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
|
||||||
if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1
|
if "%rdi_from_pdb%"=="1" %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
|
||||||
if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1
|
if "%rdi_from_dwarf%"=="1" %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
|
||||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
if "%rdi_dump%"=="1" %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
|
||||||
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
|
if "%rdi_breakpad_from_pdb%"=="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 "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.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 "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
|
||||||
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
|
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1
|
||||||
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
|
if "%mule_main%"=="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 "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
|
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || 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_hotload%"=="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
|
||||||
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.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 %obj_out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %obj_out%mule_o2.obj && %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 %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
|
|
||||||
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1
|
|
||||||
if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1
|
|
||||||
if "%unit_sizes_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\scratch\unit_sizes_from_pdb.c %compile_link% %out%unit_sizes_from_pdb.exe || exit /b1
|
|
||||||
if "%mule_peb_trample%"=="1" (
|
if "%mule_peb_trample%"=="1" (
|
||||||
set didbuild=1
|
|
||||||
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
||||||
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
|
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
|
||||||
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
|
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
|
||||||
@@ -167,23 +118,11 @@ if "%mule_peb_trample%"=="1" (
|
|||||||
)
|
)
|
||||||
popd
|
popd
|
||||||
|
|
||||||
:: --- Set Up Debugger Com Shim -----------------------------------------------
|
:: --- Unset ------------------------------------------------------------------
|
||||||
pushd build
|
for %%a in (%*) do set "%%a=0"
|
||||||
if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com
|
set raddbg=
|
||||||
popd
|
set compile=
|
||||||
|
set compile_link=
|
||||||
:: --- Warn On No Builds ------------------------------------------------------
|
set out=
|
||||||
if "%didbuild%"=="" (
|
set msvc=
|
||||||
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`.
|
set debug=
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- PGO Run ----------------------------------------------------------------
|
|
||||||
if "%pgo_run%"=="1" (
|
|
||||||
if "%radlink%"=="1" (
|
|
||||||
pushd local\lyra_pgo
|
|
||||||
call %~dp0build\radlink @lyra.rsp || exit /b 1
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
goto restart
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
# --- Unpack Arguments --------------------------------------------------------
|
|
||||||
for arg in "$@"; do declare $arg='1'; done
|
|
||||||
if [[ "$#" == "0" ]]; then raddbg='1'; fi
|
|
||||||
|
|
||||||
cc_sanitize=""
|
|
||||||
if [[ "${asan:-0}" == "1" ]]; then
|
|
||||||
echo "[asan enabled]"
|
|
||||||
cc_sanitize="-fsanitize=address"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Get Current Git Commit Id -----------------------------------------------
|
|
||||||
git_hash=$(git describe --always --dirty)
|
|
||||||
git_hash_full=$(git rev-parse HEAD)
|
|
||||||
|
|
||||||
# --- Compile/Link Line Definitions -------------------------------------------
|
|
||||||
cc_cflags_gcc=""
|
|
||||||
cc_cflags_clang=${cc_sanitize}" -fdiagnostics-absolute-paths -Wno-for-loop-analysis -Wno-incompatible-pointer-types-discards-qualifiers -Wno-initializer-overrides -Wno-compare-distinct-pointer-types -Wno-single-bit-bitfield-constant-conversion -Wno-deprecated-declarations -Wno-writable-strings -Wno-unknown-warning-option -Wno-deprecated-register -Wno-unused-local-typedef -msse2"
|
|
||||||
cc_common="-mcx16 -I../src/ -I../local/ -D_GNU_SOURCE -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wall -Wno-missing-braces -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-value -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
|
||||||
cc_debug="-g -O0 -DBUILD_DEBUG=1 ${cc_common}"
|
|
||||||
cc_release="-g -O2 -DBUILD_DEBUG=0 ${cc_common}"
|
|
||||||
cc_link="-lpthread -lm -lrt -ldl"
|
|
||||||
|
|
||||||
# --- Per-Build Settings ------------------------------------------------------
|
|
||||||
cc_link_dll="-fPIC"
|
|
||||||
|
|
||||||
# --- External Libraries ------------------------------------------------------
|
|
||||||
# sudo apt install -y pkg-config libfreetype6-dev libx11-dev libxext-dev libgl-dev libegl-dev
|
|
||||||
if [[ -x "$(command -v pkg-config)" ]]; then
|
|
||||||
cc_font_provider="$(pkg-config --cflags --libs freetype2)"
|
|
||||||
cc_os_gfx="$(pkg-config --cflags --libs x11 xext)"
|
|
||||||
cc_render="$(pkg-config --cflags --libs gl egl)"
|
|
||||||
else
|
|
||||||
cc_font_provider="-I/usr/include/freetype2 -lfreetype"
|
|
||||||
cc_os_gfx="-lX11 -lXext"
|
|
||||||
cc_render="-lGL -lEGL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Choose Compile/Link Lines -----------------------------------------------
|
|
||||||
if [[ "${gcc:-0}" == "1" ]]; then compiler="${CC:-gcc} $cc_cflags_gcc"; echo "[gcc compile]";
|
|
||||||
elif [[ "${clang:-1}" == "1" ]]; then compiler="${CC:-clang} $cc_cflags_clang"; echo "[clang compile]";
|
|
||||||
fi
|
|
||||||
if [[ "${release:-0}" == "1" ]]; then echo "[release mode]"; compile="$compiler $cc_release";
|
|
||||||
elif [[ "${debug:-1}" == "1" ]]; then echo "[debug mode]"; compile="$compiler $cc_debug";
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Prep Directories --------------------------------------------------------
|
|
||||||
mkdir -p build local
|
|
||||||
|
|
||||||
# --- Build & Run Metaprogram -------------------------------------------------
|
|
||||||
if [[ "${no_meta:-0}" == "0" ]]
|
|
||||||
then
|
|
||||||
echo "[building metagen]"
|
|
||||||
cd build
|
|
||||||
$compiler $cc_debug ../src/metagen/metagen_main.c $cc_link -o metagen
|
|
||||||
./metagen
|
|
||||||
cd ..
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Build Everything (@build_targets) ---------------------------------------
|
|
||||||
cd build
|
|
||||||
if [[ "${raddbg:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg; fi
|
|
||||||
if [[ "${raddbg_non_graphical:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg_non_graphical; fi
|
|
||||||
if [[ "${radbin:-0}" == "1" ]]; then didbuild=1 && $compile ../src/radbin/radbin_main.c $cc_link -o radbin; fi
|
|
||||||
if [[ "${radlink:-0}" == "1" ]]; then didbuild=1 && $compile ../src/linker/lnk.c $cc_link -o radlink; fi
|
|
||||||
if [[ "${torture:-0}" == "1" ]]; then didbuild=1 && $compile ../src/torture/torture_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o torture; fi
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# --- Warn On No Builds -------------------------------------------------------
|
|
||||||
if [[ "${didbuild:-0}" == "0" ]]
|
|
||||||
then
|
|
||||||
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh radlink\`."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,93 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.2.1",
|
|
||||||
"defaults": {},
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - torture",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "torture",
|
|
||||||
"args": [ "d2r_checksums" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "-gdb-set follow-fork-mode parent" },
|
|
||||||
{ "text": "-gdb-set detach-on-fork on" },
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - radbin",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "radbin",
|
|
||||||
"args": [ "-voff2line", "-voff:0x1000", "torture_artifacts/d2r_line_table/a.rdi" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "-gdb-set follow-fork-mode parent" },
|
|
||||||
{ "text": "-gdb-set detach-on-fork on" },
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - radlink",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "/mnt/c/devel/raddebugger/build/torture_artifacts/debug_p_sig_mismatch",
|
|
||||||
"program": "/mnt/c/devel/raddebugger/build/radlink",
|
|
||||||
"args": [ "/subsystem:console", "/entry:entry", "/out:a.exe", "/debug:full", "a.obj", "b.obj", "entry.obj" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - raddbg",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "/mnt/c/devel/raddebugger/build/raddbg",
|
|
||||||
//"processId": "65821",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_DUMP_H
|
|
||||||
#define DWARF_DUMP_H
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_DumperCacheFlag_InfoRanges = (1 << 0),
|
|
||||||
DW_DumperCacheFlag_CuArr = (1 << 1),
|
|
||||||
DW_DumperCacheFlag_LineVmMap = (1 << 2),
|
|
||||||
DW_DumperCacheFlag_TagTrees = (1 << 3),
|
|
||||||
} DW_DumperCacheFlags;
|
|
||||||
|
|
||||||
typedef struct DW_Dumper
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
Arch arch;
|
|
||||||
B32 is_relaxed;
|
|
||||||
B32 is_verbose;
|
|
||||||
DW_Raw *input;
|
|
||||||
DW_DumperCacheFlags cache_flags;
|
|
||||||
struct {
|
|
||||||
Rng1U64Array info_ranges;
|
|
||||||
DW_CompUnit *cu_arr;
|
|
||||||
HashTable *line_vm_map;
|
|
||||||
DW_TagTree *tag_trees;
|
|
||||||
} cache;
|
|
||||||
} DW_Dumper;
|
|
||||||
|
|
||||||
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
|
|
||||||
typedef DW_PRINTER(DW_Printer);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
// cache
|
|
||||||
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
|
|
||||||
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
|
|
||||||
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
|
|
||||||
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Stringification Helpers
|
|
||||||
|
|
||||||
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
|
|
||||||
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
|
||||||
|
|
||||||
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
|
|
||||||
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
|
||||||
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
|
|
||||||
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
|
|
||||||
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
|
||||||
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
|
||||||
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
|
|
||||||
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
|
|
||||||
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Dump Entry Point
|
|
||||||
|
|
||||||
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
|
|
||||||
|
|
||||||
#endif // DWARF_DUMP_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,233 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_EXPR_H
|
|
||||||
#define DWARF_EXPR_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// evaluator
|
|
||||||
|
|
||||||
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
|
|
||||||
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
|
|
||||||
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
|
|
||||||
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprValueType_Generic,
|
|
||||||
DW_ExprValueType_U8,
|
|
||||||
DW_ExprValueType_U16,
|
|
||||||
DW_ExprValueType_U32,
|
|
||||||
DW_ExprValueType_U64,
|
|
||||||
DW_ExprValueType_U128,
|
|
||||||
DW_ExprValueType_U256,
|
|
||||||
DW_ExprValueType_U512,
|
|
||||||
DW_ExprValueType_S8,
|
|
||||||
DW_ExprValueType_S16,
|
|
||||||
DW_ExprValueType_S32,
|
|
||||||
DW_ExprValueType_S64,
|
|
||||||
DW_ExprValueType_S128,
|
|
||||||
DW_ExprValueType_S256,
|
|
||||||
DW_ExprValueType_S512,
|
|
||||||
DW_ExprValueType_F32,
|
|
||||||
DW_ExprValueType_F64,
|
|
||||||
DW_ExprValueType_Addr,
|
|
||||||
DW_ExprValueType_Implicit,
|
|
||||||
DW_ExprValueType_Bool,
|
|
||||||
} DW_ExprValueType;
|
|
||||||
|
|
||||||
typedef S8 DW_ExprBool;
|
|
||||||
|
|
||||||
typedef struct DW_ExprValue
|
|
||||||
{
|
|
||||||
DW_ExprValueType type;
|
|
||||||
Rng1U64Array ranges;
|
|
||||||
U64 *offsets;
|
|
||||||
union {
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
U128 u128;
|
|
||||||
U256 u256;
|
|
||||||
U512 u512;
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
F32 f32;
|
|
||||||
F64 f64;
|
|
||||||
U64 addr;
|
|
||||||
DW_ExprBool boolean;
|
|
||||||
String8 implicit;
|
|
||||||
String8 generic;
|
|
||||||
};
|
|
||||||
} DW_ExprValue;
|
|
||||||
|
|
||||||
typedef struct DW_ExprValueNode
|
|
||||||
{
|
|
||||||
DW_ExprValue v;
|
|
||||||
struct DW_ExprValueNode *next;
|
|
||||||
} DW_ExprValueNode;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_PieceKind_Null,
|
|
||||||
DW_PieceKind_Value,
|
|
||||||
DW_PieceKind_Undefined,
|
|
||||||
} DW_PieceKind;
|
|
||||||
|
|
||||||
typedef struct DW_Piece
|
|
||||||
{
|
|
||||||
DW_PieceKind kind;
|
|
||||||
U64 bit_size;
|
|
||||||
U8 *value;
|
|
||||||
} DW_Piece;
|
|
||||||
|
|
||||||
typedef struct DW_PieceNode
|
|
||||||
{
|
|
||||||
DW_Piece v;
|
|
||||||
struct DW_PieceNode *next;
|
|
||||||
} DW_PieceNode;
|
|
||||||
|
|
||||||
typedef struct DW_PieceList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_PieceNode *first;
|
|
||||||
DW_PieceNode *last;
|
|
||||||
} DW_PieceList;
|
|
||||||
|
|
||||||
typedef struct DW_ExprStack
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_ExprValueNode *top;
|
|
||||||
} DW_ExprStack;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprEvalResult_Fail,
|
|
||||||
DW_ExprEvalResult_Ok,
|
|
||||||
DW_ExprEvalResult_Maybe,
|
|
||||||
DW_ExprEvalResult_ExecOpLimitReached,
|
|
||||||
} DW_ExprEvalResult;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// encoder
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprEncType_Null,
|
|
||||||
DW_ExprEncType_Op,
|
|
||||||
DW_ExprEncType_U8,
|
|
||||||
DW_ExprEncType_U16,
|
|
||||||
DW_ExprEncType_U32,
|
|
||||||
DW_ExprEncType_U64,
|
|
||||||
DW_ExprEncType_S8,
|
|
||||||
DW_ExprEncType_S16,
|
|
||||||
DW_ExprEncType_S32,
|
|
||||||
DW_ExprEncType_S64,
|
|
||||||
DW_ExprEncType_ULEB128,
|
|
||||||
DW_ExprEncType_SLEB128,
|
|
||||||
DW_ExprEncType_Addr,
|
|
||||||
DW_ExprEncType_Block,
|
|
||||||
DW_ExprEncType_DwarfUInt,
|
|
||||||
DW_ExprEncType_Label,
|
|
||||||
DW_ExprEncType_DeclLabel,
|
|
||||||
} DW_ExprEncType;
|
|
||||||
|
|
||||||
typedef struct DW_ExprEnc
|
|
||||||
{
|
|
||||||
DW_ExprEncType type;
|
|
||||||
union {
|
|
||||||
DW_ExprOp op;
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
U64 addr;
|
|
||||||
String8 block;
|
|
||||||
String8 label;
|
|
||||||
};
|
|
||||||
} DW_ExprEnc;
|
|
||||||
|
|
||||||
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
|
|
||||||
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
|
|
||||||
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
|
|
||||||
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
|
|
||||||
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
|
|
||||||
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
|
|
||||||
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
|
|
||||||
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
|
|
||||||
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
|
|
||||||
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
|
|
||||||
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
|
|
||||||
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
|
|
||||||
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
|
|
||||||
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
|
|
||||||
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
|
|
||||||
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
// pieces
|
|
||||||
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
|
|
||||||
|
|
||||||
// size -> type
|
|
||||||
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
|
|
||||||
|
|
||||||
// type -> size
|
|
||||||
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
|
|
||||||
|
|
||||||
// typer
|
|
||||||
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
|
|
||||||
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
|
|
||||||
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
|
|
||||||
|
|
||||||
// arithmetic operators
|
|
||||||
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// comparison operators
|
|
||||||
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// bitwise operators
|
|
||||||
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// unary operators
|
|
||||||
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
|
|
||||||
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
|
|
||||||
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
|
|
||||||
|
|
||||||
// stack
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
|
|
||||||
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
|
|
||||||
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
|
|
||||||
|
|
||||||
// value helpers
|
|
||||||
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
|
|
||||||
|
|
||||||
// evaluator
|
|
||||||
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
|
|
||||||
|
|
||||||
#endif //DWARF_EXPR_H
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,528 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_PARSE_H
|
|
||||||
#define DWARF_PARSE_H
|
|
||||||
|
|
||||||
typedef struct DW_Section
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 data;
|
|
||||||
B32 is_dwo;
|
|
||||||
} DW_Section;
|
|
||||||
|
|
||||||
typedef struct DW_Raw
|
|
||||||
{
|
|
||||||
DW_Section sec[DW_Section_COUNT];
|
|
||||||
DW_Section sup[DW_Section_COUNT];
|
|
||||||
} DW_Raw;
|
|
||||||
|
|
||||||
typedef struct DW_ListUnit
|
|
||||||
{
|
|
||||||
DW_Version version;
|
|
||||||
U64 address_size;
|
|
||||||
U64 segment_selector_size;
|
|
||||||
U64 entry_size;
|
|
||||||
String8 entries;
|
|
||||||
} DW_ListUnit;
|
|
||||||
|
|
||||||
typedef struct DW_ListUnitInput
|
|
||||||
{
|
|
||||||
U64 addr_count;
|
|
||||||
U64 str_offset_count;
|
|
||||||
U64 rnglist_count;
|
|
||||||
U64 loclist_count;
|
|
||||||
Rng1U64Array addr_ranges;
|
|
||||||
Rng1U64Array str_offset_ranges;
|
|
||||||
Rng1U64Array rnglist_ranges;
|
|
||||||
Rng1U64Array loclist_ranges;
|
|
||||||
DW_ListUnit *addrs;
|
|
||||||
DW_ListUnit *str_offsets;
|
|
||||||
DW_ListUnit *rnglists;
|
|
||||||
DW_ListUnit *loclists;
|
|
||||||
} DW_ListUnitInput;
|
|
||||||
|
|
||||||
typedef struct DW_AbbrevTableEntry
|
|
||||||
{
|
|
||||||
U64 id;
|
|
||||||
U64 off;
|
|
||||||
} DW_AbbrevTableEntry;
|
|
||||||
|
|
||||||
typedef struct DW_AbbrevTable DW_AbbrevTable;
|
|
||||||
struct DW_AbbrevTable
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_AbbrevTableEntry *entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum DW_AbbrevKind
|
|
||||||
{
|
|
||||||
DW_Abbrev_Null,
|
|
||||||
DW_Abbrev_Tag,
|
|
||||||
DW_Abbrev_Attrib,
|
|
||||||
DW_Abbrev_AttribSequenceEnd,
|
|
||||||
DW_Abbrev_DIEBegin,
|
|
||||||
DW_Abbrev_DIEEnd,
|
|
||||||
} DW_AbbrevKind;
|
|
||||||
|
|
||||||
typedef U32 DW_AbbrevFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
|
|
||||||
DW_AbbrevFlag_HasChildren = (1 << 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct DW_Abbrev
|
|
||||||
{
|
|
||||||
DW_AbbrevKind kind;
|
|
||||||
U64 sub_kind;
|
|
||||||
U64 id;
|
|
||||||
S64 implicit_const;
|
|
||||||
DW_AbbrevFlags flags;
|
|
||||||
} DW_Abbrev;
|
|
||||||
|
|
||||||
typedef struct DW_Attrib
|
|
||||||
{
|
|
||||||
U64 info_off;
|
|
||||||
U64 abbrev_off;
|
|
||||||
U64 abbrev_id;
|
|
||||||
DW_AttribKind attrib_kind;
|
|
||||||
DW_Form form;
|
|
||||||
} DW_Attrib;
|
|
||||||
|
|
||||||
typedef struct DW_AttribNode
|
|
||||||
{
|
|
||||||
struct DW_AttribNode *next;
|
|
||||||
DW_Attrib v;
|
|
||||||
} DW_AttribNode;
|
|
||||||
|
|
||||||
typedef struct DW_AttribList
|
|
||||||
{
|
|
||||||
DW_AttribNode *first;
|
|
||||||
DW_AttribNode *last;
|
|
||||||
U64 count;
|
|
||||||
} DW_AttribList;
|
|
||||||
|
|
||||||
typedef U8 DW_TagSpare;
|
|
||||||
typedef struct DW_Tag
|
|
||||||
{
|
|
||||||
B32 has_children;
|
|
||||||
U64 abbrev_id;
|
|
||||||
DW_TagKind kind;
|
|
||||||
DW_AttribList attribs;
|
|
||||||
U64 info_off;
|
|
||||||
DW_TagSpare v;
|
|
||||||
} DW_Tag;
|
|
||||||
|
|
||||||
typedef struct DW_TagNode
|
|
||||||
{
|
|
||||||
DW_Tag tag;
|
|
||||||
struct DW_TagNode *sibling;
|
|
||||||
struct DW_TagNode *first_child;
|
|
||||||
struct DW_TagNode *last_child;
|
|
||||||
} DW_TagNode;
|
|
||||||
|
|
||||||
typedef struct DW_Loc
|
|
||||||
{
|
|
||||||
Rng1U64 range;
|
|
||||||
String8 expr;
|
|
||||||
} DW_Loc;
|
|
||||||
|
|
||||||
typedef struct DW_LocNode
|
|
||||||
{
|
|
||||||
DW_Loc v;
|
|
||||||
struct DW_LocNode *next;
|
|
||||||
} DW_LocNode;
|
|
||||||
|
|
||||||
typedef struct DW_LocList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_LocNode *first;
|
|
||||||
DW_LocNode *last;
|
|
||||||
} DW_LocList;
|
|
||||||
|
|
||||||
typedef struct DW_CompUnit
|
|
||||||
{
|
|
||||||
B32 relaxed;
|
|
||||||
DW_Ext ext;
|
|
||||||
DW_CompUnitKind kind;
|
|
||||||
DW_Version version;
|
|
||||||
DW_Format format;
|
|
||||||
U64 address_size;
|
|
||||||
U64 abbrev_off;
|
|
||||||
Rng1U64 info_range;
|
|
||||||
U64 first_tag_info_off;
|
|
||||||
DW_AbbrevTable abbrev_table;
|
|
||||||
DW_ListUnit *addr_lu;
|
|
||||||
DW_ListUnit *str_offsets_lu;
|
|
||||||
DW_ListUnit *rnglists_lu;
|
|
||||||
DW_ListUnit *loclists_lu;
|
|
||||||
U64 low_pc;
|
|
||||||
U64 dwo_id;
|
|
||||||
DW_Tag tag;
|
|
||||||
HashTable *tag_ht;
|
|
||||||
} DW_CompUnit;
|
|
||||||
|
|
||||||
typedef struct DW_TagTree
|
|
||||||
{
|
|
||||||
DW_TagNode *root;
|
|
||||||
U64 tag_count;
|
|
||||||
} DW_TagTree;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct DW_LineFile
|
|
||||||
{
|
|
||||||
String8 path;
|
|
||||||
U64 dir_idx;
|
|
||||||
U64 time_stamp;
|
|
||||||
U64 size;
|
|
||||||
U128 md5;
|
|
||||||
String8 source;
|
|
||||||
} DW_LineFile;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileNode
|
|
||||||
{
|
|
||||||
struct DW_LineFileNode *next;
|
|
||||||
DW_LineFile file;
|
|
||||||
} DW_LineFileNode;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileList
|
|
||||||
{
|
|
||||||
U64 node_count;
|
|
||||||
DW_LineFileNode *first;
|
|
||||||
DW_LineFileNode *last;
|
|
||||||
} DW_LineFileList;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileArray
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_LineFile *v;
|
|
||||||
} DW_LineFileArray;
|
|
||||||
|
|
||||||
typedef struct DW_LineVMHeader
|
|
||||||
{
|
|
||||||
U64 unit_length;
|
|
||||||
DW_Version version;
|
|
||||||
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
|
|
||||||
U8 segment_selector_size;
|
|
||||||
U64 header_length;
|
|
||||||
U8 min_inst_len;
|
|
||||||
U8 max_ops_for_inst;
|
|
||||||
U8 default_is_stmt;
|
|
||||||
S8 line_base;
|
|
||||||
U8 line_range;
|
|
||||||
U8 opcode_base;
|
|
||||||
U64 num_opcode_lens;
|
|
||||||
U8 *opcode_lens;
|
|
||||||
U64 line_program_off;
|
|
||||||
String8Array dir_table;
|
|
||||||
DW_LineFileArray file_table;
|
|
||||||
} DW_LineVMHeader;
|
|
||||||
|
|
||||||
typedef struct DW_LineVMState
|
|
||||||
{
|
|
||||||
U64 address; // Address of a machine instruction.
|
|
||||||
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
|
|
||||||
|
|
||||||
// Line table doesn't contain full path to a file, instead
|
|
||||||
// DWARF encodes path as two indices. First index will point into a directory
|
|
||||||
// table, and second points into a file name table.
|
|
||||||
U64 file_index;
|
|
||||||
|
|
||||||
U64 line;
|
|
||||||
U64 column;
|
|
||||||
|
|
||||||
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
|
|
||||||
B32 basic_block; // Indicates that the "address" is inside a basic block.
|
|
||||||
|
|
||||||
// Indicates that "address" points to place where function starts.
|
|
||||||
// Usually prologue is the place where compiler emits instructions to
|
|
||||||
// prepare stack for a function.
|
|
||||||
B32 prologue_end;
|
|
||||||
|
|
||||||
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
|
|
||||||
U64 isa; // Instruction set that is used.
|
|
||||||
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
|
|
||||||
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
|
|
||||||
} DW_LineVMState;
|
|
||||||
|
|
||||||
typedef struct DW_LineVM
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 cursor;
|
|
||||||
String8 program;
|
|
||||||
DW_LineVMHeader header;
|
|
||||||
B32 new_line;
|
|
||||||
B32 new_seq;
|
|
||||||
B32 skip_opcode;
|
|
||||||
DW_LineVMState state;
|
|
||||||
U64 advance;
|
|
||||||
U64 opcode_off;
|
|
||||||
DW_StdOpcode opcode;
|
|
||||||
DW_ExtOpcode ext_opcode;
|
|
||||||
U64 ext_length;
|
|
||||||
U64 line_advance;
|
|
||||||
U64 addr_advance;
|
|
||||||
HashTable *ext_file_ht;
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
String8 string;
|
|
||||||
U64 u64;
|
|
||||||
S64 s64;
|
|
||||||
};
|
|
||||||
} operands[4];
|
|
||||||
String8 error;
|
|
||||||
} DW_LineVM;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// .debug_pubnames and .debug_pubtypes
|
|
||||||
|
|
||||||
typedef struct DW_PubStringsBucket
|
|
||||||
{
|
|
||||||
struct DW_PubStringsBucket *next;
|
|
||||||
String8 string;
|
|
||||||
U64 info_off;
|
|
||||||
U64 cu_info_off;
|
|
||||||
} DW_PubStringsBucket;
|
|
||||||
|
|
||||||
typedef struct DW_PubStringsTable
|
|
||||||
{
|
|
||||||
U64 size;
|
|
||||||
DW_PubStringsBucket **buckets;
|
|
||||||
} DW_PubStringsTable;
|
|
||||||
|
|
||||||
typedef struct DW_Reference
|
|
||||||
{
|
|
||||||
DW_CompUnit *cu;
|
|
||||||
U64 info_off; // global .debug_info offset
|
|
||||||
} DW_Reference;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Expression
|
|
||||||
|
|
||||||
typedef union DW_ExprOperand
|
|
||||||
{
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
|
|
||||||
String8 block;
|
|
||||||
} DW_ExprOperand;
|
|
||||||
|
|
||||||
typedef struct DW_ExprInst
|
|
||||||
{
|
|
||||||
DW_ExprOp opcode;
|
|
||||||
DW_ExprOperand *operands;
|
|
||||||
U64 size;
|
|
||||||
struct DW_ExprInst *next;
|
|
||||||
struct DW_ExprInst *prev;
|
|
||||||
} DW_ExprInst;
|
|
||||||
|
|
||||||
typedef struct DW_Expr
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_ExprInst *first;
|
|
||||||
DW_ExprInst *last;
|
|
||||||
} DW_Expr;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// .debug_frame
|
|
||||||
|
|
||||||
typedef struct DW_CIE
|
|
||||||
{
|
|
||||||
String8 insts;
|
|
||||||
String8 aug_string;
|
|
||||||
String8 aug_data;
|
|
||||||
U64 code_align_factor;
|
|
||||||
S64 data_align_factor;
|
|
||||||
U64 ret_addr_reg;
|
|
||||||
U64 ext[4];
|
|
||||||
DW_Format format;
|
|
||||||
U8 version;
|
|
||||||
U8 address_size;
|
|
||||||
U8 segment_selector_size;
|
|
||||||
} DW_CIE;
|
|
||||||
|
|
||||||
typedef struct DW_FDE
|
|
||||||
{
|
|
||||||
DW_Format format;
|
|
||||||
U64 cie_pointer;
|
|
||||||
Rng1U64 pc_range;
|
|
||||||
String8 insts;
|
|
||||||
} DW_FDE;
|
|
||||||
|
|
||||||
typedef union DW_CFA_Operand
|
|
||||||
{
|
|
||||||
U64 u64;
|
|
||||||
S64 s64;
|
|
||||||
String8 block;
|
|
||||||
} DW_CFA_Operand;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_CFA_ParseErrorCode_NewInst,
|
|
||||||
DW_CFA_ParseErrorCode_End,
|
|
||||||
DW_CFA_ParseErrorCode_OutOfData
|
|
||||||
} DW_CFA_ParseErrorCode;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_Inst
|
|
||||||
{
|
|
||||||
DW_CFA_Opcode opcode;
|
|
||||||
DW_CFA_Operand operands[DW_CFA_OperandMax];
|
|
||||||
} DW_CFA_Inst;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_InstNode
|
|
||||||
{
|
|
||||||
DW_CFA_Inst v;
|
|
||||||
struct DW_CFA_InstNode *next;
|
|
||||||
} DW_CFA_InstNode;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_InstList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_CFA_InstNode *first;
|
|
||||||
DW_CFA_InstNode *last;
|
|
||||||
} DW_CFA_InstList;
|
|
||||||
|
|
||||||
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
|
|
||||||
typedef DW_DECODE_PTR(DW_DecodePtr);
|
|
||||||
|
|
||||||
// hasher
|
|
||||||
|
|
||||||
internal U64 dw_hash_from_string(String8 string);
|
|
||||||
|
|
||||||
// deserial helpers
|
|
||||||
|
|
||||||
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
|
|
||||||
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
|
|
||||||
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
|
|
||||||
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
|
|
||||||
|
|
||||||
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
|
|
||||||
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
|
|
||||||
|
|
||||||
// list units
|
|
||||||
|
|
||||||
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
|
|
||||||
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
|
|
||||||
|
|
||||||
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
|
|
||||||
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
|
|
||||||
|
|
||||||
// abbrev table
|
|
||||||
|
|
||||||
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
|
|
||||||
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
|
|
||||||
|
|
||||||
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
|
|
||||||
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
|
|
||||||
|
|
||||||
// form and tag
|
|
||||||
|
|
||||||
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
|
|
||||||
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
|
|
||||||
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
|
|
||||||
|
|
||||||
// attrib interp
|
|
||||||
|
|
||||||
internal U64 dw_interp_sec_offset(DW_Form form);
|
|
||||||
internal String8 dw_interp_exprloc (DW_Form form);
|
|
||||||
internal U128 dw_interp_const_u128(DW_Form form);
|
|
||||||
internal U64 dw_interp_const_u64 (DW_Form form);
|
|
||||||
internal U32 dw_interp_const_u32 (DW_Form form);
|
|
||||||
internal S64 dw_interp_const_s64 (DW_Form form);
|
|
||||||
internal S32 dw_interp_const_s32 (DW_Form form);
|
|
||||||
internal B32 dw_interp_flag (DW_Form form);
|
|
||||||
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
|
|
||||||
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
|
|
||||||
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
|
|
||||||
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
|
|
||||||
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
|
|
||||||
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
|
|
||||||
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
|
|
||||||
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
|
|
||||||
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
|
|
||||||
// compile unit
|
|
||||||
|
|
||||||
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
|
|
||||||
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
|
|
||||||
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
|
|
||||||
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
|
|
||||||
|
|
||||||
// line VM
|
|
||||||
|
|
||||||
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
|
|
||||||
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
|
|
||||||
internal void dw_line_vm_release(DW_LineVM *vm);
|
|
||||||
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
|
|
||||||
internal B32 dw_line_vm_step(DW_LineVM *vm);
|
|
||||||
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
|
|
||||||
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
|
|
||||||
|
|
||||||
// helper for .debug_pubtypes and .debug_pubnames
|
|
||||||
|
|
||||||
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
|
|
||||||
|
|
||||||
// expression
|
|
||||||
|
|
||||||
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
|
|
||||||
|
|
||||||
// debug frame
|
|
||||||
|
|
||||||
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
|
|
||||||
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
|
|
||||||
|
|
||||||
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
|
|
||||||
|
|
||||||
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
|
|
||||||
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
|
|
||||||
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
|
|
||||||
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
|
|
||||||
|
|
||||||
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
|
|
||||||
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
|
||||||
|
|
||||||
#endif // DWARF_PARSE_H
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_make_cfi_row(Arena *arena, U64 reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
|
|
||||||
row->regs = push_array(arena, DW_CFI_Register, reg_count);
|
|
||||||
for EachIndex(reg_idx, reg_count) {
|
|
||||||
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
|
|
||||||
{
|
|
||||||
dst->cfa = src->cfa;
|
|
||||||
MemoryCopyTyped(dst->regs, src->regs, reg_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
|
|
||||||
dw_memcpy_cfi_row(new_row, row, reg_count);
|
|
||||||
return new_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Unwind *
|
|
||||||
dw_cfi_unwind_init(Arena *arena,
|
|
||||||
Arch arch,
|
|
||||||
DW_CIE *cie,
|
|
||||||
DW_FDE *fde,
|
|
||||||
DW_DecodePtr *decode_ptr_func,
|
|
||||||
void *decode_ptr_ud)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
|
|
||||||
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
|
|
||||||
uw->cie = cie;
|
|
||||||
uw->fde = fde;
|
|
||||||
uw->pc = fde->pc_range.min;
|
|
||||||
uw->arch = arch;
|
|
||||||
uw->reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
|
|
||||||
// setup initial register rules
|
|
||||||
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
|
|
||||||
uw->row = dw_make_cfi_row(arena, uw->reg_count);
|
|
||||||
uw->curr_inst = initial_insts.first;
|
|
||||||
if (!dw_cfi_next_row(arena, uw)) {
|
|
||||||
AssertAlways(0 && "unable to interpret initial row instructions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make first row from initial rules
|
|
||||||
uw->initial_row = uw->row;
|
|
||||||
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
|
|
||||||
uw->curr_inst = uw->insts.first;
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return uw;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
|
|
||||||
{
|
|
||||||
B32 is_row_valid = 0;
|
|
||||||
DW_CFA_InstNode *row_inst = uw->curr_inst;
|
|
||||||
|
|
||||||
// skip leading nops
|
|
||||||
while (uw->curr_inst) {
|
|
||||||
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
uw->curr_inst = uw->curr_inst->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (uw->curr_inst) {
|
|
||||||
DW_CFA_Inst *inst = &uw->curr_inst->v;
|
|
||||||
|
|
||||||
// validate register operands
|
|
||||||
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
|
|
||||||
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
|
|
||||||
for EachIndex(operand_idx, operand_count) {
|
|
||||||
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
|
|
||||||
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (inst->opcode) {
|
|
||||||
// Row Creation Instructions
|
|
||||||
case DW_CFA_SetLoc: {
|
|
||||||
uw->pc = inst->operands[0].u64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_AdvanceLoc:
|
|
||||||
case DW_CFA_AdvanceLoc1:
|
|
||||||
case DW_CFA_AdvanceLoc2:
|
|
||||||
case DW_CFA_AdvanceLoc4: {
|
|
||||||
uw->pc += inst->operands[0].u64;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// CFA Definition Instructions
|
|
||||||
case DW_CFA_DefCfa:
|
|
||||||
case DW_CFA_DefCfaSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
S64 off = inst->operands[1].s64;
|
|
||||||
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
|
|
||||||
uw->row->cfa.reg = reg;
|
|
||||||
uw->row->cfa.off = off;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaRegister: {
|
|
||||||
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
|
|
||||||
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->cfa.reg = reg;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaOffset:
|
|
||||||
case DW_CFA_DefCfaOffsetSf: {
|
|
||||||
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
|
|
||||||
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
|
|
||||||
uw->row->cfa.off = inst->operands[0].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaExpr: {
|
|
||||||
uw->row->cfa.rule = DW_CFA_Rule_Expression;
|
|
||||||
uw->row->cfa.expr = inst->operands[0].block;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Register Rule Instructions
|
|
||||||
case DW_CFA_Undefined: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_SameValue: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Offset:
|
|
||||||
case DW_CFA_OffsetExt:
|
|
||||||
case DW_CFA_OffsetExtSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_ValOffset:
|
|
||||||
case DW_CFA_ValOffsetSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Register: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Expr: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
|
|
||||||
uw->row->regs[reg].expr = inst->operands[1].block;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_ValExpr: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
|
|
||||||
uw->row->regs[reg].expr = inst->operands[1].block;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Restore:
|
|
||||||
case DW_CFA_RestoreExt: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg] = uw->initial_row->regs[reg];
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Row State Instructions
|
|
||||||
case DW_CFA_RememberState: {
|
|
||||||
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
|
|
||||||
SLLStackPush(uw->row, new_row);
|
|
||||||
} break;
|
|
||||||
case DW_CFA_RestoreState: {
|
|
||||||
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
|
|
||||||
DW_CFI_Row *free_row = uw->row;
|
|
||||||
SLLStackPop(uw->row);
|
|
||||||
SLLStackPush(uw->free_rows, free_row);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case DW_CFA_Nop: {} break;
|
|
||||||
|
|
||||||
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
|
|
||||||
}
|
|
||||||
|
|
||||||
uw->curr_inst = uw->curr_inst->next;
|
|
||||||
if (uw->curr_inst) {
|
|
||||||
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is_row_valid = row_inst != 0;
|
|
||||||
exit:;
|
|
||||||
return is_row_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
B32 is_row_found = 0;
|
|
||||||
U64 reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
|
|
||||||
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
|
|
||||||
U64 prev_pc = uw->pc;
|
|
||||||
while (dw_cfi_next_row(scratch.arena, uw)) {
|
|
||||||
if (prev_pc <= pc && pc < uw->pc) {
|
|
||||||
is_row_found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
|
|
||||||
prev_pc = uw->pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle last row
|
|
||||||
if (!is_row_found) {
|
|
||||||
if (contains_1u64(fde->pc_range, pc)) {
|
|
||||||
row = uw->row;
|
|
||||||
is_row_found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy out final row
|
|
||||||
DW_CFI_Row *result = 0;
|
|
||||||
if (is_row_found) {
|
|
||||||
result = dw_copy_cfi_row(arena, row, reg_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MachineOpResult
|
|
||||||
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
|
|
||||||
{
|
|
||||||
MachineOpResult unwind_status = MachineOpResult_Fail;
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
switch(row->cfa.rule)
|
|
||||||
{
|
|
||||||
case DW_CFA_Rule_Null:{}break;
|
|
||||||
case DW_CFA_Rule_RegOff:
|
|
||||||
{
|
|
||||||
// TODO: report error (invalid register read)
|
|
||||||
U64 cfa_reg_value = 0;
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
|
|
||||||
AssertAlways(reg_size <= sizeof(cfa_reg_value));
|
|
||||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
|
|
||||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
|
||||||
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*cfa_out = cfa_reg_value + row->cfa.off;
|
|
||||||
unwind_status = MachineOpResult_Ok;
|
|
||||||
}break;
|
|
||||||
case DW_CFA_Rule_Expression:
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0,0);
|
|
||||||
DW_ExprValue value = {0};
|
|
||||||
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
|
|
||||||
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
|
|
||||||
if (eval_result == DW_ExprEvalResult_Ok) {
|
|
||||||
if (DW_ExprValueType_IsInt(value.type)) {
|
|
||||||
*cfa_out = value.u64;
|
|
||||||
unwind_status = MachineOpResult_Ok;
|
|
||||||
}
|
|
||||||
} else if (eval_result == DW_ExprEvalResult_Maybe) {
|
|
||||||
unwind_status = MachineOpResult_Maybe;
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
return unwind_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MachineOpResult
|
|
||||||
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0,0);
|
|
||||||
MachineOpResult unwind_status = MachineOpResult_Ok;
|
|
||||||
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
|
|
||||||
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
|
|
||||||
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
|
|
||||||
|
|
||||||
U64 reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
for EachIndex(reg_idx, reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Register *reg = &row->regs[reg_idx];
|
|
||||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
|
|
||||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
|
||||||
switch(reg->rule)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case DW_CFI_RegisterRule_Undefined: {} break;
|
|
||||||
case DW_CFI_RegisterRule_SameValue: {} break;
|
|
||||||
case DW_CFI_RegisterRule_Offset:
|
|
||||||
{
|
|
||||||
// read register value from memory
|
|
||||||
U64 addr = cfa + reg->n;
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
|
|
||||||
if (unwind_status != MachineOpResult_Ok) { goto exit; }
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_ValOffset:
|
|
||||||
{
|
|
||||||
// compute register value
|
|
||||||
U64 reg_value = cfa + reg->n;
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, ®_value))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Register:
|
|
||||||
{
|
|
||||||
// read register value from another register
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (unwind_status != MachineOpResult_Ok) { goto exit; }
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Expression:
|
|
||||||
{
|
|
||||||
// TODO: evaluate expression
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_ValExpression:
|
|
||||||
{
|
|
||||||
// TODO: evaluate expression
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Architectural:
|
|
||||||
{
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update stack pointer
|
|
||||||
arch_reg_block_write_sp(arch_info, reg_block, cfa);
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
return unwind_status;
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_UNWIND_H
|
|
||||||
#define DWARF_UNWIND_H
|
|
||||||
|
|
||||||
typedef enum DW_CFI_RegisterRule
|
|
||||||
{
|
|
||||||
DW_CFI_RegisterRule_Undefined,
|
|
||||||
DW_CFI_RegisterRule_SameValue,
|
|
||||||
DW_CFI_RegisterRule_Offset,
|
|
||||||
DW_CFI_RegisterRule_ValOffset,
|
|
||||||
DW_CFI_RegisterRule_Register,
|
|
||||||
DW_CFI_RegisterRule_Expression,
|
|
||||||
DW_CFI_RegisterRule_ValExpression,
|
|
||||||
DW_CFI_RegisterRule_Architectural
|
|
||||||
} DW_CFI_RegisterRule;
|
|
||||||
|
|
||||||
typedef enum DW_CFA_Rule
|
|
||||||
{
|
|
||||||
DW_CFA_Rule_Null,
|
|
||||||
DW_CFA_Rule_RegOff,
|
|
||||||
DW_CFA_Rule_Expression
|
|
||||||
} DW_CFA_Rule;
|
|
||||||
|
|
||||||
typedef struct DW_CFA
|
|
||||||
{
|
|
||||||
DW_CFA_Rule rule;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
DW_Reg reg;
|
|
||||||
S64 off;
|
|
||||||
};
|
|
||||||
String8 expr;
|
|
||||||
};
|
|
||||||
} DW_CFA;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Register
|
|
||||||
{
|
|
||||||
DW_CFI_RegisterRule rule;
|
|
||||||
union {
|
|
||||||
S64 n;
|
|
||||||
String8 expr;
|
|
||||||
};
|
|
||||||
} DW_CFI_Register;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Row
|
|
||||||
{
|
|
||||||
DW_CFA cfa;
|
|
||||||
DW_CFI_Register *regs;
|
|
||||||
struct DW_CFI_Row *next;
|
|
||||||
} DW_CFI_Row;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Unwind
|
|
||||||
{
|
|
||||||
DW_CFA_InstList insts;
|
|
||||||
DW_CIE *cie;
|
|
||||||
DW_FDE *fde;
|
|
||||||
DW_CFI_Row *initial_row;
|
|
||||||
DW_CFI_Row *row;
|
|
||||||
DW_CFA_InstNode *curr_inst;
|
|
||||||
DW_CFI_Row *free_rows;
|
|
||||||
U64 pc;
|
|
||||||
Arch arch;
|
|
||||||
U64 reg_count;
|
|
||||||
} DW_CFI_Unwind;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
|
|
||||||
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
|
|
||||||
|
|
||||||
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
|
||||||
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
|
|
||||||
|
|
||||||
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
|
|
||||||
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
|
|
||||||
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
|
|
||||||
|
|
||||||
#endif // DWARF_UNWIND_H
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,275 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef RDI_FROM_DWARF_H
|
|
||||||
#define RDI_FROM_DWARF_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Conversion
|
|
||||||
|
|
||||||
typedef struct D2R_ConvertParams
|
|
||||||
{
|
|
||||||
String8 dbg_name;
|
|
||||||
String8 dbg_data;
|
|
||||||
String8 exe_name;
|
|
||||||
String8 exe_data;
|
|
||||||
ExecutableImageKind exe_kind;
|
|
||||||
RDIM_SubsetFlags subset_flags;
|
|
||||||
B32 deterministic;
|
|
||||||
B32 is_parse_relaxed;
|
|
||||||
} D2R_ConvertParams;
|
|
||||||
|
|
||||||
#define D2R_UNIT_CHUNK_CAP 512
|
|
||||||
#define D2R_UDT_CHUNK_CAP 1024
|
|
||||||
#define D2R_TYPE_CHUNK_CAP 1024
|
|
||||||
#define D2R_SRC_FILE_CAP 1024
|
|
||||||
#define D2R_LINE_TABLE_CAP 1024
|
|
||||||
#define D2R_GVAR_CHUNK_CAP 1024
|
|
||||||
#define D2R_TVAR_CHUNK_CAP 1024
|
|
||||||
#define D2R_LOCATIONS_CAP 4096
|
|
||||||
#define D2R_PROC_CHUNK_CAP 4096
|
|
||||||
#define D2R_SCOPE_CHUNK_CAP 4096
|
|
||||||
#define D2R_INLINE_SITE_CHUNK_CAP 4096
|
|
||||||
|
|
||||||
typedef struct D2R_Shared
|
|
||||||
{
|
|
||||||
RDIM_TopLevelInfo top_level_info;
|
|
||||||
RDIM_BinarySectionList binary_sections;
|
|
||||||
RDIM_UnitChunkList units;
|
|
||||||
RDIM_UDTChunkList udts;
|
|
||||||
RDIM_TypeChunkList types;
|
|
||||||
RDIM_SrcFileChunkList src_files;
|
|
||||||
RDIM_LineTableChunkList line_tables;
|
|
||||||
} D2R_Shared;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Value Types
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
D2R_ArithmeticType_Null,
|
|
||||||
D2R_ArithmeticType_Signed,
|
|
||||||
D2R_ArithmeticType_Unsigned,
|
|
||||||
D2R_ArithmeticType_Float,
|
|
||||||
} D2R_ArithmeticType;
|
|
||||||
|
|
||||||
#define D2R_ValueType_Signed_XList \
|
|
||||||
X(S8, Signed, 1 ) \
|
|
||||||
X(S16, Signed, 2 ) \
|
|
||||||
X(S32, Signed, 4 ) \
|
|
||||||
X(S64, Signed, 8 ) \
|
|
||||||
X(S128, Signed, 16) \
|
|
||||||
X(S256, Signed, 32) \
|
|
||||||
X(S512, Signed, 64)
|
|
||||||
|
|
||||||
#define D2R_ValueType_Unsigned_XList \
|
|
||||||
X(U8, Unsigned, 1 ) \
|
|
||||||
X(U16, Unsigned, 2 ) \
|
|
||||||
X(U32, Unsigned, 4 ) \
|
|
||||||
X(U64, Unsigned, 8 ) \
|
|
||||||
X(U128, Unsigned, 16) \
|
|
||||||
X(U256, Unsigned, 32) \
|
|
||||||
X(U512, Unsigned, 64)
|
|
||||||
|
|
||||||
#define D2R_ValueType_Float_XList \
|
|
||||||
X(F16, Float, 2 ) \
|
|
||||||
X(F32, Float, 4 ) \
|
|
||||||
X(F48, Float, 6 ) \
|
|
||||||
X(F64, Float, 8 ) \
|
|
||||||
X(F80, Float, 10) \
|
|
||||||
X(F96, Float, 12) \
|
|
||||||
X(F128, Float, 16)
|
|
||||||
|
|
||||||
#define D2R_ValueType_XList \
|
|
||||||
X(Generic, Null, 0 ) \
|
|
||||||
X(ImplicitValue, Null, 0 ) \
|
|
||||||
X(Address, Unsigned, 0 ) \
|
|
||||||
D2R_ValueType_Signed_XList \
|
|
||||||
D2R_ValueType_Unsigned_XList \
|
|
||||||
D2R_ValueType_Float_XList
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
#define X(t, ...) D2R_ValueType_##t,
|
|
||||||
D2R_ValueType_XList
|
|
||||||
#undef X
|
|
||||||
D2R_ValueType_Bool = D2R_ValueType_S8,
|
|
||||||
} D2R_ValueType;
|
|
||||||
|
|
||||||
typedef struct D2R_ValueTypeNode
|
|
||||||
{
|
|
||||||
D2R_ValueType type;
|
|
||||||
struct D2R_ValueTypeNode *next;
|
|
||||||
} D2R_ValueTypeNode;
|
|
||||||
|
|
||||||
typedef struct D2R_ValueTypeStack
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
D2R_ValueTypeNode *top;
|
|
||||||
D2R_ValueTypeNode *free_list;
|
|
||||||
} D2R_ValueTypeStack;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Table
|
|
||||||
|
|
||||||
typedef struct D2R_TypeTable
|
|
||||||
{
|
|
||||||
HashTable *ht;
|
|
||||||
RDIM_TypeChunkList *types;
|
|
||||||
U64 type_chunk_cap;
|
|
||||||
RDIM_Type **builtin_types;
|
|
||||||
} D2R_TypeTable;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Tag Iterator
|
|
||||||
|
|
||||||
typedef DW_TagSpare D2R_TagFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
D2R_TagFlags_TypeConverted = (1 << 0),
|
|
||||||
D2R_TagFlags_UdtConverted = (1 << 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D2R_TagFrame
|
|
||||||
{
|
|
||||||
DW_TagNode *node;
|
|
||||||
RDIM_Scope *scope;
|
|
||||||
struct D2R_TagFrame *next;
|
|
||||||
} D2R_TagFrame;
|
|
||||||
|
|
||||||
typedef struct D2R_TagIterator
|
|
||||||
{
|
|
||||||
D2R_TagFrame *free_list;
|
|
||||||
D2R_TagFrame *stack;
|
|
||||||
DW_TagNode *null_tag_node;
|
|
||||||
DW_TagNode *tag_node;
|
|
||||||
B32 visit_children;
|
|
||||||
} D2R_TagIterator;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Line Table Conversion
|
|
||||||
|
|
||||||
typedef struct D2R_SrcFileLookup
|
|
||||||
{
|
|
||||||
DW_LineFile *file;
|
|
||||||
DW_LineVM *vm;
|
|
||||||
RDIM_SrcFile *src_file;
|
|
||||||
} D2R_SrcFileLookup;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Contrib Map
|
|
||||||
|
|
||||||
typedef struct D2R_CompUnitContribMap
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
U64 *info_off_arr;
|
|
||||||
RDIM_Rng1U64ChunkList *voff_range_arr;
|
|
||||||
} D2R_CompUnitContribMap;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ RDIM Bytecode Extensions
|
|
||||||
|
|
||||||
internal B32 rdim_is_eval_bytecode_static (RDIM_EvalBytecode bc);
|
|
||||||
internal B32 rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ DWARF -> RDI Enums
|
|
||||||
|
|
||||||
internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v);
|
|
||||||
internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64 (DW_RegX64 v);
|
|
||||||
internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg (Arch arch, DW_Reg v);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Value Type
|
|
||||||
|
|
||||||
internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type);
|
|
||||||
internal D2R_ValueType d2r_value_type_stack_pop (D2R_ValueTypeStack *stack);
|
|
||||||
internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_signed_value_type_from_bit_size (U64 bit_size);
|
|
||||||
internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal D2R_ValueType d2r_float_type_from_bit_size (U64 bit_size);
|
|
||||||
|
|
||||||
internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type);
|
|
||||||
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
|
|
||||||
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_signed (D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_integral(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_unsigned(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_float (D2R_ValueType v);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs);
|
|
||||||
internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc);
|
|
||||||
internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
|
||||||
internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Expression Conversion
|
|
||||||
|
|
||||||
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out);
|
|
||||||
internal RDIM_Location d2r_transpile_expression (Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr);
|
|
||||||
internal RDIM_Location d2r_location_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal RDIM_LocationCaseList d2r_locset_from_attrib (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal RDIM_LocationCaseList d2r_var_locset_from_tag (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Table
|
|
||||||
|
|
||||||
internal RDIM_Type * d2r_create_type (Arena *arena, D2R_TypeTable *type_table);
|
|
||||||
internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off);
|
|
||||||
internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off);
|
|
||||||
internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Tag Iterator
|
|
||||||
|
|
||||||
internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root);
|
|
||||||
internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter);
|
|
||||||
internal void d2r_tag_iterator_skip_children (D2R_TagIterator *iter);
|
|
||||||
internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter);
|
|
||||||
internal DW_Tag d2r_tag_iterator_parent_tag (D2R_TagIterator *iter);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Conversion
|
|
||||||
|
|
||||||
internal void d2r_flag_converted_tag(DW_TagNode *tag_node);
|
|
||||||
internal B8 d2r_is_tag_converted (DW_TagNode *tag_node);
|
|
||||||
internal RDIM_Type * d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_TagNode *root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ UDT Conversion
|
|
||||||
|
|
||||||
internal B8 d2r_is_udt_tag_converted (DW_TagNode *tag_node);
|
|
||||||
internal void d2r_flag_converted_udt_tag(DW_TagNode *tag_node);
|
|
||||||
internal void d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, RDIM_UDT *udt);
|
|
||||||
internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Symbol Conversion
|
|
||||||
|
|
||||||
internal RDIM_Scope * d2r_push_scope (Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges);
|
|
||||||
internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out);
|
|
||||||
internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag);
|
|
||||||
internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, U64 image_base, Arch arch, DW_TagNode *root, RDIM_Unit *unit_rdi);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Line Table Conversion
|
|
||||||
|
|
||||||
internal U64 d2r_hash_line_file(String8 dir_path, DW_LineFile *file);
|
|
||||||
internal void d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b));
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Contrib Map
|
|
||||||
|
|
||||||
internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Raw *input, U64 image_base);
|
|
||||||
internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Entry Point
|
|
||||||
|
|
||||||
internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params);
|
|
||||||
|
|
||||||
#endif // RDI_FROM_DWARF_H
|
|
||||||
+115
-62
@@ -45,77 +45,130 @@ load_paths =
|
|||||||
|
|
||||||
commands =
|
commands =
|
||||||
{
|
{
|
||||||
//- rjf: [raddbg]
|
.rjf_f1 =
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg telemetry",
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build torture && build ryan_scratch && pushd build && torture eval2/* && ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
//- rjf: [raddbg wsl]
|
.save_dirty_files = true,
|
||||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
//- rjf: [scratch]
|
.rjf_f2 =
|
||||||
// .f2 = { .win = "pushd build && for /l %i in (1, 1, 3) do (radbin --rdi raddbg.exe --out:raddbg_%i.rdi && radbin --dump raddbg_%i.rdi --out:raddbg_%i.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.f2 = { .win = "pushd build && radbin --rdi raddbg.exe --thread_count=1 --out:1.rdi && radbin --rdi raddbg.exe --thread_count=8 --out:8.rdi && radbin --dump 1.rdi --out:1.dump && radbin --dump 8.rdi --out:8.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build mule_peb_trample",
|
||||||
|
.linux = "",
|
||||||
//- rjf: [textperf]
|
.out = "*compilation*",
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
//- rjf: [tester]
|
.cursor_at_end = false,
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
|
.rjf_f3 =
|
||||||
//- rjf: [radbin]
|
{
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
|
||||||
|
.linux = "",
|
||||||
//- rjf: running target
|
.out = "*compilation*",
|
||||||
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
// .f3 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.rjf_f4 =
|
||||||
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
|
.win = "build rdi_from_pdb release telemetry && pushd build && rdi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.rdi --capture && popd",
|
||||||
//- rjf: local target builds
|
.linux = "",
|
||||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_rdi_from_pdb = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_rdi_from_dwarf = { .win = "build rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_rdi_dump = { .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_rdi_breakpad_from_pdb = { .win = "build rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_ryan_scratch = { .win = "build ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.rjf_f5 =
|
||||||
.build_mule_main = { .win = "build mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_mule_module = { .win = "build mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "pushd build && rdi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.rdi --capture && popd",
|
||||||
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
//- rjf: wsl target builds
|
.save_dirty_files = true,
|
||||||
.build_raddbg_wsl = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_rdi_from_pdb_wsl = { .win = "wsl ./build.sh rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_rdi_from_dwarf_wsl = { .win = "wsl ./build.sh rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg =
|
||||||
.build_rdi_dump_wsl = { .win = "wsl ./build.sh rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_rdi_breakpad_from_pdb_wsl = { .win = "wsl ./build.sh rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg",
|
||||||
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_mule_hotload_wsl = { .win = "wsl ./build.sh mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_mule_peb_trample_wsl = { .win = "wsl ./build.sh mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
//- rjf: local target runs
|
.build_raddbg_release_telemetry =
|
||||||
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
|
.win = "build raddbg release telemetry",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.build_rdi_from_pdb =
|
||||||
|
{
|
||||||
|
.win = "build rdi_from_pdb",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.build_rdi_dump =
|
||||||
|
{
|
||||||
|
.win = "build rdi_dump",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.build_mule_main =
|
||||||
|
{
|
||||||
|
.win = "build mule_main",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.build_ryan_scratch =
|
||||||
|
{
|
||||||
|
.win = "build ryan_scratch",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.run_raddbg =
|
||||||
|
{
|
||||||
|
.win = "pushd build && raddbg.exe && popd",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command =
|
fkey_command =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "build_raddbg",
|
||||||
.F2 = "f2",
|
.F3 = "run_raddbg",
|
||||||
.F3 = "f3",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command_override =
|
fkey_command_override =
|
||||||
{
|
{
|
||||||
.rjf =
|
.rjf =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "rjf_f1",
|
||||||
.F2 = "f2",
|
.F2 = "rjf_f2",
|
||||||
.F3 = "f3",
|
.F3 = "rjf_f3",
|
||||||
|
.F4 = "rjf_f4",
|
||||||
|
.F5 = "rjf_f5",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// raddbg 0.9.28 project file
|
|
||||||
|
|
||||||
name: "The RAD Debugger"
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/raddbg.exe"
|
|
||||||
working_directory: "../raddebugger"
|
|
||||||
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user"
|
|
||||||
debug_subprocesses: 0
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/raddbg.exe"
|
|
||||||
working_directory: "../raddebugger"
|
|
||||||
arguments: "--user:test123"
|
|
||||||
debug_subprocesses: 0
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/mule_main.exe"
|
|
||||||
working_directory: build
|
|
||||||
output_label: output_a
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/torture.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "eval2/*"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/metagen.exe"
|
|
||||||
working_directory: build
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi raddbg"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/release_version/raddbg.exe"
|
|
||||||
working_directory: "build/release_version"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi fat.so --capture"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi fat.debug --capture"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi raddbg"
|
|
||||||
}
|
|
||||||
watch_pin: expression: tag_hash_slots
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/ryan_scratch.exe"
|
|
||||||
working_directory: build
|
|
||||||
enabled: 1
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "../../Program Files/SuperTux/bin/supertux2.exe"
|
|
||||||
working_directory: "../../Program Files/SuperTux/bin"
|
|
||||||
}
|
|
||||||
-126
@@ -1,126 +0,0 @@
|
|||||||
@echo off
|
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
set TARGET_VALUES=radlink radbin mule_main mule_module torture
|
|
||||||
set CC_VALUES=msvc clang
|
|
||||||
set MODE_VALUES=debug release
|
|
||||||
set RAW_ARGS=%*
|
|
||||||
set TORTURE_ARGS=
|
|
||||||
set RUN_TORTURE=1
|
|
||||||
|
|
||||||
:: Make test data directories
|
|
||||||
if not exist local mkdir local
|
|
||||||
pushd local
|
|
||||||
if not exist test_data mkdir test_data
|
|
||||||
popd
|
|
||||||
|
|
||||||
:: Check if we need new test data version
|
|
||||||
pushd local
|
|
||||||
set need_test_data=0
|
|
||||||
curl -sfL -o test_data_version_latest.txt https://data.raddbg.com/public/raddbg_test_data_version.txt || exit /b 1
|
|
||||||
if exist "test_data_version_current.txt" (
|
|
||||||
fc /b "test_data_version_latest.txt" "test_data_version_current.txt" > nul
|
|
||||||
) else (
|
|
||||||
echo Test data not present.
|
|
||||||
set need_test_data=1
|
|
||||||
)
|
|
||||||
if errorlevel 1 (
|
|
||||||
echo Test data out-of-date.
|
|
||||||
set need_test_data=1
|
|
||||||
)
|
|
||||||
popd
|
|
||||||
|
|
||||||
:: Download test data if stale
|
|
||||||
if "%need_test_data%"=="1" (
|
|
||||||
echo Downloading test data...
|
|
||||||
pushd local
|
|
||||||
pushd test_data
|
|
||||||
curl -sfL -o test_data.zip https://data.raddbg.com/public/raddbg_test_data.zip || exit /b 1
|
|
||||||
tar -xf test_data.zip || exit /b 1
|
|
||||||
del test_data.zip
|
|
||||||
popd
|
|
||||||
copy /y test_data_version_latest.txt test_data_version_current.txt
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
popd
|
|
||||||
|
|
||||||
:parse_args
|
|
||||||
if "%~1" == "" goto parse_done
|
|
||||||
if "%~1" == "--" goto parse_torture_args
|
|
||||||
if /i "%~1" == "msvc" set CC_VALUES=msvc && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "clang" set CC_VALUES=clang && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "debug" set MODE_VALUES=debug && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "release" set MODE_VALUES=release && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "no_torture" set RUN_TORTURE=0 && shift /1 && goto parse_args
|
|
||||||
echo usage: %~nx0 [msvc^|clang] [debug^|release] [no_torture] [-- torture-args]
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:parse_torture_args
|
|
||||||
shift /1
|
|
||||||
if "%~1" == "" set "TORTURE_ARGS=" && goto parse_done
|
|
||||||
set "TORTURE_ARGS=%RAW_ARGS%"
|
|
||||||
if "%TORTURE_ARGS:~0,3%" == "-- " set "TORTURE_ARGS=%TORTURE_ARGS:~3%" && goto parse_done
|
|
||||||
set "TORTURE_ARGS=%TORTURE_ARGS:* -- =%"
|
|
||||||
|
|
||||||
:parse_done
|
|
||||||
if not defined TORTURE_ARGS set "TORTURE_ARGS=*
|
|
||||||
|
|
||||||
for %%m in (%MODE_VALUES%) do for %%c in (%CC_VALUES%) do (
|
|
||||||
setlocal
|
|
||||||
|
|
||||||
:: nuke artifacts from last run
|
|
||||||
if exist build/torture_artifacts rmdir /s /q build\torture_artifacts
|
|
||||||
if exist build\metagen.exe del /q build\metagen.exe
|
|
||||||
for %%t in (%TARGET_VALUES%) do (
|
|
||||||
if exist build\%%t.exe del /q build\%%t.exe
|
|
||||||
if exist build\%%t.pdb del /q build\%%t.pdb
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%%c" == "clang" (
|
|
||||||
:: Prefer standalone LLVM clang over Visual Studio clang so ASAN runtime files match the compiler.
|
|
||||||
set "clang_path="
|
|
||||||
for /f "tokens=*" %%i in ('where clang') do (
|
|
||||||
set "candidate_clang_path=%%~dpi"
|
|
||||||
if "!candidate_clang_path:Microsoft Visual Studio=!"=="!candidate_clang_path!" (
|
|
||||||
if not defined clang_path set "clang_path=!candidate_clang_path!"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not defined clang_path (
|
|
||||||
echo ERROR: standalone LLVM clang not found in PATH
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
set PATH=!clang_path!;!PATH!
|
|
||||||
for /f "tokens=3 delims=. " %%v in ('clang -v 2^>^&1 ^| findstr version') do set clang_version=%%v
|
|
||||||
if not defined clang_version (
|
|
||||||
echo ERROR: failed to detect clang version
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
set PATH=!clang_path!..\lib\clang\!clang_version!\lib\windows;!PATH!
|
|
||||||
)
|
|
||||||
|
|
||||||
:: TODO: unblock asan
|
|
||||||
call build.bat meta %%c %%m raddbg raddbg_non_graphical || (endlocal exit /b 1)
|
|
||||||
|
|
||||||
:: clang does not compile with asan in release mode because it runs out of memory
|
|
||||||
if "%%c" equ "clang" (
|
|
||||||
if /i "%%m" equ "release" (
|
|
||||||
call build.bat no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
) else (
|
|
||||||
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%RUN_TORTURE%" equ "1" (
|
|
||||||
pushd build
|
|
||||||
torture %TORTURE_ARGS%
|
|
||||||
popd
|
|
||||||
if errorlevel 1 (
|
|
||||||
endlocal
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
endlocal
|
|
||||||
)
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
target_values=(raddbg raddbg_non_graphical radlink radbin torture)
|
|
||||||
cc_values=(clang gcc)
|
|
||||||
mode_values=(debug release)
|
|
||||||
run_torture=1
|
|
||||||
torture_args=()
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
torture_args=("$@")
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
clang)
|
|
||||||
cc_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
gcc)
|
|
||||||
cc_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
debug|release)
|
|
||||||
mode_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
no_torture)
|
|
||||||
run_torture=0
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "usage: $0 [clang|gcc] [debug|release] [no_torture] [-- torture-args]"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "${#torture_args[@]}" == "0" ]]; then
|
|
||||||
torture_args=("*")
|
|
||||||
fi
|
|
||||||
|
|
||||||
for m in "${mode_values[@]}"; do
|
|
||||||
for c in "${cc_values[@]}"; do
|
|
||||||
# nuke artifacts from last run
|
|
||||||
rm -rf build/torture_artifacts
|
|
||||||
rm -f build/metagen
|
|
||||||
for t in "${target_values[@]}"; do
|
|
||||||
rm -f "build/$t"
|
|
||||||
done
|
|
||||||
|
|
||||||
# build targets
|
|
||||||
./build.sh meta "$c" "$m" "${target_values[@]}"
|
|
||||||
|
|
||||||
# run torture from build folder
|
|
||||||
if [[ "$run_torture" == "1" ]]; then
|
|
||||||
torture_compiler_args=()
|
|
||||||
has_clang_arg=0
|
|
||||||
has_gcc_arg=0
|
|
||||||
for arg in "${torture_args[@]}"; do
|
|
||||||
case "$arg" in
|
|
||||||
-clang:*|--clang:*) has_clang_arg=1 ;;
|
|
||||||
-gcc:*|--gcc:*) has_gcc_arg=1 ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [[ "$c" == clang && "$has_clang_arg" == "0" ]]; then
|
|
||||||
torture_compiler_args=("-clang:$(command -v "${CC:-clang}")")
|
|
||||||
elif [[ "$c" == gcc && "$has_gcc_arg" == "0" ]]; then
|
|
||||||
torture_compiler_args=("-gcc:$(command -v "${CC:-gcc}")")
|
|
||||||
fi
|
|
||||||
(cd build && ./torture "${torture_compiler_args[@]}" "${torture_args[@]}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
done
|
|
||||||
-174
@@ -1,174 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstracted Architecture Functions
|
|
||||||
|
|
||||||
internal ARCH_Info *
|
|
||||||
arch_info_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
ARCH_Info *result = &arch_info_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
local_persist U8 trap_inst_bytes[] = {0xcc};
|
|
||||||
local_persist read_only ARCH_Info info =
|
|
||||||
{
|
|
||||||
.reg_block_size = sizeof(X64_RegBlock),
|
|
||||||
.instruction_pointer_reg_code = X64_RegCode_rip,
|
|
||||||
.stack_pointer_reg_code = X64_RegCode_rsp,
|
|
||||||
.reg_code_count = X64_RegCode_COUNT,
|
|
||||||
.trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)},
|
|
||||||
.reg_code_rng_table = x64_reg_code_rng_table,
|
|
||||||
.reg_code_name_table = x64_reg_code_name_table,
|
|
||||||
.reg_code_base_table = x64_reg_code_base_table,
|
|
||||||
.reg_code_is_vector_table = x64_reg_code_is_vector_table,
|
|
||||||
};
|
|
||||||
result = &info;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_name(ARCH_Info *arch_info, String8 name)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
for EachIndex(code, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(str8_match(arch_info->reg_code_name_table[code], name, 0))
|
|
||||||
{
|
|
||||||
result = code;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
{
|
|
||||||
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
|
|
||||||
Rng1U16 try_range = range;
|
|
||||||
Rng1U16 read_range = intersect_1u16(legal_range, try_range);
|
|
||||||
U64 read_size = dim_1u16(read_range);
|
|
||||||
if(read_size != 0)
|
|
||||||
{
|
|
||||||
MemoryCopy(dst, (U8 *)block + read_range.min, read_size);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
|
|
||||||
Rng1U16 try_range = range;
|
|
||||||
Rng1U16 write_range = intersect_1u16(legal_range, try_range);
|
|
||||||
U64 write_size = dim_1u16(write_range);
|
|
||||||
if(write_size != 0)
|
|
||||||
{
|
|
||||||
MemoryCopy((U8 *)block + write_range.min, src, write_size);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
arch_ip_from_reg_block(ARCH_Info *arch_info, void *block)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
arch_sp_from_reg_block(ARCH_Info *arch_info, void *block)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(RDI_H)
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_rdi(Arch arch, RDI_RegCode code)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
{
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch);
|
|
||||||
for EachIndex(c, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(rdi_from_reg_code_table[c] == code)
|
|
||||||
{
|
|
||||||
result = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_dw(Arch arch, DW_RegCode code)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
{
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch);
|
|
||||||
for EachIndex(c, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(dw_from_reg_code_table[c] == code)
|
|
||||||
{
|
|
||||||
result = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_H
|
|
||||||
#define ARCH_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstraction Backend Info
|
|
||||||
|
|
||||||
typedef U8 ARCH_RegCode;
|
|
||||||
|
|
||||||
typedef struct ARCH_Info ARCH_Info;
|
|
||||||
struct ARCH_Info
|
|
||||||
{
|
|
||||||
U16 reg_block_size;
|
|
||||||
ARCH_RegCode instruction_pointer_reg_code;
|
|
||||||
ARCH_RegCode stack_pointer_reg_code;
|
|
||||||
U16 reg_code_count;
|
|
||||||
String8 trap_instruction;
|
|
||||||
Rng1U16 *reg_code_rng_table;
|
|
||||||
String8 *reg_code_name_table;
|
|
||||||
U8 *reg_code_base_table;
|
|
||||||
B8 *reg_code_is_vector_table;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global read_only Rng1U16 arch_reg_code_rng_nil = {0};
|
|
||||||
global read_only String8 arch_reg_code_name_nil = {0};
|
|
||||||
global read_only U8 arch_reg_code_u8_nil = 0;
|
|
||||||
global read_only B8 arch_reg_code_b8_nil = 0;
|
|
||||||
global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstracted Architecture Functions
|
|
||||||
|
|
||||||
internal ARCH_Info *arch_info_from_arch(Arch arch);
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
|
|
||||||
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
|
|
||||||
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
|
|
||||||
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
|
|
||||||
internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block);
|
|
||||||
internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip);
|
|
||||||
internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp);
|
|
||||||
|
|
||||||
#if defined(RDI_H)
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
|
|
||||||
#endif
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // REGS_H
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#include "arch/arch.c"
|
|
||||||
#include "arch/os/arch_os.c"
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
# include "arch/dwarf/arch_dwarf.c"
|
|
||||||
#endif
|
|
||||||
#if defined(RDI_H)
|
|
||||||
# include "arch/rdi/arch_rdi.c"
|
|
||||||
#endif
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_INC_H
|
|
||||||
#define ARCH_INC_H
|
|
||||||
|
|
||||||
#include "arch/arch.h"
|
|
||||||
#include "arch/os/arch_os.h"
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
# include "arch/dwarf/arch_dwarf.h"
|
|
||||||
#endif
|
|
||||||
#if defined(RDI_H)
|
|
||||||
# include "arch/rdi/arch_rdi.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ARCH_INC_H
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal U8 *
|
|
||||||
arch_dw_from_reg_code_table_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U8 *result = &arch_reg_code_u8_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
result = dw_reg_code_from_x64_table;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_DWARF_H
|
|
||||||
#define ARCH_DWARF_H
|
|
||||||
|
|
||||||
internal U8 *arch_dw_from_reg_code_table_from_arch(Arch arch);
|
|
||||||
|
|
||||||
#endif // ARCH_DWARF_H
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
if(0){}
|
|
||||||
#define Case(arch_, os_, impl) else if((arch) == arch_ && (os) == os_) do {result = impl(reg_block, thread_ctx);}while(0)
|
|
||||||
#if defined(X64_H) && defined(WIN32_X64_H)
|
|
||||||
Case(Arch_x64, OperatingSystem_Windows, w32_x64_write_reg_block_from_thread_ctx);
|
|
||||||
#endif
|
|
||||||
#undef Case
|
|
||||||
else{}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_OS_H
|
|
||||||
#define ARCH_OS_H
|
|
||||||
|
|
||||||
internal B32 arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx);
|
|
||||||
|
|
||||||
#endif // ARCH_OS_H
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal U8 *
|
|
||||||
arch_rdi_from_reg_code_table_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U8 *result = &arch_reg_code_u8_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
result = rdi_reg_code_from_x64_table;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_RDI_H
|
|
||||||
#define ARCH_RDI_H
|
|
||||||
|
|
||||||
internal U8 *arch_rdi_from_reg_code_table_from_arch(Arch arch);
|
|
||||||
|
|
||||||
#endif // ARCH_RDI_H
|
|
||||||
@@ -1,735 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_init(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
ac_shared = push_array(arena, AC_Shared, 1);
|
|
||||||
ac_shared->arena = arena;
|
|
||||||
ac_shared->cache_slots_count = 256;
|
|
||||||
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
|
|
||||||
ac_shared->cache_stripes = stripe_array_alloc(arena);
|
|
||||||
for EachElement(idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
ac_shared->req_batches[idx].mutex = mutex_alloc();
|
|
||||||
ac_shared->req_batches[idx].arena = arena_alloc();
|
|
||||||
}
|
|
||||||
ac_shared->cancel_thread_semaphore = semaphore_alloc(0, 1, str8_zero());
|
|
||||||
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact
|
|
||||||
ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1];
|
|
||||||
|
|
||||||
//- rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(¶ms->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == params->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(write_mode && cache == 0)
|
|
||||||
{
|
|
||||||
cache = push_array(cache_stripe->arena, AC_Cache, 1);
|
|
||||||
SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache);
|
|
||||||
cache->create = params->create;
|
|
||||||
cache->destroy = params->destroy;
|
|
||||||
cache->slots_count = Max(256, params->slots_count);
|
|
||||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
|
||||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
|
||||||
cache->stripe_free_node_ptrs = push_array(cache_stripe->arena, AC_NodePtr *, cache->stripes.count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cache != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: unpack key
|
|
||||||
U64 hash = u64_hash_from_str8(key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
|
|
||||||
//- rjf: unpack thread context
|
|
||||||
B32 is_node_work_active = (ac_tctx != 0);
|
|
||||||
|
|
||||||
//- rjf: cache * key -> existing artifact
|
|
||||||
B32 artifact_is_stale = 1;
|
|
||||||
B32 got_artifact = 0;
|
|
||||||
B32 need_request = 0;
|
|
||||||
AC_Artifact artifact = {0};
|
|
||||||
RWMutexScope(stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen);
|
|
||||||
B32 is_stale = (n->last_completed_gen != params->gen);
|
|
||||||
if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh)))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = is_stale;
|
|
||||||
artifact = n->val;
|
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
|
||||||
ins_atomic_u64_eval_assign(&n->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
|
||||||
}
|
|
||||||
if(is_stale)
|
|
||||||
{
|
|
||||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
|
||||||
need_request = got_task;
|
|
||||||
if(is_node_work_active)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: didn't get artifact we want? -> fall back to slow path
|
|
||||||
if(!got_artifact || need_request)
|
|
||||||
{
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1) for(;;)
|
|
||||||
{
|
|
||||||
B32 out_of_time = (now_time_us() >= endt_us);
|
|
||||||
|
|
||||||
// rjf: find node in cache
|
|
||||||
AC_Node *node = 0;
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: no node? -> create
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
need_request = 1;
|
|
||||||
node = stripe->free;
|
|
||||||
if(node)
|
|
||||||
{
|
|
||||||
stripe->free = node->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = push_array_no_zero(stripe->arena, AC_Node, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(node);
|
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
|
||||||
// TODO(rjf): string allocator for keys
|
|
||||||
node->key = str8_copy(stripe->arena, key);
|
|
||||||
node->working_count = 1;
|
|
||||||
node->evict_threshold_us = params->evict_threshold_us;
|
|
||||||
if(is_node_work_active)
|
|
||||||
{
|
|
||||||
node->other_nodes_depend_on_me = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node->access_pt.last_time_touched_us = now_time_us();
|
|
||||||
node->access_pt.last_update_idx_touched = update_tick_idx();
|
|
||||||
|
|
||||||
// rjf: request
|
|
||||||
if(need_request)
|
|
||||||
{
|
|
||||||
need_request = 0;
|
|
||||||
MutexScope(req_batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1);
|
|
||||||
if(params->flags & AC_Flag_Wide)
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n);
|
|
||||||
req_batch->wide_count += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n);
|
|
||||||
req_batch->thin_count += 1;
|
|
||||||
}
|
|
||||||
n->v.key = str8_copy(req_batch->arena, key);
|
|
||||||
n->v.gen = params->gen;
|
|
||||||
n->v.cancel_signal = &node->cancelled;
|
|
||||||
n->v.create = params->create;
|
|
||||||
}
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
if(params->flags & AC_Flag_HighPriority)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: get value from node, if possible
|
|
||||||
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = (node->last_completed_gen != params->gen);
|
|
||||||
artifact = node->val;
|
|
||||||
access_touch(access, &node->access_pt, stripe->cv);
|
|
||||||
ins_atomic_u64_eval_assign(&node->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: abort if needed
|
|
||||||
if(out_of_time || got_artifact || is_async_thread)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: wait for results
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: report staleness
|
|
||||||
if(params->stale_out)
|
|
||||||
{
|
|
||||||
params->stale_out[0] = artifact_is_stale;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
return artifact;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_async_tick(void)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: enable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
semaphore_drop(ac_shared->cancel_thread_semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do eviction pass across all caches
|
|
||||||
//
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) &&
|
|
||||||
ins_atomic_u64_eval(&n->working_count) == 0 &&
|
|
||||||
(ins_atomic_u32_eval(&n->other_nodes_depend_on_me) == 0 || ac_shared->request_gen > n->last_touched_ac_request_gen))
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DLLRemove(slot->first, slot->last, n);
|
|
||||||
n->next = (AC_Node *)stripe->free;
|
|
||||||
stripe->free = n;
|
|
||||||
if(cache->destroy)
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: gather requests
|
|
||||||
//
|
|
||||||
typedef struct RequestBatchTask RequestBatchTask;
|
|
||||||
struct RequestBatchTask
|
|
||||||
{
|
|
||||||
AC_Request *wide;
|
|
||||||
U64 wide_count;
|
|
||||||
AC_Request *thin;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
RequestBatchTask *tasks = 0;
|
|
||||||
U64 tasks_count = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
tasks_count = 2;
|
|
||||||
tasks = push_array(scratch.arena, RequestBatchTask, tasks_count);
|
|
||||||
for EachElement(task_idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
tasks[task_idx].wide_count = batch->wide_count;
|
|
||||||
tasks[task_idx].thin_count = batch->thin_count;
|
|
||||||
tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count);
|
|
||||||
tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_wide)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v);
|
|
||||||
tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_thin)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v);
|
|
||||||
tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arena_clear(batch->arena);
|
|
||||||
batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0;
|
|
||||||
batch->wide_count = batch->thin_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync_u64(&tasks, 0);
|
|
||||||
lane_sync_u64(&tasks_count, 0);
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: set up artifact cache thread context
|
|
||||||
//
|
|
||||||
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do all requests
|
|
||||||
//
|
|
||||||
for EachIndex(task_idx, tasks_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
RequestBatchTask *task = &tasks[task_idx];
|
|
||||||
|
|
||||||
//- rjf: set up cancellation signal
|
|
||||||
U64 cancelled = 0;
|
|
||||||
U64 *cancelled_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
cancelled_ptr = &cancelled;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&cancelled_ptr, 0);
|
|
||||||
|
|
||||||
//- rjf: do all wide requests for this priority
|
|
||||||
U64 done_wide_count = 0;
|
|
||||||
ProfScope("wide requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, task->wide_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u32_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
AC_Status status = AC_Status_Good;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(status == AC_Status_NeedRetry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal))
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(status != AC_Status_NeedRetry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(status != AC_Status_NeedRetry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
B32 got_new_value = (status == AC_Status_Good);
|
|
||||||
|
|
||||||
// rjf: eliminate existing values, if any, if they do not match the current
|
|
||||||
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
|
|
||||||
{
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
MemoryZeroStruct(&n->val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write new value
|
|
||||||
if(got_new_value)
|
|
||||||
{
|
|
||||||
n->val = val;
|
|
||||||
}
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: increment count
|
|
||||||
lane_sync();
|
|
||||||
done_wide_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//- rjf: do all thin requests for this priority
|
|
||||||
U64 done_thin_count = 0;
|
|
||||||
ProfScope("thin requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
U64 req_take_counter = 0;
|
|
||||||
U64 *req_take_counter_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
req_take_counter_ptr = &req_take_counter;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&req_take_counter_ptr, 0);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
|
|
||||||
ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u64_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take next task
|
|
||||||
U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1;
|
|
||||||
if(req_idx >= task->thin_count) { break; }
|
|
||||||
AC_Request *r = &task->thin[req_idx];
|
|
||||||
|
|
||||||
// rjf: push thin lane ctx
|
|
||||||
U64 thin_lane_ctx_broadcast_memory = 0;
|
|
||||||
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
|
|
||||||
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
AC_Status status = AC_Status_Good;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
|
|
||||||
|
|
||||||
// rjf: restore wide lane ctx
|
|
||||||
lane_ctx(lane_ctx_restore);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(status == AC_Status_NeedRetry && !ins_atomic_u32_eval(r->cancel_signal))
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(status != AC_Status_NeedRetry)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(status != AC_Status_NeedRetry)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
B32 got_new_value = (status == AC_Status_Good);
|
|
||||||
|
|
||||||
// rjf: eliminate existing values, if any, if they do not match the current
|
|
||||||
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
|
|
||||||
{
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
MemoryZeroStruct(&n->val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: store
|
|
||||||
if(got_new_value)
|
|
||||||
{
|
|
||||||
n->val = val;
|
|
||||||
}
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr);
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: cancelled early, unfinished tasks? -> defer to next tick
|
|
||||||
if(lane_idx() == 0 && task_idx > 0)
|
|
||||||
{
|
|
||||||
B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count);
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
// rjf: push leftover wide tasks
|
|
||||||
for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push leftover thin tasks
|
|
||||||
for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->thin[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(need_another_try)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: increment the request gen, only if all requests are empty
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
B32 have_live_requests = 0;
|
|
||||||
for EachElement(idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
MutexScope(ac_shared->req_batches[idx].mutex)
|
|
||||||
{
|
|
||||||
have_live_requests = (ac_shared->req_batches[idx].wide_count != 0 || ac_shared->req_batches[idx].thin_count != 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!have_live_requests)
|
|
||||||
{
|
|
||||||
ac_shared->request_gen += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: reset thread context
|
|
||||||
//
|
|
||||||
ac_tctx = 0;
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: disable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_cancel_thread_entry_point(void *p)
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
sleep_ms(50);
|
|
||||||
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
|
||||||
{
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0)
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n->cancelled = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
semaphore_drop(ac_shared->cancel_thread_semaphore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARTIFACT_CACHE_H
|
|
||||||
#define ARTIFACT_CACHE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Computation Statuses
|
|
||||||
|
|
||||||
typedef enum AC_Status
|
|
||||||
{
|
|
||||||
AC_Status_Good,
|
|
||||||
AC_Status_NeedRetry,
|
|
||||||
AC_Status_Failed,
|
|
||||||
}
|
|
||||||
AC_Status;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Handle Type
|
|
||||||
|
|
||||||
typedef struct AC_Artifact AC_Artifact;
|
|
||||||
struct AC_Artifact
|
|
||||||
{
|
|
||||||
U64 u64[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Computation Function Types
|
|
||||||
|
|
||||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
|
|
||||||
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
|
|
||||||
|
|
||||||
typedef U32 AC_Flags;
|
|
||||||
typedef enum AC_FlagsEnum
|
|
||||||
{
|
|
||||||
AC_Flag_WaitForFresh = (1<<0),
|
|
||||||
AC_Flag_HighPriority = (1<<1),
|
|
||||||
AC_Flag_Wide = (1<<2),
|
|
||||||
}
|
|
||||||
AC_FlagsEnum;
|
|
||||||
|
|
||||||
typedef struct AC_ArtifactParams AC_ArtifactParams;
|
|
||||||
struct AC_ArtifactParams
|
|
||||||
{
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
U64 slots_count;
|
|
||||||
U64 gen;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
B32 *stale_out;
|
|
||||||
AC_Flags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Types
|
|
||||||
|
|
||||||
typedef struct AC_Request AC_Request;
|
|
||||||
struct AC_Request
|
|
||||||
{
|
|
||||||
String8 key;
|
|
||||||
U64 gen;
|
|
||||||
B32 *cancel_signal;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestNode AC_RequestNode;
|
|
||||||
struct AC_RequestNode
|
|
||||||
{
|
|
||||||
AC_RequestNode *next;
|
|
||||||
AC_Request v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_NodePtr AC_NodePtr;
|
|
||||||
struct AC_NodePtr
|
|
||||||
{
|
|
||||||
AC_NodePtr *next;
|
|
||||||
struct AC_Node *node;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Node AC_Node;
|
|
||||||
struct AC_Node
|
|
||||||
{
|
|
||||||
AC_Node *next;
|
|
||||||
AC_Node *prev;
|
|
||||||
|
|
||||||
// rjf: key/gen/value
|
|
||||||
String8 key;
|
|
||||||
U64 last_requested_gen;
|
|
||||||
U64 last_completed_gen;
|
|
||||||
AC_Artifact val;
|
|
||||||
|
|
||||||
// rjf: metadata
|
|
||||||
AccessPt access_pt;
|
|
||||||
U64 working_count;
|
|
||||||
U64 completion_count;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
U64 last_touched_ac_request_gen;
|
|
||||||
B32 cancelled;
|
|
||||||
B32 other_nodes_depend_on_me;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Slot AC_Slot;
|
|
||||||
struct AC_Slot
|
|
||||||
{
|
|
||||||
AC_Node *first;
|
|
||||||
AC_Node *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Cache AC_Cache;
|
|
||||||
struct AC_Cache
|
|
||||||
{
|
|
||||||
// rjf: link / key for cache-cache
|
|
||||||
AC_Cache *next;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
|
|
||||||
// rjf: artifact cache
|
|
||||||
U64 slots_count;
|
|
||||||
AC_Slot *slots;
|
|
||||||
StripeArray stripes;
|
|
||||||
AC_NodePtr **stripe_free_node_ptrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
|
||||||
struct AC_RequestBatch
|
|
||||||
{
|
|
||||||
Mutex mutex;
|
|
||||||
Arena *arena;
|
|
||||||
AC_RequestNode *first_wide;
|
|
||||||
AC_RequestNode *last_wide;
|
|
||||||
AC_RequestNode *first_thin;
|
|
||||||
AC_RequestNode *last_thin;
|
|
||||||
U64 wide_count;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_TCTX AC_TCTX;
|
|
||||||
struct AC_TCTX
|
|
||||||
{
|
|
||||||
U64 _unused_;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Shared AC_Shared;
|
|
||||||
struct AC_Shared
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 request_gen;
|
|
||||||
|
|
||||||
// rjf: cache cache
|
|
||||||
U64 cache_slots_count;
|
|
||||||
AC_Cache **cache_slots;
|
|
||||||
StripeArray cache_stripes;
|
|
||||||
|
|
||||||
// rjf: requests
|
|
||||||
AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority
|
|
||||||
|
|
||||||
// rjf: cancel thread
|
|
||||||
Thread cancel_thread;
|
|
||||||
Semaphore cancel_thread_semaphore;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global AC_Shared *ac_shared = 0;
|
|
||||||
thread_static AC_TCTX *ac_tctx = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void ac_init(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us);
|
|
||||||
#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
#if !defined(NEED_ASYNC)
|
|
||||||
# define NEED_ASYNC 1
|
|
||||||
#endif
|
|
||||||
internal void ac_async_tick(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void ac_cancel_thread_entry_point(void *p);
|
|
||||||
|
|
||||||
#endif // ARTIFACT_CACHE_H
|
|
||||||
+213
-301
@@ -1,139 +1,83 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Global Arena Table
|
// Implementation
|
||||||
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
typedef struct ArenaTableNode ArenaTableNode;
|
|
||||||
struct ArenaTableNode
|
|
||||||
{
|
|
||||||
ArenaTableNode *next;
|
|
||||||
Arena *arena;
|
|
||||||
};
|
|
||||||
global U64 arena_table_take_init = 0;
|
|
||||||
global U64 arena_table_inited = 0;
|
|
||||||
global U64 arena_table_lock = 0;
|
|
||||||
global ArenaTableNode *arena_table = 0;
|
|
||||||
global U64 arena_table_count = 0;
|
|
||||||
global U64 arena_table_cap = 0;
|
|
||||||
global ArenaTableNode *free_arena_table_node = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Arena Functions
|
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
|
||||||
|
|
||||||
internal Arena *
|
internal Arena *
|
||||||
arena_alloc_(ArenaParams *params)
|
arena_alloc__sized(U64 init_res, U64 init_cmt)
|
||||||
|
{
|
||||||
|
ProfBeginFunction();
|
||||||
|
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
||||||
|
|
||||||
|
void *memory = 0;
|
||||||
|
U64 res = 0;
|
||||||
|
U64 cmt = 0;
|
||||||
|
B32 large_pages = os_large_pages_enabled();
|
||||||
|
if(large_pages)
|
||||||
|
{
|
||||||
|
U64 page_size = os_large_page_size();
|
||||||
|
res = AlignPow2(init_res, page_size);
|
||||||
|
#if OS_WINDOWS
|
||||||
|
cmt = res;
|
||||||
|
#else
|
||||||
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
#endif
|
||||||
|
memory = os_reserve_large(res);
|
||||||
|
if(!os_commit_large(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
U64 page_size = os_page_size();
|
||||||
|
res = AlignPow2(init_res, page_size);
|
||||||
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
memory = os_reserve(res);
|
||||||
|
if(!os_commit(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena *arena = (Arena*)memory;
|
||||||
|
if(arena)
|
||||||
|
{
|
||||||
|
AsanPoisonMemoryRegion(memory, cmt);
|
||||||
|
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
|
||||||
|
arena->prev = 0;
|
||||||
|
arena->current = arena;
|
||||||
|
arena->base_pos = 0;
|
||||||
|
arena->pos = ARENA_HEADER_SIZE;
|
||||||
|
arena->cmt = cmt;
|
||||||
|
arena->res = res;
|
||||||
|
arena->align = 8;
|
||||||
|
arena->grow = 1;
|
||||||
|
arena->large_pages = large_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfEnd();
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Arena *
|
||||||
|
arena_alloc(void)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
ProfBeginFunction();
|
||||||
|
|
||||||
U64 reserve_size = params->reserve_size;
|
U64 init_res, init_cmt;
|
||||||
U64 commit_size = params->commit_size;
|
if (os_large_pages_enabled()) {
|
||||||
|
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES;
|
||||||
// rjf: reserve/commit initial block
|
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES;
|
||||||
void *base = params->optional_backing_buffer;
|
} else {
|
||||||
if(base == 0)
|
init_res = ARENA_RESERVE_SIZE;
|
||||||
{
|
init_cmt = ARENA_COMMIT_SIZE;
|
||||||
// rjf: round up reserve/commit sizes
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, get_system_info()->page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, get_system_info()->page_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
Arena *arena = arena_alloc__sized(init_res, init_cmt);
|
||||||
{
|
|
||||||
base = reserve_memory_large(reserve_size);
|
|
||||||
commit_memory_large(base, commit_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base = reserve_memory(reserve_size);
|
|
||||||
commit_memory(base, commit_size);
|
|
||||||
}
|
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
|
||||||
// TODO(rjf): we need to reintroduce this later when we have the ability to remove annotations...
|
|
||||||
// raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AsanPoisonMemoryRegion(base, params->reserve_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: panic on arena creation failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
if(Unlikely(base == 0))
|
|
||||||
{
|
|
||||||
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
|
||||||
abort_self(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
|
||||||
Arena *arena = base;
|
|
||||||
arena->current = arena;
|
|
||||||
arena->flags = params->flags;
|
|
||||||
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;
|
|
||||||
arena->allocation_site_file = params->allocation_site_file;
|
|
||||||
arena->allocation_site_line = params->allocation_site_line;
|
|
||||||
arena->name = params->name;
|
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
arena->free_last = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: store in global arena table
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
if(ins_atomic_u64_eval_cond_assign(&arena_table_take_init, 1, 0) == 0)
|
|
||||||
{
|
|
||||||
arena_table = reserve_memory(GB(256));
|
|
||||||
arena_table_cap = 4096;
|
|
||||||
commit_memory(arena_table, arena_table_cap * sizeof(arena_table[0]));
|
|
||||||
ins_atomic_u64_inc_eval(&arena_table_inited);
|
|
||||||
}
|
|
||||||
for(;!ins_atomic_u64_eval(&arena_table_inited);) {}
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
|
|
||||||
if(got_lock)
|
|
||||||
{
|
|
||||||
ArenaTableNode *node = free_arena_table_node;
|
|
||||||
if(node != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(free_arena_table_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = &arena_table[arena_table_count];
|
|
||||||
if(arena_table_count >= arena_table_cap)
|
|
||||||
{
|
|
||||||
U64 arena_table_cap__pre_grow = arena_table_cap;
|
|
||||||
arena_table_cap *= 2;
|
|
||||||
U64 arena_table_cap__post_grow = arena_table_cap;
|
|
||||||
commit_memory(arena_table + arena_table_cap__pre_grow, sizeof(arena_table[0]) * (arena_table_cap__post_grow - arena_table_cap__pre_grow));
|
|
||||||
}
|
|
||||||
arena_table_count += 1;
|
|
||||||
}
|
|
||||||
node->arena = arena;
|
|
||||||
arena->table_node = node;
|
|
||||||
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
return arena;
|
return arena;
|
||||||
@@ -142,168 +86,88 @@ arena_alloc_(ArenaParams *params)
|
|||||||
internal void
|
internal void
|
||||||
arena_release(Arena *arena)
|
arena_release(Arena *arena)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
|
||||||
|
prev = node->prev;
|
||||||
#if PROFILE_TELEMETRY
|
os_release(node, node->res);
|
||||||
{
|
|
||||||
Arena *base_arena = arena;
|
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, 0, "%s/%p", base_arena->name, base_arena);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
for(Arena *n = arena->current; n != 0; n = n->prev)
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
|
|
||||||
if(got_lock)
|
|
||||||
{
|
|
||||||
ArenaTableNode *table_node = n->table_node;
|
|
||||||
MemoryZeroStruct(table_node);
|
|
||||||
SLLStackPush(free_arena_table_node, table_node);
|
|
||||||
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
|
||||||
{
|
|
||||||
prev = n->prev;
|
|
||||||
AsanUnpoisonMemoryRegion(n, n->cmt);
|
|
||||||
release_memory(n, n->res);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop core functions
|
internal U64
|
||||||
|
arena_huge_push_threshold(void)
|
||||||
|
{
|
||||||
|
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE;
|
||||||
|
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1;
|
||||||
|
return threshold;
|
||||||
|
}
|
||||||
|
|
||||||
internal void *
|
internal void *
|
||||||
arena_push(Arena *arena, U64 size, U64 align, B32 zero)
|
arena_push__impl(Arena *arena, U64 size)
|
||||||
{
|
{
|
||||||
Arena *current = arena->current;
|
Arena *current = arena->current;
|
||||||
U64 pos_pre = AlignPow2(current->pos, align);
|
U64 pos_mem = AlignPow2(current->pos, arena->align);
|
||||||
U64 pos_pst = pos_pre + size;
|
U64 pos_new = pos_mem + size;
|
||||||
|
|
||||||
// TODO: Newly allocated arenas already have zeroed commited pages,
|
if (current->res < pos_new && arena->grow) {
|
||||||
// so this unnecessarily zeroes them again.
|
Arena *new_block;
|
||||||
//
|
|
||||||
// rjf: compute the size we need to zero
|
|
||||||
U64 size_to_zero = 0;
|
|
||||||
if(zero)
|
|
||||||
{
|
|
||||||
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: chain, if needed
|
|
||||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if(new_block->res >= AlignPow2(new_block->pos, align) + size)
|
|
||||||
{
|
|
||||||
if(prev_block)
|
|
||||||
{
|
|
||||||
prev_block->prev = new_block->prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arena->free_last = new_block->prev;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#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,
|
|
||||||
.allocation_site_file = current->allocation_site_file,
|
|
||||||
.allocation_site_line = current->allocation_site_line);
|
|
||||||
|
|
||||||
size_to_zero = 0;
|
// normal growth path
|
||||||
|
if (size < arena_huge_push_threshold()) {
|
||||||
|
new_block = arena_alloc();
|
||||||
}
|
}
|
||||||
else
|
// huge growth path
|
||||||
{
|
else {
|
||||||
size_to_zero = size;
|
U64 new_block_size = size + ARENA_HEADER_SIZE;
|
||||||
|
new_block = arena_alloc__sized(new_block_size, new_block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_block) {
|
||||||
new_block->base_pos = current->base_pos + current->res;
|
new_block->base_pos = current->base_pos + current->res;
|
||||||
SLLStackPush_N(arena->current, new_block, prev);
|
SLLStackPush_N(arena->current, new_block, prev);
|
||||||
|
|
||||||
current = new_block;
|
current = new_block;
|
||||||
pos_pre = AlignPow2(current->pos, align);
|
pos_mem = AlignPow2(current->pos, current->align);
|
||||||
pos_pst = pos_pre + size;
|
pos_new = pos_mem + size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: commit new pages, if needed
|
if (current->cmt < pos_new) {
|
||||||
if(current->cmt < pos_pst)
|
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
|
||||||
{
|
B32 is_cmt_ok;
|
||||||
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
|
|
||||||
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
|
if (current->large_pages) {
|
||||||
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
|
||||||
U64 cmt_size = cmt_pst_clamped - current->cmt;
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
if(current->flags & ArenaFlag_LargePages)
|
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
|
||||||
{
|
} else {
|
||||||
commit_memory_large(cmt_ptr, cmt_size);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
|
||||||
}
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
else
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
{
|
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
|
||||||
commit_memory(cmt_ptr, cmt_size);
|
|
||||||
}
|
|
||||||
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
|
|
||||||
current->cmt = cmt_pst_clamped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: push onto current block
|
if (is_cmt_ok) {
|
||||||
void *result = 0;
|
current->cmt = cmt_new_clamped;
|
||||||
if(current->cmt >= pos_pst)
|
}
|
||||||
{
|
|
||||||
result = (U8 *)current+pos_pre;
|
|
||||||
current->pos = pos_pst;
|
|
||||||
AsanUnpoisonMemoryRegion(result, size);
|
|
||||||
MemoryZero(result, size_to_zero);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
void *memory = 0;
|
||||||
if(size > KB(1))
|
|
||||||
{
|
if (current->cmt >= pos_new) {
|
||||||
Arena *base_arena = arena;
|
memory = (U8*)current + pos_mem;
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
current->pos = pos_new;
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
|
AsanUnpoisonMemoryRegion(memory, size);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: panic on failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(result == 0))
|
if(Unlikely(memory == 0))
|
||||||
{
|
{
|
||||||
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
abort_self(1);
|
os_exit_process(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
@@ -315,45 +179,85 @@ arena_pos(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_pop_to(Arena *arena, U64 pos)
|
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
|
||||||
{
|
{
|
||||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||||
Arena *current = arena->current;
|
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
// unroll the chain
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
Arena *current = arena->current;
|
||||||
{
|
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
|
||||||
prev = current->prev;
|
prev = current->prev;
|
||||||
current->pos = ARENA_HEADER_SIZE;
|
os_release(current, current->res);
|
||||||
SLLStackPush_N(arena->free_last, current, prev);
|
|
||||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE);
|
|
||||||
}
|
}
|
||||||
#else
|
AssertAlways(current);
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
|
||||||
{
|
|
||||||
prev = current->prev;
|
|
||||||
AsanUnpoisonMemoryRegion(current, current->cmt);
|
|
||||||
release_memory(current, current->res);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
arena->current = current;
|
arena->current = current;
|
||||||
|
|
||||||
|
// compute arena-relative position
|
||||||
U64 new_pos = big_pos - current->base_pos;
|
U64 new_pos = big_pos - current->base_pos;
|
||||||
AssertAlways(new_pos <= current->pos);
|
AssertAlways(new_pos <= current->pos);
|
||||||
|
|
||||||
|
// poison popped memory block
|
||||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||||
|
|
||||||
|
// update position
|
||||||
current->pos = new_pos;
|
current->pos = new_pos;
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
if((pos - (new_pos + current->base_pos)) > KB(1))
|
|
||||||
{
|
|
||||||
Arena *base_arena = arena;
|
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void
|
||||||
|
arena_absorb(Arena *arena, Arena *sub)
|
||||||
|
{
|
||||||
|
// base adjustment
|
||||||
|
Arena *current = arena->current;
|
||||||
|
U64 base_adjust = current->base_pos + current->res;
|
||||||
|
for (Arena *node = sub->current; node != 0; node = node->prev) {
|
||||||
|
node->base_pos += base_adjust;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach sub to arena
|
||||||
|
sub->prev = arena->current;
|
||||||
|
arena->current = sub->current;
|
||||||
|
sub->current = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
void *memory = arena_push__impl(arena, size);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push_contiguous(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
B32 restore = arena->grow;
|
||||||
|
arena->grow = 0;
|
||||||
|
void *memory = arena_push(arena, size);
|
||||||
|
arena->grow = restore;
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_push_align(Arena *arena, U64 align)
|
||||||
|
{
|
||||||
|
Assert(IsPow2(align));
|
||||||
|
U64 amt = AlignPadPow2(arena->pos, align);
|
||||||
|
void *ptr = arena_push(arena, amt);
|
||||||
|
MemoryZero(ptr, amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_put_back(Arena *arena, U64 amt)
|
||||||
|
{
|
||||||
|
U64 pos_old = arena_pos(arena);
|
||||||
|
U64 pos_new = pos_old;
|
||||||
|
if (amt < pos_old) {
|
||||||
|
pos_new = pos_old - amt;
|
||||||
|
}
|
||||||
|
arena_pop_to(arena, pos_new);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_clear(Arena *arena)
|
arena_clear(Arena *arena)
|
||||||
@@ -361,20 +265,6 @@ arena_clear(Arena *arena)
|
|||||||
arena_pop_to(arena, 0);
|
arena_pop_to(arena, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
arena_pop(Arena *arena, U64 amt)
|
|
||||||
{
|
|
||||||
U64 pos_old = arena_pos(arena);
|
|
||||||
U64 pos_new = pos_old;
|
|
||||||
if(amt < pos_old)
|
|
||||||
{
|
|
||||||
pos_new = pos_old - amt;
|
|
||||||
}
|
|
||||||
arena_pop_to(arena, pos_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: temporary arena scopes
|
|
||||||
|
|
||||||
internal Temp
|
internal Temp
|
||||||
temp_begin(Arena *arena)
|
temp_begin(Arena *arena)
|
||||||
{
|
{
|
||||||
@@ -388,3 +278,25 @@ temp_end(Temp temp)
|
|||||||
{
|
{
|
||||||
arena_pop_to(temp.arena, temp.pos);
|
arena_pop_to(temp.arena, temp.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
|
||||||
|
B32 result = 0;
|
||||||
|
U8 *cmt = (U8*)*cmtptr;
|
||||||
|
if (cmt < (U8*)pos){
|
||||||
|
U64 cmt_size_raw = (U8*)pos - cmt;
|
||||||
|
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
|
||||||
|
if (os_commit(cmt, cmt_size)){
|
||||||
|
*cmtptr = cmt + cmt_size;
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+45
-51
@@ -1,56 +1,44 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_ARENA_H
|
#ifndef BASE_ARENA_H
|
||||||
#define BASE_ARENA_H
|
#define BASE_ARENA_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Types
|
//~ rjf: Constants
|
||||||
|
|
||||||
#define ARENA_HEADER_SIZE 128
|
#define ARENA_HEADER_SIZE 128
|
||||||
|
|
||||||
typedef U64 ArenaFlags;
|
#ifndef ARENA_RESERVE_SIZE
|
||||||
enum
|
# define ARENA_RESERVE_SIZE MB(64)
|
||||||
{
|
#endif
|
||||||
ArenaFlag_NoChain = (1<<0),
|
#ifndef ARENA_COMMIT_SIZE
|
||||||
ArenaFlag_LargePages = (1<<1),
|
# define ARENA_COMMIT_SIZE KB(64)
|
||||||
};
|
#endif
|
||||||
|
|
||||||
typedef struct ArenaParams ArenaParams;
|
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES
|
||||||
struct ArenaParams
|
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8)
|
||||||
{
|
#endif
|
||||||
ArenaFlags flags;
|
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES
|
||||||
U64 reserve_size;
|
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2)
|
||||||
U64 commit_size;
|
#endif
|
||||||
void *optional_backing_buffer;
|
|
||||||
char *allocation_site_file;
|
////////////////////////////////
|
||||||
int allocation_site_line;
|
//~ rjf: Arena Types
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
Arena *prev; // previous arena in chain
|
struct Arena *prev;
|
||||||
Arena *current; // current arena in chain
|
struct Arena *current;
|
||||||
ArenaFlags flags;
|
|
||||||
U64 cmt_size;
|
|
||||||
U64 res_size;
|
|
||||||
U64 base_pos;
|
U64 base_pos;
|
||||||
U64 pos;
|
U64 pos;
|
||||||
U64 cmt;
|
U64 cmt;
|
||||||
U64 res;
|
U64 res;
|
||||||
char *allocation_site_file;
|
U64 align;
|
||||||
int allocation_site_line;
|
B8 grow;
|
||||||
char *name;
|
B8 large_pages;
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
Arena *free_last;
|
|
||||||
#endif
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
struct ArenaTableNode *table_node;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
|
||||||
|
|
||||||
typedef struct Temp Temp;
|
typedef struct Temp Temp;
|
||||||
struct Temp
|
struct Temp
|
||||||
@@ -60,34 +48,40 @@ struct Temp
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Functions
|
// Implementation
|
||||||
|
|
||||||
global U64 arena_default_reserve_size = MB(64);
|
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
|
||||||
global U64 arena_default_commit_size = KB(64);
|
|
||||||
global ArenaFlags arena_default_flags = 0;
|
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
internal Arena* arena_alloc(void);
|
||||||
internal Arena *arena_alloc_(ArenaParams *params);
|
|
||||||
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, .allocation_site_file = __FILE__, .allocation_site_line = __LINE__, __VA_ARGS__})
|
|
||||||
internal void arena_release(Arena *arena);
|
internal void arena_release(Arena *arena);
|
||||||
|
|
||||||
//- rjf: arena push/pop/pos core functions
|
internal void* arena_push__impl(Arena *arena, U64 size);
|
||||||
internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero);
|
|
||||||
internal U64 arena_pos(Arena *arena);
|
internal U64 arena_pos(Arena *arena);
|
||||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void arena_absorb(Arena *arena, Arena *sub);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void* arena_push(Arena *arena, U64 size);
|
||||||
|
internal void* arena_push_contiguous(Arena *arena, U64 size);
|
||||||
internal void arena_clear(Arena *arena);
|
internal void arena_clear(Arena *arena);
|
||||||
internal void arena_pop(Arena *arena, U64 amt);
|
internal void arena_push_align(Arena *arena, U64 align);
|
||||||
|
internal void arena_put_back(Arena *arena, U64 amt);
|
||||||
|
|
||||||
//- rjf: temporary arena scopes
|
|
||||||
internal Temp temp_begin(Arena *arena);
|
internal Temp temp_begin(Arena *arena);
|
||||||
internal void temp_end(Temp temp);
|
internal void temp_end(Temp temp);
|
||||||
|
|
||||||
//- rjf: push helper macros
|
////////////////////////////////
|
||||||
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
#define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1))
|
|
||||||
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
|
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
|
||||||
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Main API Macros
|
||||||
|
|
||||||
|
#define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
|
||||||
|
#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c))
|
||||||
|
|
||||||
#endif // BASE_ARENA_H
|
#endif // BASE_ARENA_H
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Command Line Parsing Functions
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
cmd_line_hash_from_string(String8 string)
|
||||||
|
{
|
||||||
|
U64 result = 5381;
|
||||||
|
for(U64 i = 0; i < string.size; i += 1)
|
||||||
|
{
|
||||||
|
result = ((result << 5) + result) + string.str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal CmdLineOpt **
|
internal CmdLineOpt **
|
||||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||||
@@ -10,7 +21,7 @@ cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
|||||||
CmdLineOpt **slot = 0;
|
CmdLineOpt **slot = 0;
|
||||||
if(cmd_line->option_table_size != 0)
|
if(cmd_line->option_table_size != 0)
|
||||||
{
|
{
|
||||||
U64 hash = u64_hash_from_str8(string);
|
U64 hash = cmd_line_hash_from_string(string);
|
||||||
U64 bucket = hash % cmd_line->option_table_size;
|
U64 bucket = hash % cmd_line->option_table_size;
|
||||||
slot = &cmd_line->option_table[bucket];
|
slot = &cmd_line->option_table[bucket];
|
||||||
}
|
}
|
||||||
@@ -53,7 +64,7 @@ cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List
|
|||||||
{
|
{
|
||||||
var = push_array(arena, CmdLineOpt, 1);
|
var = push_array(arena, CmdLineOpt, 1);
|
||||||
var->hash_next = *slot;
|
var->hash_next = *slot;
|
||||||
var->hash = u64_hash_from_str8(string);
|
var->hash = cmd_line_hash_from_string(string);
|
||||||
var->string = push_str8_copy(arena, string);
|
var->string = push_str8_copy(arena, string);
|
||||||
var->value_strings = values;
|
var->value_strings = values;
|
||||||
StringJoin join = {0};
|
StringJoin join = {0};
|
||||||
@@ -72,25 +83,27 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
|||||||
{
|
{
|
||||||
CmdLine parsed = {0};
|
CmdLine parsed = {0};
|
||||||
parsed.exe_name = command_line.first->string;
|
parsed.exe_name = command_line.first->string;
|
||||||
parsed.option_table_size = 64;
|
|
||||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
|
||||||
|
|
||||||
//- rjf: parse options / inputs
|
// NOTE(rjf): Set up config option table.
|
||||||
|
{
|
||||||
|
parsed.option_table_size = 4096;
|
||||||
|
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(rjf): Parse command line.
|
||||||
B32 after_passthrough_option = 0;
|
B32 after_passthrough_option = 0;
|
||||||
B32 first_passthrough = 1;
|
B32 first_passthrough = 1;
|
||||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||||
{
|
{
|
||||||
next = node->next;
|
next = node->next;
|
||||||
|
|
||||||
//- 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 passthrough input strings.
|
|
||||||
B32 is_option = 0;
|
|
||||||
String8 option_name = node->string;
|
String8 option_name = node->string;
|
||||||
if(!after_passthrough_option)
|
|
||||||
|
// 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.
|
||||||
|
B32 is_option = 1;
|
||||||
|
if(after_passthrough_option == 0)
|
||||||
{
|
{
|
||||||
is_option = 1;
|
|
||||||
if(str8_match(node->string, str8_lit("--"), 0))
|
if(str8_match(node->string, str8_lit("--"), 0))
|
||||||
{
|
{
|
||||||
after_passthrough_option = 1;
|
after_passthrough_option = 1;
|
||||||
@@ -104,82 +117,73 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
|||||||
{
|
{
|
||||||
option_name = str8_skip(option_name, 1);
|
option_name = str8_skip(option_name, 1);
|
||||||
}
|
}
|
||||||
else if(OperatingSystem_CURRENT == OperatingSystem_Windows &&
|
|
||||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
|
||||||
{
|
|
||||||
option_name = str8_skip(option_name, 1);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_option = 0;
|
is_option = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
is_option = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: string is an option
|
// NOTE(rjf): This string is an option.
|
||||||
if(is_option)
|
if(is_option)
|
||||||
{
|
{
|
||||||
// rjf: unpack option prefix
|
B32 has_arguments = 0;
|
||||||
B32 has_values = 0;
|
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||||
U64 value_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||||
U64 value_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||||
U64 value_signifier_position = Min(value_signifier_position1, value_signifier_position2);
|
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||||
String8 value_portion_this_string = str8_skip(option_name, value_signifier_position+1);
|
if(arg_signifier_position < option_name.size)
|
||||||
if(value_signifier_position < option_name.size)
|
|
||||||
{
|
{
|
||||||
has_values = 1;
|
has_arguments = 1;
|
||||||
}
|
}
|
||||||
option_name = str8_prefix(option_name, value_signifier_position);
|
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||||
|
|
||||||
// rjf: parse option's values
|
String8List arguments = {0};
|
||||||
String8List values = {0};
|
|
||||||
if(has_values)
|
// NOTE(rjf): Parse arguments.
|
||||||
|
if(has_arguments)
|
||||||
{
|
{
|
||||||
for(String8Node *n = node; n; n = n->next)
|
for(String8Node *n = node; n; n = n->next)
|
||||||
{
|
{
|
||||||
next = n->next;
|
next = n->next;
|
||||||
|
|
||||||
String8 string = n->string;
|
String8 string = n->string;
|
||||||
if(n == node)
|
if(n == node)
|
||||||
{
|
{
|
||||||
string = value_portion_this_string;
|
string = arg_portion_this_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
U8 splits[] = { ',' };
|
U8 splits[] = { ',' };
|
||||||
String8List values_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||||
for(String8Node *sub_val = values_in_this_string.first; sub_val; sub_val = sub_val->next)
|
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &values, sub_val->string);
|
str8_list_push(arena, &arguments, sub_arg->string);
|
||||||
}
|
}
|
||||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||||
(n != node || value_portion_this_string.size != 0))
|
(n != node || arg_portion_this_string.size != 0))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: store
|
// NOTE(rjf): Register config variable.
|
||||||
cmd_line_insert_opt(arena, &parsed, option_name, values);
|
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: default path - treat as a passthrough input
|
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||||
|
// handled by tool-specific code.
|
||||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &parsed.inputs, node->string);
|
str8_list_push(arena, &parsed.inputs, node->string);
|
||||||
|
after_passthrough_option = 1;
|
||||||
first_passthrough = 0;
|
first_passthrough = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- 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;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +221,12 @@ internal B32
|
|||||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||||
{
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
return (var != 0);
|
return(var != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||||
{
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
return (var != 0 && var->value_strings.node_count > 0);
|
return(var != 0 && var->value_strings.node_count > 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_COMMAND_LINE_H
|
#ifndef BASE_COMMAND_LINE_H
|
||||||
@@ -34,13 +34,12 @@ struct CmdLine
|
|||||||
String8List inputs;
|
String8List inputs;
|
||||||
U64 option_table_size;
|
U64 option_table_size;
|
||||||
CmdLineOpt **option_table;
|
CmdLineOpt **option_table;
|
||||||
U64 argc;
|
|
||||||
char **argv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Command Line Parsing Functions
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
|
internal U64 cmd_line_hash_from_string(String8 string);
|
||||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_CONTEXT_CRACKING_H
|
#ifndef BASE_CONTEXT_CRACKING_H
|
||||||
@@ -138,10 +138,6 @@
|
|||||||
# define BUILD_DEBUG 1
|
# define BUILD_DEBUG 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_TESTS)
|
|
||||||
# define BUILD_TESTS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
||||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
# define BUILD_SUPPLEMENTARY_UNIT 0
|
||||||
#endif
|
#endif
|
||||||
@@ -159,11 +155,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_MINOR)
|
#if !defined(BUILD_VERSION_MINOR)
|
||||||
# define BUILD_VERSION_MINOR 9
|
# define BUILD_VERSION_MINOR 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_PATCH)
|
#if !defined(BUILD_VERSION_PATCH)
|
||||||
# define BUILD_VERSION_PATCH 28
|
# define BUILD_VERSION_PATCH 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||||
@@ -248,48 +244,4 @@
|
|||||||
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// extra intrinisc includes, so older clang versions are happy
|
|
||||||
// when optiona intrinsics like avx2 & avx512 are used later
|
|
||||||
// these must come first before any other intrinsic includes
|
|
||||||
// otherwise compiler will define macros that prevent declarations
|
|
||||||
// of intrinsics when included next time
|
|
||||||
|
|
||||||
#if ARCH_X64 && COMPILER_CLANG
|
|
||||||
# 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("__SHA__")
|
|
||||||
# pragma push_macro("__AVX__")
|
|
||||||
# pragma push_macro("__AVX2__")
|
|
||||||
# pragma push_macro("__BMI2__")
|
|
||||||
# pragma push_macro("__SSE4_1__")
|
|
||||||
# pragma push_macro("__AVX512F__")
|
|
||||||
# pragma push_macro("__AVX512VL__")
|
|
||||||
# pragma push_macro("__AVX512BW__")
|
|
||||||
# pragma push_macro("__AVX512VBMI__")
|
|
||||||
# define __SHA__ 1
|
|
||||||
# define __AVX__ 1
|
|
||||||
# define __AVX2__ 1
|
|
||||||
# define __BMI2__ 1
|
|
||||||
# define __SSE4_1__ 1
|
|
||||||
# define __AVX512F__ 1
|
|
||||||
# define __AVX512VL__ 1
|
|
||||||
# define __AVX512BW__ 1
|
|
||||||
# define __AVX512VBMI__ 1
|
|
||||||
# include <immintrin.h>
|
|
||||||
# pragma pop_macro("__AVX512VBMI__")
|
|
||||||
# pragma pop_macro("__AVX512BW__")
|
|
||||||
# pragma pop_macro("__AVX512VL__")
|
|
||||||
# pragma pop_macro("__AVX512F__")
|
|
||||||
# pragma pop_macro("__SSE4_1__")
|
|
||||||
# pragma pop_macro("__BMI2__")
|
|
||||||
# pragma pop_macro("__AVX2__")
|
|
||||||
# pragma pop_macro("__AVX__")
|
|
||||||
# pragma pop_macro("__SHA__")
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BASE_CONTEXT_CRACKING_H
|
#endif // BASE_CONTEXT_CRACKING_H
|
||||||
|
|||||||
+91
-338
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -41,7 +41,7 @@ u128_zero(void)
|
|||||||
internal U128
|
internal U128
|
||||||
u128_make(U64 v0, U64 v1)
|
u128_make(U64 v0, U64 v1)
|
||||||
{
|
{
|
||||||
U128 v = { .u64 = { v0, v1 }};
|
U128 v = {v0, v1};
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,21 +79,19 @@ u64_up_to_pow2(U64 x){
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal S32
|
internal S32
|
||||||
extend_sign32(U32 x, U32 size)
|
extend_sign32(U32 x, U32 size){
|
||||||
{
|
U32 high_bit = size * 8;
|
||||||
U32 n = size * 8;
|
U32 shift = 32 - high_bit;
|
||||||
U32 m = (U32)1 << (n - 1);
|
S32 result = ((S32)x << shift) >> shift;
|
||||||
S32 r = (S32)((x ^ m) - m);
|
return result;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal S64
|
internal S64
|
||||||
extend_sign64(U64 x, U64 size)
|
extend_sign64(U64 x, U64 size){
|
||||||
{
|
U64 high_bit = size * 8;
|
||||||
U64 n = size * 8;
|
U64 shift = 64 - high_bit;
|
||||||
U64 m = (U64)1 << (n - 1);
|
S64 result = ((S64)x << shift) >> shift;
|
||||||
S64 r = (S64)((x ^ m) - m);
|
return result;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal F32
|
internal F32
|
||||||
@@ -145,6 +143,12 @@ bswap_u64(U64 x)
|
|||||||
|
|
||||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
return __popcnt16(val);
|
||||||
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
count_bits_set32(U32 val)
|
count_bits_set32(U32 val)
|
||||||
{
|
{
|
||||||
@@ -191,40 +195,46 @@ clz64(U64 mask)
|
|||||||
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
count_bits_set32(U32 val)
|
count_bits_set32(U32 val)
|
||||||
{
|
{
|
||||||
return __builtin_popcount(val);
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
count_bits_set64(U64 val)
|
count_bits_set64(U64 val)
|
||||||
{
|
{
|
||||||
return __builtin_popcountll(val);
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
ctz32(U32 val)
|
ctz32(U32 val)
|
||||||
{
|
{
|
||||||
return __builtin_ctz(val);
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
clz32(U32 val)
|
clz32(U32 val)
|
||||||
{
|
{
|
||||||
return __builtin_clz(val);
|
NotImplemented;
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
internal U64
|
|
||||||
ctz64(U64 val)
|
|
||||||
{
|
|
||||||
return __builtin_ctzll(val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
clz64(U64 val)
|
clz64(U64 val)
|
||||||
{
|
{
|
||||||
return __builtin_clzll(val);
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -248,8 +258,7 @@ sign_from_side_F32(Side side){
|
|||||||
//~ rjf: Memory Functions
|
//~ rjf: Memory Functions
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
memory_is_zero(void *ptr, U64 size)
|
memory_is_zero(void *ptr, U64 size){
|
||||||
{
|
|
||||||
B32 result = 1;
|
B32 result = 1;
|
||||||
|
|
||||||
// break down size
|
// break down size
|
||||||
@@ -260,10 +269,8 @@ memory_is_zero(void *ptr, U64 size)
|
|||||||
U64 *p64 = (U64*)ptr;
|
U64 *p64 = (U64*)ptr;
|
||||||
if(result)
|
if(result)
|
||||||
{
|
{
|
||||||
for(U64 i = 0; i < count8; i += 1, p64 += 1)
|
for (U64 i = 0; i < count8; i += 1, p64 += 1){
|
||||||
{
|
if (*p64 != 0){
|
||||||
if(*p64 != 0)
|
|
||||||
{
|
|
||||||
result = 0;
|
result = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -274,10 +281,8 @@ memory_is_zero(void *ptr, U64 size)
|
|||||||
if(result)
|
if(result)
|
||||||
{
|
{
|
||||||
U8 *p8 = (U8*)p64;
|
U8 *p8 = (U8*)p64;
|
||||||
for(U64 i = 0; i < extra; i += 1, p8 += 1)
|
for (U64 i = 0; i < extra; i += 1, p8 += 1){
|
||||||
{
|
if (*p8 != 0){
|
||||||
if(*p8 != 0)
|
|
||||||
{
|
|
||||||
result = 0;
|
result = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -285,57 +290,7 @@ memory_is_zero(void *ptr, U64 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:;
|
done:;
|
||||||
return result;
|
return(result);
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write16(void *ptr, U16 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write32(void *ptr, U32 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write64(void *ptr, U64 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U8 UBSAN_NO_ALIGN
|
|
||||||
memory_read8(void *ptr)
|
|
||||||
{
|
|
||||||
U8 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U16 UBSAN_NO_ALIGN
|
|
||||||
memory_read16(void *ptr)
|
|
||||||
{
|
|
||||||
U16 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U32 UBSAN_NO_ALIGN
|
|
||||||
memory_read32(void *ptr)
|
|
||||||
{
|
|
||||||
U32 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64 UBSAN_NO_ALIGN
|
|
||||||
memory_read64(void *ptr)
|
|
||||||
{
|
|
||||||
U64 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -444,66 +399,69 @@ txt_rng_contains(TxtRng r, TxtPt pt)
|
|||||||
//~ rjf: Toolchain/Environment Enum Functions
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
bit_size_from_arch(Arch arch)
|
bit_size_from_arch(Architecture arch)
|
||||||
{
|
{
|
||||||
// TODO(rjf): metacode
|
// TODO(rjf): metacode
|
||||||
U64 arch_bitsize = 0;
|
U64 arch_bitsize = 0;
|
||||||
switch(arch)
|
switch(arch)
|
||||||
{
|
{
|
||||||
case Arch_x64: arch_bitsize = 64; break;
|
case Architecture_x64: arch_bitsize = 64; break;
|
||||||
case Arch_x86: arch_bitsize = 32; break;
|
case Architecture_x86: arch_bitsize = 32; break;
|
||||||
case Arch_arm64: arch_bitsize = 64; break;
|
case Architecture_arm64: arch_bitsize = 64; break;
|
||||||
case Arch_arm32: arch_bitsize = 32; break;
|
case Architecture_arm32: arch_bitsize = 32; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return arch_bitsize;
|
return arch_bitsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
byte_size_from_arch(Arch arch)
|
max_instruction_size_from_arch(Architecture arch)
|
||||||
{
|
|
||||||
return bit_size_from_arch(arch) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
max_ops_per_instruction_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U64 max_ops = 0;
|
|
||||||
switch (arch)
|
|
||||||
{
|
|
||||||
case Arch_Null: break;
|
|
||||||
case Arch_x64: max_ops = 1; break;
|
|
||||||
case Arch_x86:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_arm64: NotImplemented; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return max_ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
min_instruction_size_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U64 min_instruction_size = 0;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
case Arch_Null: break;
|
|
||||||
case Arch_x64: min_instruction_size = 1; break;
|
|
||||||
case Arch_x86:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_arm64: NotImplemented; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return min_instruction_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
max_instruction_size_from_arch(Arch arch)
|
|
||||||
{
|
{
|
||||||
// TODO(rjf): make this real
|
// TODO(rjf): make this real
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal OperatingSystem
|
||||||
|
operating_system_from_context(void){
|
||||||
|
OperatingSystem os = OperatingSystem_Null;
|
||||||
|
#if OS_WINDOWS
|
||||||
|
os = OperatingSystem_Windows;
|
||||||
|
#elif OS_LINUX
|
||||||
|
os = OperatingSystem_Linux;
|
||||||
|
#elif OS_MAC
|
||||||
|
os = OperatingSystem_Mac;
|
||||||
|
#endif
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Architecture
|
||||||
|
architecture_from_context(void){
|
||||||
|
Architecture arch = Architecture_Null;
|
||||||
|
#if ARCH_X64
|
||||||
|
arch = Architecture_x64;
|
||||||
|
#elif ARCH_X86
|
||||||
|
arch = Architecture_x86;
|
||||||
|
#elif ARCH_ARM64
|
||||||
|
arch = Architecture_arm64;
|
||||||
|
#elif ARCH_ARM32
|
||||||
|
arch = Architecture_arm32;
|
||||||
|
#endif
|
||||||
|
return arch;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Compiler
|
||||||
|
compiler_from_context(void){
|
||||||
|
Compiler compiler = Compiler_Null;
|
||||||
|
#if COMPILER_MSVC
|
||||||
|
compiler = Compiler_msvc;
|
||||||
|
#elif COMPILER_GCC
|
||||||
|
compiler = Compiler_gcc;
|
||||||
|
#elif COMPILER_CLANG
|
||||||
|
compiler = Compiler_clang;
|
||||||
|
#endif
|
||||||
|
return compiler;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Time Functions
|
//~ rjf: Time Functions
|
||||||
|
|
||||||
@@ -568,65 +526,11 @@ date_time_from_micro_seconds(U64 time){
|
|||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DateTime
|
|
||||||
date_time_from_unix_time(U64 unix_time)
|
|
||||||
{
|
|
||||||
DateTime date = {0};
|
|
||||||
date.year = 1970;
|
|
||||||
date.day = 1 + (unix_time / 86400);
|
|
||||||
date.sec = (U32)unix_time % 60;
|
|
||||||
date.min = (U32)(unix_time / 60) % 60;
|
|
||||||
date.hour = (U32)(unix_time / 3600) % 24;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
for(date.month = 0; date.month < 12; ++date.month)
|
|
||||||
{
|
|
||||||
U64 c = 0;
|
|
||||||
switch(date.month)
|
|
||||||
{
|
|
||||||
case Month_Jan: c = 31; break;
|
|
||||||
case Month_Feb:
|
|
||||||
{
|
|
||||||
if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0))
|
|
||||||
{
|
|
||||||
c = 29;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = 28;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Month_Mar: c = 31; break;
|
|
||||||
case Month_Apr: c = 30; break;
|
|
||||||
case Month_May: c = 31; break;
|
|
||||||
case Month_Jun: c = 30; break;
|
|
||||||
case Month_Jul: c = 31; break;
|
|
||||||
case Month_Aug: c = 31; break;
|
|
||||||
case Month_Sep: c = 30; break;
|
|
||||||
case Month_Oct: c = 31; break;
|
|
||||||
case Month_Nov: c = 30; break;
|
|
||||||
case Month_Dec: c = 31; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
if(date.day <= c)
|
|
||||||
{
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
date.day -= c;
|
|
||||||
}
|
|
||||||
++date.year;
|
|
||||||
}
|
|
||||||
exit:;
|
|
||||||
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Wrapped Ring Buffer Reads/Writes
|
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
|
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
|
||||||
{
|
{
|
||||||
Assert(src_data_size <= ring_size);
|
Assert(src_data_size <= ring_size);
|
||||||
{
|
{
|
||||||
@@ -643,7 +547,7 @@ wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 sr
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
|
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
|
||||||
{
|
{
|
||||||
Assert(read_size <= ring_size);
|
Assert(read_size <= ring_size);
|
||||||
{
|
{
|
||||||
@@ -656,154 +560,3 @@ wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 rea
|
|||||||
}
|
}
|
||||||
return read_size;
|
return read_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
u64_array_bsearch(U64 *arr, U64 count, U64 value)
|
|
||||||
{
|
|
||||||
if(count > 1 && arr[0] <= value && value < arr[count-1])
|
|
||||||
{
|
|
||||||
U64 l = 0;
|
|
||||||
U64 r = count - 1;
|
|
||||||
for(; l <= r; )
|
|
||||||
{
|
|
||||||
U64 m = l + (r - l) / 2;
|
|
||||||
if(arr[m] == value)
|
|
||||||
{
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
else if(arr[m] < value)
|
|
||||||
{
|
|
||||||
l = m + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = m - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (count == 1 && arr[0] == value)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U32
|
|
||||||
idx_of_zero_byte64(U8 *ptr, U64 size)
|
|
||||||
{
|
|
||||||
Assert(size == 8);
|
|
||||||
#if ARCH_X64
|
|
||||||
__m128i v = _mm_loadl_epi64((__m128i*)ptr);
|
|
||||||
__m128i m = _mm_cmpeq_epi8(v, _mm_setzero_si128());
|
|
||||||
U32 bits = _mm_movemask_epi8(m);
|
|
||||||
return ctz32(bits);
|
|
||||||
#else
|
|
||||||
U64 x;
|
|
||||||
MemoryCopyStruct(&x, ptr);
|
|
||||||
U64 splat = ~0ULL / 255;
|
|
||||||
U64 mask_lsb = 0x01 * splat;
|
|
||||||
U64 mask_msb = 0x80 * splat;
|
|
||||||
U64 t = (x - mask_lsb) & (~x & mask_msb);
|
|
||||||
return ctz64(t) / 8;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
index_of_zero_u32(U32 *ptr, U64 count)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < count; i += 1) {
|
|
||||||
if (ptr[i] == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
index_of_zero_u64(U64 *ptr, U64 count)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < count; i += 1) {
|
|
||||||
if (ptr[i] == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_digits_u64(U64 v, U64 radix)
|
|
||||||
{
|
|
||||||
if (v == 0) { return 1; }
|
|
||||||
U64 count = 0;
|
|
||||||
for (U64 x = v; x > 0; x /= radix) { count += 1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Third Party Includes
|
|
||||||
|
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning (push, 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# define STB_SPRINTF_IMPLEMENTATION
|
|
||||||
# define STB_SPRINTF_STATIC
|
|
||||||
# include "third_party/stb/stb_sprintf.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning (pop, 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String <-> Integer Tables
|
|
||||||
|
|
||||||
read_only global U8 integer_symbols[16] =
|
|
||||||
{
|
|
||||||
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE(rjf): Includes reverses for uppercase and lowercase hex.
|
|
||||||
read_only global U8 integer_symbol_reverse[128] =
|
|
||||||
{
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only global U8 base64[64] =
|
|
||||||
{
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
||||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
'_', '$',
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only global U8 base64_reverse[128] =
|
|
||||||
{
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
|
|
||||||
0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,
|
|
||||||
0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
|
|
||||||
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
};
|
|
||||||
|
|||||||
+72
-425
@@ -1,26 +1,17 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_CORE_H
|
#ifndef BASE_TYPES_H
|
||||||
#define BASE_CORE_H
|
#define BASE_TYPES_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Foreign Includes
|
//~ rjf: Foreign Includes
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <stdarg.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Third Party Includes
|
|
||||||
|
|
||||||
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
|
||||||
#define STB_SPRINTF_STATIC
|
|
||||||
#include "third_party/stb/stb_sprintf.h"
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Codebase Keywords
|
//~ rjf: Codebase Keywords
|
||||||
@@ -47,24 +38,6 @@
|
|||||||
# define thread_static __declspec(thread)
|
# define thread_static __declspec(thread)
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
# define thread_static __thread
|
# define thread_static __thread
|
||||||
#else
|
|
||||||
# error thread_static not defined for this compiler.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define force_inline __forceinline
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
# define force_inline __attribute__((always_inline))
|
|
||||||
#else
|
|
||||||
# error force_inline not defined for this compiler.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define no_inline __declspec(noinline)
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
# define no_inline __attribute__((noinline))
|
|
||||||
#else
|
|
||||||
# error no_inline not defined for this compiler.
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -86,45 +59,6 @@
|
|||||||
# define C_LINKAGE
|
# define C_LINKAGE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Optimization Settings
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define OPTIMIZE_BEGIN _Pragma("optimize(\"\", on)")
|
|
||||||
# define OPTIMIZE_END _Pragma("optimize(\"\", off)")
|
|
||||||
#elif COMPILER_CLANG
|
|
||||||
# define OPTIMIZE_BEGIN _Pragma("clang optimize on")
|
|
||||||
# define OPTIMIZE_END _Pragma("clang optimize off")
|
|
||||||
#elif COMPILER_GCC
|
|
||||||
# define OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O2\")")
|
|
||||||
# define OPTIMIZE_END _Pragma("GCC pop_options")
|
|
||||||
#else
|
|
||||||
# define OPTIMIZE_BEGIN
|
|
||||||
# define OPTIMIZE_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER_MSVC && !BUILD_DEBUG
|
|
||||||
# define NO_OPTIMIZE_BEGIN _Pragma("optimize(\"\", off)")
|
|
||||||
# define NO_OPTIMIZE_END _Pragma("optimize(\"\", on)")
|
|
||||||
#elif COMPILER_CLANG && !BUILD_DEBUG
|
|
||||||
# define NO_OPTIMIZE_BEGIN _Pragma("clang optimize off")
|
|
||||||
# define NO_OPTIMIZE_END _Pragma("clang optimize on")
|
|
||||||
#elif COMPILER_GCC && !BUILD_DEBUG
|
|
||||||
# define NO_OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O0\")")
|
|
||||||
# define NO_OPTIMIZE_END _Pragma("GCC pop_options")
|
|
||||||
#else
|
|
||||||
# define NO_OPTIMIZE_BEGIN
|
|
||||||
# define NO_OPTIMIZE_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Versions
|
|
||||||
|
|
||||||
#define Version(major, minor, patch) (U64)((((U64)(major) & 0xffff) << 32) | ((((U64)(minor) & 0xffff) << 16)) | ((((U64)(patch) & 0xffff) << 0)))
|
|
||||||
#define MajorFromVersion(version) (((version) & 0xffff00000000ull) >> 32)
|
|
||||||
#define MinorFromVersion(version) (((version) & 0x0000ffff0000ull) >> 16)
|
|
||||||
#define PatchFromVersion(version) (((version) & 0x00000000ffffull) >> 0)
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Units
|
//~ rjf: Units
|
||||||
|
|
||||||
@@ -157,34 +91,12 @@
|
|||||||
#define ClampBot(X,B) Max(X,B)
|
#define ClampBot(X,B) Max(X,B)
|
||||||
#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X))
|
#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X))
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type -> Alignment
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define AlignOf(T) __alignof(T)
|
|
||||||
#elif COMPILER_CLANG
|
|
||||||
# define AlignOf(T) __alignof(T)
|
|
||||||
#elif COMPILER_GCC
|
|
||||||
# define AlignOf(T) __alignof__(T)
|
|
||||||
#else
|
|
||||||
# error AlignOf not defined for this compiler.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define AlignType(x) __declspec(align(x))
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
# define AlignType(x) __attribute__((aligned(x)))
|
|
||||||
#else
|
|
||||||
# error AlignType not defined for this compiler.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Member Offsets
|
//~ rjf: Member Offsets
|
||||||
|
|
||||||
#define Member(T,m) (((T*)0)->m)
|
#define Member(T,m) (((T*)0)->m)
|
||||||
#define OffsetOf(T,m) offsetof(T, m)
|
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
|
||||||
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
||||||
#define MemberFromPtr(T,ptr,m) (void*)((((U8 *)ptr)+OffsetOf(T,m)))
|
|
||||||
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -193,13 +105,8 @@
|
|||||||
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
||||||
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
||||||
|
|
||||||
#define EachIndex(it, count) (U64 it = 0; it < (count); it += 1)
|
#define EachEnumVal(type, it) type it = (type)0; it < type##_COUNT; it = (type)(it+1)
|
||||||
#define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1)
|
#define EachNonZeroEnumVal(type, it) type it = (type)1; it < type##_COUNT; it = (type)(it+1)
|
||||||
#define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1))
|
|
||||||
#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1))
|
|
||||||
#define EachInRange(it, range) (U64 it = (range).min; it < (range).max; it += 1)
|
|
||||||
#define EachNode(it, T, first) (T *it = first; it != 0; it = it->next)
|
|
||||||
#define EachBit(it, flags) (U64 (_i_) = (flags), it = (flags) & -(flags); (_i_) != 0; (_i_) &= ((_i_) - 1), it = (flags) & -(flags))
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Memory Operation Macros
|
//~ rjf: Memory Operation Macros
|
||||||
@@ -207,11 +114,11 @@
|
|||||||
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
||||||
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
||||||
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
|
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
|
||||||
|
#define MemoryStrlen(ptr) strlen(ptr)
|
||||||
|
|
||||||
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
||||||
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
|
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
|
||||||
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
|
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
|
||||||
#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size)
|
|
||||||
|
|
||||||
#define MemoryZero(s,z) memset((s),0,(z))
|
#define MemoryZero(s,z) memset((s),0,(z))
|
||||||
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
|
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
|
||||||
@@ -222,7 +129,8 @@
|
|||||||
#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a)))
|
#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a)))
|
||||||
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
||||||
|
|
||||||
#define MemoryIsZeroStruct(ptr) memory_is_zero((ptr), sizeof(*(ptr)))
|
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
|
||||||
|
#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Asserts
|
//~ rjf: Asserts
|
||||||
@@ -249,57 +157,33 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Atomic Operations
|
//~ rjf: Atomic Operations
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
#if OS_WINDOWS
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tmmintrin.h>
|
||||||
|
# include <wmmintrin.h>
|
||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
# if ARCH_X64
|
# if ARCH_X64
|
||||||
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)_InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)(c))
|
# define ins_atomic_u64_eval(x) InterlockedAdd64((volatile __int64 *)(x), 0)
|
||||||
# define ins_atomic_u64_eval(x) (U64)__iso_volatile_load64((__int64*)(x))
|
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||||
# define ins_atomic_u64_inc_eval(x) _InterlockedIncrement64((__int64 *)(x))
|
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||||
# define ins_atomic_u64_dec_eval(x) _InterlockedDecrement64((__int64 *)(x))
|
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||||
# define ins_atomic_u64_eval_assign(x,c) _InterlockedExchange64((__int64 *)(x), (c))
|
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((volatile __int64 *)(x), c)
|
||||||
# define ins_atomic_u64_add_eval(x,c) _interlockedadd64((__int64 *)(x), (c))
|
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((volatile __int64 *)(x),(k),(c))
|
||||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) _InterlockedCompareExchange64((__int64 *)(x), (k), (c))
|
# define ins_atomic_u32_eval(x,c) InterlockedAdd((volatile LONG *)(x), 0)
|
||||||
# define ins_atomic_u32_eval(x) (U32)__iso_volatile_load32((__int32*)(x))
|
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||||
# define ins_atomic_u32_inc_eval(x) _InterlockedIncrement((long *)(x))
|
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||||
# define ins_atomic_u32_dec_eval(x) _InterlockedDecrement((long *)(x))
|
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||||
# define ins_atomic_u32_eval_assign(x,c) _InterlockedExchange((long *)(x), (c))
|
|
||||||
# define ins_atomic_u32_eval_cond_assign(x,k,c) _InterlockedCompareExchange((long *)(x), (k), (c))
|
|
||||||
# define ins_atomic_u32_add_eval(x,c) _interlockedadd((long *)(x), (c))
|
|
||||||
# define ins_atomic_u8_eval_assign(x,c) _InterlockedExchange8((char *)(x), (char)(c))
|
|
||||||
# define ins_atomic_u8_or(x,c) _InterlockedOr8((char *)(x), (char)(c))
|
|
||||||
# define ins_atomic_u32_or(x,c) _InterlockedOr((long *)(x), (long)(c))
|
|
||||||
# else
|
# else
|
||||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||||
|
# endif
|
||||||
|
#elif OS_LINUX
|
||||||
|
# if ARCH_X64
|
||||||
|
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||||
|
# else
|
||||||
|
# error Atomic intrinsics not defined for this operating system / architecture combination.
|
||||||
# endif
|
# endif
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
# include <immintrin.h>
|
|
||||||
# include <emmintrin.h>
|
|
||||||
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)__atomic_compare_exchange_n((__int128 *)(x),(__int128 *)(c),*(__int128 *)(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u64_eval(x) __atomic_load_n((U64 *)(x), __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u64_inc_eval(x) __atomic_add_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u64_dec_eval(x) __atomic_sub_fetch((U64 *)(x), 1, __ATOMIC_SEQ_CST)
|
|
||||||
# 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_add_fetch((U64 *)(x), c, __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) ({ U64 _new = (c); __atomic_compare_exchange_n((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_add_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u32_dec_eval(x) __atomic_sub_fetch((U32 *)(x), 1, __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u32_add_eval(x,c) __atomic_add_fetch((U32 *)(x), c, __ATOMIC_SEQ_CST)
|
|
||||||
# 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((U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; })
|
|
||||||
# define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u8_or(x,c) __atomic_fetch_or((U8 *)(x), (U8)(c), __ATOMIC_SEQ_CST)
|
|
||||||
# define ins_atomic_u32_or(x,c) __atomic_fetch_or((U32 *)(x), (U32)(c), __ATOMIC_SEQ_CST)
|
|
||||||
#else
|
#else
|
||||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
# error Atomic intrinsics not defined for this operating system.
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ARCH_64BIT
|
|
||||||
# define ins_atomic_ptr_eval_cond_assign(x,k,c) (void *)ins_atomic_u64_eval_cond_assign((U64 *)(x), (U64)(k), (U64)(c))
|
|
||||||
# define ins_atomic_ptr_eval_assign(x,c) (void *)ins_atomic_u64_eval_assign((U64 *)(x), (U64)(c))
|
|
||||||
# define ins_atomic_ptr_eval(x) (void *)ins_atomic_u64_eval((U64 *)x)
|
|
||||||
#else
|
|
||||||
# error Atomic intrinsics for pointers not defined for this architecture.
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -369,7 +253,9 @@ CheckNil(nil,p) ? \
|
|||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
# if defined(__SANITIZE_ADDRESS__)
|
# if defined(__SANITIZE_ADDRESS__)
|
||||||
# define ASAN_ENABLED 1
|
# define ASAN_ENABLED 1
|
||||||
# define ASAN_NO_ADDR __declspec(no_sanitize_address)
|
# define NO_ASAN __declspec(no_sanitize_address)
|
||||||
|
# else
|
||||||
|
# define NO_ASAN
|
||||||
# endif
|
# endif
|
||||||
#elif COMPILER_CLANG
|
#elif COMPILER_CLANG
|
||||||
# if defined(__has_feature)
|
# if defined(__has_feature)
|
||||||
@@ -377,18 +263,13 @@ CheckNil(nil,p) ? \
|
|||||||
# define ASAN_ENABLED 1
|
# define ASAN_ENABLED 1
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# define ASAN_NO_ADDR __attribute__((no_sanitize("address")))
|
# define NO_ASAN __attribute__((no_sanitize("address")))
|
||||||
# define UBSAN_NO_ALIGN __attribute__((no_sanitize("alignment")))
|
#else
|
||||||
#endif
|
# error "NO_ASAN is not defined for this compiler."
|
||||||
|
|
||||||
#ifndef ASAN_NO_ADDR
|
|
||||||
# define ASAN_NO_ADDR
|
|
||||||
#endif
|
|
||||||
#ifndef UBSAN_NO_ALIGN
|
|
||||||
# define UBSAN_NO_ALIGN
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ASAN_ENABLED
|
#if ASAN_ENABLED
|
||||||
|
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
||||||
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||||
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||||
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
||||||
@@ -420,10 +301,9 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
|
|||||||
#else
|
#else
|
||||||
# error Missing pointer-to-integer cast for this architecture.
|
# error Missing pointer-to-integer cast for this architecture.
|
||||||
#endif
|
#endif
|
||||||
#define PtrFromInt(i) (void*)(i)
|
#define PtrFromInt(i) (void*)((U8*)0 + (i))
|
||||||
|
|
||||||
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b))
|
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
||||||
#define Compose32Bit(a,b) ((((U32)a) << 16) | ((U32)b))
|
|
||||||
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
||||||
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
||||||
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
||||||
@@ -431,9 +311,6 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
|
|||||||
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
||||||
|
|
||||||
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
||||||
#define Extract8(word, pos) (((word) >> ((pos)*8)) & max_U8)
|
|
||||||
#define Extract16(word, pos) (((word) >> ((pos)*16)) & max_U16)
|
|
||||||
#define Extract32(word, pos) (((word) >> ((pos)*32)) & max_U32)
|
|
||||||
|
|
||||||
#if LANG_CPP
|
#if LANG_CPP
|
||||||
# define zero_struct {}
|
# define zero_struct {}
|
||||||
@@ -447,9 +324,6 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s
|
|||||||
# define this_function_name __func__
|
# define this_function_name __func__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TryRead(func__, cursor__, label__) do { U64 size__ = (func__); if (size__ == 0) { goto label__; } cursor__ += size__; } while (0)
|
|
||||||
#define TryReadBreak(func__, cursor__) { U64 size__ = (func__); if (size__ == 0) { break; } cursor__ += size__; }
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Types
|
//~ rjf: Base Types
|
||||||
|
|
||||||
@@ -468,78 +342,10 @@ typedef S64 B64;
|
|||||||
typedef float F32;
|
typedef float F32;
|
||||||
typedef double F64;
|
typedef double F64;
|
||||||
typedef void VoidProc(void);
|
typedef void VoidProc(void);
|
||||||
typedef union U128 U128;
|
typedef struct U128 U128;
|
||||||
union U128
|
struct U128
|
||||||
{
|
{
|
||||||
U8 u8[16];
|
|
||||||
U16 u16[8];
|
|
||||||
U32 u32[4];
|
|
||||||
U64 u64[2];
|
U64 u64[2];
|
||||||
F32 f32[4];
|
|
||||||
F64 f64[2];
|
|
||||||
};
|
|
||||||
typedef union U256 U256;
|
|
||||||
union U256
|
|
||||||
{
|
|
||||||
U8 u8[32];
|
|
||||||
U16 u16[16];
|
|
||||||
U32 u32[8];
|
|
||||||
U64 u64[4];
|
|
||||||
U128 u128[2];
|
|
||||||
F32 f32[8];
|
|
||||||
F64 f64[4];
|
|
||||||
};
|
|
||||||
typedef union U512 U512;
|
|
||||||
union U512
|
|
||||||
{
|
|
||||||
U8 u8[64];
|
|
||||||
U16 u16[32];
|
|
||||||
U32 u32[16];
|
|
||||||
U64 u64[8];
|
|
||||||
U128 u128[4];
|
|
||||||
U256 u256[2];
|
|
||||||
F32 f32[16];
|
|
||||||
F64 f64[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct U80 U80;
|
|
||||||
struct U80
|
|
||||||
{
|
|
||||||
U64 int1_frac63;
|
|
||||||
U16 sign1_exp15;
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Type Structures
|
|
||||||
|
|
||||||
typedef struct U16Array U16Array;
|
|
||||||
struct U16Array
|
|
||||||
{
|
|
||||||
U16 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct U32Array U32Array;
|
|
||||||
struct U32Array
|
|
||||||
{
|
|
||||||
U32 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct U64Array U64Array;
|
|
||||||
struct U64Array
|
|
||||||
{
|
|
||||||
U64 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct U128Array U128Array;
|
|
||||||
struct U128Array
|
|
||||||
{
|
|
||||||
U128 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -608,50 +414,19 @@ typedef enum OperatingSystem
|
|||||||
OperatingSystem_Linux,
|
OperatingSystem_Linux,
|
||||||
OperatingSystem_Mac,
|
OperatingSystem_Mac,
|
||||||
OperatingSystem_COUNT,
|
OperatingSystem_COUNT,
|
||||||
#if OS_WINDOWS
|
|
||||||
OperatingSystem_CURRENT = OperatingSystem_Windows,
|
|
||||||
#elif OS_LINUX
|
|
||||||
OperatingSystem_CURRENT = OperatingSystem_Linux,
|
|
||||||
#elif OS_MAC
|
|
||||||
OperatingSystem_CURRENT = OperatingSystem_Mac,
|
|
||||||
#else
|
|
||||||
OperatingSystem_CURRENT = OperatingSystem_Null,
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
OperatingSystem;
|
OperatingSystem;
|
||||||
|
|
||||||
typedef enum ExecutableImageKind
|
typedef enum Architecture
|
||||||
{
|
{
|
||||||
ExecutableImageKind_Null,
|
Architecture_Null,
|
||||||
ExecutableImageKind_CoffPe,
|
Architecture_x64,
|
||||||
ExecutableImageKind_Elf32,
|
Architecture_x86,
|
||||||
ExecutableImageKind_Elf64,
|
Architecture_arm64,
|
||||||
ExecutableImageKind_Macho,
|
Architecture_arm32,
|
||||||
ExecutableImageKind_COUNT
|
Architecture_COUNT,
|
||||||
}
|
}
|
||||||
ExecutableImageKind;
|
Architecture;
|
||||||
|
|
||||||
typedef enum Arch
|
|
||||||
{
|
|
||||||
Arch_Null,
|
|
||||||
Arch_x64,
|
|
||||||
Arch_x86,
|
|
||||||
Arch_arm64,
|
|
||||||
Arch_arm32,
|
|
||||||
Arch_COUNT,
|
|
||||||
}
|
|
||||||
Arch;
|
|
||||||
#if ARCH_X64
|
|
||||||
# define Arch_CURRENT Arch_x64
|
|
||||||
#elif ARCH_X86
|
|
||||||
# define Arch_CURRENT Arch_x86
|
|
||||||
#elif ARCH_ARM64
|
|
||||||
# define Arch_CURRENT Arch_arm64
|
|
||||||
#elif ARCH_ARM32
|
|
||||||
# define Arch_CURRENT Arch_arm32
|
|
||||||
#else
|
|
||||||
# define Arch_CURRENT Arch_Null
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum Compiler
|
typedef enum Compiler
|
||||||
{
|
{
|
||||||
@@ -662,40 +437,6 @@ typedef enum Compiler
|
|||||||
Compiler_COUNT,
|
Compiler_COUNT,
|
||||||
}
|
}
|
||||||
Compiler;
|
Compiler;
|
||||||
#if COMPILER_MSVC
|
|
||||||
# define Compiler_CURRENT Compiler_msvc
|
|
||||||
#elif COMPILER_GCC
|
|
||||||
# define Compiler_CURRENT Compiler_gcc
|
|
||||||
#elif COMPILER_CLANG
|
|
||||||
# define Compiler_CURRENT Compiler_clang
|
|
||||||
#else
|
|
||||||
# define Compiler_CURRENT Compiler_Null
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum Linker
|
|
||||||
{
|
|
||||||
Linker_Null,
|
|
||||||
Linker_radlink,
|
|
||||||
Linker_msvc,
|
|
||||||
Linker_lld,
|
|
||||||
Linker_COUNT
|
|
||||||
}
|
|
||||||
Linker;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Access Flags
|
|
||||||
|
|
||||||
typedef U32 AccessFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
AccessFlag_Read = (1<<0),
|
|
||||||
AccessFlag_Write = (1<<1),
|
|
||||||
AccessFlag_Execute = (1<<2),
|
|
||||||
AccessFlag_Append = (1<<3),
|
|
||||||
AccessFlag_ShareRead = (1<<4),
|
|
||||||
AccessFlag_ShareWrite = (1<<5),
|
|
||||||
AccessFlag_Inherited = (1<<6),
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Text 2D Coordinates & Ranges
|
//~ rjf: Text 2D Coordinates & Ranges
|
||||||
@@ -715,47 +456,7 @@ struct TxtRng
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globally Unique Ids
|
//~ NOTE(allen): Constants
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Machine Ops
|
|
||||||
|
|
||||||
typedef enum MachineOpResult
|
|
||||||
{
|
|
||||||
MachineOpResult_Null,
|
|
||||||
MachineOpResult_Ok,
|
|
||||||
MachineOpResult_Fail,
|
|
||||||
MachineOpResult_Maybe,
|
|
||||||
} MachineOpResult;
|
|
||||||
|
|
||||||
#define MACHINE_OP_REG_READ(name) MachineOpResult name(U64 reg_id, void *buffer, U64 buffer_max, void *ud)
|
|
||||||
typedef MACHINE_OP_REG_READ(MachineOp_RegRead);
|
|
||||||
|
|
||||||
#define MACHINE_OP_REG_WRITE(name) MachineOpResult name(U64 reg_id, void *value, U64 value_size, void *ud)
|
|
||||||
typedef MACHINE_OP_REG_WRITE(MachineOp_RegWrite);
|
|
||||||
|
|
||||||
#define MACHINE_OP_MEM_READ(name) MachineOpResult name(U64 addr, void *buffer, U64 buffer_size, void *ud)
|
|
||||||
typedef MACHINE_OP_MEM_READ(MachineOp_MemRead);
|
|
||||||
|
|
||||||
#define MACHINE_OP_MEM_WRITE(name) MachineOpResult name(U64 addr, void *value, U64 value_size, void *ud)
|
|
||||||
typedef MACHINE_OP_MEM_WRITE(MachineOp_MemWrite);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Constants
|
|
||||||
|
|
||||||
global U32 sign32 = 0x80000000;
|
global U32 sign32 = 0x80000000;
|
||||||
global U32 exponent32 = 0x7F800000;
|
global U32 exponent32 = 0x7F800000;
|
||||||
@@ -773,15 +474,15 @@ global U32 max_U32 = 0xffffffff;
|
|||||||
global U16 max_U16 = 0xffff;
|
global U16 max_U16 = 0xffff;
|
||||||
global U8 max_U8 = 0xff;
|
global U8 max_U8 = 0xff;
|
||||||
|
|
||||||
global S64 max_S64 = (S64)0x7fffffffffffffffll;
|
global S64 max_S64 = (S64)0x7fffffffffffffffull;
|
||||||
global S32 max_S32 = (S32)0x7fffffff;
|
global S32 max_S32 = (S32)0x7fffffff;
|
||||||
global S16 max_S16 = (S16)0x7fff;
|
global S16 max_S16 = (S16)0x7fff;
|
||||||
global S8 max_S8 = (S8)0x7f;
|
global S8 max_S8 = (S8)0x7f;
|
||||||
|
|
||||||
global S64 min_S64 = (S64)0x8000000000000000ll;
|
global S64 min_S64 = (S64)0xffffffffffffffffull;
|
||||||
global S32 min_S32 = (S32)0x80000000;
|
global S32 min_S32 = (S32)0xffffffff;
|
||||||
global S16 min_S16 = (S16)0x8000;
|
global S16 min_S16 = (S16)0xffff;
|
||||||
global S8 min_S8 = (S8)0x80;
|
global S8 min_S8 = (S8)0xff;
|
||||||
|
|
||||||
global const U32 bitmask1 = 0x00000001;
|
global const U32 bitmask1 = 0x00000001;
|
||||||
global const U32 bitmask2 = 0x00000003;
|
global const U32 bitmask2 = 0x00000003;
|
||||||
@@ -916,7 +617,7 @@ global const U64 bit63 = (1ull<<62);
|
|||||||
global const U64 bit64 = (1ull<<63);
|
global const U64 bit64 = (1ull<<63);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Time Types
|
//~ allen: Time
|
||||||
|
|
||||||
typedef enum WeekDay
|
typedef enum WeekDay
|
||||||
{
|
{
|
||||||
@@ -974,7 +675,7 @@ struct DateTime
|
|||||||
typedef U64 DenseTime;
|
typedef U64 DenseTime;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: File Types
|
//~ allen: Files
|
||||||
|
|
||||||
typedef U32 FilePropertyFlags;
|
typedef U32 FilePropertyFlags;
|
||||||
enum
|
enum
|
||||||
@@ -1020,16 +721,7 @@ internal U16 bswap_u16(U16 x);
|
|||||||
internal U32 bswap_u32(U32 x);
|
internal U32 bswap_u32(U32 x);
|
||||||
internal U64 bswap_u64(U64 x);
|
internal U64 bswap_u64(U64 x);
|
||||||
|
|
||||||
#if ARCH_LITTLE_ENDIAN
|
internal U64 count_bits_set16(U16 val);
|
||||||
# define from_be_u16(x) bswap_u16(x)
|
|
||||||
# define from_be_u32(x) bswap_u32(x)
|
|
||||||
# define from_be_u64(x) bswap_u64(x)
|
|
||||||
#else
|
|
||||||
# define from_be_u16(x) (x)
|
|
||||||
# define from_be_u32(x) (x)
|
|
||||||
# define from_be_u64(x) (x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
internal U64 count_bits_set32(U32 val);
|
internal U64 count_bits_set32(U32 val);
|
||||||
internal U64 count_bits_set64(U64 val);
|
internal U64 count_bits_set64(U64 val);
|
||||||
|
|
||||||
@@ -1049,15 +741,6 @@ internal F32 sign_from_side_F32(Side side);
|
|||||||
|
|
||||||
internal B32 memory_is_zero(void *ptr, U64 size);
|
internal B32 memory_is_zero(void *ptr, U64 size);
|
||||||
|
|
||||||
internal void memory_write16(void *ptr, U16 v);
|
|
||||||
internal void memory_write32(void *ptr, U32 v);
|
|
||||||
internal void memory_write64(void *ptr, U64 v);
|
|
||||||
|
|
||||||
internal U8 memory_read8(void *ptr);
|
|
||||||
internal U16 memory_read16(void *ptr);
|
|
||||||
internal U32 memory_read32(void *ptr);
|
|
||||||
internal U64 memory_read64(void *ptr);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Text 2D Coordinate/Range Functions
|
//~ rjf: Text 2D Coordinate/Range Functions
|
||||||
|
|
||||||
@@ -1074,11 +757,12 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Toolchain/Environment Enum Functions
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
|
|
||||||
internal U64 bit_size_from_arch(Arch arch);
|
internal U64 bit_size_from_arch(Architecture arch);
|
||||||
internal U64 byte_size_from_arch(Arch arch);
|
internal U64 max_instruction_size_from_arch(Architecture arch);
|
||||||
internal U64 max_ops_per_instruction_from_arch(Arch arch);
|
|
||||||
internal U64 min_instruction_size_from_arch(Arch arch);
|
internal OperatingSystem operating_system_from_context(void);
|
||||||
internal U64 max_instruction_size_from_arch(Arch arch);
|
internal Architecture architecture_from_context(void);
|
||||||
|
internal Compiler compiler_from_context(void);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Time Functions
|
//~ rjf: Time Functions
|
||||||
@@ -1086,50 +770,13 @@ internal U64 max_instruction_size_from_arch(Arch arch);
|
|||||||
internal DenseTime dense_time_from_date_time(DateTime date_time);
|
internal DenseTime dense_time_from_date_time(DateTime date_time);
|
||||||
internal DateTime date_time_from_dense_time(DenseTime time);
|
internal DateTime date_time_from_dense_time(DenseTime time);
|
||||||
internal DateTime date_time_from_micro_seconds(U64 time);
|
internal DateTime date_time_from_micro_seconds(U64 time);
|
||||||
internal DateTime date_time_from_unix_time(U64 unix_time);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @per_os_impl Debugger Attachment Checking
|
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||||
|
|
||||||
internal B32 debugger_is_attached(void);
|
internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
|
||||||
|
internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
|
||||||
////////////////////////////////
|
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
//~ rjf: @per_os_impl Platform Time Functions
|
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
|
|
||||||
internal U64 now_time_us(void);
|
|
||||||
internal U32 now_time_unix(void);
|
|
||||||
internal DateTime now_time_universal(void);
|
|
||||||
internal DateTime universal_from_local_time(DateTime *dt);
|
|
||||||
internal DateTime local_from_universal_time(DateTime *dt);
|
|
||||||
internal void sleep_ms(U32 ms);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Platform GUID Functions
|
|
||||||
|
|
||||||
internal Guid make_guid(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Wrapped Ring Buffer Reads/Writes
|
|
||||||
|
|
||||||
internal U64 wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
|
|
||||||
internal U64 wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
|
|
||||||
#define wrapped_write_struct(ring_base, ring_size, ring_pos, ptr) wrapped_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
|
||||||
#define wrapped_read_struct(ring_base, ring_size, ring_pos, ptr) wrapped_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Sorts
|
|
||||||
|
|
||||||
#define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U32 idx_of_zero_byte64(U8 *ptr, U64 size); // size must be exactly 8 bytes
|
|
||||||
internal U64 index_of_zero_u32(U32 *ptr, U64 count);
|
|
||||||
internal U64 index_of_zero_u64(U64 *ptr, U64 count);
|
|
||||||
internal U64 count_digits_u64(U64 v, U64 radix);
|
|
||||||
|
|
||||||
#endif // BASE_CORE_H
|
#endif // BASE_CORE_H
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_DYNAMIC_LIBARIES_H
|
|
||||||
#define BASE_DYNAMIC_LIBARIES_H
|
|
||||||
|
|
||||||
typedef struct Library Library;
|
|
||||||
struct Library
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Dynamically-Loaded Libraries
|
|
||||||
|
|
||||||
internal Library library_open(String8 path);
|
|
||||||
internal void library_close(Library lib);
|
|
||||||
internal VoidProc *library_load_proc(Library lib, String8 name);
|
|
||||||
|
|
||||||
#endif // BASE_DYNAMIC_LIBARIES_H
|
|
||||||
+47
-201
@@ -1,92 +1,58 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
global U64 global_update_tick_idx = 0;
|
|
||||||
global U64 async_threads_count = 0;
|
|
||||||
global CondVar async_tick_start_cond_var = {0};
|
|
||||||
global Mutex async_tick_start_mutex = {0};
|
|
||||||
global Mutex async_tick_stop_mutex = {0};
|
|
||||||
global B32 async_loop_again = 0;
|
|
||||||
global B32 async_loop_again_high_priority = 0;
|
|
||||||
global B32 global_async_exit = 0;
|
|
||||||
thread_static B32 is_async_thread = 0;
|
|
||||||
|
|
||||||
// NOTE(rjf): defined by target
|
|
||||||
raddbg_entry_point(entry_point);
|
|
||||||
internal void entry_point(CmdLine *cmdline);
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
|
||||||
{
|
{
|
||||||
ThreadNameF("main_thread");
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//- rjf: set up async thread group info
|
|
||||||
async_tick_start_cond_var = cond_var_alloc();
|
|
||||||
async_tick_start_mutex = mutex_alloc();
|
|
||||||
async_tick_stop_mutex = mutex_alloc();
|
|
||||||
|
|
||||||
//- rjf: set up telemetry
|
|
||||||
#if PROFILE_TELEMETRY
|
#if PROFILE_TELEMETRY
|
||||||
local_persist char tm_data[MB(64)];
|
local_persist U8 tm_data[MB(64)];
|
||||||
tmLoadLibrary(TM_RELEASE);
|
tmLoadLibrary(TM_RELEASE);
|
||||||
tmSetMaxThreadCount(256);
|
tmSetMaxThreadCount(256);
|
||||||
tmInitialize(sizeof(tm_data), tm_data);
|
tmInitialize(sizeof(tm_data), (char *)tm_data);
|
||||||
#endif
|
#endif
|
||||||
|
TCTX tctx;
|
||||||
//- rjf: set up spall
|
tctx_init_and_equip(&tctx);
|
||||||
#if PROFILE_SPALL
|
ThreadNameF("[main thread]");
|
||||||
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
|
Temp scratch = scratch_begin(0, 0);
|
||||||
#endif
|
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
|
||||||
|
|
||||||
//- rjf: parse command line
|
|
||||||
String8List command_line_argument_strings = {0};
|
|
||||||
{
|
|
||||||
for EachIndex(idx, arguments_count)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||||
|
|
||||||
//- rjf: begin captures
|
|
||||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
||||||
if(capture)
|
if(capture)
|
||||||
{
|
{
|
||||||
ProfBeginCapture(arguments[0]);
|
ProfBeginCapture(arguments[0]);
|
||||||
ProfMsg(BUILD_TITLE);
|
|
||||||
}
|
}
|
||||||
|
#if defined(OS_CORE_H) && !defined(OS_INIT_MANUAL)
|
||||||
//- rjf: initialize all included layers
|
os_init();
|
||||||
#if defined(HTTP_H) && !defined(HTTP_INIT_MANUAL)
|
|
||||||
http_init();
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(SYMBOL_SERVER_H) && !defined(SMSV_INIT_MANUAL)
|
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
|
||||||
smsv_init();
|
ts_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
|
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
|
||||||
ac_init();
|
hs_init();
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
|
||||||
c_init();
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
||||||
fs_init();
|
fs_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL)
|
||||||
mtx_init();
|
txt_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
|
||||||
di_init(&cmdline);
|
dasm_init();
|
||||||
|
#endif
|
||||||
|
#if defined(DI_H) && !defined(DI_INIT_MANUAL)
|
||||||
|
di_init();
|
||||||
|
#endif
|
||||||
|
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
|
||||||
|
fzy_init();
|
||||||
|
#endif
|
||||||
|
#if defined(TXTI_H) && !defined(TXTI_INIT_MANUAL)
|
||||||
|
txti_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||||
dmn_init();
|
dmn_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
|
||||||
d_init();
|
ctrl_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
|
#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL)
|
||||||
wm_init();
|
os_graphical_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
||||||
fp_init();
|
fp_init();
|
||||||
@@ -94,156 +60,36 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
|
|||||||
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
||||||
r_init(&cmdline);
|
r_init(&cmdline);
|
||||||
#endif
|
#endif
|
||||||
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL)
|
||||||
fnt_init();
|
tex_init();
|
||||||
#endif
|
#endif
|
||||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL)
|
||||||
rd_init(&cmdline);
|
geo_init();
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL)
|
||||||
//- rjf: launch async threads
|
f_init();
|
||||||
#if NEED_ASYNC
|
|
||||||
Thread *async_threads = 0;
|
|
||||||
U64 lane_broadcast_val = 0;
|
|
||||||
{
|
|
||||||
U64 num_main_threads = 1;
|
|
||||||
#if defined(DBG_ENGINE_CORE_H)
|
|
||||||
num_main_threads += 1;
|
|
||||||
#endif
|
#endif
|
||||||
U64 num_async_threads = get_system_info()->logical_processor_count;
|
#if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL)
|
||||||
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
DF_StateDeltaHistory *hist = df_state_delta_history_alloc();
|
||||||
num_async_threads -= num_main_threads_clamped;
|
df_core_init(&cmdline, hist);
|
||||||
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
#endif
|
||||||
if(num_async_threads_string.size != 0)
|
#if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL)
|
||||||
{
|
df_gfx_init(update_and_render, df_state_delta_history());
|
||||||
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
|
|
||||||
}
|
|
||||||
num_async_threads = Max(1, num_async_threads);
|
|
||||||
Barrier barrier = barrier_alloc(num_async_threads);
|
|
||||||
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
|
|
||||||
async_threads_count = num_async_threads;
|
|
||||||
async_threads = push_array(scratch.arena, Thread, async_threads_count);
|
|
||||||
for EachIndex(idx, num_async_threads)
|
|
||||||
{
|
|
||||||
lane_ctxs[idx].lane_idx = idx;
|
|
||||||
lane_ctxs[idx].lane_count = async_threads_count;
|
|
||||||
lane_ctxs[idx].barrier = barrier;
|
|
||||||
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
|
|
||||||
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//- rjf: call into entry point
|
|
||||||
entry_point(&cmdline);
|
entry_point(&cmdline);
|
||||||
|
|
||||||
//- rjf: join async threads
|
|
||||||
#if NEED_ASYNC
|
|
||||||
ins_atomic_u32_inc_eval(&global_async_exit);
|
|
||||||
ins_atomic_u32_inc_eval(&async_loop_again);
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
for EachIndex(idx, async_threads_count)
|
|
||||||
{
|
|
||||||
thread_join(async_threads[idx], max_U64);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: end captures
|
|
||||||
if(capture)
|
if(capture)
|
||||||
{
|
{
|
||||||
ProfEndCapture();
|
ProfEndCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
|
tctx_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
||||||
{
|
{
|
||||||
TCTX *tctx = tctx_alloc();
|
TCTX tctx;
|
||||||
tctx_select(tctx);
|
tctx_init_and_equip(&tctx);
|
||||||
entry_point(params);
|
entry_point(params);
|
||||||
tctx_release(tctx);
|
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);
|
|
||||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
|
||||||
#if defined(FONT_CACHE_H)
|
|
||||||
fnt_frame();
|
|
||||||
#endif
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
B32 result = frame();
|
|
||||||
#else
|
|
||||||
B32 result = 0;
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
async_thread_entry_point(void *params)
|
|
||||||
{
|
|
||||||
LaneCtx lctx = *(LaneCtx *)params;
|
|
||||||
lane_ctx(lctx);
|
|
||||||
is_async_thread = 1;
|
|
||||||
ThreadNameF("async_thread_%I64u", lane_idx());
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: wait for signal if we need, otherwise reset loop signal & continue
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
if(!ins_atomic_u32_eval(&async_loop_again))
|
|
||||||
{
|
|
||||||
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, now_time_us()+1000000);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 0);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: do all ticks for all layers
|
|
||||||
ProfScope("async tick")
|
|
||||||
{
|
|
||||||
#if defined(ARTIFACT_CACHE_H)
|
|
||||||
ac_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H)
|
|
||||||
c_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(FILE_STREAM_H)
|
|
||||||
fs_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(HTTP_H)
|
|
||||||
http_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(SYMBOL_SERVER_H)
|
|
||||||
smsv_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_INFO_H)
|
|
||||||
di_async_tick();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take exit signal; break if set
|
|
||||||
lane_sync();
|
|
||||||
B32 need_exit = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
need_exit = ins_atomic_u32_eval(&global_async_exit);
|
|
||||||
}
|
|
||||||
lane_sync_u64(&need_exit, 0);
|
|
||||||
if(need_exit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_ENTRY_POINT_H
|
#ifndef BASE_ENTRY_POINT_H
|
||||||
#define BASE_ENTRY_POINT_H
|
#define BASE_ENTRY_POINT_H
|
||||||
|
|
||||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
internal void main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count);
|
||||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||||
internal U64 update_tick_idx(void);
|
|
||||||
internal B32 update(void);
|
|
||||||
internal void async_thread_entry_point(void *params);
|
|
||||||
|
|
||||||
#endif // BASE_ENTRY_POINT_H
|
#endif // BASE_ENTRY_POINT_H
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal File
|
|
||||||
file_zero(void)
|
|
||||||
{
|
|
||||||
File f = {0};
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
file_match(File a, File b)
|
|
||||||
{
|
|
||||||
B32 result = MemoryMatchStruct(&a, &b);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
data_from_file_path(Arena *arena, String8 path)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
|
|
||||||
FileProperties props = properties_from_file(file);
|
|
||||||
String8 data = string_from_file_range(arena, file, r1u64(0, props.size));
|
|
||||||
file_close(file);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
write_data_to_file_path(String8 path, String8 data)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
File file = file_open(AccessFlag_Write, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
U64 bytes_written = file_write(file, r1u64(0, data.size), data.str);
|
|
||||||
good = (bytes_written == data.size);
|
|
||||||
file_close(file);
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
write_data_list_to_file_path(String8 path, String8List list)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
File file = file_open(AccessFlag_Write, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
U64 write_buffer_size = KB(64);
|
|
||||||
U8 *write_buffer = push_array_no_zero(scratch.arena, U8, write_buffer_size);
|
|
||||||
U64 write_buffer_write_pos = 0;
|
|
||||||
U64 write_buffer_read_pos = 0;
|
|
||||||
U64 file_off = 0;
|
|
||||||
{
|
|
||||||
for(String8Node *n = list.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
for(U64 n_off = 0; n_off < n->string.size;)
|
|
||||||
{
|
|
||||||
U64 write_buffer_unconsumed_size = (write_buffer_write_pos - write_buffer_read_pos);
|
|
||||||
U64 write_buffer_available_size = (write_buffer_size - write_buffer_unconsumed_size);
|
|
||||||
if(write_buffer_available_size == 0)
|
|
||||||
{
|
|
||||||
U64 file_write_size = file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer);
|
|
||||||
if(file_write_size != write_buffer_size)
|
|
||||||
{
|
|
||||||
goto dbl_break;
|
|
||||||
}
|
|
||||||
file_off += write_buffer_size;
|
|
||||||
write_buffer_read_pos += write_buffer_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
U64 bytes_to_copy = Min(write_buffer_available_size, n->string.size - n_off);
|
|
||||||
write_buffer_write_pos += wrapped_write(write_buffer, write_buffer_size, write_buffer_write_pos, n->string.str + n_off, bytes_to_copy);
|
|
||||||
n_off += bytes_to_copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(write_buffer_write_pos > write_buffer_read_pos)
|
|
||||||
{
|
|
||||||
U64 file_write_size = file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer);
|
|
||||||
file_off += file_write_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dbl_break:;
|
|
||||||
good = (file_off == list.total_size);
|
|
||||||
file_close(file);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
append_data_to_file_path(String8 path, String8 data)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
if(data.size != 0)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Write|AccessFlag_Append, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
U64 pos = properties_from_file(file).size;
|
|
||||||
U64 bytes_written = file_write(file, r1u64(pos, pos+data.size), data.str);
|
|
||||||
good = (bytes_written == data.size);
|
|
||||||
file_close(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal FileID
|
|
||||||
id_from_file_path(String8 path)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
|
|
||||||
FileID id = id_from_file(file);
|
|
||||||
file_close(file);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal S64
|
|
||||||
file_id_compare(FileID a, FileID b)
|
|
||||||
{
|
|
||||||
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
string_from_file_range(Arena *arena, File file, Rng1U64 range)
|
|
||||||
{
|
|
||||||
U64 pre_pos = arena_pos(arena);
|
|
||||||
String8 result;
|
|
||||||
result.size = dim_1u64(range);
|
|
||||||
result.str = push_array_no_zero(arena, U8, result.size);
|
|
||||||
U64 actual_read_size = file_read(file, range, result.str);
|
|
||||||
if(actual_read_size < result.size)
|
|
||||||
{
|
|
||||||
arena_pop_to(arena, pre_pos + actual_read_size);
|
|
||||||
result.size = actual_read_size;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
file_read_cstring(Arena *arena, File file, U64 off)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List block_list = {0};
|
|
||||||
for(U64 cursor = off, stride = 256;; cursor += stride)
|
|
||||||
{
|
|
||||||
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
|
|
||||||
U64 read_size = file_read(file, 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;
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_FILES_H
|
|
||||||
#define BASE_FILES_H
|
|
||||||
|
|
||||||
typedef U32 FileIterFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
FileIterFlag_SkipFolders = (1 << 0),
|
|
||||||
FileIterFlag_SkipFiles = (1 << 1),
|
|
||||||
FileIterFlag_SkipHiddenFiles = (1 << 2),
|
|
||||||
FileIterFlag_Done = (1 << 31),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileIter FileIter;
|
|
||||||
struct FileIter
|
|
||||||
{
|
|
||||||
FileIterFlags flags;
|
|
||||||
U8 memory[800];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileInfo FileInfo;
|
|
||||||
struct FileInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
FileProperties props;
|
|
||||||
};
|
|
||||||
|
|
||||||
// nick: on-disk file identifier
|
|
||||||
typedef struct FileID FileID;
|
|
||||||
struct FileID
|
|
||||||
{
|
|
||||||
U64 v[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct File File;
|
|
||||||
struct File
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileMap FileMap;
|
|
||||||
struct FileMap
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal File file_zero(void);
|
|
||||||
internal B32 file_match(File a, File b);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
|
||||||
|
|
||||||
internal String8 data_from_file_path(Arena *arena, String8 path);
|
|
||||||
internal B32 write_data_to_file_path(String8 path, String8 data);
|
|
||||||
internal B32 write_data_list_to_file_path(String8 path, String8List list);
|
|
||||||
internal B32 append_data_to_file_path(String8 path, String8 data);
|
|
||||||
internal FileID id_from_file_path(String8 path);
|
|
||||||
internal S64 file_id_compare(FileID a, FileID b);
|
|
||||||
internal String8 string_from_file_range(Arena *arena, File file, Rng1U64 range);
|
|
||||||
internal String8 file_read_cstring(Arena *arena, File file, U64 off);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl File System (Implemented Per-OS)
|
|
||||||
|
|
||||||
//- rjf: files
|
|
||||||
internal File file_open(AccessFlags flags, String8 path);
|
|
||||||
internal void file_close(File file);
|
|
||||||
internal U64 file_read(File file, Rng1U64 rng, void *out_data);
|
|
||||||
#define file_read_struct(f, off, ptr) file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr))
|
|
||||||
internal U64 file_write(File file, Rng1U64 rng, void *data);
|
|
||||||
internal B32 file_set_times(File file, DateTime time);
|
|
||||||
internal FileProperties properties_from_file(File file);
|
|
||||||
internal FileID id_from_file(File file);
|
|
||||||
internal B32 file_reserve_size(File file, U64 size);
|
|
||||||
internal B32 delete_file_at_path(String8 path);
|
|
||||||
internal B32 copy_file_path(String8 dst, String8 src);
|
|
||||||
internal B32 move_file_path(String8 dst, String8 src);
|
|
||||||
internal String8 full_path_from_path(Arena *arena, String8 path);
|
|
||||||
internal B32 file_path_exists(String8 path);
|
|
||||||
internal B32 folder_path_exists(String8 path);
|
|
||||||
internal FileProperties properties_from_file_path(String8 path);
|
|
||||||
|
|
||||||
//- rjf: file maps
|
|
||||||
internal FileMap file_map_open(AccessFlags flags, File file);
|
|
||||||
internal void file_map_close(FileMap map);
|
|
||||||
internal void * file_map_view_open(FileMap map, AccessFlags flags, Rng1U64 range);
|
|
||||||
internal void file_map_view_close(FileMap map, void *ptr, Rng1U64 range);
|
|
||||||
|
|
||||||
//- rjf: directory iteration
|
|
||||||
internal FileIter *file_iter_begin(Arena *arena, String8 path, FileIterFlags flags);
|
|
||||||
internal B32 file_iter_next(Arena *arena, FileIter *iter, FileInfo *info_out);
|
|
||||||
internal void file_iter_end(FileIter *iter);
|
|
||||||
|
|
||||||
//- rjf: directory creation
|
|
||||||
internal B32 make_directory(String8 path);
|
|
||||||
|
|
||||||
#endif // BASE_FILES_H
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/md5.h"
|
|
||||||
|
|
||||||
internal MD5
|
|
||||||
md5_from_data(String8 data)
|
|
||||||
{
|
|
||||||
md5_ctx ctx = {0};
|
|
||||||
md5_init(&ctx);
|
|
||||||
md5_update(&ctx, (void*)data.str, data.size);
|
|
||||||
MD5 result = {0};
|
|
||||||
md5_finish(&ctx, result.u8);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/sha1.h"
|
|
||||||
#include "third_party/martins_hash/sha256.h"
|
|
||||||
|
|
||||||
internal SHA1
|
|
||||||
sha1_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA1 result = {0};
|
|
||||||
{
|
|
||||||
sha1_ctx ctx = {0};
|
|
||||||
sha1_init(&ctx);
|
|
||||||
sha1_update(&ctx, data.str, data.size);
|
|
||||||
sha1_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SHA256
|
|
||||||
sha256_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA256 result = {0};
|
|
||||||
{
|
|
||||||
sha256_ctx ctx = {0};
|
|
||||||
sha256_init(&ctx);
|
|
||||||
sha256_update(&ctx, data.str, data.size);
|
|
||||||
sha256_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_HASH_H
|
|
||||||
#define BASE_HASH_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Hash Result Types
|
|
||||||
|
|
||||||
typedef union MD5 MD5;
|
|
||||||
union MD5
|
|
||||||
{
|
|
||||||
U8 u8[16];
|
|
||||||
U16 u16[8];
|
|
||||||
U32 u32[4];
|
|
||||||
U64 u64[2];
|
|
||||||
U128 u128;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA1 SHA1;
|
|
||||||
union SHA1
|
|
||||||
{
|
|
||||||
U8 u8[20];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA256 SHA256;
|
|
||||||
union SHA256
|
|
||||||
{
|
|
||||||
U8 u8[32];
|
|
||||||
U16 u16[16];
|
|
||||||
U32 u32[8];
|
|
||||||
U64 u64[4];
|
|
||||||
U128 u128[2];
|
|
||||||
U256 u256;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
internal MD5 md5_from_data(String8 data);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
internal SHA1 sha1_from_data(String8 data);
|
|
||||||
internal SHA256 sha256_from_data(String8 data);
|
|
||||||
|
|
||||||
#endif // BASE_HASH_H
|
|
||||||
+3
-23
@@ -1,39 +1,19 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#undef LAYER_COLOR
|
#undef RADDBG_LAYER_COLOR
|
||||||
#define LAYER_COLOR 0x3399ccff
|
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||||
|
|
||||||
#include "base_core.c"
|
#include "base_core.c"
|
||||||
#include "base_profile.c"
|
#include "base_profile.c"
|
||||||
#include "base_memory.c"
|
|
||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_strings.c"
|
||||||
#include "base_memory_map.c"
|
|
||||||
#include "base_hash.c"
|
|
||||||
#include "base_system.c"
|
|
||||||
#include "base_threads.c"
|
|
||||||
#include "base_ring.c"
|
|
||||||
#include "base_thread_context.c"
|
#include "base_thread_context.c"
|
||||||
#include "base_files.c"
|
|
||||||
#include "base_shared_memory.c"
|
|
||||||
#include "base_processes.c"
|
|
||||||
#include "base_dynamic_libraries.c"
|
|
||||||
#include "base_command_line.c"
|
#include "base_command_line.c"
|
||||||
#include "base_markup.c"
|
#include "base_markup.c"
|
||||||
#include "base_meta.c"
|
|
||||||
#include "base_log.c"
|
#include "base_log.c"
|
||||||
#include "base_test.c"
|
|
||||||
#include "base_entry_point.c"
|
#include "base_entry_point.c"
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
# include "win32/base/win32_base.c"
|
|
||||||
#elif OS_LINUX
|
|
||||||
# include "linux/base/linux_base.c"
|
|
||||||
#else
|
|
||||||
# error Operating system backend not found for base layer.
|
|
||||||
#endif
|
|
||||||
|
|||||||
+1
-21
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_INC_H
|
#ifndef BASE_INC_H
|
||||||
@@ -11,33 +11,13 @@
|
|||||||
|
|
||||||
#include "base_core.h"
|
#include "base_core.h"
|
||||||
#include "base_profile.h"
|
#include "base_profile.h"
|
||||||
#include "base_memory.h"
|
|
||||||
#include "base_arena.h"
|
#include "base_arena.h"
|
||||||
#include "base_math.h"
|
#include "base_math.h"
|
||||||
#include "base_strings.h"
|
#include "base_strings.h"
|
||||||
#include "base_memory_map.h"
|
|
||||||
#include "base_hash.h"
|
|
||||||
#include "base_system.h"
|
|
||||||
#include "base_threads.h"
|
|
||||||
#include "base_ring.h"
|
|
||||||
#include "base_thread_context.h"
|
#include "base_thread_context.h"
|
||||||
#include "base_files.h"
|
|
||||||
#include "base_shared_memory.h"
|
|
||||||
#include "base_processes.h"
|
|
||||||
#include "base_dynamic_libraries.h"
|
|
||||||
#include "base_command_line.h"
|
#include "base_command_line.h"
|
||||||
#include "base_markup.h"
|
#include "base_markup.h"
|
||||||
#include "base_meta.h"
|
|
||||||
#include "base_log.h"
|
#include "base_log.h"
|
||||||
#include "base_test.h"
|
|
||||||
#include "base_entry_point.h"
|
#include "base_entry_point.h"
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
# include "win32/base/win32_base.h"
|
|
||||||
#elif OS_LINUX
|
|
||||||
# include "linux/base/linux_base.h"
|
|
||||||
#else
|
|
||||||
# error Operating system backend not found for base layer.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BASE_INC_H
|
#endif // BASE_INC_H
|
||||||
|
|||||||
+3
-8
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -9,8 +9,6 @@ C_LINKAGE thread_static Log *log_active;
|
|||||||
C_LINKAGE thread_static Log *log_active = 0;
|
C_LINKAGE thread_static Log *log_active = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String8 g_logs_folder;
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Log Creation/Selection
|
//~ rjf: Log Creation/Selection
|
||||||
|
|
||||||
@@ -90,12 +88,9 @@ log_scope_end(Arena *arena)
|
|||||||
SLLStackPop(log_active->top_scope);
|
SLLStackPop(log_active->top_scope);
|
||||||
if(arena != 0)
|
if(arena != 0)
|
||||||
{
|
{
|
||||||
for EachEnumVal(LogMsgKind, kind)
|
for(EachEnumVal(LogMsgKind, kind))
|
||||||
{
|
{
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
result.strings[kind] = str8_list_join(arena, &scope->strings[kind], 0);
|
||||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
|
||||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arena_pop_to(log_active->arena, scope->pos);
|
arena_pop_to(log_active->arena, scope->pos);
|
||||||
|
|||||||
+3
-11
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_LOG_H
|
#ifndef BASE_LOG_H
|
||||||
@@ -36,11 +36,6 @@ struct Log
|
|||||||
LogScope *top_scope;
|
LogScope *top_scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Globals
|
|
||||||
|
|
||||||
extern String8 g_logs_folder;
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Log Creation/Selection
|
//~ rjf: Log Creation/Selection
|
||||||
|
|
||||||
@@ -54,12 +49,9 @@ internal void log_select(Log *log);
|
|||||||
internal void log_msg(LogMsgKind kind, String8 string);
|
internal void log_msg(LogMsgKind kind, String8 string);
|
||||||
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
||||||
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
||||||
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
|
#define log_infof(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__)
|
||||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
||||||
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__)
|
#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__)
|
||||||
|
|
||||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
|
||||||
#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Log Scopes
|
//~ rjf: Log Scopes
|
||||||
|
|||||||
+20
-1
@@ -1,2 +1,21 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
internal void
|
||||||
|
thread_name(String8 string)
|
||||||
|
{
|
||||||
|
ProfThreadName("%.*s", str8_varg(string));
|
||||||
|
os_set_thread_name(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
thread_namef(char *fmt, ...)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||||
|
thread_name(string);
|
||||||
|
va_end(args);
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|||||||
+5
-13
@@ -1,20 +1,12 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MARKUP_H
|
#ifndef BASE_MARKUP_H
|
||||||
#define BASE_MARKUP_H
|
#define BASE_MARKUP_H
|
||||||
|
|
||||||
#define RADDBG_MARKUP_IMPLEMENTATION
|
internal void thread_name(String8 string);
|
||||||
#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf
|
internal void thread_namef(char *fmt, ...);
|
||||||
#if OS_LINUX
|
#define ThreadNameF(...) (ProfThreadName(__VA_ARGS__), thread_namef(__VA_ARGS__))
|
||||||
# define RADDBG_MARKUP_STUBS
|
#define ThreadName(str) (ProfThreadName("%.*s", str8_varg(str)), thread_name(str))
|
||||||
#endif
|
|
||||||
#include "lib_raddbg_markup/raddbg_markup.h"
|
|
||||||
|
|
||||||
#if !defined(LAYER_COLOR)
|
|
||||||
# define LAYER_COLOR 0x404040ff
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
|
|
||||||
|
|
||||||
#endif // BASE_MARKUP_H
|
#endif // BASE_MARKUP_H
|
||||||
|
|||||||
+22
-255
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scalar Math Ops
|
//~ rjf: Scalar Ops
|
||||||
|
|
||||||
internal F32
|
internal F32
|
||||||
mix_1f32(F32 a, F32 b, F32 t)
|
mix_1f32(F32 a, F32 b, F32 t)
|
||||||
@@ -42,6 +42,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.
|
|||||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
|
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
|
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
|
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
|
||||||
|
internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;}
|
||||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
|
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
|
||||||
@@ -53,6 +54,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.
|
|||||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
|
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
|
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
|
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
|
||||||
|
internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;}
|
||||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
|
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
|
||||||
@@ -64,6 +66,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S
|
|||||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
|
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
|
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
|
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
|
||||||
|
internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;}
|
||||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
|
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
|
||||||
@@ -78,14 +81,6 @@ internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f3
|
|||||||
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
||||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
||||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = v.x*m.v[0][0] + v.y*m.v[1][0] + v.z*m.v[2][0];
|
|
||||||
result.y = v.x*m.v[0][1] + v.y*m.v[1][1] + v.z*m.v[2][1];
|
|
||||||
result.z = v.x*m.v[0][2] + v.y*m.v[1][2] + v.z*m.v[2][2];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
||||||
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
||||||
@@ -96,6 +91,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.
|
|||||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
||||||
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
||||||
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
|
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
|
||||||
|
internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;}
|
||||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
|
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
|
||||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||||
|
|
||||||
@@ -120,6 +116,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.
|
|||||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
||||||
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
||||||
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
|
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
|
||||||
|
internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;}
|
||||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
|
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -389,50 +386,15 @@ derotate_4x4f32(Mat4x4F32 mat)
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Mat4x4F32
|
|
||||||
transpose_4x4f32(Mat4x4F32 mat)
|
|
||||||
{
|
|
||||||
Mat4x4F32 result =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
mat.v[0][0], mat.v[1][0], mat.v[2][0], mat.v[3][0],
|
|
||||||
mat.v[0][1], mat.v[1][1], mat.v[2][1], mat.v[3][1],
|
|
||||||
mat.v[0][2], mat.v[1][2], mat.v[2][2], mat.v[3][2],
|
|
||||||
mat.v[0][3], mat.v[1][3], mat.v[2][3], mat.v[3][3],
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ rjf: Range Ops
|
||||||
|
|
||||||
internal Rng1U8 rng_1u8(U8 min, U8 max) {Rng1U8 r = {min, max}; if(r.min > r.max) { Swap(U8, r.min, r.max); } return r;}
|
|
||||||
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x) {r.min += x; r.max += x; return r;}
|
|
||||||
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x) {r.min -= x; r.max += x; return r;}
|
|
||||||
internal U8 center_1u8(Rng1U8 r) {U8 c = (r.min+r.max)/2; return c;}
|
|
||||||
internal B32 contains_1u8(Rng1U8 r, U8 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
|
||||||
internal U8 dim_1u8(Rng1U8 r) {U8 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
|
||||||
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
|
||||||
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
|
||||||
internal U8 clamp_1u8(Rng1U8 r, U8 v) {v = Clamp(r.min, v, r.max); return v;}
|
|
||||||
|
|
||||||
internal Rng1U16 rng_1u16(U16 min, U16 max) {Rng1U16 r = {min, max}; if(r.min > r.max) { Swap(U16, r.min, r.max); } return r;}
|
|
||||||
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x) {r.min += x; r.max += x; return r;}
|
|
||||||
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x) {r.min -= x; r.max += x; return r;}
|
|
||||||
internal U16 center_1u16(Rng1U16 r) {U16 c = (r.min+r.max)/2; return c;}
|
|
||||||
internal B32 contains_1u16(Rng1U16 r, U16 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
|
||||||
internal U16 dim_1u16(Rng1U16 r) {U16 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
|
||||||
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
|
||||||
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
|
||||||
internal U16 clamp_1u16(Rng1U16 r, U16 v) {v = Clamp(r.min, v, r.max); return v;}
|
|
||||||
|
|
||||||
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
|
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
|
||||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
|
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
|
||||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
|
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal U32 dim_1u32(Rng1U32 r) {U32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;}
|
||||||
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -442,7 +404,7 @@ internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.m
|
|||||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
|
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal S32 dim_1s32(Rng1S32 r) {S32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;}
|
||||||
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -452,7 +414,7 @@ internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.m
|
|||||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
|
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal U64 dim_1u64(Rng1U64 r) {U64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;}
|
||||||
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -462,7 +424,7 @@ internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.m
|
|||||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
|
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal S64 dim_1s64(Rng1S64 r) {S64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;}
|
||||||
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -472,7 +434,7 @@ internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.m
|
|||||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
|
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal F32 dim_1f32(Rng1F32 r) {F32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;}
|
||||||
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -482,7 +444,7 @@ internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s1
|
|||||||
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
|
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
|
||||||
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
|
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
|
||||||
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0)), (S16)(((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0))}; return dim;}
|
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;}
|
||||||
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -492,7 +454,7 @@ internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s3
|
|||||||
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
|
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
|
||||||
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -502,7 +464,7 @@ internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s6
|
|||||||
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
|
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
|
||||||
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -512,15 +474,13 @@ internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f3
|
|||||||
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
|
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
|
||||||
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Color Operations
|
//~ rjf: Miscellaneous Ops
|
||||||
|
|
||||||
//- rjf: hsv <-> rgb
|
|
||||||
|
|
||||||
internal Vec3F32
|
internal Vec3F32
|
||||||
hsv_from_rgb(Vec3F32 rgb)
|
hsv_from_rgb(Vec3F32 rgb)
|
||||||
@@ -607,102 +567,16 @@ rgba_from_hsva(Vec4F32 hsva)
|
|||||||
return rgba;
|
return rgba;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: srgb <-> linear
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
linear_from_srgb(Vec3F32 srgb)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
for EachElement(idx, srgb.v)
|
|
||||||
{
|
|
||||||
result.v[idx] = (srgb.v[idx] < 0.0404482362771082f ? srgb.v[idx] / 12.92f : pow_f32((srgb.v[idx] + 0.055f) / 1.055f, 2.4f));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
srgb_from_linear(Vec3F32 linear)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
for EachElement(idx, linear.v)
|
|
||||||
{
|
|
||||||
result.v[idx] = (0 <= linear.v[idx] && linear.v[idx] < 0.00313066844250063) ? linear.v[idx]*12.92f : 1.05f * pow_f32(linear.v[idx], 1.f/2.4f) - 0.055f;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
internal Vec4F32
|
||||||
linear_from_srgba(Vec4F32 srgba)
|
rgba_from_u32(U32 hex)
|
||||||
{
|
{
|
||||||
Vec4F32 result;
|
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
|
||||||
result.xyz = linear_from_srgb(srgba.xyz);
|
((hex&0x00ff0000)>>16)/255.f,
|
||||||
result.w = srgba.w;
|
((hex&0x0000ff00)>> 8)/255.f,
|
||||||
|
((hex&0x000000ff)>> 0)/255.f);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
srgba_from_linear(Vec4F32 linear)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = srgb_from_linear(linear.xyz);
|
|
||||||
result.w = linear.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: oklab <-> linear
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
oklab_from_linear(Vec3F32 linear)
|
|
||||||
{
|
|
||||||
F32 l = (0.4122214708f * linear.x + 0.5363325363f * linear.y + 0.0514459929f * linear.z);
|
|
||||||
F32 m = (0.2119034982f * linear.x + 0.6806995451f * linear.y + 0.1073969566f * linear.z);
|
|
||||||
F32 s = (0.0883024619f * linear.x + 0.2817188376f * linear.y + 0.6299787005f * linear.z);
|
|
||||||
F32 l_ = cbrt_f32(l);
|
|
||||||
F32 m_ = cbrt_f32(m);
|
|
||||||
F32 s_ = cbrt_f32(s);
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_;
|
|
||||||
result.y = 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_;
|
|
||||||
result.z = 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
linear_from_oklab(Vec3F32 oklab)
|
|
||||||
{
|
|
||||||
F32 l_ = oklab.x + 0.3963377774f * oklab.y + 0.2158037573f * oklab.z;
|
|
||||||
F32 m_ = oklab.x - 0.1055613458f * oklab.y - 0.0638541728f * oklab.z;
|
|
||||||
F32 s_ = oklab.x - 0.0894841775f * oklab.y - 1.2914855480f * oklab.z;
|
|
||||||
F32 l = l_*l_*l_;
|
|
||||||
F32 m = m_*m_*m_;
|
|
||||||
F32 s = s_*s_*s_;
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s;
|
|
||||||
result.y = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s;
|
|
||||||
result.z = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
oklab_from_lineara(Vec4F32 lineara)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = oklab_from_linear(lineara.xyz);
|
|
||||||
result.w = lineara.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
lineara_from_oklab(Vec4F32 oklab)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = linear_from_oklab(oklab.xyz);
|
|
||||||
result.w = oklab.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: rgba <-> u32
|
|
||||||
|
|
||||||
internal U32
|
internal U32
|
||||||
u32_from_rgba(Vec4F32 rgba)
|
u32_from_rgba(Vec4F32 rgba)
|
||||||
{
|
{
|
||||||
@@ -714,99 +588,9 @@ u32_from_rgba(Vec4F32 rgba)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
rgba_from_u32(U32 hex)
|
|
||||||
{
|
|
||||||
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
|
|
||||||
((hex&0x00ff0000)>>16)/255.f,
|
|
||||||
((hex&0x0000ff00)>> 8)/255.f,
|
|
||||||
((hex&0x000000ff)>> 0)/255.f);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: List Type Functions
|
//~ rjf: List Type Functions
|
||||||
|
|
||||||
internal void
|
|
||||||
rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n)
|
|
||||||
{
|
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng1U64Node *
|
|
||||||
rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
|
|
||||||
{
|
|
||||||
Rng1U64Node *n = push_array(arena, Rng1U64Node, 1);
|
|
||||||
MemoryCopyStruct(&n->v, &rng);
|
|
||||||
rng1u64_list_push_node(list, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
list->count += to_concat->count;
|
|
||||||
MemoryZeroStruct(to_concat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng1U64Array
|
|
||||||
rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
|
|
||||||
{
|
|
||||||
Rng1U64Array arr = {0};
|
|
||||||
arr.count = list->count;
|
|
||||||
arr.v = push_array_no_zero(arena, Rng1U64, arr.count);
|
|
||||||
U64 idx = 0;
|
|
||||||
for(Rng1U64Node *n = list->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
arr.v[idx] = n->v;
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
if(array->count > 0 && array->v[0].min <= value && value < array->v[array->count-1].max)
|
|
||||||
{
|
|
||||||
U64 min_idx = 0;
|
|
||||||
U64 max_idx = array->count - 1;
|
|
||||||
for(;min_idx <= max_idx;)
|
|
||||||
{
|
|
||||||
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
|
|
||||||
if(contains_1u64(array->v[mid_idx], value))
|
|
||||||
{
|
|
||||||
result = mid_idx+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(array->v[mid_idx].min < value)
|
|
||||||
{
|
|
||||||
min_idx = mid_idx + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
max_idx = mid_idx - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
|
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
|
||||||
{
|
{
|
||||||
@@ -830,20 +614,3 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list)
|
|||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: N -> M Element Subdivision
|
|
||||||
|
|
||||||
internal Rng1U64
|
|
||||||
m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count)
|
|
||||||
{
|
|
||||||
U64 main_idxes_per_lane = m_count/n_count;
|
|
||||||
U64 leftover_idxes_count = m_count - main_idxes_per_lane*n_count;
|
|
||||||
U64 leftover_idxes_before_this_lane_count = Min(n_idx, leftover_idxes_count);
|
|
||||||
U64 lane_base_idx = n_idx*main_idxes_per_lane + leftover_idxes_before_this_lane_count;
|
|
||||||
U64 lane_base_idx__clamped = Min(lane_base_idx, m_count);
|
|
||||||
U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((n_idx < leftover_idxes_count) ? 1 : 0);
|
|
||||||
U64 lane_opl_idx__clamped = Min(lane_opl_idx, m_count);
|
|
||||||
Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
+16
-117
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MATH_H
|
#ifndef BASE_MATH_H
|
||||||
@@ -177,28 +177,6 @@ struct Mat4x4F32
|
|||||||
|
|
||||||
//- rjf: 1-range
|
//- rjf: 1-range
|
||||||
|
|
||||||
typedef union Rng1U8 Rng1U8;
|
|
||||||
union Rng1U8
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
U8 min;
|
|
||||||
U8 max;
|
|
||||||
};
|
|
||||||
U8 v[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union Rng1U16 Rng1U16;
|
|
||||||
union Rng1U16
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
U16 min;
|
|
||||||
U16 max;
|
|
||||||
};
|
|
||||||
U16 v[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union Rng1U32 Rng1U32;
|
typedef union Rng1U32 Rng1U32;
|
||||||
union Rng1U32
|
union Rng1U32
|
||||||
{
|
{
|
||||||
@@ -349,29 +327,7 @@ union Rng2S64
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range List Types
|
//~ rjf: List Types
|
||||||
|
|
||||||
typedef struct Rng1U64Node Rng1U64Node;
|
|
||||||
struct Rng1U64Node
|
|
||||||
{
|
|
||||||
Rng1U64Node *next;
|
|
||||||
Rng1U64 v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64List Rng1U64List;
|
|
||||||
struct Rng1U64List
|
|
||||||
{
|
|
||||||
Rng1U64Node *first;
|
|
||||||
Rng1U64Node *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64Array Rng1U64Array;
|
|
||||||
struct Rng1U64Array
|
|
||||||
{
|
|
||||||
Rng1U64 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1S64Node Rng1S64Node;
|
typedef struct Rng1S64Node Rng1S64Node;
|
||||||
struct Rng1S64Node
|
struct Rng1S64Node
|
||||||
@@ -396,20 +352,19 @@ struct Rng1S64Array
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scalar Math Ops
|
//~ rjf: Scalar Ops
|
||||||
|
|
||||||
#define abs_s64(v) (S64)llabs(v)
|
#define abs_s64(v) (S64)llabs(v)
|
||||||
|
|
||||||
#define sqrt_f32(v) sqrtf(v)
|
#define sqrt_f32(v) sqrtf(v)
|
||||||
#define cbrt_f32(v) cbrtf(v)
|
|
||||||
#define mod_f32(a, b) fmodf((a), (b))
|
#define mod_f32(a, b) fmodf((a), (b))
|
||||||
#define pow_f32(b, e) powf((b), (e))
|
#define pow_f32(b, e) powf((b), (e))
|
||||||
#define ceil_f32(v) ceilf(v)
|
#define ceil_f32(v) ceilf(v)
|
||||||
#define floor_f32(v) floorf(v)
|
#define floor_f32(v) floorf(v)
|
||||||
#define round_f32(v) roundf(v)
|
#define round_f32(v) roundf(v)
|
||||||
#define abs_f32(v) fabsf(v)
|
#define abs_f32(v) fabsf(v)
|
||||||
#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f))
|
#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f)
|
||||||
#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f))
|
#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f)
|
||||||
#define degrees_from_turns_f32(v) ((v)*360.f)
|
#define degrees_from_turns_f32(v) ((v)*360.f)
|
||||||
#define turns_from_degrees_f32(v) ((v)/360.f)
|
#define turns_from_degrees_f32(v) ((v)/360.f)
|
||||||
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
||||||
@@ -419,15 +374,14 @@ struct Rng1S64Array
|
|||||||
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
||||||
|
|
||||||
#define sqrt_f64(v) sqrt(v)
|
#define sqrt_f64(v) sqrt(v)
|
||||||
#define cbrt_f64(v) cbrt(v)
|
|
||||||
#define mod_f64(a, b) fmod((a), (b))
|
#define mod_f64(a, b) fmod((a), (b))
|
||||||
#define pow_f64(b, e) pow((b), (e))
|
#define pow_f64(b, e) pow((b), (e))
|
||||||
#define ceil_f64(v) ceil(v)
|
#define ceil_f64(v) ceil(v)
|
||||||
#define floor_f64(v) floor(v)
|
#define floor_f64(v) floor(v)
|
||||||
#define round_f64(v) round(v)
|
#define round_f64(v) round(v)
|
||||||
#define abs_f64(v) fabs(v)
|
#define abs_f64(v) fabs(v)
|
||||||
#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897))
|
#define radians_from_turns_f64(v) ((v)*2*3.1415926535897)
|
||||||
#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897))
|
#define turns_from_radians_f64(v) ((v)/2*3.1415926535897)
|
||||||
#define degrees_from_turns_f64(v) ((v)*360.0)
|
#define degrees_from_turns_f64(v) ((v)*360.0)
|
||||||
#define turns_from_degrees_f64(v) ((v)/360.0)
|
#define turns_from_degrees_f64(v) ((v)/360.0)
|
||||||
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
||||||
@@ -465,6 +419,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
|
|||||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
||||||
internal S64 length_squared_2s64(Vec2S64 v);
|
internal S64 length_squared_2s64(Vec2S64 v);
|
||||||
internal S64 length_2s64(Vec2S64 v);
|
internal S64 length_2s64(Vec2S64 v);
|
||||||
|
internal Vec2S64 normalize_2s64(Vec2S64 v);
|
||||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
||||||
|
|
||||||
#define v2s32(x, y) vec_2s32((x), (y))
|
#define v2s32(x, y) vec_2s32((x), (y))
|
||||||
@@ -477,6 +432,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s);
|
|||||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
||||||
internal S32 length_squared_2s32(Vec2S32 v);
|
internal S32 length_squared_2s32(Vec2S32 v);
|
||||||
internal S32 length_2s32(Vec2S32 v);
|
internal S32 length_2s32(Vec2S32 v);
|
||||||
|
internal Vec2S32 normalize_2s32(Vec2S32 v);
|
||||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
||||||
|
|
||||||
#define v2s16(x, y) vec_2s16((x), (y))
|
#define v2s16(x, y) vec_2s16((x), (y))
|
||||||
@@ -489,6 +445,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s);
|
|||||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
||||||
internal S16 length_squared_2s16(Vec2S16 v);
|
internal S16 length_squared_2s16(Vec2S16 v);
|
||||||
internal S16 length_2s16(Vec2S16 v);
|
internal S16 length_2s16(Vec2S16 v);
|
||||||
|
internal Vec2S16 normalize_2s16(Vec2S16 v);
|
||||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
||||||
|
|
||||||
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
||||||
@@ -504,7 +461,6 @@ internal F32 length_3f32(Vec3F32 v);
|
|||||||
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
||||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
||||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
||||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m);
|
|
||||||
|
|
||||||
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
||||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
||||||
@@ -516,6 +472,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s);
|
|||||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
internal S32 length_squared_3s32(Vec3S32 v);
|
internal S32 length_squared_3s32(Vec3S32 v);
|
||||||
internal S32 length_3s32(Vec3S32 v);
|
internal S32 length_3s32(Vec3S32 v);
|
||||||
|
internal Vec3S32 normalize_3s32(Vec3S32 v);
|
||||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
||||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
|
|
||||||
@@ -542,6 +499,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s);
|
|||||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
||||||
internal S32 length_squared_4s32(Vec4S32 v);
|
internal S32 length_squared_4s32(Vec4S32 v);
|
||||||
internal S32 length_4s32(Vec4S32 v);
|
internal S32 length_4s32(Vec4S32 v);
|
||||||
|
internal Vec4S32 normalize_4s32(Vec4S32 v);
|
||||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -563,37 +521,11 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
|
|||||||
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
||||||
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
||||||
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
||||||
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ rjf: Range Ops
|
||||||
|
|
||||||
#define r1u8(min, max) rng_1u8((min), (max))
|
|
||||||
#define r1u8s(min, size) rng_1u8((min), (min)+(size))
|
|
||||||
internal Rng1U8 rng_1u8(U8 min, U8 max);
|
|
||||||
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal U8 center_1u8(Rng1U8 r);
|
|
||||||
internal B32 contains_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal U8 dim_1u8(Rng1U8 r);
|
|
||||||
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b);
|
|
||||||
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b);
|
|
||||||
internal U8 clamp_1u8(Rng1U8 r, U8 v);
|
|
||||||
|
|
||||||
#define r1u16(min, max) rng_1u16((min), (max))
|
|
||||||
#define r1u16s(min, size) rng_1u16((min), (min)+(size))
|
|
||||||
internal Rng1U16 rng_1u16(U16 min, U16 max);
|
|
||||||
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal U16 center_1u16(Rng1U16 r);
|
|
||||||
internal B32 contains_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal U16 dim_1u16(Rng1U16 r);
|
|
||||||
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b);
|
|
||||||
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b);
|
|
||||||
internal U16 clamp_1u16(Rng1U16 r, U16 v);
|
|
||||||
|
|
||||||
#define r1u32(min, max) rng_1u32((min), (max))
|
#define r1u32(min, max) rng_1u32((min), (max))
|
||||||
#define r1u32s(min, size) rng_1u32((min), (min)+(size))
|
|
||||||
internal Rng1U32 rng_1u32(U32 min, U32 max);
|
internal Rng1U32 rng_1u32(U32 min, U32 max);
|
||||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
||||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
|
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
|
||||||
@@ -605,7 +537,6 @@ internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b);
|
|||||||
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
||||||
|
|
||||||
#define r1s32(min, max) rng_1s32((min), (max))
|
#define r1s32(min, max) rng_1s32((min), (max))
|
||||||
#define r1s32s(min,size) rng_1s32((min), (min)+(size))
|
|
||||||
internal Rng1S32 rng_1s32(S32 min, S32 max);
|
internal Rng1S32 rng_1s32(S32 min, S32 max);
|
||||||
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
||||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
|
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
|
||||||
@@ -617,7 +548,6 @@ internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b);
|
|||||||
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
||||||
|
|
||||||
#define r1u64(min, max) rng_1u64((min), (max))
|
#define r1u64(min, max) rng_1u64((min), (max))
|
||||||
#define r1u64s(min, size) rng_1u64((min), (min)+(size))
|
|
||||||
internal Rng1U64 rng_1u64(U64 min, U64 max);
|
internal Rng1U64 rng_1u64(U64 min, U64 max);
|
||||||
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
||||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
|
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
|
||||||
@@ -629,7 +559,6 @@ internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b);
|
|||||||
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
||||||
|
|
||||||
#define r1s64(min, max) rng_1s64((min), (max))
|
#define r1s64(min, max) rng_1s64((min), (max))
|
||||||
#define r1s64s(min, size) rng_1s64((min), (min)+(size))
|
|
||||||
internal Rng1S64 rng_1s64(S64 min, S64 max);
|
internal Rng1S64 rng_1s64(S64 min, S64 max);
|
||||||
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
||||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
|
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
|
||||||
@@ -641,7 +570,6 @@ internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b);
|
|||||||
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
||||||
|
|
||||||
#define r1f32(min, max) rng_1f32((min), (max))
|
#define r1f32(min, max) rng_1f32((min), (max))
|
||||||
#define r1f32s(min, size) rng_1f32((min), (min)+(size))
|
|
||||||
internal Rng1F32 rng_1f32(F32 min, F32 max);
|
internal Rng1F32 rng_1f32(F32 min, F32 max);
|
||||||
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
||||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
|
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
|
||||||
@@ -653,7 +581,6 @@ internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b);
|
|||||||
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
||||||
|
|
||||||
#define r2s16(min, max) rng_2s16((min), (max))
|
#define r2s16(min, max) rng_2s16((min), (max))
|
||||||
#define r2s16s(min, size) r2s16((min), (min)+(size))
|
|
||||||
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
||||||
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
||||||
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
||||||
@@ -666,7 +593,6 @@ internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b);
|
|||||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
||||||
|
|
||||||
#define r2s32(min, max) rng_2s32((min), (max))
|
#define r2s32(min, max) rng_2s32((min), (max))
|
||||||
#define r2s32s(min, size) r2s32((min), (min)+(size))
|
|
||||||
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
||||||
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
||||||
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
||||||
@@ -679,7 +605,6 @@ internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b);
|
|||||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
||||||
|
|
||||||
#define r2s64(min, max) rng_2s64((min), (max))
|
#define r2s64(min, max) rng_2s64((min), (max))
|
||||||
#define r2s64s(min, size) r2s64((min), (min)+(size))
|
|
||||||
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
||||||
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
||||||
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
||||||
@@ -692,7 +617,6 @@ internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b);
|
|||||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
||||||
|
|
||||||
#define r2f32(min, max) rng_2f32((min), (max))
|
#define r2f32(min, max) rng_2f32((min), (max))
|
||||||
#define r2f32s(min, size) r2f32((min), (min)+(size))
|
|
||||||
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
||||||
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
||||||
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
||||||
@@ -705,46 +629,21 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b);
|
|||||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Color Operations
|
//~ rjf: Miscellaneous Ops
|
||||||
|
|
||||||
//- rjf: hsv <-> rgb
|
|
||||||
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
||||||
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
||||||
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
||||||
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
||||||
|
|
||||||
//- rjf: srgb <-> linear
|
|
||||||
internal Vec3F32 linear_from_srgb(Vec3F32 srgb);
|
|
||||||
internal Vec3F32 srgb_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec4F32 linear_from_srgba(Vec4F32 srgba);
|
|
||||||
internal Vec4F32 srgba_from_linear(Vec4F32 linear);
|
|
||||||
|
|
||||||
//- rjf: oklab <-> linear
|
|
||||||
internal Vec3F32 oklab_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec3F32 linear_from_oklab(Vec3F32 oklab);
|
|
||||||
internal Vec4F32 oklab_from_lineara(Vec4F32 lineara);
|
|
||||||
internal Vec4F32 lineara_from_oklab(Vec4F32 oklab);
|
|
||||||
|
|
||||||
//- rjf: rgba <-> u32
|
|
||||||
internal U32 u32_from_rgba(Vec4F32 rgba);
|
|
||||||
internal Vec4F32 rgba_from_u32(U32 hex);
|
internal Vec4F32 rgba_from_u32(U32 hex);
|
||||||
|
internal U32 u32_from_rgba(Vec4F32 rgba);
|
||||||
|
|
||||||
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: List Type Functions
|
//~ rjf: List Type Functions
|
||||||
|
|
||||||
internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
|
|
||||||
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
|
||||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
|
||||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
|
||||||
internal U64 rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value);
|
|
||||||
|
|
||||||
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
||||||
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
||||||
|
|
||||||
////////////////////////////////
|
#endif // BASE_MATH_H
|
||||||
//~ rjf: N -> M Element Subdivision
|
|
||||||
|
|
||||||
internal Rng1U64 m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count);
|
|
||||||
|
|
||||||
#endif //BASE_MATH_H
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_MEMORY_H
|
|
||||||
#define BASE_MEMORY_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Platform Memory Allocation
|
|
||||||
|
|
||||||
//- rjf: basic
|
|
||||||
internal void *reserve_memory(U64 size);
|
|
||||||
internal B32 commit_memory(void *ptr, U64 size);
|
|
||||||
internal void decommit_memory(void *ptr, U64 size);
|
|
||||||
internal void release_memory(void *ptr, U64 size);
|
|
||||||
|
|
||||||
//- rjf: large pages
|
|
||||||
internal void *reserve_memory_large(U64 size);
|
|
||||||
internal B32 commit_memory_large(void *ptr, U64 size);
|
|
||||||
|
|
||||||
#endif // BASE_MEMORY_H
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Functions
|
|
||||||
|
|
||||||
internal void
|
|
||||||
memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data)
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *n = push_array(arena, MemoryMapRangeNode, 1);
|
|
||||||
n->v.vaddr_range = vaddr_range;
|
|
||||||
n->v.base = data;
|
|
||||||
SLLQueuePush(map->first_range, map->last_range, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
|
|
||||||
{
|
|
||||||
U64 dst_vaddr = range.min;
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
U64 start_dst_vaddr = dst_vaddr;
|
|
||||||
B32 found = 0;
|
|
||||||
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(contains_1u64(n->v.vaddr_range, dst_vaddr))
|
|
||||||
{
|
|
||||||
U64 src_off = dst_vaddr - n->v.vaddr_range.min;
|
|
||||||
U64 num_bytes_possible = n->v.vaddr_range.max - dst_vaddr;
|
|
||||||
U64 num_bytes_needed = range.max - dst_vaddr;
|
|
||||||
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
|
|
||||||
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
|
|
||||||
dst_vaddr += num_bytes_to_read;
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found || start_dst_vaddr == dst_vaddr)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
U64 bytes_read = (dst_vaddr - range.min);
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
result.size = dim_1u64(range);
|
|
||||||
result.str = push_array(arena, U8, result.size);
|
|
||||||
memory_map_read(map, range, result.str);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_MEMORY_MAP_H
|
|
||||||
#define BASE_MEMORY_MAP_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Types
|
|
||||||
|
|
||||||
typedef struct MemoryMapRange MemoryMapRange;
|
|
||||||
struct MemoryMapRange
|
|
||||||
{
|
|
||||||
Rng1U64 vaddr_range;
|
|
||||||
void *base;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MemoryMapRangeNode MemoryMapRangeNode;
|
|
||||||
struct MemoryMapRangeNode
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *next;
|
|
||||||
MemoryMapRange v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MemoryMap MemoryMap;
|
|
||||||
struct MemoryMap
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *first_range;
|
|
||||||
MemoryMapRangeNode *last_range;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Functions
|
|
||||||
|
|
||||||
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
|
|
||||||
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
|
|
||||||
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
|
|
||||||
internal String8 memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range);
|
|
||||||
|
|
||||||
#endif // BASE_MEMORY_MAP_H
|
|
||||||
@@ -1,421 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *
|
|
||||||
member_from_name(Type *type, String8 name)
|
|
||||||
{
|
|
||||||
Member *member = &member_nil;
|
|
||||||
if(type->members != 0 && name.size != 0)
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
|
||||||
{
|
|
||||||
if(str8_match(type->members[idx].name, name, 0))
|
|
||||||
{
|
|
||||||
member = &type->members[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void
|
|
||||||
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
typedef struct RebaseTypeTask RebaseTypeTask;
|
|
||||||
struct RebaseTypeTask
|
|
||||||
{
|
|
||||||
RebaseTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U8 *ptr;
|
|
||||||
};
|
|
||||||
RebaseTypeTask start_task = {0, type, data.str};
|
|
||||||
RebaseTypeTask *first_task = &start_task;
|
|
||||||
RebaseTypeTask *last_task = first_task;
|
|
||||||
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
|
|
||||||
}break;
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->ptr = t->ptr + t->type->direct->size * idx;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
Member *member = &t->type->members[idx];
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = member->type;
|
|
||||||
task->ptr = t->ptr + member->value;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List strings = {0};
|
|
||||||
str8_serial_begin(scratch.arena, &strings);
|
|
||||||
{
|
|
||||||
typedef struct SerializeTypeTask SerializeTypeTask;
|
|
||||||
struct SerializeTypeTask
|
|
||||||
{
|
|
||||||
SerializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *src;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
SerializeTypeTask start_task = {0, type, 1, data.str};
|
|
||||||
SerializeTypeTask *first_task = &start_task;
|
|
||||||
SerializeTypeTask *last_task = first_task;
|
|
||||||
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> just copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> subtract base, divide direct size, write index
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->src = *(void **)t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: write pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
U64 off = 0;
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->src;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result = str8_serial_end(arena, &strings);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
result.size = type->size;
|
|
||||||
result.str = push_array(arena, U8, result.size);
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
typedef struct DeserializeTypeTask DeserializeTypeTask;
|
|
||||||
struct DeserializeTypeTask
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *dst;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
U64 read_off = 0;
|
|
||||||
DeserializeTypeTask start_task = {0, type, 1, result.str};
|
|
||||||
DeserializeTypeTask *first_task = &start_task;
|
|
||||||
DeserializeTypeTask *last_task = first_task;
|
|
||||||
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
U8 *t_src = data.str + read_off;
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> add base, multiply direct size
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: allocate buffer for pointer destination; write address into pointer value slot
|
|
||||||
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
|
|
||||||
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
|
|
||||||
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->dst = ptr_dest_buffer;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: read pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->dst;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(params->advance_out != 0)
|
|
||||||
{
|
|
||||||
params->advance_out[0] = read_off;
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
|
|
||||||
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return data_copy;
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_META_H
|
|
||||||
#define BASE_META_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Meta Markup Features
|
|
||||||
|
|
||||||
#define EmbedFile(name, path)
|
|
||||||
#define TweakB32(name, default) (TWEAK_##name)
|
|
||||||
#define TweakF32(name, default, min, max) (TWEAK_##name)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tweak Info Tables
|
|
||||||
|
|
||||||
typedef struct TweakB32Info TweakB32Info;
|
|
||||||
struct TweakB32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
B32 default_value;
|
|
||||||
B32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32Info TweakF32Info;
|
|
||||||
struct TweakF32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
F32 default_value;
|
|
||||||
Rng1F32 value_range;
|
|
||||||
F32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakB32InfoTable TweakB32InfoTable;
|
|
||||||
struct TweakB32InfoTable
|
|
||||||
{
|
|
||||||
TweakB32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32InfoTable TweakF32InfoTable;
|
|
||||||
struct TweakF32InfoTable
|
|
||||||
{
|
|
||||||
TweakF32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfo EmbedInfo;
|
|
||||||
struct EmbedInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 *data;
|
|
||||||
U128 *hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfoTable EmbedInfoTable;
|
|
||||||
struct EmbedInfoTable
|
|
||||||
{
|
|
||||||
EmbedInfo *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Types
|
|
||||||
|
|
||||||
typedef enum TypeKind
|
|
||||||
{
|
|
||||||
TypeKind_Null,
|
|
||||||
|
|
||||||
// rjf: leaves
|
|
||||||
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
|
|
||||||
TypeKind_U8,
|
|
||||||
TypeKind_U16,
|
|
||||||
TypeKind_U32,
|
|
||||||
TypeKind_U64,
|
|
||||||
TypeKind_S8,
|
|
||||||
TypeKind_S16,
|
|
||||||
TypeKind_S32,
|
|
||||||
TypeKind_S64,
|
|
||||||
TypeKind_B8,
|
|
||||||
TypeKind_B16,
|
|
||||||
TypeKind_B32,
|
|
||||||
TypeKind_B64,
|
|
||||||
TypeKind_F32,
|
|
||||||
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
|
|
||||||
|
|
||||||
// rjf: operators
|
|
||||||
TypeKind_Ptr,
|
|
||||||
TypeKind_Array,
|
|
||||||
|
|
||||||
// rjf: user-defined-types
|
|
||||||
TypeKind_Struct,
|
|
||||||
TypeKind_Union,
|
|
||||||
TypeKind_Enum,
|
|
||||||
|
|
||||||
TypeKind_COUNT
|
|
||||||
}
|
|
||||||
TypeKind;
|
|
||||||
|
|
||||||
typedef U32 TypeFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TypeFlag_IsPlainText = (1<<0),
|
|
||||||
TypeFlag_IsCodeText = (1<<1),
|
|
||||||
TypeFlag_IsPathText = (1<<2),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 MemberFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MemberFlag_DoNotSerialize = (1<<0),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
typedef struct Member Member;
|
|
||||||
struct Member
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 pretty_name;
|
|
||||||
Type *type;
|
|
||||||
U64 value;
|
|
||||||
MemberFlags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
struct Type
|
|
||||||
{
|
|
||||||
TypeKind kind;
|
|
||||||
TypeFlags flags;
|
|
||||||
U64 size;
|
|
||||||
Type *direct;
|
|
||||||
String8 name;
|
|
||||||
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
|
|
||||||
U64 count;
|
|
||||||
Member *members;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Serialization Parameters
|
|
||||||
|
|
||||||
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
|
|
||||||
struct TypeSerializePtrRefInfo
|
|
||||||
{
|
|
||||||
Type *type; // pointers to this
|
|
||||||
void *indexify_base; // can be indexified using this
|
|
||||||
void *offsetify_base; // can be offsetified using this
|
|
||||||
void *nil_ptr; // is terminal if matching 0 or this
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TypeSerializeParams TypeSerializeParams;
|
|
||||||
struct TypeSerializeParams
|
|
||||||
{
|
|
||||||
U64 *advance_out;
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_infos;
|
|
||||||
U64 ptr_ref_infos_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Name -> Type Info
|
|
||||||
|
|
||||||
#define type(T) (&T##__type)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Table Initializer Helpers
|
|
||||||
|
|
||||||
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
|
|
||||||
#define struct_members(S) read_only global Member S##__members[] =
|
|
||||||
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
|
|
||||||
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
|
|
||||||
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
|
|
||||||
read_only global Member member_nil = {{0}, {0}, &type_nil};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Built-In Types
|
|
||||||
|
|
||||||
//- rjf: leaves
|
|
||||||
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
|
|
||||||
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
|
|
||||||
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
|
|
||||||
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
|
|
||||||
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
|
|
||||||
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
|
|
||||||
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
|
|
||||||
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
|
|
||||||
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
|
|
||||||
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
|
|
||||||
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
|
|
||||||
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
member_lit_comp(Rng1U64, type(U64), min),
|
|
||||||
member_lit_comp(Rng1U64, type(U64), max),
|
|
||||||
};
|
|
||||||
struct_type(Rng1U64);
|
|
||||||
|
|
||||||
//- rjf: String8
|
|
||||||
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
|
|
||||||
struct_members(String8)
|
|
||||||
{
|
|
||||||
member_lit_comp(String8, &String8__str_ptr_type, str),
|
|
||||||
member_lit_comp(String8, type(U64), size),
|
|
||||||
};
|
|
||||||
struct_type(String8);
|
|
||||||
|
|
||||||
//- rjf: String8Node
|
|
||||||
extern Type String8Node__type;
|
|
||||||
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
|
|
||||||
Member String8Node__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
|
|
||||||
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
|
|
||||||
};
|
|
||||||
Type String8Node__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8Node),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8Node"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8Node__members),
|
|
||||||
String8Node__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: String8List
|
|
||||||
Member String8List__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
|
|
||||||
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
|
|
||||||
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
|
|
||||||
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
|
|
||||||
};
|
|
||||||
Type String8List__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8List),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8List"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8List__members),
|
|
||||||
String8List__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *member_from_name(Type *type, String8 name);
|
|
||||||
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
|
|
||||||
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
|
|
||||||
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
|
|
||||||
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
|
|
||||||
#endif // BASE_META_H
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
process_zero(void)
|
|
||||||
{
|
|
||||||
Process p = {0};
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
process_match(Process a, Process b)
|
|
||||||
{
|
|
||||||
B32 result = MemoryMatchStruct(&a, &b);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
process_list_push(Arena *arena, ProcessList *list, Process p)
|
|
||||||
{
|
|
||||||
ProcessNode *n = push_array(arena, ProcessNode, 1);
|
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
n->v = p;
|
|
||||||
list->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Process Launcher Helpers
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
launch_cmd_line(String8 string)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
U8 split_chars[] = {' '};
|
|
||||||
String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0);
|
|
||||||
Process process = {0};
|
|
||||||
if(parts.node_count != 0)
|
|
||||||
{
|
|
||||||
// rjf: unpack exe part
|
|
||||||
String8 exe = parts.first->string;
|
|
||||||
String8 exe_folder = str8_chop_last_slash(exe);
|
|
||||||
if(exe_folder.size == 0)
|
|
||||||
{
|
|
||||||
exe_folder = get_current_path(scratch.arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: find stdout delimiter
|
|
||||||
String8Node *stdout_delimiter_n = 0;
|
|
||||||
for(String8Node *n = parts.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->string, str8_lit(">"), 0))
|
|
||||||
{
|
|
||||||
stdout_delimiter_n = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: read stdout path
|
|
||||||
String8 stdout_path = {0};
|
|
||||||
if(stdout_delimiter_n && stdout_delimiter_n->next)
|
|
||||||
{
|
|
||||||
stdout_path = stdout_delimiter_n->next->string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: open stdout handle
|
|
||||||
File stdout_handle = {0};
|
|
||||||
if(stdout_path.size != 0)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Write|AccessFlag_Read, stdout_path);
|
|
||||||
file_close(file);
|
|
||||||
stdout_handle = file_open(AccessFlag_Write|AccessFlag_Append|AccessFlag_ShareRead|AccessFlag_ShareWrite|AccessFlag_Inherited, stdout_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: form command line
|
|
||||||
String8List cmdline = {0};
|
|
||||||
for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &cmdline, n->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: launch
|
|
||||||
ProcessLaunchParams params = {0};
|
|
||||||
params.cmd_line = cmdline;
|
|
||||||
params.path = exe_folder;
|
|
||||||
params.inherit_env = 1;
|
|
||||||
params.stdout_file = stdout_handle;
|
|
||||||
process = process_launch(¶ms);
|
|
||||||
|
|
||||||
// rjf: close stdout handle
|
|
||||||
{
|
|
||||||
if(stdout_path.size != 0)
|
|
||||||
{
|
|
||||||
file_close(stdout_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return process;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
launch_cmd_linef(char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = str8fv(scratch.arena, fmt, args);
|
|
||||||
Process result = launch_cmd_line(string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_PROCESSES_H
|
|
||||||
#define BASE_PROCESSES_H
|
|
||||||
|
|
||||||
typedef struct ProcessInfo ProcessInfo;
|
|
||||||
struct ProcessInfo
|
|
||||||
{
|
|
||||||
U32 pid;
|
|
||||||
B32 large_pages_allowed;
|
|
||||||
String8 binary_file_path;
|
|
||||||
String8 binary_path;
|
|
||||||
String8 initial_path;
|
|
||||||
String8 user_program_config_data_path;
|
|
||||||
String8 user_program_cache_data_path;
|
|
||||||
String8 user_program_logs_data_path;
|
|
||||||
String8List module_load_paths;
|
|
||||||
String8List environment;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Process Process;
|
|
||||||
struct Process
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessNode ProcessNode;
|
|
||||||
struct ProcessNode
|
|
||||||
{
|
|
||||||
ProcessNode *next;
|
|
||||||
Process v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessList ProcessList;
|
|
||||||
struct ProcessList
|
|
||||||
{
|
|
||||||
ProcessNode *first;
|
|
||||||
ProcessNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessLaunchParams ProcessLaunchParams;
|
|
||||||
struct ProcessLaunchParams
|
|
||||||
{
|
|
||||||
String8List cmd_line;
|
|
||||||
String8 path;
|
|
||||||
String8List env;
|
|
||||||
B32 inherit_env;
|
|
||||||
B32 debug_subprocesses;
|
|
||||||
B32 consoleless;
|
|
||||||
File stdout_file;
|
|
||||||
File stderr_file;
|
|
||||||
File stdin_file;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal Process process_zero(void);
|
|
||||||
internal B32 process_match(Process a, Process b);
|
|
||||||
internal void process_list_push(Arena *arena, ProcessList *list, Process p);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Process Launcher Helpers
|
|
||||||
|
|
||||||
internal Process launch_cmd_line(String8 string);
|
|
||||||
internal Process launch_cmd_linef(char *fmt, ...);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Aborting
|
|
||||||
|
|
||||||
internal void abort_self(U64 exit_code);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Process Info
|
|
||||||
|
|
||||||
internal ProcessInfo *get_process_info(void);
|
|
||||||
internal String8 get_current_path(Arena *arena);
|
|
||||||
internal U32 get_process_start_time_unix(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Child Processes
|
|
||||||
|
|
||||||
internal Process process_launch(ProcessLaunchParams *params);
|
|
||||||
internal U64 pid_from_process(Process process);
|
|
||||||
internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out);
|
|
||||||
internal void process_detach(Process process);
|
|
||||||
internal B32 process_kill(Process process);
|
|
||||||
|
|
||||||
#endif // BASE_PROCESSES_H
|
|
||||||
+1
-30
@@ -1,31 +1,2 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
internal inline void
|
|
||||||
spall_begin(char *fmt, ...)
|
|
||||||
{
|
|
||||||
if(spall_buffer.data == 0)
|
|
||||||
{
|
|
||||||
spall_buffer.length = MB(1);
|
|
||||||
spall_buffer.data = os_reserve(spall_buffer.length);
|
|
||||||
os_commit(spall_buffer.data, spall_buffer.length);
|
|
||||||
spall_buffer_init(&spall_profile, &spall_buffer);
|
|
||||||
}
|
|
||||||
if(spall_pid == 0)
|
|
||||||
{
|
|
||||||
spall_pid = os_get_process_info()->pid;
|
|
||||||
}
|
|
||||||
if(spall_tid == 0)
|
|
||||||
{
|
|
||||||
spall_tid = os_tid();
|
|
||||||
}
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, now_time_us(), spall_tid, spall_pid);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
+5
-57
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_PROFILE_H
|
#ifndef BASE_PROFILE_H
|
||||||
@@ -10,8 +10,9 @@
|
|||||||
#if !defined(PROFILE_TELEMETRY)
|
#if !defined(PROFILE_TELEMETRY)
|
||||||
# define PROFILE_TELEMETRY 0
|
# define PROFILE_TELEMETRY 0
|
||||||
#endif
|
#endif
|
||||||
#if !defined(PROFILE_SPALL)
|
|
||||||
# define PROFILE_SPALL 0
|
#if !defined(MARKUP_LAYER_COLOR)
|
||||||
|
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -20,11 +21,8 @@
|
|||||||
#if PROFILE_TELEMETRY
|
#if PROFILE_TELEMETRY
|
||||||
# include "rad_tm.h"
|
# include "rad_tm.h"
|
||||||
# if OS_WINDOWS
|
# if OS_WINDOWS
|
||||||
# pragma comment(lib, "ws2_32.lib")
|
|
||||||
# pragma comment(lib, "rad_tm_win64.lib")
|
# pragma comment(lib, "rad_tm_win64.lib")
|
||||||
# endif
|
# endif
|
||||||
#elif PROFILE_SPALL
|
|
||||||
# include "spall.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -44,55 +42,7 @@
|
|||||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||||
# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f)
|
# 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: Spall Profile Defines
|
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
global U64 spall_capturing = 0;
|
|
||||||
global SpallProfile spall_profile = {0};
|
|
||||||
thread_static SpallBuffer spall_buffer = {0};
|
|
||||||
thread_static U32 spall_tid = 0;
|
|
||||||
thread_static U32 spall_pid = 0;
|
|
||||||
internal inline void spall_begin(char *fmt, ...);
|
|
||||||
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, now_time_us(), spall_tid, spall_pid)), 0 : 0)
|
|
||||||
# define ProfTick(...)
|
|
||||||
# define ProfIsCapturing(...) (!!spall_capturing)
|
|
||||||
# define ProfBeginCapture(...) (spall_capturing = 1)
|
|
||||||
# define ProfEndCapture(...) (spall_capturing = 0, spall_flush(&spall_profile))
|
|
||||||
# define ProfThreadName(...)
|
|
||||||
# define ProfMsg(...)
|
|
||||||
# define ProfBeginLockWait(...)
|
|
||||||
# define ProfEndLockWait(...)
|
|
||||||
# define ProfLockTake(...)
|
|
||||||
# define ProfLockDrop(...)
|
|
||||||
# define ProfColor(color)
|
|
||||||
# define ProfBeginV(...)
|
|
||||||
# define ProfNoteV(...)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -113,8 +63,6 @@ internal inline void spall_begin(char *fmt, ...);
|
|||||||
# define ProfLockTake(...) (0)
|
# define ProfLockTake(...) (0)
|
||||||
# define ProfLockDrop(...) (0)
|
# define ProfLockDrop(...) (0)
|
||||||
# define ProfColor(...) (0)
|
# define ProfColor(...) (0)
|
||||||
# define ProfBeginV(...) (0)
|
|
||||||
# define ProfNoteV(...) (0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Ring Functions
|
|
||||||
|
|
||||||
internal Ring *
|
|
||||||
make_ring(Arena *arena, U64 size)
|
|
||||||
{
|
|
||||||
Ring *ring = push_array(arena, Ring, 1);
|
|
||||||
ring->size = size;
|
|
||||||
ring->base = push_array(arena, U8, ring->size);
|
|
||||||
return ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
ring_try_write(Ring *ring, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
|
|
||||||
U64 bytes_available = ring->size - bytes_unconsumed;
|
|
||||||
B32 result = 0;
|
|
||||||
if(bytes_available >= size)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
ring->write_pos += wrapped_write(ring->base, ring->size, ring->write_pos, ptr, size);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
ring_try_read(Ring *ring, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
|
|
||||||
B32 result = 0;
|
|
||||||
if(bytes_unconsumed >= size)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
ring->read_pos += wrapped_read(ring->base, ring->size, ring->read_pos, ptr, size);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Guarded Ring Functions
|
|
||||||
|
|
||||||
internal GuardedRing *
|
|
||||||
guarded_ring_alloc(Arena *arena, U64 size)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
GuardedRing *gr = push_array(arena, GuardedRing, 1);
|
|
||||||
gr->ring = make_ring(arena, size);
|
|
||||||
gr->mutex = mutex_alloc();
|
|
||||||
gr->cv = cond_var_alloc();
|
|
||||||
ProfEnd();
|
|
||||||
return gr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
guarded_ring_release(GuardedRing *ring)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
mutex_release(ring->mutex);
|
|
||||||
cond_var_release(ring->cv);
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal RingGuard
|
|
||||||
guarded_ring_open(GuardedRing *ring)
|
|
||||||
{
|
|
||||||
RingGuard guard = {ring};
|
|
||||||
mutex_take(ring->mutex);
|
|
||||||
return guard;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
guarded_ring_close(RingGuard *guard)
|
|
||||||
{
|
|
||||||
mutex_drop(guard->r->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
B32 result = ring_try_write(guard->r->ring, size, ptr);
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
cond_var_broadcast(guard->r->cv);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
B32 result = ring_try_read(guard->r->ring, size, ptr);
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
cond_var_broadcast(guard->r->cv);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
|
|
||||||
{
|
|
||||||
B32 write_good = 0;
|
|
||||||
for(;!write_good;)
|
|
||||||
{
|
|
||||||
write_good = guarded_ring_try_write(guard, size, ptr);
|
|
||||||
if(now_time_us() >= endt_us)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!write_good)
|
|
||||||
{
|
|
||||||
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return write_good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
|
|
||||||
{
|
|
||||||
B32 read_good = 0;
|
|
||||||
for(;!read_good;)
|
|
||||||
{
|
|
||||||
read_good = guarded_ring_try_read(guard, size, ptr);
|
|
||||||
if(now_time_us() >= endt_us)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!read_good)
|
|
||||||
{
|
|
||||||
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return read_good;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_RING_H
|
|
||||||
#define BASE_RING_H
|
|
||||||
|
|
||||||
typedef struct Ring Ring;
|
|
||||||
struct Ring
|
|
||||||
{
|
|
||||||
U8 *base;
|
|
||||||
U64 size;
|
|
||||||
U64 write_pos;
|
|
||||||
U64 read_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct GuardedRing GuardedRing;
|
|
||||||
struct GuardedRing
|
|
||||||
{
|
|
||||||
Ring *ring;
|
|
||||||
Mutex mutex;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RingGuard RingGuard;
|
|
||||||
struct RingGuard
|
|
||||||
{
|
|
||||||
GuardedRing *r;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Ring Functions
|
|
||||||
|
|
||||||
internal Ring *make_ring(Arena *arena, U64 size);
|
|
||||||
internal B32 ring_try_write(Ring *ring, U64 size, void *ptr);
|
|
||||||
internal B32 ring_try_read(Ring *ring, U64 size, void *ptr);
|
|
||||||
#define ring_try_write_struct(ring, ptr) ring_try_write((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
#define ring_try_read_struct(ring, ptr) ring_try_read((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Guarded Ring Functions
|
|
||||||
|
|
||||||
internal GuardedRing *guarded_ring_alloc(Arena *arena, U64 size);
|
|
||||||
internal void guarded_ring_release(GuardedRing *ring);
|
|
||||||
internal RingGuard guarded_ring_open(GuardedRing *ring);
|
|
||||||
internal void guarded_ring_close(RingGuard *guard);
|
|
||||||
internal B32 guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr);
|
|
||||||
internal B32 guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr);
|
|
||||||
#define guarded_ring_try_write_struct(ring, ptr) guarded_ring_try_write((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
#define guarded_ring_try_read_struct(ring, ptr) guarded_ring_try_read((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
internal B32 guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
|
|
||||||
internal B32 guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
|
|
||||||
#define guarded_ring_write_struct_or_wait(ring, ptr, endt_us) guarded_ring_write_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
|
|
||||||
#define guarded_ring_read_struct_or_wait(ring, ptr, endt_us) guarded_ring_read_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
|
|
||||||
#define guarded_ring_write_string_or_wait(ring, string, endt_us) guarded_ring_write_or_wait((ring), (string).size, (string).str, (endt_us))
|
|
||||||
|
|
||||||
#endif // BASE_RING_H
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_SHARED_MEMORY_H
|
|
||||||
#define BASE_SHARED_MEMORY_H
|
|
||||||
|
|
||||||
typedef struct SharedMemory SharedMemory;
|
|
||||||
struct SharedMemory
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Shared Memory
|
|
||||||
|
|
||||||
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
|
|
||||||
internal SharedMemory shared_memory_open(String8 name);
|
|
||||||
internal void shared_memory_close(SharedMemory handle);
|
|
||||||
internal void * shared_memory_view_open(SharedMemory handle, Rng1U64 range);
|
|
||||||
internal void shared_memory_view_close(SharedMemory handle, void *ptr, Rng1U64 range);
|
|
||||||
|
|
||||||
#endif // BASE_SHARED_MEMORY_H
|
|
||||||
+521
-1860
File diff suppressed because it is too large
Load Diff
+51
-155
@@ -1,9 +1,15 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_STRINGS_H
|
#ifndef BASE_STRINGS_H
|
||||||
#define BASE_STRINGS_H
|
#define BASE_STRINGS_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
|
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||||
|
#include "third_party/stb/stb_sprintf.h"
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Types
|
//~ rjf: String Types
|
||||||
|
|
||||||
@@ -38,6 +44,13 @@ struct String8Node
|
|||||||
String8 string;
|
String8 string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct String8MetaNode String8MetaNode;
|
||||||
|
struct String8MetaNode
|
||||||
|
{
|
||||||
|
String8MetaNode *next;
|
||||||
|
String8Node *node;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct String8List String8List;
|
typedef struct String8List String8List;
|
||||||
struct String8List
|
struct String8List
|
||||||
{
|
{
|
||||||
@@ -50,9 +63,8 @@ struct String8List
|
|||||||
typedef struct String8Array String8Array;
|
typedef struct String8Array String8Array;
|
||||||
struct String8Array
|
struct String8Array
|
||||||
{
|
{
|
||||||
String8 *v;
|
String8 *strings;
|
||||||
U64 count;
|
U64 count;
|
||||||
U64 total_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -74,7 +86,6 @@ enum
|
|||||||
|
|
||||||
typedef enum PathStyle
|
typedef enum PathStyle
|
||||||
{
|
{
|
||||||
PathStyle_Null,
|
|
||||||
PathStyle_Relative,
|
PathStyle_Relative,
|
||||||
PathStyle_WindowsAbsolute,
|
PathStyle_WindowsAbsolute,
|
||||||
PathStyle_UnixAbsolute,
|
PathStyle_UnixAbsolute,
|
||||||
@@ -84,7 +95,7 @@ typedef enum PathStyle
|
|||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||||
#else
|
#else
|
||||||
# error Absolute path style is undefined for this OS.
|
# error "absolute path style is undefined for this OS"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
PathStyle;
|
PathStyle;
|
||||||
@@ -146,9 +157,9 @@ internal B32 char_is_lower(U8 c);
|
|||||||
internal B32 char_is_alpha(U8 c);
|
internal B32 char_is_alpha(U8 c);
|
||||||
internal B32 char_is_slash(U8 c);
|
internal B32 char_is_slash(U8 c);
|
||||||
internal B32 char_is_digit(U8 c, U32 base);
|
internal B32 char_is_digit(U8 c, U32 base);
|
||||||
internal U8 lower_from_char(U8 c);
|
internal U8 char_to_lower(U8 c);
|
||||||
internal U8 upper_from_char(U8 c);
|
internal U8 char_to_upper(U8 c);
|
||||||
internal U8 correct_slash_from_char(U8 c);
|
internal U8 char_to_correct_slash(U8 c);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: C-String Measurement
|
//~ rjf: C-String Measurement
|
||||||
@@ -160,11 +171,8 @@ internal U64 cstring32_length(U32 *c);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Constructors
|
//~ rjf: String Constructors
|
||||||
|
|
||||||
#define s(S) str8_lit(S)
|
|
||||||
|
|
||||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||||
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
||||||
#define str8_lit_cstr(S) str8((U8*)(S), sizeof(S))
|
|
||||||
#define str8_varg(S) (int)((S).size), ((S).str)
|
#define str8_varg(S) (int)((S).size), ((S).str)
|
||||||
|
|
||||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||||
@@ -184,7 +192,6 @@ internal String8 str8_cstring(char *c);
|
|||||||
internal String16 str16_cstring(U16 *c);
|
internal String16 str16_cstring(U16 *c);
|
||||||
internal String32 str32_cstring(U32 *c);
|
internal String32 str32_cstring(U32 *c);
|
||||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||||
internal String16 str16_cstring_capped(void *cstr, void *cap);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Stylization
|
//~ rjf: String Stylization
|
||||||
@@ -196,17 +203,9 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Matching
|
//~ rjf: String Matching
|
||||||
|
|
||||||
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
|
|
||||||
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
|
|
||||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||||
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
|
|
||||||
internal B32 str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags);
|
|
||||||
internal B32 str8_starts_with(String8 string, String8 expected_prefix);
|
|
||||||
internal B32 str8_starts_withi(String8 string, String8 expected_prefix);
|
|
||||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, 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);
|
||||||
internal B32 str8_is_before(String8 a, String8 b);
|
|
||||||
#define str8_ends_with(string, end, flags) str8_match(str8_postfix((string), (end).size), (end), (flags))
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Slicing
|
//~ rjf: String Slicing
|
||||||
@@ -216,23 +215,15 @@ internal String8 str8_prefix(String8 str, U64 size);
|
|||||||
internal String8 str8_skip(String8 str, U64 amt);
|
internal String8 str8_skip(String8 str, U64 amt);
|
||||||
internal String8 str8_postfix(String8 str, U64 size);
|
internal String8 str8_postfix(String8 str, U64 size);
|
||||||
internal String8 str8_chop(String8 str, U64 amt);
|
internal String8 str8_chop(String8 str, U64 amt);
|
||||||
internal String8 str8_chop_line(String8 *str);
|
|
||||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||||
internal String8 str8_skip_chop_slashes(String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Formatting & Copying
|
//~ rjf: String Formatting & Copying
|
||||||
|
|
||||||
internal String8 str8_cat(Arena *arena, String8 s1, String8 s2);
|
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||||
internal String8 str8_copy(Arena *arena, String8 s);
|
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||||
internal String8 str8fv(Arena *arena, char *fmt, va_list args);
|
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||||
internal String8 str8f(Arena *arena, char *fmt, ...);
|
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||||
// TODO(rjf): remove these once we're ready to convert all usages:
|
|
||||||
#define push_str8_cat(arena, s1, s2) str8_cat((arena), (s1), (s2))
|
|
||||||
#define push_str8_copy(arena, s) str8_copy((arena), (s))
|
|
||||||
#define push_str8fv(arena, fmt, args) str8fv((arena), (fmt), (args))
|
|
||||||
#define push_str8f(arena, ...) str8f((arena), __VA_ARGS__)
|
|
||||||
internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unnecessary - this is implied by `push_str8_copy`. need to remove.
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String <=> Integer Conversions
|
//~ rjf: String <=> Integer Conversions
|
||||||
@@ -240,19 +231,13 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn
|
|||||||
//- rjf: string -> integer
|
//- rjf: string -> integer
|
||||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||||
internal B32 str8_is_integer_signed(String8 string, U32 radix);
|
|
||||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||||
internal U32 u32_from_str8(String8 string, U32 radix);
|
|
||||||
internal S32 s32_from_str8(String8 string, U32 radix);
|
|
||||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||||
|
|
||||||
//- rjf: integer -> string
|
//- rjf: integer -> string
|
||||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||||
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_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);
|
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||||
|
|
||||||
@@ -264,19 +249,17 @@ internal F64 f64_from_str8(String8 string);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String List Construction Functions
|
//~ rjf: String List Construction Functions
|
||||||
|
|
||||||
internal String8Node *str8_list_push_node(String8List *list, String8Node *node);
|
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||||
internal String8Node *str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
internal String8Node *str8_list_push_node_front(String8List *list, String8Node *node);
|
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||||
internal String8Node *str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
internal String8Node *str8_list_push(Arena *arena, String8List *list, String8 string);
|
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||||
internal String8Node *str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||||
internal String8Node* str8_list_pop_front(String8List *list);
|
|
||||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||||
internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 range);
|
|
||||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -284,46 +267,19 @@ internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 r
|
|||||||
|
|
||||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||||
|
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||||
|
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Data Stringification Helpers
|
|
||||||
|
|
||||||
internal String8List numeric_str8_list_from_data(Arena *arena, U32 radix, String8 data, U64 stride);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf; String Arrays
|
//~ rjf; String Arrays
|
||||||
|
|
||||||
internal String8Array str8_array_zero(void);
|
|
||||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||||
internal String8Array str8_array_copy(Arena *arena, String8Array array);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String <-> Version Helpers
|
|
||||||
|
|
||||||
internal U64 version_from_str8(String8 string);
|
|
||||||
internal String8 str8_from_version(Arena *arena, U64 version);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Path Helpers
|
//~ rjf: String Path Helpers
|
||||||
|
|
||||||
global read_only struct
|
|
||||||
{
|
|
||||||
String8 string;
|
|
||||||
PathStyle path_style;
|
|
||||||
}
|
|
||||||
g_path_style_map[] =
|
|
||||||
{
|
|
||||||
{ str8_lit_comp(""), PathStyle_Null },
|
|
||||||
{ str8_lit_comp("relative"), PathStyle_Relative },
|
|
||||||
{ str8_lit_comp("windows"), PathStyle_WindowsAbsolute },
|
|
||||||
{ str8_lit_comp("unix"), PathStyle_UnixAbsolute },
|
|
||||||
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
|
||||||
};
|
|
||||||
|
|
||||||
internal String8 program_ext_postfix_from_os(OperatingSystem os, B32 require_ext);
|
|
||||||
|
|
||||||
internal String8 str8_chop_last_slash(String8 string);
|
internal String8 str8_chop_last_slash(String8 string);
|
||||||
internal String8 str8_skip_last_slash(String8 string);
|
internal String8 str8_skip_last_slash(String8 string);
|
||||||
internal String8 str8_chop_last_dot(String8 string);
|
internal String8 str8_chop_last_dot(String8 string);
|
||||||
@@ -336,29 +292,6 @@ internal String8 str8_path_list_join_by_style(Arena *arena, String8List *pat
|
|||||||
|
|
||||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Relative <-> Absolute Path
|
|
||||||
|
|
||||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
|
||||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Path Normalization
|
|
||||||
|
|
||||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
|
||||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
|
||||||
internal B32 path_match_normalized(String8 left, String8 right);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Misc. Path Helpers
|
|
||||||
|
|
||||||
internal PathStyle path_style_from_string(String8 string);
|
|
||||||
internal String8 string_from_path_style(PathStyle style);
|
|
||||||
internal String8 path_separator_string_from_style(PathStyle style);
|
|
||||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
|
||||||
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
|
|
||||||
internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||||
|
|
||||||
@@ -366,6 +299,7 @@ internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
|||||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||||
|
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Unicode String Conversions
|
//~ rjf: Unicode String Conversions
|
||||||
@@ -376,39 +310,24 @@ internal String8 str8_from_32(Arena *arena, String32 in);
|
|||||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Basic Types & Space Enum <-> String Conversions
|
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||||
|
|
||||||
internal OperatingSystem operating_system_from_string(String8 string);
|
|
||||||
internal String8 string_from_dimension(Dimension dimension);
|
internal String8 string_from_dimension(Dimension dimension);
|
||||||
internal String8 string_from_side(Side side);
|
internal String8 string_from_side(Side side);
|
||||||
internal String8 string_from_operating_system(OperatingSystem os);
|
internal String8 string_from_operating_system(OperatingSystem os);
|
||||||
internal String8 string_from_arch(Arch arch);
|
internal String8 string_from_architecture(Architecture arch);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Time Types -> String
|
||||||
|
|
||||||
internal String8 string_from_week_day(WeekDay week_day);
|
internal String8 string_from_week_day(WeekDay week_day);
|
||||||
internal String8 string_from_month(Month month);
|
internal String8 string_from_month(Month month);
|
||||||
internal String8 string_from_date_time(Arena *arena, DateTime *date_time);
|
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
internal String8 string_from_date_time__file_name(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);
|
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String <-> Globally Unique IDs
|
//~ rjf: Textual String Wrapping
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Escaping
|
|
||||||
|
|
||||||
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
|
|
||||||
internal String8 raw_from_escaped_str8(Arena *arena, String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Wrapping
|
|
||||||
|
|
||||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||||
|
|
||||||
@@ -434,12 +353,12 @@ internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 alig
|
|||||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||||
internal void * str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||||
internal void * str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
||||||
internal void * str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||||
internal void * str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||||
internal void * str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||||
internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||||
|
|
||||||
@@ -448,33 +367,10 @@ internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8
|
|||||||
|
|
||||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);
|
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||||
internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
|
||||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
|
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||||
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
|
|
||||||
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ string buffer
|
|
||||||
|
|
||||||
internal B32 str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip);
|
|
||||||
internal U64 str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out);
|
|
||||||
internal U64 str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out);
|
|
||||||
internal U64 str8_buffer_write(String8Node *buf, U64 *pos, String8 data);
|
|
||||||
internal U64 str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v);
|
|
||||||
internal U64 str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v);
|
|
||||||
internal U64 str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size);
|
|
||||||
internal U64 str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic String Hashes
|
|
||||||
|
|
||||||
internal U64 u64_hash_from_seed_str8(U64 seed, String8 string);
|
|
||||||
internal U64 u64_hash_from_str8(String8 string);
|
|
||||||
internal U128 u128_hash_from_seed_str8(U64 seed, String8 string);
|
|
||||||
internal U128 u128_hash_from_str8(String8 string);
|
|
||||||
|
|
||||||
#endif // BASE_STRINGS_H
|
#endif // BASE_STRINGS_H
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_SYSTEM_H
|
|
||||||
#define BASE_SYSTEM_H
|
|
||||||
|
|
||||||
typedef struct SystemInfo SystemInfo;
|
|
||||||
struct SystemInfo
|
|
||||||
{
|
|
||||||
U32 logical_processor_count;
|
|
||||||
U64 page_size;
|
|
||||||
U64 large_page_size;
|
|
||||||
U64 allocation_granularity;
|
|
||||||
String8 machine_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl System Info
|
|
||||||
|
|
||||||
internal SystemInfo *get_system_info(void);
|
|
||||||
|
|
||||||
#endif // BASE_SYSTEM_H
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if BUILD_TESTS
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_build_exe_path(Arena *arena, String8 name)
|
|
||||||
{
|
|
||||||
String8 folder = get_process_info()->binary_path;
|
|
||||||
String8 path = str8f(arena, "%S/%S%S", folder, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 0));
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_input_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S", ctx->input_data_path, name);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S%S", ctx->input_data_path, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 1));
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S", ctx->exemplars_path, name);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
base_register_test(char *func_name_cstr, TestFunctionType *fn, char *file_path_cstr, int line, int skip)
|
|
||||||
{
|
|
||||||
String8 file_path = str8_cstring(file_path_cstr);
|
|
||||||
U64 src_min = str8_find_needle(file_path, 0, s("src/"), StringMatchFlag_SlashInsensitive);
|
|
||||||
U64 src_max = src_min + str8_lit("src/").size;
|
|
||||||
U64 layer_slash_max = str8_find_needle(file_path, src_max, s("/"), StringMatchFlag_SlashInsensitive);
|
|
||||||
|
|
||||||
TestInfo *t = &test_infos[test_infos_count++];
|
|
||||||
t->layer = str8_substr(file_path, r1u64(src_max, layer_slash_max));
|
|
||||||
t->label = str8_cstring(func_name_cstr);
|
|
||||||
t->decl_line = line;
|
|
||||||
t->skip = skip;
|
|
||||||
t->test_fn = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_TEST_H
|
|
||||||
#define BASE_TEST_H
|
|
||||||
|
|
||||||
typedef enum TestStatus
|
|
||||||
{
|
|
||||||
TestStatus_Fail,
|
|
||||||
TestStatus_Crash,
|
|
||||||
TestStatus_Pass,
|
|
||||||
TestStatus_Skip,
|
|
||||||
TestStatus_COUNT
|
|
||||||
}
|
|
||||||
TestStatus;
|
|
||||||
|
|
||||||
typedef struct TestResult TestResult;
|
|
||||||
struct TestResult
|
|
||||||
{
|
|
||||||
TestStatus status;
|
|
||||||
char *fail_file;
|
|
||||||
int fail_line;
|
|
||||||
char *fail_cond;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TestCtx TestCtx;
|
|
||||||
struct TestCtx
|
|
||||||
{
|
|
||||||
CmdLine *cmdline;
|
|
||||||
String8 exemplars_path;
|
|
||||||
String8 artifacts_path;
|
|
||||||
String8 input_data_path;
|
|
||||||
TestResult *result_out;
|
|
||||||
String8List *test_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, TestCtx *ctx)
|
|
||||||
#define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name)
|
|
||||||
typedef TEST_FUNCTION_SIG(TestFunctionType);
|
|
||||||
|
|
||||||
typedef struct TestInfo TestInfo;
|
|
||||||
struct TestInfo
|
|
||||||
{
|
|
||||||
String8 layer;
|
|
||||||
String8 label;
|
|
||||||
S64 decl_line;
|
|
||||||
B32 skip;
|
|
||||||
TestFunctionType *test_fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if BUILD_TESTS
|
|
||||||
|
|
||||||
// alloc storage for the tests
|
|
||||||
global U16 test_infos_count = 0;
|
|
||||||
global TestInfo test_infos[0xffff] = {0};
|
|
||||||
|
|
||||||
internal String8 test_build_exe_path(Arena *arena, String8 name);
|
|
||||||
internal String8 test_input_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal String8 test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal String8 test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal void base_register_test(char *func_name, TestFunctionType *fn, char *file_path, int line, int skip);
|
|
||||||
|
|
||||||
#define AddTest(name, file_path, line, skip_, ...) \
|
|
||||||
TEST_FUNCTION_DEF(name); \
|
|
||||||
__VA_ARGS__ void add_test__##name(void) { base_register_test(Stringify(name), test__##name, file_path, line, skip_); }
|
|
||||||
|
|
||||||
# if COMPILER_MSVC
|
|
||||||
# pragma section(".CRT$XCU", read)
|
|
||||||
# define DeclareTest(name, skip) \
|
|
||||||
/* register test */ AddTest(name, __FILE__, __LINE__, (skip)) \
|
|
||||||
/* alloc function pointer */ __declspec(allocate(".CRT$XCU")) void (*add_test_ptr__##name)(void) = add_test__##name; \
|
|
||||||
/* do not GC test caller */ __pragma(comment(linker, "/include:" Stringify(add_test_ptr__##name)))
|
|
||||||
# elif COMPILER_GCC || COMPILER_CLANG
|
|
||||||
// clang and gcc allocate memory for the function pointer automatically
|
|
||||||
# define DeclareTest(name, skip) AddTest(name, __FILE__, __LINE__, (skip), __attribute__((constructor)))
|
|
||||||
# else
|
|
||||||
# error DeclareTest not defined for this compiler.
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define DeclareTest(name, skip)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Test(name) DeclareTest(name, 0) TEST_FUNCTION_DEF(name)
|
|
||||||
#define SkippedTest(name) DeclareTest(name, 1) TEST_FUNCTION_DEF(name)
|
|
||||||
|
|
||||||
#define TestCheck(c) do { if (!(c)) { \
|
|
||||||
/* record failed check */ ctx->result_out[0] = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) }; \
|
|
||||||
/* under debugger? -> trap */ if(debugger_is_attached()) { Trap(); } \
|
|
||||||
/* exit test */ return; \
|
|
||||||
} } while(0)
|
|
||||||
|
|
||||||
#define TestSkip() do { \
|
|
||||||
ctx->result_out[0] = (TestResult){ .status = TestStatus_Skip }; \
|
|
||||||
return; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
// test log
|
|
||||||
#define test_out(string) str8_list_push(arena, ctx->test_out, (string))
|
|
||||||
#define test_outf(...) str8_list_pushf(arena, ctx->test_out, __VA_ARGS__)
|
|
||||||
|
|
||||||
#endif // BASE_TEST_H
|
|
||||||
+38
-185
@@ -1,234 +1,87 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local;
|
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
#if !BUILD_SUPPLEMENTARY_UNIT
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
|
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Context Functions
|
|
||||||
|
|
||||||
//- rjf: thread-context allocation & selection
|
|
||||||
|
|
||||||
internal TCTX *
|
|
||||||
tctx_alloc(void)
|
|
||||||
{
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
thread_static static char name[2][1024];
|
|
||||||
raddbg_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
|
|
||||||
raddbg_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", tid());
|
|
||||||
Arena *arena_0 = arena_alloc(.name = name[0]);
|
|
||||||
Arena *arena_1 = arena_alloc(.name = name[1]);
|
|
||||||
#else
|
|
||||||
Arena *arena_0 = arena_alloc();
|
|
||||||
Arena *arena_1 = arena_alloc();
|
|
||||||
#endif
|
|
||||||
TCTX *tctx = push_array(arena_0, TCTX, 1);
|
|
||||||
tctx->arenas[0] = arena_0;
|
|
||||||
tctx->arenas[1] = arena_1;
|
|
||||||
tctx->lane_ctx.lane_count = 1;
|
|
||||||
return tctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_release(TCTX *tctx)
|
tctx_init_and_equip(TCTX *tctx){
|
||||||
{
|
MemoryZeroStruct(tctx);
|
||||||
arena_release(tctx->arenas[1]);
|
Arena **arena_ptr = tctx->arenas;
|
||||||
arena_release(tctx->arenas[0]);
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
}
|
*arena_ptr = arena_alloc();
|
||||||
|
}
|
||||||
internal void
|
|
||||||
tctx_select(TCTX *tctx)
|
|
||||||
{
|
|
||||||
tctx_thread_local = tctx;
|
tctx_thread_local = tctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TCTX *
|
internal void
|
||||||
tctx_selected(void)
|
tctx_release(void)
|
||||||
{
|
{
|
||||||
return tctx_thread_local;
|
for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1)
|
||||||
|
{
|
||||||
|
arena_release(tctx_thread_local->arenas[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: scratch arenas
|
internal TCTX*
|
||||||
|
tctx_get_equipped(void){
|
||||||
|
return(tctx_thread_local);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Arena*
|
||||||
|
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||||
|
TCTX *tctx = tctx_get_equipped();
|
||||||
|
|
||||||
internal Arena *
|
|
||||||
tctx_get_scratch(Arena **conflicts, U64 count)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
Arena *result = 0;
|
Arena *result = 0;
|
||||||
Arena **arena_ptr = tctx->arenas;
|
Arena **arena_ptr = tctx->arenas;
|
||||||
for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1)
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
{
|
|
||||||
Arena **conflict_ptr = conflicts;
|
Arena **conflict_ptr = conflicts;
|
||||||
B32 has_conflict = 0;
|
B32 has_conflict = 0;
|
||||||
for(U64 j = 0; j < count; j += 1, conflict_ptr += 1)
|
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||||
{
|
if (*arena_ptr == *conflict_ptr){
|
||||||
if(*arena_ptr == *conflict_ptr)
|
|
||||||
{
|
|
||||||
has_conflict = 1;
|
has_conflict = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!has_conflict)
|
if (!has_conflict){
|
||||||
{
|
|
||||||
result = *arena_ptr;
|
result = *arena_ptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: lane metadata
|
return(result);
|
||||||
|
|
||||||
internal LaneCtx
|
|
||||||
tctx_set_lane_ctx(LaneCtx lane_ctx)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
LaneCtx restore = tctx->lane_ctx;
|
|
||||||
tctx->lane_ctx = lane_ctx;
|
|
||||||
return restore;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx)
|
tctx_set_thread_name(String8 string){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
ProfBeginFunction();
|
|
||||||
ProfColor(0x00000ff);
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy to broadcast memory on source lane
|
|
||||||
U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0]));
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: all cases: barrier
|
|
||||||
barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> barrier on all lanes
|
|
||||||
if(broadcast_ptr != 0)
|
|
||||||
{
|
|
||||||
barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_set_thread_name(String8 string)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||||
MemoryCopy(tctx->thread_name, string.str, size);
|
MemoryCopy(tctx->thread_name, string.str, size);
|
||||||
tctx->thread_name_size = size;
|
tctx->thread_name_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
tctx_get_thread_name(void)
|
tctx_get_thread_name(void){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_write_srcloc(char *file_name, U64 line_number)
|
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
tctx->file_name = file_name;
|
tctx->file_name = file_name;
|
||||||
tctx->line_number = line_number;
|
tctx->line_number = line_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_read_srcloc(char **file_name, U64 *line_number)
|
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
*file_name = tctx->file_name;
|
*file_name = tctx->file_name;
|
||||||
*line_number = tctx->line_number;
|
*line_number = tctx->line_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Touch Scope Functions
|
|
||||||
|
|
||||||
internal Access *
|
|
||||||
access_open(void)
|
|
||||||
{
|
|
||||||
if(tctx_thread_local->access_arena == 0)
|
|
||||||
{
|
|
||||||
tctx_thread_local->access_arena = arena_alloc();
|
|
||||||
}
|
|
||||||
Access *access = tctx_thread_local->free_access;
|
|
||||||
if(access != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_access);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
access = push_array_no_zero(tctx_thread_local->access_arena, Access, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(access);
|
|
||||||
return access;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_close(Access *access)
|
|
||||||
{
|
|
||||||
for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next)
|
|
||||||
{
|
|
||||||
next = touch->next;
|
|
||||||
ins_atomic_u64_dec_eval(&touch->pt->access_refcount);
|
|
||||||
if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); }
|
|
||||||
SLLStackPush(tctx_thread_local->free_touch, touch);
|
|
||||||
}
|
|
||||||
SLLStackPush(tctx_thread_local->free_access, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_touch(Access *access, AccessPt *pt, CondVar cv)
|
|
||||||
{
|
|
||||||
ins_atomic_u64_inc_eval(&pt->access_refcount);
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, now_time_us());
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
|
|
||||||
Touch *touch = tctx_thread_local->free_touch;
|
|
||||||
if(touch != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_touch);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
touch = push_array_no_zero(tctx_thread_local->access_arena, Touch, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(touch);
|
|
||||||
SLLStackPush(access->top_touch, touch);
|
|
||||||
touch->cv = cv;
|
|
||||||
touch->pt = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: access points
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
|
|
||||||
{
|
|
||||||
U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount);
|
|
||||||
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
|
|
||||||
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
|
|
||||||
B32 result = (access_refcount == 0 &&
|
|
||||||
last_time_touched_us + params->time <= now_time_us() &&
|
|
||||||
last_update_idx_touched + params->update_idxs <= update_tick_idx());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
+10
-101
@@ -1,132 +1,41 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_THREAD_CONTEXT_H
|
#ifndef BASE_THREAD_CONTEXT_H
|
||||||
#define BASE_THREAD_CONTEXT_H
|
#define BASE_THREAD_CONTEXT_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Lane Context
|
// NOTE(allen): Thread Context
|
||||||
|
|
||||||
typedef struct LaneCtx LaneCtx;
|
|
||||||
struct LaneCtx
|
|
||||||
{
|
|
||||||
U64 lane_idx;
|
|
||||||
U64 lane_count;
|
|
||||||
Barrier barrier;
|
|
||||||
U64 *broadcast_memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Access Scopes
|
|
||||||
|
|
||||||
typedef struct AccessPt AccessPt;
|
|
||||||
struct AccessPt
|
|
||||||
{
|
|
||||||
U64 access_refcount;
|
|
||||||
U64 last_time_touched_us;
|
|
||||||
U64 last_update_idx_touched;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AccessPtExpireParams AccessPtExpireParams;
|
|
||||||
struct AccessPtExpireParams
|
|
||||||
{
|
|
||||||
U64 time;
|
|
||||||
U64 update_idxs;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Touch Touch;
|
|
||||||
struct Touch
|
|
||||||
{
|
|
||||||
Touch *next;
|
|
||||||
AccessPt *pt;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Access Access;
|
|
||||||
struct Access
|
|
||||||
{
|
|
||||||
Access *next;
|
|
||||||
Touch *top_touch;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Base Per-Thread State Bundle
|
|
||||||
|
|
||||||
typedef struct TCTX TCTX;
|
typedef struct TCTX TCTX;
|
||||||
struct TCTX
|
struct TCTX
|
||||||
{
|
{
|
||||||
// rjf: scratch arenas
|
|
||||||
Arena *arenas[2];
|
Arena *arenas[2];
|
||||||
|
|
||||||
// rjf: thread name
|
|
||||||
U8 thread_name[32];
|
U8 thread_name[32];
|
||||||
U64 thread_name_size;
|
U64 thread_name_size;
|
||||||
|
|
||||||
// rjf: lane context
|
|
||||||
LaneCtx lane_ctx;
|
|
||||||
|
|
||||||
// rjf: source location info
|
|
||||||
char *file_name;
|
char *file_name;
|
||||||
U64 line_number;
|
U64 line_number;
|
||||||
|
|
||||||
// rjf: accesses
|
|
||||||
Arena *access_arena;
|
|
||||||
Access *free_access;
|
|
||||||
Touch *free_touch;
|
|
||||||
|
|
||||||
// rjf: progress
|
|
||||||
U64 *progress_counter_ptr;
|
|
||||||
U64 *progress_target_ptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Thread Context Functions
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
//- rjf: thread-context allocation & selection
|
internal void tctx_init_and_equip(TCTX *tctx);
|
||||||
internal TCTX *tctx_alloc(void);
|
internal void tctx_release(void);
|
||||||
internal void tctx_release(TCTX *tctx);
|
internal TCTX* tctx_get_equipped(void);
|
||||||
internal void tctx_select(TCTX *tctx);
|
|
||||||
internal TCTX *tctx_selected(void);
|
|
||||||
|
|
||||||
//- rjf: scratch arenas
|
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
|
||||||
internal Arena *tctx_get_scratch(Arena **conflicts, U64 count);
|
|
||||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
|
||||||
#define scratch_end(scratch) temp_end(scratch)
|
|
||||||
|
|
||||||
//- rjf: lane metadata
|
|
||||||
internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx);
|
|
||||||
internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx);
|
|
||||||
#define lane_idx() (tctx_selected()->lane_ctx.lane_idx)
|
|
||||||
#define lane_count() (tctx_selected()->lane_ctx.lane_count)
|
|
||||||
#define lane_from_task_idx(idx) ((idx)%lane_count())
|
|
||||||
#define lane_ctx(ctx) tctx_set_lane_ctx((ctx))
|
|
||||||
#define lane_sync() tctx_lane_barrier_wait(0, 0, 0)
|
|
||||||
#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx))
|
|
||||||
#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count))
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
internal void tctx_set_thread_name(String8 name);
|
internal void tctx_set_thread_name(String8 name);
|
||||||
internal String8 tctx_get_thread_name(void);
|
internal String8 tctx_get_thread_name(void);
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
||||||
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
||||||
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
||||||
|
|
||||||
//- rjf: access scopes
|
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||||
internal Access *access_open(void);
|
#define scratch_end(scratch) temp_end(scratch)
|
||||||
internal void access_close(Access *access);
|
|
||||||
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: access points
|
#endif //BASE_THREAD_CONTEXT_H
|
||||||
internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params);
|
|
||||||
#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__})
|
|
||||||
|
|
||||||
//- rjf: progress counters
|
|
||||||
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
|
|
||||||
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
|
|
||||||
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
|
|
||||||
|
|
||||||
#endif // BASE_THREAD_CONTEXT_H
|
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripe Functions
|
|
||||||
|
|
||||||
internal StripeArray
|
|
||||||
stripe_array_alloc(Arena *arena)
|
|
||||||
{
|
|
||||||
StripeArray array = {0};
|
|
||||||
array.count = get_system_info()->logical_processor_count;
|
|
||||||
array.v = push_array(arena, Stripe, array.count);
|
|
||||||
for EachIndex(idx, array.count)
|
|
||||||
{
|
|
||||||
array.v[idx].arena = arena_alloc();
|
|
||||||
array.v[idx].rw_mutex = rw_mutex_alloc();
|
|
||||||
array.v[idx].cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
stripe_array_release(StripeArray *stripes)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, stripes->count)
|
|
||||||
{
|
|
||||||
arena_release(stripes->v[idx].arena);
|
|
||||||
rw_mutex_release(stripes->v[idx].rw_mutex);
|
|
||||||
cond_var_release(stripes->v[idx].cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Stripe *
|
|
||||||
stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
|
|
||||||
{
|
|
||||||
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
|
|
||||||
return stripe;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Info Helpers
|
|
||||||
|
|
||||||
internal void
|
|
||||||
set_thread_name(String8 string)
|
|
||||||
{
|
|
||||||
ProfThreadName("%.*s", str8_varg(string));
|
|
||||||
set_platform_thread_name(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
set_thread_namef(char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
set_thread_name(string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: slow barriers
|
|
||||||
|
|
||||||
typedef struct BarrierNode BarrierNode;
|
|
||||||
struct BarrierNode
|
|
||||||
{
|
|
||||||
BarrierNode *next;
|
|
||||||
U64 count;
|
|
||||||
U64 threads_left_to_enter;
|
|
||||||
U64 threads_left_to_leave;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct BarrierTCTX BarrierTCTX;
|
|
||||||
struct BarrierTCTX
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
BarrierNode *free_barrier_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_static BarrierTCTX *barrier_tctx = 0;
|
|
||||||
|
|
||||||
internal Barrier
|
|
||||||
slow_barrier_alloc(U64 count)
|
|
||||||
{
|
|
||||||
if(barrier_tctx == 0)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
|
||||||
barrier_tctx->arena = arena;
|
|
||||||
}
|
|
||||||
BarrierNode *n = barrier_tctx->free_barrier_node;
|
|
||||||
if(n != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(barrier_tctx->free_barrier_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(n);
|
|
||||||
n->count = count;
|
|
||||||
n->threads_left_to_enter = count;
|
|
||||||
n->rw_mutex = rw_mutex_alloc();
|
|
||||||
n->cv = cond_var_alloc();
|
|
||||||
Barrier result = {(U64)n};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
slow_barrier_release(Barrier barrier)
|
|
||||||
{
|
|
||||||
if(barrier_tctx == 0)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
|
||||||
barrier_tctx->arena = arena;
|
|
||||||
}
|
|
||||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
|
||||||
rw_mutex_release(n->rw_mutex);
|
|
||||||
cond_var_release(n->cv);
|
|
||||||
SLLStackPush(barrier_tctx->free_barrier_node, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
slow_barrier_wait(Barrier barrier)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
|
||||||
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
|
|
||||||
|
|
||||||
//- rjf: threads left to enter > 0 => wait
|
|
||||||
if(threads_left_to_enter > 0)
|
|
||||||
{
|
|
||||||
// rjf: first try a spin loop
|
|
||||||
B32 done_waiting = 0;
|
|
||||||
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
|
||||||
{
|
|
||||||
done_waiting = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: not done waiting -> need to do slow wait on condition variable
|
|
||||||
if(!done_waiting) ProfScope("slow wait")
|
|
||||||
{
|
|
||||||
RWMutexScope(n->rw_mutex, 0) for(;;)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: decrement leave counter
|
|
||||||
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
|
|
||||||
{
|
|
||||||
ProfScope("signal") cond_var_signal(n->cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: threads left to enter == 0 -> last thread, wakeup
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
|
|
||||||
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
|
|
||||||
}
|
|
||||||
ProfScope("signal") cond_var_signal(n->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: wait for threads left to leave == 0
|
|
||||||
ProfScope("wait for threads to leave")
|
|
||||||
{
|
|
||||||
for(U64 spin_count = 0;; spin_count += 1)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
///~ Semaphore
|
|
||||||
|
|
||||||
internal void
|
|
||||||
semaphore_drop(Semaphore semaphore)
|
|
||||||
{
|
|
||||||
semaphore_drop_count(semaphore, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_THREADS_H
|
|
||||||
#define BASE_THREADS_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Types
|
|
||||||
|
|
||||||
typedef struct Thread Thread;
|
|
||||||
struct Thread
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
typedef void ThreadEntryPointFunctionType(void *p);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Synchronization Primitive Types
|
|
||||||
|
|
||||||
typedef struct Mutex Mutex;
|
|
||||||
struct Mutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RWMutex RWMutex;
|
|
||||||
struct RWMutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CondVar CondVar;
|
|
||||||
struct CondVar
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Semaphore Semaphore;
|
|
||||||
struct Semaphore
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Barrier Barrier;
|
|
||||||
struct Barrier
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripes
|
|
||||||
|
|
||||||
typedef struct Stripe Stripe;
|
|
||||||
struct Stripe
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
void *free;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct StripeArray StripeArray;
|
|
||||||
struct StripeArray
|
|
||||||
{
|
|
||||||
Stripe *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripe Functions
|
|
||||||
|
|
||||||
internal StripeArray stripe_array_alloc(Arena *arena);
|
|
||||||
internal void stripe_array_release(StripeArray *stripes);
|
|
||||||
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Info Helpers
|
|
||||||
|
|
||||||
internal void set_thread_name(String8 string);
|
|
||||||
internal void set_thread_namef(char *fmt, ...);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Current Thread Info
|
|
||||||
|
|
||||||
internal U32 tid(void);
|
|
||||||
internal void set_platform_thread_name(String8 name);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Thread Functions
|
|
||||||
|
|
||||||
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
|
|
||||||
internal B32 thread_join(Thread thread, U64 endt_us);
|
|
||||||
internal void thread_detach(Thread thread);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: recursive mutexes
|
|
||||||
internal Mutex mutex_alloc(void);
|
|
||||||
internal void mutex_release(Mutex mutex);
|
|
||||||
internal void mutex_take(Mutex mutex);
|
|
||||||
internal void mutex_drop(Mutex mutex);
|
|
||||||
|
|
||||||
//- rjf: reader/writer mutexes
|
|
||||||
internal RWMutex rw_mutex_alloc(void);
|
|
||||||
internal void rw_mutex_release(RWMutex mutex);
|
|
||||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode);
|
|
||||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode);
|
|
||||||
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
|
|
||||||
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
|
|
||||||
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
|
|
||||||
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
|
|
||||||
|
|
||||||
//- rjf: condition variables
|
|
||||||
internal CondVar cond_var_alloc(void);
|
|
||||||
internal void cond_var_release(CondVar cv);
|
|
||||||
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
|
|
||||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
|
|
||||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
|
|
||||||
#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt))
|
|
||||||
#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt))
|
|
||||||
internal void cond_var_signal(CondVar cv);
|
|
||||||
internal void cond_var_broadcast(CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: cross-process semaphores
|
|
||||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
|
|
||||||
internal void semaphore_release(Semaphore semaphore);
|
|
||||||
internal Semaphore semaphore_open(String8 name);
|
|
||||||
internal void semaphore_close(Semaphore semaphore);
|
|
||||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
|
||||||
internal void semaphore_drop(Semaphore semaphore);
|
|
||||||
internal void semaphore_drop_count(Semaphore semaphore, U64 drop_count);
|
|
||||||
|
|
||||||
//- rjf: barriers
|
|
||||||
internal Barrier barrier_alloc(U64 count);
|
|
||||||
internal void barrier_release(Barrier barrier);
|
|
||||||
internal void barrier_wait(Barrier barrier);
|
|
||||||
|
|
||||||
//- rjf: scope macros
|
|
||||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
|
||||||
#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode)))
|
|
||||||
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
|
|
||||||
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
|
|
||||||
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: slow barriers
|
|
||||||
internal Barrier slow_barrier_alloc(U64 count);
|
|
||||||
internal void slow_barrier_release(Barrier barrier);
|
|
||||||
internal void slow_barrier_wait(Barrier barrier);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Safe Calls
|
|
||||||
|
|
||||||
internal void safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr);
|
|
||||||
|
|
||||||
#endif // BASE_THREADS_H
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
Test(str8_list_substr)
|
|
||||||
{
|
|
||||||
String8List zero_list = {0};
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "b");
|
|
||||||
str8_list_pushf(arena, &list, "c");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(0, 3));
|
|
||||||
String8 result = str8_list_join(arena, &list, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("abc"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "b");
|
|
||||||
str8_list_pushf(arena, &list, "c");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(0, max_U64));
|
|
||||||
String8 result = str8_list_join(arena, &list, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("abc"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "bcd");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(2, 3));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("c"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "bcd");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(1, 2));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("b"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "ab");
|
|
||||||
str8_list_pushf(arena, &list, "cd");
|
|
||||||
str8_list_pushf(arena, &list, "ef");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(1, 5));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("bcde"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "abc");
|
|
||||||
|
|
||||||
String8List zero = str8_list_substr(arena, list, r1u64(0, 0));
|
|
||||||
T_Ok(MemoryMatchStruct(&zero, &zero_list));
|
|
||||||
|
|
||||||
String8List out_of_bounds_range = str8_list_substr(arena, list, r1u64(max_U64/2, max_U64));
|
|
||||||
T_Ok(MemoryMatchStruct(&out_of_bounds_range, &zero_list));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(bit_array)
|
|
||||||
{
|
|
||||||
for (U64 start=0; start<32*3; start++) {
|
|
||||||
for (U64 end=start; end<32*3; end++) {
|
|
||||||
U32 v[3] = { 0 };
|
|
||||||
for (U64 i=start; i<end; i++) {
|
|
||||||
v[i/32] |= 1 << (i%32);
|
|
||||||
}
|
|
||||||
for (U64 lo=0; lo<32*3; lo++) {
|
|
||||||
for (U64 hi=0; hi<32*3; hi++) {
|
|
||||||
U64 expected_idx = Min(hi, end) - 1;
|
|
||||||
B32 expected_r = hi <= start || lo >= end || lo >= hi || start >= end ? 0 : 1;
|
|
||||||
U64 idx = bit_array_scan_right_to_left32((U32Array){.v=v, .count=ArrayCount(v)}, lo, hi, 1);
|
|
||||||
B32 r = idx < hi;
|
|
||||||
T_Ok(r == expected_r);
|
|
||||||
if (r) {
|
|
||||||
T_Ok(idx == expected_idx);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(count_digits)
|
|
||||||
{
|
|
||||||
T_Ok(count_digits_u64(0, 10) == 1);
|
|
||||||
T_Ok(count_digits_u64(99, 10) == 2);
|
|
||||||
T_Ok(count_digits_u64(999, 10) == 3);
|
|
||||||
T_Ok(count_digits_u64(9999, 10) == 4);
|
|
||||||
T_Ok(count_digits_u64(99999, 10) == 5);
|
|
||||||
T_Ok(count_digits_u64(999999, 10) == 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(match_wildcard)
|
|
||||||
{
|
|
||||||
// empty strings
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit(""), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("**"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit(""), 0) == 0);
|
|
||||||
|
|
||||||
// exact
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("a"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), 0) == 0);
|
|
||||||
|
|
||||||
// ?
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("a?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?b"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("??"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a?c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("???"), 0) == 0);
|
|
||||||
|
|
||||||
// *
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("b*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("**"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a**c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*b*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*a*d*"), 0) == 0);
|
|
||||||
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abcd"), str8_lit("a*d"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abefcdgiescdfimde"), str8_lit("ab*cd?i*de"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("mississippi"), str8_lit("m*iss*ppi"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("aa"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("aa"), str8_lit("a"), 0) == 0);
|
|
||||||
|
|
||||||
// case insensitive
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("FooBar"), str8_lit("foobar"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("Foobar"), str8_lit("foo*"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
|
|
||||||
// right side sloppy
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("ab"), StringMatchFlag_RightSideSloppy) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit(""), StringMatchFlag_RightSideSloppy) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("a"), StringMatchFlag_RightSideSloppy) == 0);
|
|
||||||
|
|
||||||
// slash insensitive
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b/c"), str8_lit("a\\*\\c"), StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
|
|
||||||
// combined
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("Ab\\Cde"), str8_lit("ab/*e"), StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*?*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*?*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("?*?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?*?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?*?"), 0) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(hash_map)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 test_count = 256;
|
|
||||||
for EachIndex(i, test_count) { hash_map_push_u64_u64(arena, &hm, i, i*2); }
|
|
||||||
|
|
||||||
// test tombstone reuse
|
|
||||||
for (U64 i = 10; i < test_count; ++i) {
|
|
||||||
HashMapNode *test_node = hash_map_search(&hm, hash_map_hasher(str8_struct(&i)), (HashMapKey){ .key_u64 = i }, hash_map_match_u64);
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, i) == 1);
|
|
||||||
T_Ok(hash_map_push_u64_u64(arena, &hm, i, 10) == test_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete some items and after search them
|
|
||||||
for (U64 i = 0; i < 10; ++i) {
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, i));
|
|
||||||
}
|
|
||||||
T_Ok(hm.tombstone_count == 10);
|
|
||||||
for (U64 i = 0; i < 10; ++i) {
|
|
||||||
T_Ok(hash_map_search_u64_raw(&hm, i) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract pairs and test sorting
|
|
||||||
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
|
|
||||||
sort_hash_map_key_value_u64(pairs, hm.count);
|
|
||||||
for (U64 i = 1; i < hm.count; ++i) {
|
|
||||||
T_Ok(pairs[i-1].key.key_u64 < pairs[i].key.key_u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// did purge put all the nodes on free list?
|
|
||||||
hash_map_purge(&hm);
|
|
||||||
U64 free_list_count = 0;
|
|
||||||
for (HashMapNode *n = hm.free_list; n != 0; n = n->next) { free_list_count += 1; }
|
|
||||||
T_Ok(free_list_count == test_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test search through tombstones
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 hash = 12345;
|
|
||||||
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 1 }, .value = { .value_u64 = 10 } }, hash_map_match_u64);
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 2 }, .value = { .value_u64 = 20 } }, hash_map_match_u64);
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 3 }, .value = { .value_u64 = 30 } }, hash_map_match_u64);
|
|
||||||
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 1));
|
|
||||||
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 2 }, hash_map_match_u64)->v.value.value_u64 == 20);
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 3 }, hash_map_match_u64)->v.value.value_u64 == 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
// interleaved purges
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
for EachIndex(round, 100) {
|
|
||||||
for EachIndex(i, 256) { hash_map_push_u64_u64(arena, &hm, i, round); }
|
|
||||||
for (U64 i = 0; i < 256; i += 2) { hash_map_purge_u64(&hm, i); }
|
|
||||||
for (U64 i = 0; i < 256; i += 2) { hash_map_push_u64_u64(arena, &hm, i, round + 1); }
|
|
||||||
|
|
||||||
T_Ok(hm.count == 256);
|
|
||||||
T_Ok(hm.tombstone_count == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for EachIndex(i, 100) {
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 123123123 + i) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// empty hash map test
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_u64_raw(&hm, 123) == 0);
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 123) == 0);
|
|
||||||
|
|
||||||
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
|
|
||||||
T_Ok(pairs == 0 || hm.count == 0);
|
|
||||||
|
|
||||||
hash_map_purge(&hm);
|
|
||||||
T_Ok(hm.count == 0);
|
|
||||||
T_Ok(hm.tombstone_count == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// heavy collision
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 hash = 12345;
|
|
||||||
U64 count = 1024;
|
|
||||||
|
|
||||||
for EachIndex(i, count) {
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = i }, .value = { .value_u64 = i*3 } }, hash_map_match_u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
for EachIndex(i, count) {
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = i }, hash_map_match_u64)->v.value.value_u64 == i*3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// duplicate key test
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 a = 1;
|
|
||||||
U64 b = 2;
|
|
||||||
|
|
||||||
HashMapNode *n0 = hash_map_push_u64_u64(arena, &hm, 1, a);
|
|
||||||
HashMapNode *n1 = hash_map_push_u64_u64(arena, &hm, 1, b);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 1);
|
|
||||||
T_Ok(n0 == n1);
|
|
||||||
U64 test = *hash_map_search_u64_u64(&hm, 1);
|
|
||||||
T_Ok(test != b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test paths
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 foo = 0;
|
|
||||||
U64 bar = 1;
|
|
||||||
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
|
|
||||||
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 2);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:/devel/test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:\\devel\\TEST")) == &foo);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/mnt/devel")) == &bar);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/MNT/DEVEL")) == &bar);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test strings
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 foo = 0;
|
|
||||||
U64 bar = 1;
|
|
||||||
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
|
|
||||||
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 5);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/DEVEL/test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:\\DEVEL\\test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/devel\\test")) == &foo);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/mnt/devel")) == &bar);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/MNT/devel")) == &bar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+433
-997
File diff suppressed because it is too large
Load Diff
+1233
-1063
File diff suppressed because it is too large
Load Diff
+34
-42
@@ -246,7 +246,7 @@ cv_string_from_arch:
|
|||||||
{MANTYPREF - 0x1028}
|
{MANTYPREF - 0x1028}
|
||||||
{UNAMESPACE_ST - 0x1029}
|
{UNAMESPACE_ST - 0x1029}
|
||||||
{ST_MAX - 0x1100}
|
{ST_MAX - 0x1100}
|
||||||
{OBJNAME ObjName 0x1101}
|
{OBJNAME Objname 0x1101}
|
||||||
{THUNK32 Thunk32 0x1102}
|
{THUNK32 Thunk32 0x1102}
|
||||||
{BLOCK32 Block32 0x1103}
|
{BLOCK32 Block32 0x1103}
|
||||||
{WITH32 - 0x1104}
|
{WITH32 - 0x1104}
|
||||||
@@ -395,48 +395,48 @@ CV_BasicTypeTable:
|
|||||||
{FBASICSTR 0x06 "" }
|
{FBASICSTR 0x06 "" }
|
||||||
{NOTTRANS 0x07 "" }
|
{NOTTRANS 0x07 "" }
|
||||||
{HRESULT 0x08 "HRESULT" }
|
{HRESULT 0x08 "HRESULT" }
|
||||||
{CHAR 0x10 "CHAR" }
|
{CHAR 0x10 "char" }
|
||||||
{SHORT 0x11 "SHORT" }
|
{SHORT 0x11 "S16" }
|
||||||
{LONG 0x12 "LONG" }
|
{LONG 0x12 "S32" }
|
||||||
{QUAD 0x13 "QUAD" }
|
{QUAD 0x13 "S64" }
|
||||||
{OCT 0x14 "OCT" }
|
{OCT 0x14 "S128" }
|
||||||
{UCHAR 0x20 "UCHAR" }
|
{UCHAR 0x20 "UCHAR" }
|
||||||
{USHORT 0x21 "USHORT" }
|
{USHORT 0x21 "U16" }
|
||||||
{ULONG 0x22 "ULONG" }
|
{ULONG 0x22 "U32" }
|
||||||
{UQUAD 0x23 "UQUAD" }
|
{UQUAD 0x23 "U64" }
|
||||||
{UOCT 0x24 "UOCT" }
|
{UOCT 0x24 "U128" }
|
||||||
{BOOL8 0x30 "BOOL8" }
|
{BOOL8 0x30 "B8" }
|
||||||
{BOOL16 0x31 "BOOL16" }
|
{BOOL16 0x31 "B16" }
|
||||||
{BOOL32 0x32 "BOOL32" }
|
{BOOL32 0x32 "B32" }
|
||||||
{BOOL64 0x33 "BOOL64" }
|
{BOOL64 0x33 "B64" }
|
||||||
{FLOAT32 0x40 "FLOAT32" }
|
{FLOAT32 0x40 "F32" }
|
||||||
{FLOAT64 0x41 "FLOAT64" }
|
{FLOAT64 0x41 "F64" }
|
||||||
{FLOAT80 0x42 "FLOAT80" }
|
{FLOAT80 0x42 "F80" }
|
||||||
{FLOAT128 0x43 "FLOAT128" }
|
{FLOAT128 0x43 "F128" }
|
||||||
{FLOAT48 0x44 "FLOAT48" }
|
{FLOAT48 0x44 "F48" }
|
||||||
{FLOAT32PP 0x45 "FLOAT32PP" }
|
{FLOAT32PP 0x45 "F32PP" }
|
||||||
{FLOAT16 0x46 "FLOAT16" }
|
{FLOAT16 0x46 "F16" }
|
||||||
{COMPLEX32 0x50 "ComplexF32" }
|
{COMPLEX32 0x50 "ComplexF32" }
|
||||||
{COMPLEX64 0x51 "ComplexF64" }
|
{COMPLEX64 0x51 "ComplexF64" }
|
||||||
{COMPLEX80 0x52 "ComplexF80" }
|
{COMPLEX80 0x52 "ComplexF80" }
|
||||||
{COMPLEX128 0x53 "ComplexF128" }
|
{COMPLEX128 0x53 "ComplexF128" }
|
||||||
{BIT 0x60 "" }
|
{BIT 0x60 "" }
|
||||||
{PASCHAR 0x61 "" }
|
{PASCHAR 0x61 "" }
|
||||||
{BOOL32FF 0x62 "BOOL32FF" }
|
{BOOL32FF 0x62 "B32FF" }
|
||||||
{INT8 0x68 "int8" }
|
{INT8 0x68 "S8" }
|
||||||
{UINT8 0x69 "uint8" }
|
{UINT8 0x69 "U8" }
|
||||||
{RCHAR 0x70 "char" }
|
{RCHAR 0x70 "char" }
|
||||||
{WCHAR 0x71 "WCHAR" }
|
{WCHAR 0x71 "WCHAR" }
|
||||||
{INT16 0x72 "int16" }
|
{INT16 0x72 "S16" }
|
||||||
{UINT16 0x73 "uint16" }
|
{UINT16 0x73 "U16" }
|
||||||
{INT32 0x74 "int32" }
|
{INT32 0x74 "S32" }
|
||||||
{UINT32 0x75 "uint32" }
|
{UINT32 0x75 "U32" }
|
||||||
{INT64 0x76 "int64" }
|
{INT64 0x76 "S64" }
|
||||||
{UINT64 0x77 "uint64" }
|
{UINT64 0x77 "U64" }
|
||||||
{INT128 0x78 "int128" }
|
{INT128 0x78 "S128" }
|
||||||
{UINT128 0x79 "uint128" }
|
{UINT128 0x79 "U128" }
|
||||||
{CHAR16 0x7a "char16" }
|
{CHAR16 0x7a "CHAR16" }
|
||||||
{CHAR32 0x7b "char32" }
|
{CHAR32 0x7b "CHAR32" }
|
||||||
{CHAR8 0x7c "char" }
|
{CHAR8 0x7c "char" }
|
||||||
{PTR 0xf0 "PTR" }
|
{PTR 0xf0 "PTR" }
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,6 @@ CV_BasicTypeTable:
|
|||||||
@table(name header_type_name val)
|
@table(name header_type_name val)
|
||||||
CV_LeafKindTable:
|
CV_LeafKindTable:
|
||||||
{
|
{
|
||||||
{NOTYPE - 0x0000}
|
|
||||||
{MODIFIER_16t - 0x0001}
|
{MODIFIER_16t - 0x0001}
|
||||||
{POINTER_16t - 0x0002}
|
{POINTER_16t - 0x0002}
|
||||||
{ARRAY_16t - 0x0003}
|
{ARRAY_16t - 0x0003}
|
||||||
@@ -587,13 +586,6 @@ CV_LeafKindTable:
|
|||||||
{VECTOR - 0x151b}
|
{VECTOR - 0x151b}
|
||||||
{MATRIX - 0x151c}
|
{MATRIX - 0x151c}
|
||||||
{VFTABLE - 0x151d}
|
{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}
|
{CLASS2 Struct2 0x1608}
|
||||||
{STRUCT2 Struct2 0x1609}
|
{STRUCT2 Struct2 0x1609}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
|
|
||||||
{
|
|
||||||
String8 result = str8_zero();
|
|
||||||
switch (num.kind) {
|
|
||||||
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
|
|
||||||
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
|
|
||||||
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
|
|
||||||
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
|
|
||||||
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
|
|
||||||
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
|
|
||||||
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
|
|
||||||
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
|
|
||||||
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
|
|
||||||
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
|
|
||||||
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
|
|
||||||
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
|
|
||||||
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_DUMP_H
|
|
||||||
#define CODEVIEW_DUMP_H
|
|
||||||
|
|
||||||
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_DUMP_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,320 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_PARSE_H
|
|
||||||
#define CODEVIEW_PARSE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Common Parser Types
|
|
||||||
|
|
||||||
// CV_Numeric layout
|
|
||||||
// x: U16
|
|
||||||
// buf: U8[]
|
|
||||||
// case (x < 0x8000): kind=U16 val=x
|
|
||||||
// case (x >= 0x8000): kind=x val=buf
|
|
||||||
|
|
||||||
typedef struct CV_NumericParsed CV_NumericParsed;
|
|
||||||
struct CV_NumericParsed
|
|
||||||
{
|
|
||||||
CV_NumericKind kind;
|
|
||||||
U8 *val;
|
|
||||||
U64 encoded_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRange CV_RecRange;
|
|
||||||
struct CV_RecRange
|
|
||||||
{
|
|
||||||
U32 off;
|
|
||||||
CV_RecHeader hdr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CV_REC_RANGE_CHUNK_SIZE 511
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeChunk CV_RecRangeChunk;
|
|
||||||
struct CV_RecRangeChunk
|
|
||||||
{
|
|
||||||
struct CV_RecRangeChunk *next;
|
|
||||||
CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeStream CV_RecRangeStream;
|
|
||||||
struct CV_RecRangeStream
|
|
||||||
{
|
|
||||||
CV_RecRangeChunk *first_chunk;
|
|
||||||
CV_RecRangeChunk *last_chunk;
|
|
||||||
U64 total_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_RecRangeArray CV_RecRangeArray;
|
|
||||||
struct CV_RecRangeArray
|
|
||||||
{
|
|
||||||
CV_RecRange *ranges;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Sym Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo;
|
|
||||||
struct CV_SymTopLevelInfo
|
|
||||||
{
|
|
||||||
CV_Arch arch;
|
|
||||||
CV_Language language;
|
|
||||||
String8 compiler_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_SymParsed CV_SymParsed;
|
|
||||||
struct CV_SymParsed
|
|
||||||
{
|
|
||||||
// source information
|
|
||||||
String8 data;
|
|
||||||
U64 sym_align;
|
|
||||||
|
|
||||||
// sym index derived from source
|
|
||||||
CV_RecRangeArray sym_ranges;
|
|
||||||
|
|
||||||
// top-level info derived from the syms
|
|
||||||
CV_SymTopLevelInfo info;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Leaf Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_LeafParsed CV_LeafParsed;
|
|
||||||
struct CV_LeafParsed
|
|
||||||
{
|
|
||||||
// source information
|
|
||||||
String8 data;
|
|
||||||
CV_TypeId itype_first;
|
|
||||||
CV_TypeId itype_opl;
|
|
||||||
|
|
||||||
// leaf index derived from source
|
|
||||||
CV_RecRangeArray leaf_ranges;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView C13 Info Parser Types
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineSiteDecoder CV_C13InlineSiteDecoder;
|
|
||||||
struct CV_C13InlineSiteDecoder
|
|
||||||
{
|
|
||||||
U64 cursor;
|
|
||||||
U64 parent_voff;
|
|
||||||
CV_InlineRangeKind range_kind;
|
|
||||||
U32 code_length;
|
|
||||||
U32 code_offset;
|
|
||||||
U32 file_off;
|
|
||||||
S32 ln;
|
|
||||||
S32 cn;
|
|
||||||
U64 code_offset_lo;
|
|
||||||
B32 code_offset_changed;
|
|
||||||
B32 code_offset_lo_changed;
|
|
||||||
B32 code_length_changed;
|
|
||||||
B32 ln_changed;
|
|
||||||
B32 file_off_changed;
|
|
||||||
Rng1U64 last_range;
|
|
||||||
U32 file_count;
|
|
||||||
Rng1U64 file_last_range;
|
|
||||||
U64 file_line_count;
|
|
||||||
U64 file_last_ln;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 CV_C13InlineSiteDecoderStepFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitRange = (1 << 0),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_ExtendLastRange = (1 << 1),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitFile = (1 << 2),
|
|
||||||
CV_C13InlineSiteDecoderStepFlag_EmitLine = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineSiteDecoderStep CV_C13InlineSiteDecoderStep;
|
|
||||||
struct CV_C13InlineSiteDecoderStep
|
|
||||||
{
|
|
||||||
CV_C13InlineSiteDecoderStepFlags flags;
|
|
||||||
Rng1U64 range;
|
|
||||||
U64 line_voff;
|
|
||||||
U64 line_voff_end;
|
|
||||||
U64 ln;
|
|
||||||
U64 cn;
|
|
||||||
U32 file_off;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13LinesParsed CV_C13LinesParsed;
|
|
||||||
struct CV_C13LinesParsed
|
|
||||||
{
|
|
||||||
// raw info
|
|
||||||
U32 sec_idx;
|
|
||||||
U32 file_off;
|
|
||||||
U64 secrel_base_off;
|
|
||||||
|
|
||||||
// parsed info
|
|
||||||
String8 file_name;
|
|
||||||
CV_C13ChecksumKind checksum_kind;
|
|
||||||
String8 checksum;
|
|
||||||
U64 *voffs; // [line_count + 1]
|
|
||||||
U32 *line_nums; // [line_count]
|
|
||||||
U16 *col_nums; // [2*line_count]
|
|
||||||
U32 line_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode;
|
|
||||||
struct CV_C13LinesParsedNode
|
|
||||||
{
|
|
||||||
CV_C13LinesParsedNode *next;
|
|
||||||
CV_C13LinesParsed v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
|
|
||||||
struct CV_C13InlineeLinesParsed
|
|
||||||
{
|
|
||||||
CV_ItemId inlinee;
|
|
||||||
U32 file_off;
|
|
||||||
String8 file_name;
|
|
||||||
CV_C13ChecksumKind checksum_kind;
|
|
||||||
String8 checksum;
|
|
||||||
U32 first_source_ln;
|
|
||||||
U32 extra_file_count;
|
|
||||||
U32 *extra_files;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
|
|
||||||
struct CV_C13InlineeLinesParsedNode
|
|
||||||
{
|
|
||||||
CV_C13InlineeLinesParsedNode *next;
|
|
||||||
CV_C13InlineeLinesParsedNode *hash_next;
|
|
||||||
CV_C13InlineeLinesParsed v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13SubSectionNode CV_C13SubSectionNode;
|
|
||||||
struct CV_C13SubSectionNode
|
|
||||||
{
|
|
||||||
struct CV_C13SubSectionNode *next;
|
|
||||||
CV_C13SubSectionKind kind;
|
|
||||||
U32 off;
|
|
||||||
U32 size;
|
|
||||||
CV_C13LinesParsedNode *lines_first;
|
|
||||||
CV_C13LinesParsedNode *lines_last;
|
|
||||||
CV_C13InlineeLinesParsedNode *inlinee_lines_first;
|
|
||||||
CV_C13InlineeLinesParsedNode *inlinee_lines_last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_C13Parsed CV_C13Parsed;
|
|
||||||
struct CV_C13Parsed
|
|
||||||
{
|
|
||||||
// rjf: source data
|
|
||||||
String8 data;
|
|
||||||
|
|
||||||
// rjf: full sub-section list
|
|
||||||
CV_C13SubSectionNode *first_sub_section;
|
|
||||||
CV_C13SubSectionNode *last_sub_section;
|
|
||||||
U64 sub_section_count;
|
|
||||||
|
|
||||||
// rjf: fastpath to file checksums section
|
|
||||||
CV_C13SubSectionNode *file_chksms_sub_section;
|
|
||||||
|
|
||||||
// rjf: fastpath to map inlinee CV_ItemId -> CV_InlineeLinesParsed quickly
|
|
||||||
CV_C13InlineeLinesParsedNode **inlinee_lines_parsed_slots;
|
|
||||||
U64 inlinee_lines_parsed_slots_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CV_UDTInfo CV_UDTInfo;
|
|
||||||
struct CV_UDTInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 unique_name;
|
|
||||||
CV_TypeProps props;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ CodeView Compound Types
|
|
||||||
|
|
||||||
typedef struct CV_TypeIdArray CV_TypeIdArray;
|
|
||||||
struct CV_TypeIdArray
|
|
||||||
{
|
|
||||||
CV_TypeId *itypes;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Record Iterator
|
|
||||||
|
|
||||||
typedef struct CV_RecIter CV_RecIter;
|
|
||||||
struct CV_RecIter
|
|
||||||
{
|
|
||||||
U64 num;
|
|
||||||
U16 kind;
|
|
||||||
void *struct_base;
|
|
||||||
void *opl;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
//- Hasher
|
|
||||||
|
|
||||||
internal U64 cv_hash_from_string(String8 string);
|
|
||||||
internal U64 cv_hash_from_item_id(CV_ItemId item_id);
|
|
||||||
|
|
||||||
//- Numeric Decoder
|
|
||||||
|
|
||||||
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);
|
|
||||||
internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num);
|
|
||||||
|
|
||||||
internal U64 cv_u64_from_numeric(CV_NumericParsed *num);
|
|
||||||
internal S64 cv_s64_from_numeric(CV_NumericParsed *num);
|
|
||||||
internal F64 cv_f64_from_numeric(CV_NumericParsed *num);
|
|
||||||
|
|
||||||
//- Inlinee Lines Binary Annot Decoder
|
|
||||||
|
|
||||||
internal U64 cv_decode_inline_annot_u32(String8 data, U64 offset, U32 *out_value);
|
|
||||||
internal U64 cv_decode_inline_annot_s32(String8 data, U64 offset, S32 *out_value);
|
|
||||||
internal S32 cv_inline_annot_signed_from_unsigned_operand(U32 value);
|
|
||||||
|
|
||||||
internal CV_C13InlineSiteDecoder cv_c13_inline_site_decoder_init(U32 file_off, U32 first_source_ln, U32 parent_voff);
|
|
||||||
internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots);
|
|
||||||
|
|
||||||
//- Symbol/Leaf Helpers
|
|
||||||
|
|
||||||
internal B32 cv_is_udt_name_anon(String8 name);
|
|
||||||
|
|
||||||
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_udt(CV_LeafKind kind);
|
|
||||||
internal B32 cv_is_leaf_type_server(CV_LeafKind kind);
|
|
||||||
internal B32 cv_is_leaf_pch(CV_LeafKind kind);
|
|
||||||
internal CV_TypeIndexSource cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind);
|
|
||||||
|
|
||||||
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 U64 cv_name_offset_from_symbol(CV_SymKind kind, String8 data);
|
|
||||||
internal String8 cv_name_from_symbol(CV_SymKind kind, String8 data);
|
|
||||||
|
|
||||||
internal CV_UDTInfo cv_get_udt_info(CV_LeafKind kind, String8 data);
|
|
||||||
internal String8 cv_name_from_udt_info(CV_UDTInfo udt_info);
|
|
||||||
|
|
||||||
//- rjf: record range stream parsing
|
|
||||||
internal CV_RecRangeStream * cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align);
|
|
||||||
internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream);
|
|
||||||
|
|
||||||
//- rjf: sym stream parsing
|
|
||||||
internal CV_SymParsed * cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align);
|
|
||||||
|
|
||||||
//- rjf: leaf stream parsing
|
|
||||||
internal CV_LeafParsed * cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first);
|
|
||||||
internal CV_C13Parsed * cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_SectionHeaderArray sections);
|
|
||||||
|
|
||||||
//- rjf: record iterator
|
|
||||||
internal B32 cv_rec_next(String8 data, CV_RecRangeArray *recs, B32 is_leaf, CV_RecIter *iter);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_PARSE_H
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef CODEVIEW_STRINGIZE_H
|
||||||
|
#define CODEVIEW_STRINGIZE_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView Stringize Helper Types
|
||||||
|
|
||||||
|
typedef struct CV_StringizeSymParams{
|
||||||
|
CV_Arch arch;
|
||||||
|
} CV_StringizeSymParams;
|
||||||
|
|
||||||
|
typedef struct CV_StringizeLeafParams{
|
||||||
|
U32 dummy;
|
||||||
|
} CV_StringizeLeafParams;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView Common Stringize Functions
|
||||||
|
|
||||||
|
internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num);
|
||||||
|
|
||||||
|
internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out,
|
||||||
|
CV_LvarAddrRange *range);
|
||||||
|
internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap);
|
||||||
|
internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out,
|
||||||
|
void *first, void *opl);
|
||||||
|
|
||||||
|
internal String8 cv_string_from_basic_type(CV_BasicType basic_type);
|
||||||
|
internal String8 cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind);
|
||||||
|
internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg);
|
||||||
|
internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind);
|
||||||
|
internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode);
|
||||||
|
internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind);
|
||||||
|
internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView Flags Stringize Functions
|
||||||
|
|
||||||
|
internal void cv_stringize_modifier_flags(Arena *arena, String8List *out,
|
||||||
|
U32 indent, CV_ModifierFlags flags);
|
||||||
|
|
||||||
|
internal void cv_stringize_type_props(Arena *arena, String8List *out,
|
||||||
|
U32 indent, CV_TypeProps props);
|
||||||
|
|
||||||
|
internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out,
|
||||||
|
U32 indent, CV_PointerAttribs attribs);
|
||||||
|
|
||||||
|
internal void cv_stringize_local_flags(Arena *arena, String8List *out,
|
||||||
|
U32 indent, CV_LocalFlags flags);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView Sym Stringize Functions
|
||||||
|
|
||||||
|
internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym);
|
||||||
|
|
||||||
|
internal void cv_stringize_sym_range(Arena *arena, String8List *out,
|
||||||
|
CV_RecRange *range, String8 data,
|
||||||
|
CV_StringizeSymParams *p);
|
||||||
|
internal void cv_stringize_sym_array(Arena *arena, String8List *out,
|
||||||
|
CV_RecRangeArray *ranges, String8 data,
|
||||||
|
CV_StringizeSymParams *p);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView Leaf Stringize Functions
|
||||||
|
|
||||||
|
internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf);
|
||||||
|
|
||||||
|
internal void cv_stringize_leaf_range(Arena *arena, String8List *out,
|
||||||
|
CV_RecRange *range, CV_TypeId itype, String8 data,
|
||||||
|
CV_StringizeLeafParams *p);
|
||||||
|
internal void cv_stringize_leaf_array(Arena *arena, String8List *out,
|
||||||
|
CV_RecRangeArray *ranges, CV_TypeId itype_first,
|
||||||
|
String8 data,
|
||||||
|
CV_StringizeLeafParams *p);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ CodeView C13 Stringize Functions
|
||||||
|
|
||||||
|
internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13);
|
||||||
|
|
||||||
|
#endif // CODEVIEW_STRINGIZE_H
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
//- GENERATED CODE
|
//- GENERATED CODE
|
||||||
@@ -392,48 +392,48 @@ case CV_BasicType_NBASICSTR:{result = str8_lit("");}break;
|
|||||||
case CV_BasicType_FBASICSTR:{result = str8_lit("");}break;
|
case CV_BasicType_FBASICSTR:{result = str8_lit("");}break;
|
||||||
case CV_BasicType_NOTTRANS:{result = str8_lit("");}break;
|
case CV_BasicType_NOTTRANS:{result = str8_lit("");}break;
|
||||||
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break;
|
||||||
case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break;
|
case CV_BasicType_CHAR:{result = str8_lit("char");}break;
|
||||||
case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break;
|
case CV_BasicType_SHORT:{result = str8_lit("S16");}break;
|
||||||
case CV_BasicType_LONG:{result = str8_lit("LONG");}break;
|
case CV_BasicType_LONG:{result = str8_lit("S32");}break;
|
||||||
case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break;
|
case CV_BasicType_QUAD:{result = str8_lit("S64");}break;
|
||||||
case CV_BasicType_OCT:{result = str8_lit("OCT");}break;
|
case CV_BasicType_OCT:{result = str8_lit("S128");}break;
|
||||||
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break;
|
||||||
case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break;
|
case CV_BasicType_USHORT:{result = str8_lit("U16");}break;
|
||||||
case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break;
|
case CV_BasicType_ULONG:{result = str8_lit("U32");}break;
|
||||||
case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break;
|
case CV_BasicType_UQUAD:{result = str8_lit("U64");}break;
|
||||||
case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break;
|
case CV_BasicType_UOCT:{result = str8_lit("U128");}break;
|
||||||
case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break;
|
case CV_BasicType_BOOL8:{result = str8_lit("B8");}break;
|
||||||
case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break;
|
case CV_BasicType_BOOL16:{result = str8_lit("B16");}break;
|
||||||
case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break;
|
case CV_BasicType_BOOL32:{result = str8_lit("B32");}break;
|
||||||
case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break;
|
case CV_BasicType_BOOL64:{result = str8_lit("B64");}break;
|
||||||
case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break;
|
case CV_BasicType_FLOAT32:{result = str8_lit("F32");}break;
|
||||||
case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break;
|
case CV_BasicType_FLOAT64:{result = str8_lit("F64");}break;
|
||||||
case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break;
|
case CV_BasicType_FLOAT80:{result = str8_lit("F80");}break;
|
||||||
case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break;
|
case CV_BasicType_FLOAT128:{result = str8_lit("F128");}break;
|
||||||
case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break;
|
case CV_BasicType_FLOAT48:{result = str8_lit("F48");}break;
|
||||||
case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break;
|
case CV_BasicType_FLOAT32PP:{result = str8_lit("F32PP");}break;
|
||||||
case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break;
|
case CV_BasicType_FLOAT16:{result = str8_lit("F16");}break;
|
||||||
case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break;
|
case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break;
|
||||||
case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break;
|
case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break;
|
||||||
case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break;
|
case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break;
|
||||||
case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break;
|
case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break;
|
||||||
case CV_BasicType_BIT:{result = str8_lit("");}break;
|
case CV_BasicType_BIT:{result = str8_lit("");}break;
|
||||||
case CV_BasicType_PASCHAR:{result = str8_lit("");}break;
|
case CV_BasicType_PASCHAR:{result = str8_lit("");}break;
|
||||||
case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break;
|
case CV_BasicType_BOOL32FF:{result = str8_lit("B32FF");}break;
|
||||||
case CV_BasicType_INT8:{result = str8_lit("int8");}break;
|
case CV_BasicType_INT8:{result = str8_lit("S8");}break;
|
||||||
case CV_BasicType_UINT8:{result = str8_lit("uint8");}break;
|
case CV_BasicType_UINT8:{result = str8_lit("U8");}break;
|
||||||
case CV_BasicType_RCHAR:{result = str8_lit("char");}break;
|
case CV_BasicType_RCHAR:{result = str8_lit("char");}break;
|
||||||
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break;
|
||||||
case CV_BasicType_INT16:{result = str8_lit("int16");}break;
|
case CV_BasicType_INT16:{result = str8_lit("S16");}break;
|
||||||
case CV_BasicType_UINT16:{result = str8_lit("uint16");}break;
|
case CV_BasicType_UINT16:{result = str8_lit("U16");}break;
|
||||||
case CV_BasicType_INT32:{result = str8_lit("int32");}break;
|
case CV_BasicType_INT32:{result = str8_lit("S32");}break;
|
||||||
case CV_BasicType_UINT32:{result = str8_lit("uint32");}break;
|
case CV_BasicType_UINT32:{result = str8_lit("U32");}break;
|
||||||
case CV_BasicType_INT64:{result = str8_lit("int64");}break;
|
case CV_BasicType_INT64:{result = str8_lit("S64");}break;
|
||||||
case CV_BasicType_UINT64:{result = str8_lit("uint64");}break;
|
case CV_BasicType_UINT64:{result = str8_lit("U64");}break;
|
||||||
case CV_BasicType_INT128:{result = str8_lit("int128");}break;
|
case CV_BasicType_INT128:{result = str8_lit("S128");}break;
|
||||||
case CV_BasicType_UINT128:{result = str8_lit("uint128");}break;
|
case CV_BasicType_UINT128:{result = str8_lit("U128");}break;
|
||||||
case CV_BasicType_CHAR16:{result = str8_lit("char16");}break;
|
case CV_BasicType_CHAR16:{result = str8_lit("CHAR16");}break;
|
||||||
case CV_BasicType_CHAR32:{result = str8_lit("char32");}break;
|
case CV_BasicType_CHAR32:{result = str8_lit("CHAR32");}break;
|
||||||
case CV_BasicType_CHAR8:{result = str8_lit("char");}break;
|
case CV_BasicType_CHAR8:{result = str8_lit("char");}break;
|
||||||
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
case CV_BasicType_PTR:{result = str8_lit("PTR");}break;
|
||||||
}
|
}
|
||||||
@@ -447,7 +447,6 @@ String8 result = str8_lit("<Unknown CV_LeafKind>");
|
|||||||
switch(v)
|
switch(v)
|
||||||
{
|
{
|
||||||
default:{}break;
|
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_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break;
|
||||||
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break;
|
||||||
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break;
|
||||||
@@ -572,13 +571,6 @@ case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break;
|
|||||||
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break;
|
||||||
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break;
|
||||||
case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}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_CLASS2:{result = str8_lit("CLASS2");}break;
|
||||||
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break;
|
||||||
}
|
}
|
||||||
@@ -600,7 +592,7 @@ case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break;
|
|||||||
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break;
|
||||||
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break;
|
||||||
case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}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_THUNK32:{result = sizeof(CV_SymThunk32);}break;
|
||||||
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break;
|
||||||
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break;
|
||||||
@@ -704,15 +696,11 @@ case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break;
|
|||||||
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break;
|
||||||
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break;
|
||||||
case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}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_CLASS2:{result = sizeof(CV_LeafStruct2);}break;
|
||||||
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
C_LINKAGE_BEGIN
|
||||||
|
C_LINKAGE_END
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
//- GENERATED CODE
|
//- GENERATED CODE
|
||||||
@@ -381,7 +381,6 @@ CV_BasicType_PTR = 0xf0,
|
|||||||
typedef U16 CV_LeafKind;
|
typedef U16 CV_LeafKind;
|
||||||
typedef enum CV_LeafKindEnum
|
typedef enum CV_LeafKindEnum
|
||||||
{
|
{
|
||||||
CV_LeafKind_NOTYPE = 0x0000,
|
|
||||||
CV_LeafKind_MODIFIER_16t = 0x0001,
|
CV_LeafKind_MODIFIER_16t = 0x0001,
|
||||||
CV_LeafKind_POINTER_16t = 0x0002,
|
CV_LeafKind_POINTER_16t = 0x0002,
|
||||||
CV_LeafKind_ARRAY_16t = 0x0003,
|
CV_LeafKind_ARRAY_16t = 0x0003,
|
||||||
@@ -506,13 +505,6 @@ CV_LeafKind_BINTERFACE = 0x151a,
|
|||||||
CV_LeafKind_VECTOR = 0x151b,
|
CV_LeafKind_VECTOR = 0x151b,
|
||||||
CV_LeafKind_MATRIX = 0x151c,
|
CV_LeafKind_MATRIX = 0x151c,
|
||||||
CV_LeafKind_VFTABLE = 0x151d,
|
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_CLASS2 = 0x1608,
|
||||||
CV_LeafKind_STRUCT2 = 0x1609,
|
CV_LeafKind_STRUCT2 = 0x1609,
|
||||||
} CV_LeafKindEnum;
|
} CV_LeafKindEnum;
|
||||||
@@ -525,4 +517,7 @@ internal String8 cv_type_name_from_basic_type(CV_BasicType v);
|
|||||||
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
internal String8 cv_string_from_leaf_kind(CV_LeafKind v);
|
||||||
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);
|
||||||
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);
|
||||||
|
C_LINKAGE_BEGIN
|
||||||
|
C_LINKAGE_END
|
||||||
|
|
||||||
#endif // CODEVIEW_META_H
|
#endif // CODEVIEW_META_H
|
||||||
|
|||||||
+934
-779
File diff suppressed because it is too large
Load Diff
+689
-469
File diff suppressed because it is too large
Load Diff
@@ -1,819 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void
|
|
||||||
coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp);
|
|
||||||
|
|
||||||
rd_printf("Name : %S" , header.name );
|
|
||||||
rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp );
|
|
||||||
rd_printf("User ID : %u" , header.user_id );
|
|
||||||
rd_printf("Group ID : %u" , header.group_id);
|
|
||||||
rd_printf("Mode : %S" , header.mode );
|
|
||||||
rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_section_table(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_Symbol32Array symbol_table,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 *symlinks = push_array(scratch.arena, String8, section_count);
|
|
||||||
for (U64 i = 0; i < symbol_table.count; ++i) {
|
|
||||||
COFF_Symbol32 *symbol = symbol_table.v+i;
|
|
||||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class);
|
|
||||||
if (interp == COFF_SymbolValueInterp_Regular &&
|
|
||||||
symbol->aux_symbol_count == 0 &&
|
|
||||||
(symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) {
|
|
||||||
if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) {
|
|
||||||
COFF_SectionHeader *header = section_table+(symbol->section_number-1);
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
|
||||||
symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += symbol->aux_symbol_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section_count) {
|
|
||||||
rd_printf("# Section Table");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-5s %-10s %s",
|
|
||||||
"No.",
|
|
||||||
"Name",
|
|
||||||
"VirtSize",
|
|
||||||
"VirtOff",
|
|
||||||
"FileSize",
|
|
||||||
"FileOff",
|
|
||||||
"RelocOff",
|
|
||||||
"LinesOff",
|
|
||||||
"RelocCnt",
|
|
||||||
"LineCnt",
|
|
||||||
"Align",
|
|
||||||
"Flags",
|
|
||||||
"Symlink");
|
|
||||||
|
|
||||||
for (U64 i = 0; i < section_count; ++i) {
|
|
||||||
COFF_SectionHeader *header = section_table+i;
|
|
||||||
|
|
||||||
String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name));
|
|
||||||
String8 full_name = coff_name_from_section_header(string_table, header);
|
|
||||||
|
|
||||||
String8 align;
|
|
||||||
{
|
|
||||||
U64 align_size = coff_align_size_from_section_flags(header->flags);
|
|
||||||
align = push_str8f(scratch.arena, "%u", align_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 flags;
|
|
||||||
{
|
|
||||||
String8List mem_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_MemRead) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "r");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemWrite) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "w");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemExecute) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "x");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List cnt_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_CntCode) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_CntInitializedData) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "d");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_CntUninitializedData) {
|
|
||||||
str8_list_pushf(scratch.arena, &cnt_flags, "u");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List mem_extra_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_MemShared) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_flags, "s");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_Mem16Bit) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "h");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemLocked) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "l");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemDiscardable) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "d");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemNotCached) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_MemNotPaged) {
|
|
||||||
str8_list_pushf(scratch.arena, &mem_extra_flags, "p");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List lnk_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkRemove) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "r");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "c");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkOther) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "o");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkInfo) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "i");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl) {
|
|
||||||
str8_list_pushf(scratch.arena, &lnk_flags, "f");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List other_flags = {0};
|
|
||||||
if (header->flags & COFF_SectionFlag_TypeNoPad) {
|
|
||||||
str8_list_pushf(scratch.arena, &other_flags, "n");
|
|
||||||
}
|
|
||||||
if (header->flags & COFF_SectionFlag_GpRel) {
|
|
||||||
str8_list_pushf(scratch.arena, &other_flags, "g");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 mem = str8_list_join(scratch.arena, &mem_flags, 0);
|
|
||||||
String8 cnt = str8_list_join(scratch.arena, &cnt_flags, 0);
|
|
||||||
String8 lnk = str8_list_join(scratch.arena, &lnk_flags, 0);
|
|
||||||
String8 ext = str8_list_join(scratch.arena, &mem_extra_flags, 0);
|
|
||||||
String8 oth = str8_list_join(scratch.arena, &other_flags, 0);
|
|
||||||
|
|
||||||
String8List f = {0};
|
|
||||||
str8_list_push(scratch.arena, &f, mem);
|
|
||||||
str8_list_push(scratch.arena, &f, cnt);
|
|
||||||
str8_list_push(scratch.arena, &f, ext);
|
|
||||||
str8_list_push(scratch.arena, &f, lnk);
|
|
||||||
str8_list_push(scratch.arena, &f, oth);
|
|
||||||
|
|
||||||
flags = str8_list_join(scratch.arena, &f, &(StringJoin){ .sep = str8_lit("-") });
|
|
||||||
|
|
||||||
if (!flags.size) {
|
|
||||||
flags = str8_lit("none");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List l = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-4x", i+1 );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-8S", name );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->vsize );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->voff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->fsize );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->foff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->relocs_foff);
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->lines_foff );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->reloc_count);
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%08x", header->line_count );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-5S", align );
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%-10S", flags );
|
|
||||||
if (symlinks[i].size > 0) {
|
|
||||||
str8_list_pushf(scratch.arena, &l, "%S", symlinks[i]);
|
|
||||||
} else {
|
|
||||||
str8_list_pushf(scratch.arena, &l, "[no symlink]");
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 line = str8_list_join(scratch.arena, &l, &(StringJoin){ .sep = str8_lit(" "), });
|
|
||||||
rd_printf("%S", line);
|
|
||||||
|
|
||||||
if (full_name.size != name.size) {
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Full Name: %S", full_name);
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_newline();
|
|
||||||
rd_printf("Flags:");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("r = MemRead w = MemWrite x = MemExecute");
|
|
||||||
rd_printf("c = CntCode d = InitializedData u = UninitializedData");
|
|
||||||
rd_printf("s = MemShared h = Mem16bit l = MemLocked d = MemDiscardable c = MemNotCached p = MemNotPaged");
|
|
||||||
rd_printf("r = LnkRemove c = LnkComdat o = LnkOther i = LnkInfo f = LnkNRelocOvfl");
|
|
||||||
rd_printf("g = GpRel n = TypeNoPad");
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_disasm_sections(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
U64 image_base,
|
|
||||||
B32 is_obj,
|
|
||||||
RD_MarkerArray *section_markers,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *sections)
|
|
||||||
{
|
|
||||||
if (section_count) {
|
|
||||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect = sections+sect_idx;
|
|
||||||
if (sect->flags & COFF_SectionFlag_CntCode) {
|
|
||||||
U64 sect_off = is_obj ? sect->foff : sect->voff;
|
|
||||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
|
||||||
String8 raw_code = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
|
||||||
U64 sect_number = sect_idx+1;
|
|
||||||
RD_MarkerArray markers = section_markers[sect_number];
|
|
||||||
|
|
||||||
rd_printf("# Disassembly [Section No. %#llx]", sect_number);
|
|
||||||
rd_indent();
|
|
||||||
rd_print_disasm(arena, out, indent, arch_from_coff_machine(machine), image_base, sect_off, markers.count, markers.v, raw_code);
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_raw_data_sections(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
B32 is_obj,
|
|
||||||
RD_MarkerArray *section_markers,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
if (section_count) {
|
|
||||||
for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect = section_table+sect_idx;
|
|
||||||
if (sect->fsize > 0) {
|
|
||||||
U64 sect_size = is_obj ? sect->fsize : sect->vsize;
|
|
||||||
String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size));
|
|
||||||
RD_MarkerArray markers = section_markers[sect_idx];
|
|
||||||
|
|
||||||
rd_printf("# Raw Data [Section No. %#llx]", (sect_idx+1));
|
|
||||||
rd_indent();
|
|
||||||
rd_print_raw_data(arena, out, indent, 32, markers.count, markers.v, raw_sect);
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_relocs(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_MachineType machine,
|
|
||||||
U64 sect_count,
|
|
||||||
COFF_SectionHeader *sect_headers,
|
|
||||||
COFF_Symbol32Array symbols)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
B32 print_header = 1;
|
|
||||||
|
|
||||||
for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) {
|
|
||||||
COFF_SectionHeader *sect_header = sect_headers+sect_idx;
|
|
||||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(raw_data, sect_header);
|
|
||||||
|
|
||||||
if (reloc_info.count) {
|
|
||||||
if (print_header) {
|
|
||||||
print_header = 0;
|
|
||||||
rd_printf("# Relocations");
|
|
||||||
rd_indent();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_printf("## Section %llx", sect_idx);
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-16s %-16s %-8s %-7s", "No.", "Offset", "Type", "ApplyTo", "SymIdx", "SymName");
|
|
||||||
|
|
||||||
for (U64 reloc_idx = 0; reloc_idx < reloc_info.count; ++reloc_idx) {
|
|
||||||
COFF_Reloc *reloc = (COFF_Reloc*)(raw_data.str + reloc_info.array_off) + reloc_idx;
|
|
||||||
String8 type = coff_string_from_reloc(machine, reloc->type);
|
|
||||||
U64 apply_size = coff_apply_size_from_reloc(machine, reloc->type);
|
|
||||||
|
|
||||||
U64 apply_foff = sect_header->foff + reloc->apply_off;
|
|
||||||
if (apply_foff + apply_size > raw_data.size) {
|
|
||||||
rd_errorf("out of bounds apply file offset %#llx in relocation %#llx", apply_foff, reloc_idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 raw_apply;
|
|
||||||
AssertAlways(apply_size <= sizeof(raw_apply));
|
|
||||||
MemoryCopy(&raw_apply, raw_data.str + apply_foff, apply_size);
|
|
||||||
S64 apply = extend_sign64(raw_apply, apply_size);
|
|
||||||
|
|
||||||
if (reloc->isymbol > symbols.count) {
|
|
||||||
rd_errorf("out of bounds symbol index %u in relocation %#llx", reloc->isymbol, reloc_idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_Symbol32 *symbol = symbols.v+reloc->isymbol;
|
|
||||||
String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
|
|
||||||
String8List line = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%08x", reloc->apply_off);
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-16S", type );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%016x", apply );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%S", symbol_name );
|
|
||||||
|
|
||||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep=str8_lit(" ")});
|
|
||||||
rd_printf("%S", l);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!print_header) {
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
rd_newline();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_symbol_table(Arena *arena,
|
|
||||||
String8List *out,
|
|
||||||
String8 indent,
|
|
||||||
String8 raw_data,
|
|
||||||
B32 is_big_obj,
|
|
||||||
String8 string_table,
|
|
||||||
COFF_Symbol32Array symbols)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
if (symbols.count) {
|
|
||||||
rd_printf("# Symbol Table");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("%-4s %-8s %-10s %-4s %-4s %-4s %-16s %-20s",
|
|
||||||
"No.", "Value", "SectNum", "Aux", "Msb", "Lsb", "Storage", "Name");
|
|
||||||
|
|
||||||
for (U64 i = 0; i < symbols.count; ++i) {
|
|
||||||
COFF_Symbol32 *symbol = &symbols.v[i];
|
|
||||||
String8 name = coff_read_symbol_name(string_table, &symbol->name);
|
|
||||||
String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb);
|
|
||||||
String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb);
|
|
||||||
String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class);
|
|
||||||
String8 section_number;
|
|
||||||
switch (symbol->section_number) {
|
|
||||||
case COFF_Symbol_UndefinedSection: section_number = str8_lit("Undef"); break;
|
|
||||||
case COFF_Symbol_AbsSection32: section_number = str8_lit("Abs"); break;
|
|
||||||
case COFF_Symbol_DebugSection32: section_number = str8_lit("Debug"); break;
|
|
||||||
default: section_number = push_str8f(scratch.arena, "%010x", symbol->section_number); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String8List line = {0};
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4x", i );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%08x", symbol->value );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-10S", section_number );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4u", symbol->aux_symbol_count);
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4S", msb );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-4S", lsb );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%-16S", storage_class );
|
|
||||||
str8_list_pushf(scratch.arena, &line, "%S", name );
|
|
||||||
|
|
||||||
String8 l = str8_list_join(scratch.arena, &line, &(StringJoin){.sep = str8_lit(" ")});
|
|
||||||
rd_printf("%S", l);
|
|
||||||
|
|
||||||
rd_indent();
|
|
||||||
for (U64 k=i+1, c = i+symbol->aux_symbol_count; k <= c; ++k) {
|
|
||||||
void *raw_aux = &symbols.v[k];
|
|
||||||
switch (symbol->storage_class) {
|
|
||||||
case COFF_SymStorageClass_External: {
|
|
||||||
COFF_SymbolFuncDef *func_def = (COFF_SymbolFuncDef*)&symbols.v[k];
|
|
||||||
rd_printf("Tag Index %#x, Total Size %#x, Line Numbers %#x, Next Function %#x",
|
|
||||||
func_def->tag_index, func_def->total_size, func_def->ptr_to_ln, func_def->ptr_to_next_func);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_Function: {
|
|
||||||
COFF_SymbolFunc *func = raw_aux;
|
|
||||||
rd_printf("Ordinal Line Number %#x, Next Function %#x", func->ln, func->ptr_to_next_func);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_WeakExternal: {
|
|
||||||
COFF_SymbolWeakExt *weak = raw_aux;
|
|
||||||
String8 type = coff_string_from_weak_ext_type(weak->characteristics);
|
|
||||||
rd_printf("Tag Index %#x, Characteristics %S", weak->tag_index, type);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_File: {
|
|
||||||
COFF_SymbolFile *file = raw_aux;
|
|
||||||
String8 name = str8_cstring_capped(file->name, file->name+sizeof(file->name));
|
|
||||||
rd_printf("Name %S", name);
|
|
||||||
} break;
|
|
||||||
case COFF_SymStorageClass_Static: {
|
|
||||||
COFF_SymbolSecDef *sd = raw_aux;
|
|
||||||
String8 selection = coff_string_from_comdat_select_type(sd->selection);
|
|
||||||
U32 number = sd->number_lo;
|
|
||||||
if (is_big_obj) {
|
|
||||||
number |= (U32)sd->number_hi << 16;
|
|
||||||
}
|
|
||||||
if (number) {
|
|
||||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x, Section %x, Selection %S",
|
|
||||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum, number, selection);
|
|
||||||
} else {
|
|
||||||
rd_printf("Length %x, Reloc Count %u, Line Count %u, Checksum %x",
|
|
||||||
sd->length, sd->number_of_relocations, sd->number_of_ln, sd->check_sum);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
rd_printf("???");
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i += symbol->aux_symbol_count;
|
|
||||||
rd_unindent();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
|
|
||||||
rd_printf("# Big Obj");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp);
|
|
||||||
rd_printf("Machine : %#x (%S)", header->machine, machine );
|
|
||||||
rd_printf("Section Count: %u", header->section_count );
|
|
||||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff);
|
|
||||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
String8 flags = coff_string_from_flags(scratch.arena, header->flags);
|
|
||||||
|
|
||||||
rd_printf("# COFF File Header");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp );
|
|
||||||
rd_printf("Machine : %#x %S", header->machine, machine );
|
|
||||||
rd_printf("Section Count : %u", header->section_count );
|
|
||||||
rd_printf("Symbol Table : %#x", header->symbol_table_foff );
|
|
||||||
rd_printf("Symbol Count : %u", header->symbol_count );
|
|
||||||
rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size);
|
|
||||||
rd_printf("Flags : %#x (%S)", header->flags, flags );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8 machine = coff_string_from_machine_type(header->machine);
|
|
||||||
String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header->time_stamp);
|
|
||||||
|
|
||||||
rd_printf("# Import");
|
|
||||||
rd_indent();
|
|
||||||
rd_printf("Version : %u", header->version );
|
|
||||||
rd_printf("Machine : %S", machine );
|
|
||||||
rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp );
|
|
||||||
rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size);
|
|
||||||
rd_printf("Hint : %u", header->hint_or_ordinal);
|
|
||||||
rd_printf("Type : %u", header->type );
|
|
||||||
rd_printf("Import By : %u", header->import_by );
|
|
||||||
rd_printf("Function : %S", header->func_name );
|
|
||||||
rd_printf("DLL : %S", header->dll_name );
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
|
||||||
|
|
||||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
|
||||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
|
||||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
|
||||||
|
|
||||||
COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str;
|
|
||||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
|
||||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count);
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_big_obj_header(arena, out, indent, big_obj);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Sections) {
|
|
||||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*big_obj), sizeof(*big_obj) + sizeof(COFF_SectionHeader)*big_obj->section_count);
|
|
||||||
Rng1U64 symbols_range = rng_1u64(big_obj->symbol_table_foff, big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count);
|
|
||||||
|
|
||||||
if (sect_headers_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read big obj section headers");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (big_obj->symbol_count) {
|
|
||||||
if (symbols_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read big obj symbol table");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
|
||||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
|
||||||
rd_errorf("section headers and symbol table ranges overlap");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Relocs) {
|
|
||||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Symbols) {
|
|
||||||
coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data);
|
|
||||||
|
|
||||||
String8 raw_header = str8_substr(raw_data, header_info.header_range);
|
|
||||||
String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range);
|
|
||||||
String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range);
|
|
||||||
|
|
||||||
COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str;
|
|
||||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
|
||||||
COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count);
|
|
||||||
Arch arch = arch_from_coff_machine(header->machine);
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_file_header(arena, out, indent, header);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Sections) {
|
|
||||||
Rng1U64 sect_headers_range = rng_1u64(sizeof(*header), sizeof(*header) + sizeof(COFF_SectionHeader)*header->section_count);
|
|
||||||
Rng1U64 symbols_range = rng_1u64(header->symbol_table_foff, header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count);
|
|
||||||
|
|
||||||
if (sect_headers_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read obj section headers");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (header->symbol_count) {
|
|
||||||
if (symbols_range.max > raw_data.size) {
|
|
||||||
rd_errorf("not enough bytes to read obj symbol table");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (contains_1u64(symbols_range, sect_headers_range.min) ||
|
|
||||||
contains_1u64(symbols_range, sect_headers_range.max)) {
|
|
||||||
rd_errorf("section headers and symbol table ranges overlap");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Relocs) {
|
|
||||||
coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Symbols) {
|
|
||||||
coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
RD_MarkerArray *section_markers = 0;
|
|
||||||
if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) {
|
|
||||||
section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Rawdata) {
|
|
||||||
coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Disasm) {
|
|
||||||
coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Codeview) {
|
|
||||||
cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts & RD_Option_Dwarf) {
|
|
||||||
DW_Raw dwarf_input = dw_raw_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table);
|
|
||||||
dw_format(arena, out, indent, opts, &dwarf_input, arch, ExecutableImageKind_CoffPe);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
COFF_ArchiveParse archive_parse = coff_archive_parse_from_data(raw_archive);
|
|
||||||
|
|
||||||
if (archive_parse.error.size) {
|
|
||||||
rd_errorf("%S", archive_parse.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_ArchiveFirstMember first_member = archive_parse.first_member;
|
|
||||||
{
|
|
||||||
rd_printf("# First Header");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("Symbol Count : %u", first_member.symbol_count);
|
|
||||||
rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size);
|
|
||||||
|
|
||||||
rd_printf("Members:");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
String8List string_table = str8_split_by_string_chars(scratch.arena, first_member.string_table, str8_lit("\0"), 0);
|
|
||||||
|
|
||||||
if (string_table.node_count == first_member.member_offset_count) {
|
|
||||||
String8Node *string_n = string_table.first;
|
|
||||||
|
|
||||||
for (U64 i = 0; i < string_table.node_count; ++i, string_n = string_n->next) {
|
|
||||||
U32 offset = from_be_u32(first_member.member_offsets[i]);
|
|
||||||
rd_printf("[%4u] %#08x %S", i, offset, string_n->string);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rd_errorf("Member offset count (%llu) doesn't match string table count (%llu)", first_member.member_offset_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archive_parse.has_second_header) {
|
|
||||||
COFF_ArchiveSecondMember second_member = archive_parse.second_member;
|
|
||||||
|
|
||||||
rd_printf("# Second Header");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
rd_printf("Member Count : %u", second_member.member_count);
|
|
||||||
rd_printf("Symbol Count : %u", second_member.symbol_count);
|
|
||||||
rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size);
|
|
||||||
|
|
||||||
String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0);
|
|
||||||
|
|
||||||
rd_printf("Members:");
|
|
||||||
rd_indent();
|
|
||||||
if (second_member.symbol_index_count == second_member.symbol_count) {
|
|
||||||
String8Node *string_n = string_table.first;
|
|
||||||
for (U64 i = 0; i < second_member.symbol_count; ++i, string_n = string_n->next) {
|
|
||||||
U16 symbol_number = second_member.symbol_indices[i];
|
|
||||||
if (symbol_number > 0 && symbol_number <= second_member.member_offset_count) {
|
|
||||||
U16 symbol_idx = symbol_number - 1;
|
|
||||||
U32 member_offset = second_member.member_offsets[i];
|
|
||||||
rd_printf("[%4u] %#08x %S", i, member_offset, string_n->string);
|
|
||||||
} else {
|
|
||||||
rd_errorf("[%4u] Out of bounds symbol number %u", i, symbol_number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rd_errorf("Symbol index count %u doesn't match symbol count %u",
|
|
||||||
second_member.symbol_index_count, second_member.symbol_count);
|
|
||||||
}
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (archive_parse.has_long_names && opts & RD_Option_LongNames) {
|
|
||||||
rd_printf("# Long Names");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
String8List long_names = str8_split_by_string_chars(scratch.arena, archive_parse.long_names, str8_lit("\0"), 0);
|
|
||||||
U64 name_idx = 0;
|
|
||||||
for (String8Node *name_n = long_names.first; name_n != 0; name_n = name_n->next, ++name_idx) {
|
|
||||||
U64 offset = (U64)(name_n->string.str - archive_parse.long_names.str);
|
|
||||||
rd_printf("[%-4u] %#08x %S", name_idx, offset, name_n->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 member_offset_count = 0;
|
|
||||||
U32 *member_offsets = 0;
|
|
||||||
if (archive_parse.has_second_header) {
|
|
||||||
member_offset_count = archive_parse.second_member.member_offset_count;
|
|
||||||
member_offsets = archive_parse.second_member.member_offsets;
|
|
||||||
} else {
|
|
||||||
HashTable *ht = hash_table_init(scratch.arena, 0x1000);
|
|
||||||
for (U64 i = 0; i < archive_parse.first_member.member_offset_count; ++i) {
|
|
||||||
U32 member_offset = from_be_u32(archive_parse.first_member.member_offsets[i]);
|
|
||||||
if (!hash_table_search_u32(ht, member_offset)) {
|
|
||||||
hash_table_push_u32_raw(scratch.arena, ht, member_offset, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
member_offset_count = ht->count;
|
|
||||||
member_offsets = keys_from_hash_table_u32(scratch.arena, ht);
|
|
||||||
radsort(member_offsets, member_offset_count, u32_is_before);
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_printf("# Members");
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
for (U64 i = 0; i < member_offset_count; ++i) {
|
|
||||||
U64 next_member_offset = i+1 < member_offset_count ? member_offsets[i+1] : raw_archive.size;
|
|
||||||
U64 member_offset = member_offsets[i];
|
|
||||||
String8 raw_member = str8_substr(raw_archive, rng_1u64(member_offset, next_member_offset));
|
|
||||||
COFF_ArchiveMember member = coff_archive_member_from_data(raw_member);
|
|
||||||
COFF_DataType member_type = coff_data_type_from_data(member.data);
|
|
||||||
|
|
||||||
rd_printf("Member @ %#llx", member_offset);
|
|
||||||
rd_indent();
|
|
||||||
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
coff_print_archive_member_header(arena, out, indent, member.header, archive_parse.long_names);
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (member_type) {
|
|
||||||
case COFF_DataType_Obj: {
|
|
||||||
coff_print_obj(arena, out, indent, member.data, opts);
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_BigObj: {
|
|
||||||
coff_print_big_obj(arena, out, indent, member.data, opts);
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_Import: {
|
|
||||||
if (opts & RD_Option_Headers) {
|
|
||||||
COFF_ParsedArchiveImportHeader header = {0};
|
|
||||||
U64 parse_size = coff_parse_import(member.data, 0, &header);
|
|
||||||
if (parse_size) {
|
|
||||||
coff_print_import(arena, out, indent, &header);
|
|
||||||
} else {
|
|
||||||
rd_errorf("not enough bytes to parse import header");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case COFF_DataType_Null: {
|
|
||||||
rd_errorf("unknown member format", member_offset);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
rd_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
rd_unindent();
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef COFF_DUMP_H
|
|
||||||
#define COFF_DUMP_H
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names);
|
|
||||||
internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers);
|
|
||||||
internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
|
||||||
internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections);
|
|
||||||
internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols);
|
|
||||||
internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, String8 string_table, COFF_Symbol32Array symbols);
|
|
||||||
internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header);
|
|
||||||
internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header);
|
|
||||||
internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header);
|
|
||||||
internal void coff_print_big_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
|
||||||
internal void coff_print_obj (Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Option opts);
|
|
||||||
internal void coff_print_archive (Arena *arena, String8List *out, String8 indent, String8 raw_archive, RD_Option opts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // COFF_DUMP_H
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user