784 changed files with 165154 additions and 410239 deletions
-8
View File
@@ -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
+9 -132
View File
@@ -8,144 +8,21 @@ on:
paths-ignore:
- '**.md'
env:
TORTURE_FLAGS: "--gen_crash_dump"
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:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
target:
- raddbg
- radlink
- radbin
- mule_main
compiler:
- msvc
- clang
mode:
- debug
- release
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true
- name: checkout
uses: actions/checkout@v2
- name: build (vs 2022)
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 build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
run-ubuntu-24-04:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
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
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build raddbg msvc debug || exit /b 1
call build raddbg_from_pdb msvc debug || exit /b 1
call build raddbg_from_dwarf msvc debug || exit /b 1
call build raddbg clang debug || exit /b 1
call build raddbg_from_pdb clang debug || exit /b 1
call build raddbg_from_dwarf clang debug || exit /b 1
-2
View File
@@ -1,5 +1,3 @@
/build/
/local/
*~
.vs
tags
-399
View File
@@ -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 -1
View File
@@ -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
this software and associated documentation files (the “Software”), to deal in
+137 -240
View File
@@ -1,93 +1,42 @@
# The RAD Debugger Project
_**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's README, which includes usage instructions and tips, can be found
packaged along with debugger releases, or within the `build` folder after a
local copy has been built. You can find pre-built release binaries
[here](https://github.com/EpicGames/raddebugger/releases)._
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
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
support native Linux debugging and DWARF debug info.
The debugger is currently in *ALPHA*. In order to get the debugger
bullet-proof, it'd greatly help out if you submitted the issues you find
[here](https://github.com/EpicGames/raddebugger/issues), along with any
information you can gather, like dump files (along with the build you used),
instructions to reproduce, test executables, and so on.
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
proof, it'd greatly help out if you submitted the issues you find here, along
with any information you can gather, like dump files (along with the build you
used), instructions to reproduce, test executables, and so on.
In addition to the debugger, we aim to further improve the toolchain with two
additional related technologies: **(1)** the RAD Debug Info (RDI) format, and
**(2)** the RAD Linker.
You can download pre-built binaries for the debugger
[here](https://github.com/EpicGames/raddebugger/releases).
## 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 RADDBG debug info format, which is what the debugger parses and uses. To
work with existing toolchains, we convert PDB (and eventually PE/ELF files
with embedded DWARF) into the RADDBG format on-demand. This conversion process
is currently an unoptimized reference version. Nevertheless it's still quite
fast for smaller PDB files (in many cases faster than many other programs
simply deserialize the PDBs). It is much slower for much larger projects at the
moment, but we expect this will vastly improve overtime.
The RAD Debug Info (RDI) format is our custom debug information format, which
the debugger parses and uses, rather than the debug information natively
produced by toolchains, like PDB or DWARF. To work with these existing
toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF)
into the RDI format on-demand.
The RADDBG format is currently specified in code, in the files within the
`src/raddbg_format` folder. The other relevant folders for working with the
format are:
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
[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format
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.
- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files.
- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress
implementation of a DWARF-to-RADDBG) conversion.
- `raddbg_dump`: Code for textually dumping information from RADDBG files.
We also have an in-progress library for constructing and serializing RDI data,
located within the `src/lib_rdi_make` folder.
## Development Setup Instructions
Our `radbin` utility (accessible through the debugger too, via the `--bin`
command line argument) is capable of converting native debug information formats
to RDI, and of producing textual dumps of contents stored within RDI files.
**Note: Currently, only x64 Windows development is supported.**
## The RAD Linker
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries.
It is designed to be very fast when creating gigantic executables. It generates
standard PDB files for debugging, but it can also (optionally) 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:
![AMD Ryzen Threadripper PRO 3995WX 64-Cores, 256 GiB RAM (Windows x64)](https://github.com/user-attachments/assets/a95b382a-76b4-4a4c-b809-b61fe25e667a)
---
# Project Development Setup Instructions
**NOTE: Currently, only x64 Windows development is supported for the project.**
## 1. Installing the Required Tools (MSVC & Windows SDK)
### 1. Installing the Required Tools (MSVC & Windows SDK)
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
@@ -96,7 +45,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++
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
ability to call either MSVC or Clang from command line.
@@ -140,63 +89,45 @@ You should see the following output:
[msvc compile]
[default mode, assuming `raddbg` build]
metagen_main.c
searching C:\devel\raddebugger/src... 458 files found
parsing metadesk... 16 metadesk files parsed
gathering tables... 97 tables found
searching C:\devel\raddebugger/src... 299 files found
parsing metadesk... 12 metadesk files parsed
gathering tables... 37 tables found
generating layer code...
raddbg_main.c
raddbg.cpp
```
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`.
This `raddbg.exe` will have been built in **debug mode**, which is not built
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
## Short-To-Medium-Term Roadmap
### The Initial Alpha Battle-Testing Phase
The first priority for the project is to ensure that the most crucial components
are functioning extremely reliably for local, x64, Windows development.
For the debugger, this would include parts like debug info conversion, debug
info loading, process control, stepping, evaluation (correct usage of both
location info and type info), and a robust frontend which ensures the lower
level parts are usable. For the linker, this is a matter of reliability and
convergence with existing linker behavior.
The first priority for the project is to ensure that the most crucial debugger
components are functioning extremely reliably for local, x64, Windows
debugging. This would include parts like debug info conversion, debug info
loading, process control, stepping, evaluation (correct usage of both location
info and type info), and a robust frontend which ensures the lower level parts
are usable.
We feel that we've already come a long way in all of these respects, but given
the massive set of possible combinations of languages, build settings,
toolchains, used language features, and patterns of generated code, we still
expect some issues, and are prioritizing these issues being resolved first.
We feel that the debugger has already come a long way in all of these respects,
but given the massive set of possible combinations of languages, build
settings, toolchains, used language features, and patterns of generated code,
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,
such that the debugging experience is rock solid.
We also hope to continue to improve performance in this phase. For the debugger,
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).
Additionally, the debug info conversion process is not fast (nor wide) enough
to support extremely large projects. This is for two reasons: (a) the
PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the
debugger learns of new modules (and thus which PDBs to load) in a
serially-dependent way (this is necessarily the case for correct debugging
results). We expect that the conversion process' performance can be massively
improved, and also that some heuristics can be used to begin converting PDBs
to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the
associated RADDBG files are ready instantaneously when the associated modules
are finally loaded by the debugger. Improving this situation is a major part of
this phase, as it will make the debugger much more usable for large projects.
### Local x64 Linux Debugging Phase
@@ -212,10 +143,11 @@ The major parts of this phase are:
- Porting the `src/demon` layer to implement the Demon local process control
abstraction API.
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
- Creating a DWARF-to-RDI converter (in the same way that we've built a
PDB-to-RDI converter). A partial implementation of this is in
`src/rdi_from_dwarf`.
- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there
is only an x64 PE unwinding implementation).
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
to-RADDBG converter). A partial implementation of this is in
`src/raddbg_convert/dwarf`.
- Porting the `src/render` layer to implement all of the rendering features the
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
- Porting the `src/font_provider` layer to a Linux-compatible font
@@ -237,10 +169,6 @@ like remote debugging, porting to different architectures, further improving
the debugger's features (like improving the visualization engine), and so on.
But for now, we're mostly focused on those first two phases.
---
# Codebase Introduction
## Top-Level Directory Descriptions
- `data`: Small binary files which are used when building, either to embed
@@ -251,10 +179,9 @@ After setting up the codebase and building, the following directories will
also exist:
- `build`: All build artifacts. Not checked in to version control.
- `local`: Local files, used for local build configuration input files. Not
checked in to version control.
- `local`: Local files, used for local build configuration input files.
## Layer Descriptions
## Codebase Introduction
The codebase is organized into *layers*. Layers are separated either to isolate
certain problems, and to allow inclusion into various builds without needing to
@@ -279,88 +206,56 @@ Layers depend on other layers, but circular dependencies would break the
separability and isolation utility of layers (in effect, forming one big layer),
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
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
layers are prefixed with `lib_`, like `lib_rdi`.
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,
memory allocators, helper macros, command-line parsing, and so on. Requires
no other codebase layers.
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
memory allocators, helper macros, command-line parsing, and so on. Depends
on no other codebase layers.
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
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
asynchronous process control, stepping, and breakpoints for all attached
processes. Runs in lockstep with attached processes. When it runs, attached
processes are halted. When attached processes are running, it is halted.
Driven by a debugger frontend on another thread.
- `dbg_engine` (`D_`): Implements the core debugger system, without any
graphical components. This contains top-level logic for things like stepping,
launching, freezing threads, mid-run breakpoint addition, some caches, and so
on.
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
Launches separate processes for on-demand conversion to the RDI format if
necessary. Also provides various asynchronous operations for using debug info,
like fuzzy searching across all records in loaded debug info.
- `demon` (`DMN_`): An abstraction layer for local-machine, low-level process
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
disassembly for a particular virtual address range in a process, and threads
implemented in this layer decode and cache the disassembly for that range.
- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug
info stored in the RADDBG format. Users ask for debug info for a particular
executable, and on separate threads, this layer loads the associated debug
info file. If necessary, it will launch a separate conversion process to
convert original debug info into the RADDBG format.
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
control. The abstraction is used to provide a common interface for process
control on target platforms. Used to implement part of `ctrl`.
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
ability to compute and cache disassembly asynchronously.
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
debugger's purposes, using the underlying `render` abstraction layer. Provides
high-level APIs for various draw commands, but takes care of batching them,
and so on.
- `dwarf` (`DW_`): Code for parsing the DWARF format.
- `eh` (`EH_`): Code for parsing the EH frame format.
- `elf` (`ELF_`): Code for parsing the ELF format.
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
variables, registers, types, and more, from debugger-attached processes,
debug info, debugger state, and files. Broken into several phases mostly
corresponding to traditional compiler phases: lexer, parser, type-checker, IR
generation, and IR evaluation.
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
visualization engine, which can be used to visualize evaluations (provided by
the `eval` layer) in a number of ways. Implements core data structures and
transforms for watch tables.
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
artifacts inside of the cache implemented by the `content` and
`artifact_cache` layers, hot-reloading the contents of files when they change.
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.
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
debugger "entity cache" (where "entities" include processes, threads, modules,
breakpoints, source files, targets, and so on). Implements a command loop
for driving process control, which is used to implement stepping commands and
user breakpoints. Implements extractors and caches for various entity-related
data, like full thread unwinds and local variable maps. Also implements core
building blocks for evaluation and evaluation visualization.
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
`df/core` to provide all graphical features, including windows, panels, all
of the various debugger interfaces, and evaluation visualization.
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
purposes, using the underlying `render` abstraction layer. Provides high-level
APIs for various draw commands, but takes care of batching them, and so on.
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
evaluation of variables, registers, and so on from debugger-attached processes
and/or debug info. Broken into several phases mostly corresponding to
traditional compiler phases - lexer, parser, type-checker, IR generation, and
IR evaluation.
- `font_cache` (`F_`): 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
and font rasterization backends.
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
programs to work with various features in the debugger. Does not 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
data. Does not depend on `base`, and can be independently relocated
to other codebases.
- `linker` (`LNK_`): The layer which implements the RAD Linker executable
itself.
- `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which
is the JSON-like (technically a JSON superset) text format used for the
debugger's user and project configuration files and metacode, which is parsed
and used to generate code with the `metagen` layer.
- `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.
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code 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
@@ -369,13 +264,14 @@ 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
associated data tables. There are also a number of other generation features,
like embedding binary files or complex multi-line strings into source code.
- `msf` (`MSF_`): Code for parsing and writing the MSF file format.
- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT.
This layer cannot depend on any other layer in the codebase directly,
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.
- `mule` (no namespace): Test executables for battle testing debugger
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
types in other debuggers.
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
@@ -384,29 +280,23 @@ 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
graphical operating system features under an abstract API, which is
implemented per-target-operating-system.
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
format.
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
executable.
- `raddbg` (`RD_`): The layer which ties everything together for the main
graphical debugger executable. Implements the debugger's graphical frontend,
all of the debugger-specific UI, the debugger executable's command line
interface, and all of the built-in visualizers.
- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with
codebase-specific helpers, to easily include the library in codebase programs,
and have it be integrated with codebase constructs.
- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the
equivalent RDI data.
- `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.
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
networking operating system features under an abstract API, which is
implemented per-target-operating-system.
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
file format.
- `raddbg` (no namespace): The layer which ties everything together for the main
graphical debugger. Not much "meat", just drives `df`, implements command line
options, and so on.
- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the
RADDBG debug info file format.
- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations
of RADDBG debug info files.
- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the
RADDBG debug info file format. Does not depend on `base`.
- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user
programs to work with various features in the `raddbg` debugger. Does not
depend on `base`.
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
supported architectures. Used in reading/writing registers in `demon`, or in
looking up register metadata.
@@ -415,14 +305,21 @@ 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
as-needed basis. Higher level drawing features are implemented in the `draw`
layer.
- `scratch` (no namespace): Scratch space for small and transient test programs.
- `tester` (no namespace): A program used for automated testing.
- `text` (`TXT_`): Implements text processing functions, like parsing line
breaks, and lexing and parsing source code. Also offers an API to do this
asynchronously.
- `third_party` (no namespace): External code from other projects, which some
layers in the codebase depend on. All external code is included and built
directly within the codebase.
- `scratch` (no namespace): Scratch space for small and transient test or sample
programs.
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
texture data, filled by data sourced in the `hash_store` layer's cache. Used
for asynchronously preparing data for memory visualization in the debugger.
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
reloaded, asynchronously parsed, and asynchronously mutated source code files.
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
RADDBG 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
core immediate mode hierarchical user interface data structure building
API, and has helper layers for building some higher-level widgets.
- `unwind` (`UNW_`): Code for generating unwind information from threads, for
supported operating systems and architectures.
+51 -120
View File
@@ -1,22 +1,21 @@
@echo off
setlocal enabledelayedexpansion
setlocal
cd /D "%~dp0"
:restart
:: --- Usage Notes (2024/1/10) ------------------------------------------------
::
:: This is a central build script for the RAD Debugger project, for use in
:: Windows development environments. It takes a list of simple alphanumeric-
:: only arguments which control (a) what is built, (b) which compiler & linker
:: are used, and (c) extra high-level build options. By default, if no options
:: are passed, then the main "raddbg" graphical debugger is built.
:: This is a central build script for the RAD Debugger project. It takes a list
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
:: which compiler & linker are used, and (c) extra high-level build options. By
:: default, if no options are passed, then the main "raddbg" graphical debugger
:: is built.
::
:: Below is a non-exhaustive list of possible ways to use the script:
:: `build raddbg`
:: `build raddbg clang`
:: `build raddbg release`
:: `build raddbg asan telemetry`
:: `build rdi_from_pdb`
:: `build raddbg_from_pdb`
::
:: For a full list of possible build targets and their build command lines,
:: search for @build_targets in this file.
@@ -24,91 +23,55 @@ cd /D "%~dp0"
:: Below is a list of all possible non-target command line options:
::
:: - `asan`: enable address sanitizer
:: - `ubsan`: enable undefined-behavior sanitizer
:: - `telemetry`: enable RAD telemetry profiling support
:: - `spall`: enable spall profiling support
:: --- 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 "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc 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"=="release" if "%~2"=="" 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
:: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags=
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 "%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
)
)
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
:: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %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 cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
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 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags%
set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DNDEBUG %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_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_obj_out= -o
set clang_linker= -Xlinker
:: --- Per-Build Settings -----------------------------------------------------
set link_icon=logo.res
if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker%
if "%msvc%"=="1" set only_compile=/c
if "%clang%"=="1" set only_compile=-c
if "%msvc%"=="1" set EHsc=/EHsc
if "%clang%"=="1" set EHsc=
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc
if "%msvc%"=="1" set link_dll=/link /DLL
if "%clang%"=="1" set link_dll=-Xlinker -DLL
set gfx=-DOS_FEATURE_GRAPHICAL=1
set net=-DOS_FEATURE_SOCKET=1
set link_dll=-DLL
if "%msvc%"=="1" set only_compile=/c
if "%clang%"=="1" set only_compile=-c
if "%msvc%"=="1" set EHsc=/EHsc
if "%clang%"=="1" set EHsc=
if "%msvc%"=="1" set rc=rc.exe
if "%clang%"=="1" set rc=llvm-rc.exe
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link%
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_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out%
if "%clang%"=="1" set obj_out=%clang_obj_out%
if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release%
@@ -122,68 +85,36 @@ pushd build
popd
:: --- Get Current Git Commit Id ----------------------------------------------
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------
pushd build
if "%meta%"=="1" (
echo [building metagen]
if "%no_meta%"=="1" echo [skipping metagen]
if not "%no_meta%"=="1" (
pushd build
%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
popd
)
popd
:: --- Build Everything (@build_targets) --------------------------------------
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_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 "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.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 "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.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" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%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" (
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_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
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
move mule_peb_trample_new.exe mule_peb_trample.exe
)
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe || exit /b 1
if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe || exit /b 1
if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe || exit /b 1
if "%ryan_scratch%"=="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 "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.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% %out%mule_main.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 "%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
popd
:: --- Set Up Debugger Com Shim -----------------------------------------------
pushd build
if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com
popd
:: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
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
)
:: --- Unset ------------------------------------------------------------------
for %%a in (%*) do set "%%a=0"
set raddbg=
set compile=
set compile_link=
set out=
set msvc=
set debug=
-77
View File
@@ -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.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
-93
View File
@@ -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
-73
View File
@@ -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
-233
View File
@@ -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
-528
View File
@@ -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
-373
View File
@@ -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, &reg_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;
}
-81
View File
@@ -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
+86 -62
View File
@@ -45,77 +45,101 @@ load_paths =
commands =
{
//- rjf: [raddbg]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build torture && build ryan_scratch && pushd build && torture eval2/* && ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [scratch]
// .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, },
//- rjf: [textperf]
// .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, },
//- rjf: [tester]
// .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: [radbin]
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: running target
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .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, },
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: local target builds
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.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_from_dwarf = { .win = "build rdi_from_dwarf", .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_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, },
.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, },
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: wsl target builds
.build_raddbg_wsl = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .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_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, },
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.build_mule_hotload_wsl = { .win = "wsl ./build.sh mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.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, },
//- rjf: local target runs
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.rjf_f1 =
{
.win = "build raddbg telemetry",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.rjf_f2 =
{
.win = "build raddbg_from_pdb",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.rjf_f3 =
{
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg =
{
.win = "build raddbg",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_release_telemetry =
{
.win = "build raddbg release telemetry",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_from_pdb =
{
.win = "build raddbg_from_pdb",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_raddbg_dump =
{
.win = "build raddbg_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,
},
.run_raddbg =
{
.win = "pushd build && raddbg.exe && popd",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
};
fkey_command =
{
.F1 = "f1",
.F2 = "f2",
.F3 = "f3",
.F1 = "build_raddbg",
.F3 = "run_raddbg",
};
fkey_command_override =
{
.rjf =
{
.F1 = "f1",
.F2 = "f2",
.F3 = "f3",
.F1 = "rjf_f1",
.F2 = "rjf_f2",
.F3 = "rjf_f3",
},
};
-75
View File
@@ -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
View File
@@ -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
)
-77
View File
@@ -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
+1
View File
@@ -4,6 +4,7 @@ $path_root = git rev-parse --show-toplevel
if ($IsWindows) {
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
# This HandmadeHero implementation is only designed for 64-bit systems
& $devshell -arch amd64
}
-174
View File
@@ -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
-54
View File
@@ -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
-11
View File
@@ -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
-16
View File
@@ -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
-19
View File
@@ -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;
}
-9
View File
@@ -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
-16
View File
@@ -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;
}
-9
View File
@@ -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
-19
View File
@@ -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;
}
-9
View File
@@ -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
-735
View File
@@ -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(&params->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);
}
}
-192
View File
@@ -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
+223 -298
View File
@@ -1,139 +1,86 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Global Arena Table
#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
// Implementation
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);
U64 reserve_size = params->reserve_size;
U64 commit_size = params->commit_size;
// rjf: reserve/commit initial block
void *base = params->optional_backing_buffer;
if(base == 0)
void *memory = 0;
U64 res = 0;
U64 cmt = 0;
B32 large_pages = os_large_pages_enabled();
if(large_pages)
{
// rjf: round up reserve/commit sizes
if(params->flags & ArenaFlag_LargePages)
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))
{
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
memory = 0;
os_release(memory, res);
}
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)
{
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)
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))
{
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;
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;
#if ENABLE_DEV
arena->dev = 0;
#endif
arena->grow = 1;
arena->large_pages = large_pages;
}
ProfEnd();
return arena;
}
internal Arena *
arena_alloc(void)
{
ProfBeginFunction();
U64 init_res, init_cmt;
if (os_large_pages_enabled()) {
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES;
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES;
} else {
init_res = ARENA_RESERVE_SIZE;
init_cmt = ARENA_COMMIT_SIZE;
}
Arena *arena = arena_alloc__sized(init_res, init_cmt);
ProfEnd();
return arena;
@@ -142,168 +89,88 @@ arena_alloc_(ArenaParams *params)
internal void
arena_release(Arena *arena)
{
ProfBeginFunction();
#if PROFILE_TELEMETRY
{
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);
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
prev = node->prev;
os_release(node, node->res);
}
#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 *
arena_push(Arena *arena, U64 size, U64 align, B32 zero)
arena_push__impl(Arena *arena, U64 size)
{
Arena *current = arena->current;
U64 pos_pre = AlignPow2(current->pos, align);
U64 pos_pst = pos_pre + size;
U64 pos_mem = AlignPow2(current->pos, arena->align);
U64 pos_new = pos_mem + size;
// TODO: Newly allocated arenas already have zeroed commited pages,
// so this unnecessarily zeroes them again.
//
// 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;
}
if (current->res < pos_new && arena->grow) {
Arena *new_block;
// 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;
}
}
// normal growth path
if (size < arena_huge_push_threshold()) {
new_block = arena_alloc();
}
#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;
}
else
{
size_to_zero = size;
// huge growth path
else {
U64 new_block_size = size + ARENA_HEADER_SIZE;
new_block = arena_alloc__sized(new_block_size, new_block_size);
}
new_block->base_pos = current->base_pos + current->res;
SLLStackPush_N(arena->current, new_block, prev);
if (new_block) {
new_block->base_pos = current->base_pos + current->res;
SLLStackPush_N(arena->current, new_block, prev);
current = new_block;
pos_pre = AlignPow2(current->pos, align);
pos_pst = pos_pre + size;
}
// rjf: commit new pages, if needed
if(current->cmt < pos_pst)
{
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
U64 cmt_size = cmt_pst_clamped - current->cmt;
U8 *cmt_ptr = (U8 *)current + current->cmt;
if(current->flags & ArenaFlag_LargePages)
{
commit_memory_large(cmt_ptr, cmt_size);
current = new_block;
pos_mem = AlignPow2(current->pos, current->align);
pos_new = pos_mem + size;
}
else
{
commit_memory(cmt_ptr, cmt_size);
}
if (current->cmt < pos_new) {
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
B32 is_cmt_ok;
if (current->large_pages) {
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
cmt_new_size = cmt_new_clamped - current->cmt;
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
} else {
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
cmt_new_size = cmt_new_clamped - current->cmt;
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
}
if (is_cmt_ok) {
current->cmt = cmt_new_clamped;
}
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
current->cmt = cmt_pst_clamped;
}
// rjf: push onto current block
void *result = 0;
if(current->cmt >= pos_pst)
{
result = (U8 *)current+pos_pre;
current->pos = pos_pst;
AsanUnpoisonMemoryRegion(result, size);
MemoryZero(result, size_to_zero);
void *memory = 0;
if (current->cmt >= pos_new) {
memory = (U8*)current + pos_mem;
current->pos = pos_new;
AsanUnpoisonMemoryRegion(memory, size);
}
#if PROFILE_TELEMETRY
if(size > 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: panic on failure
#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."));
abort_self(1);
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
os_exit_process(1);
}
#endif
return result;
return memory;
}
internal U64
@@ -315,45 +182,95 @@ arena_pos(Arena *arena)
}
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);
Arena *current = arena->current;
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
#if ARENA_FREE_LIST
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
// unroll the chain
Arena *current = arena->current;
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
prev = current->prev;
current->pos = ARENA_HEADER_SIZE;
SLLStackPush_N(arena->free_last, current, prev);
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE);
os_release(current, current->res);
}
#else
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
AsanUnpoisonMemoryRegion(current, current->cmt);
release_memory(current, current->res);
}
#endif
AssertAlways(current);
arena->current = current;
// compute arena-relative position
U64 new_pos = big_pos - current->base_pos;
AssertAlways(new_pos <= current->pos);
// poison popped memory block
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
// update position
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)
{
#if ENABLE_DEV
arena_annotate_absorb__dev(arena, sub);
#endif
// 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);
#if ENABLE_DEV
arena_annotate_push__dev(arena, size, memory);
#endif
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;
#if ENABLE_DEV
arena_annotate_push__dev(arena, size, memory);
#endif
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
arena_clear(Arena *arena)
@@ -361,20 +278,6 @@ arena_clear(Arena *arena)
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
temp_begin(Arena *arena)
{
@@ -388,3 +291,25 @@ temp_end(Temp temp)
{
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);
}
+58 -57
View File
@@ -1,56 +1,45 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ARENA_H
#define BASE_ARENA_H
////////////////////////////////
//~ rjf: Arena Types
//~ rjf: Constants
#define ARENA_HEADER_SIZE 128
typedef U64 ArenaFlags;
enum
{
ArenaFlag_NoChain = (1<<0),
ArenaFlag_LargePages = (1<<1),
};
#ifndef ARENA_RESERVE_SIZE
# define ARENA_RESERVE_SIZE MB(64)
#endif
#ifndef ARENA_COMMIT_SIZE
# define ARENA_COMMIT_SIZE KB(64)
#endif
typedef struct ArenaParams ArenaParams;
struct ArenaParams
{
ArenaFlags flags;
U64 reserve_size;
U64 commit_size;
void *optional_backing_buffer;
char *allocation_site_file;
int allocation_site_line;
char *name;
};
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8)
#endif
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2)
#endif
////////////////////////////////
//~ rjf: Arena Types
typedef struct Arena Arena;
struct Arena
{
Arena *prev; // previous arena in chain
Arena *current; // current arena in chain
ArenaFlags flags;
U64 cmt_size;
U64 res_size;
struct Arena *prev;
struct Arena *current;
U64 base_pos;
U64 pos;
U64 cmt;
U64 res;
char *allocation_site_file;
int allocation_site_line;
char *name;
#if ARENA_FREE_LIST
Arena *free_last;
#endif
#if ARENA_TABLE_DEBUG
struct ArenaTableNode *table_node;
#endif
U64 align;
struct ArenaDev *dev;
B8 grow;
B8 large_pages;
};
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
typedef struct Temp Temp;
struct Temp
@@ -60,34 +49,46 @@ struct Temp
};
////////////////////////////////
//~ rjf: Arena Functions
// Implementation
global U64 arena_default_reserve_size = MB(64);
global U64 arena_default_commit_size = KB(64);
global ArenaFlags arena_default_flags = 0;
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
//- rjf: arena creation/destruction
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 Arena* arena_alloc(void);
internal void arena_release(Arena *arena);
//- rjf: arena push/pop/pos core functions
internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero);
internal U64 arena_pos(Arena *arena);
internal void arena_pop_to(Arena *arena, U64 pos);
internal void* arena_push__impl(Arena *arena, U64 size);
internal U64 arena_pos(Arena *arena);
internal void arena_pop_to(Arena *arena, U64 pos);
//- rjf: arena push/pop helpers
internal void arena_clear(Arena *arena);
internal void arena_pop(Arena *arena, U64 amt);
internal void arena_absorb(Arena *arena, Arena *sub);
//- rjf: temporary arena scopes
internal Temp temp_begin(Arena *arena);
internal void temp_end(Temp temp);
////////////////////////////////
// Wrappers
//- rjf: push helper macros
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
#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)))
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
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_push_align(Arena *arena, U64 align);
internal void arena_put_back(Arena *arena, U64 amt);
internal Temp temp_begin(Arena *arena);
internal void temp_end(Temp temp);
////////////////////////////////
//~ NOTE(allen): "Mini-Arena" Helper
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
////////////////////////////////
//~ NOTE(allen): Main API Macros
#if !ENABLE_DEV
# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
#else
# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c)))
#endif
#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((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
+197
View File
@@ -0,0 +1,197 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Dev Arena
#if ENABLE_DEV
internal void
arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){
ArenaDev *dev = arena->dev;
if (dev != 0 && ptr != 0){
//- read location
char *file_name = 0;
U64 line_number = 0;
tctx_read_srcloc(&file_name, &line_number);
tctx_write_srcloc(0, 0);
//- profile
ArenaProf *prof = dev->prof;
if (prof != 0){
// c string -> string
String8 file_name_str = str8_lit("(null)");
if (file_name != 0){
file_name_str = str8_cstring(file_name);
}
// record
arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1);
}
}
}
internal void
arena_annotate_absorb__dev(Arena *arena, Arena *sub){
ArenaDev *dev = arena->dev;
ArenaDev *sub_dev = sub->dev;
if (dev != 0 && sub_dev != 0){
//- merge profiles
ArenaProf *prof = dev->prof;
ArenaProf *sub_prof = sub_dev->prof;
if (prof != 0 && sub_prof != 0){
for (ArenaProfNode *sub_node = sub_prof->first;
sub_node != 0;
sub_node = sub_node->next){
arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line,
sub_node->size, sub_node->count);
}
}
}
//- release the sub dev memory
if (sub_dev != 0){
arena_release(sub_dev->arena);
}
}
internal ArenaDev*
arena_equip__dev(Arena *arena){
ArenaDev *result = arena->dev;
if (result == 0){
Arena *dev_arena = arena_alloc();
ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev));
MemoryZeroStruct(dev);
dev->arena = dev_arena;
arena->dev = dev;
result = dev;
}
return(result);
}
internal void
arena_equip_profile__dev(Arena *arena){
ArenaDev *dev = arena_equip__dev(arena);
if (dev->prof == 0){
dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf));
MemoryZeroStruct(dev->prof);
}
}
internal void
arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){
Assert(arena != out_arena);
//- get dev & disable
ArenaDev *dev = arena->dev;
arena->dev = 0;
//- get prof
ArenaProf *prof = (dev != 0)?dev->prof:0;
//- not equipped with prof
if (prof == 0){
str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n"));
}
//- print prof
if (prof != 0){
Temp scratch = temp_begin(dev->arena);
//- make flat array
U64 note_count = prof->count;
ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count);
{
ArenaProfNode **note_ptr = notes;
for (ArenaProfNode *node = prof->first;
node != 0;
node = node->next, note_ptr += 1){
*note_ptr = node;
}
}
//- file name size
U64 max_file_name_size = 0;
{
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size);
}
}
//- sort (> size, < [address])
for (U64 i = 0; i < note_count; i += 1){
ArenaProfNode **i_note = notes + i;
ArenaProfNode **min_note = i_note;
for (U64 j = i + 1; j < note_count; j += 1){
ArenaProfNode **j_note = notes + j;
if ((**j_note).size > (**min_note).size ||
((**j_note).size == (**min_note).size && *j_note < *min_note)){
min_note = j_note;
}
}
if (min_note != i_note){
ArenaProfNode *t = *i_note;
*i_note = *min_note;
*min_note = t;
}
}
//- total size
U64 total_size = 0;
{
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
ArenaProfNode *note = *note_ptr;
total_size += note->size;
}
}
//- print
{
str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size);
ArenaProfNode **note_ptr = notes;
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
ArenaProfNode *note = *note_ptr;
String8 location = push_str8f(scratch.arena, "%S:%5llu:",
note->file_name, note->line);
F32 percent = 100.f*((F32)note->size)/total_size;
str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n",
max_file_name_size + 7, str8_varg(location),
note->size, percent, note->count);
}
}
temp_end(scratch);
}
//- restore dev
arena->dev = dev;
}
internal void
arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line,
U64 size, U64 count){
// find existing profile node
ArenaProfNode *prof_node = 0;
for (ArenaProfNode *node = prof->first;
node != 0;
node = node->next){
if (node->line == line && str8_match(file_name, node->file_name, 0)){
prof_node = node;
break;
}
}
// make new histogram node if necessary
if (prof_node == 0){
prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node));
SLLQueuePush(prof->first, prof->last, prof_node);
prof->count += 1;
prof_node->file_name = file_name;
prof_node->line = line;
}
// record this allocation
prof_node->size += size;
prof_node->count += count;
}
#endif
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ARENA_DEV_H
#define BASE_ARENA_DEV_H
////////////////////////////////
//~ NOTE(allen): Dev Arena Types
typedef struct ArenaDev ArenaDev;
struct ArenaDev
{
Arena *arena;
struct ArenaProf *prof;
};
typedef struct ArenaProf ArenaProf;
struct ArenaProf
{
struct ArenaProfNode *first;
struct ArenaProfNode *last;
U64 count;
};
typedef struct ArenaProfNode ArenaProfNode;
struct ArenaProfNode
{
ArenaProfNode *next;
String8 file_name;
U64 line;
U64 size;
U64 count;
};
////////////////////////////////
//~ NOTE(allen): Dev Arena Functions
#if ENABLE_DEV
internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr);
internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub);
internal ArenaDev* arena_equip__dev(Arena *arena);
internal void arena_equip_profile__dev(Arena *arena);
internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out);
internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count);
#endif
#endif // BASE_ARENA_DEV_H
+103
View File
@@ -0,0 +1,103 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
internal U64
count_bits_set16(U16 val)
{
return __popcnt16(val);
}
internal U64
count_bits_set32(U32 val)
{
return __popcnt(val);
}
internal U64
count_bits_set64(U64 val)
{
return __popcnt64(val);
}
internal U64
ctz32(U32 mask)
{
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
internal U64
ctz64(U64 mask)
{
unsigned long idx;
_BitScanForward64(&idx, mask);
return idx;
}
internal U64
clz32(U32 mask)
{
unsigned long idx;
_BitScanReverse(&idx, mask);
return 31 - idx;
}
internal U64
clz64(U64 mask)
{
unsigned long idx;
_BitScanReverse64(&idx, mask);
return 63 - idx;
}
#elif COMPILER_CLANG || COMPILER_GCC
internal U64
count_bits_set16(U16 val)
{
NotImplemented;
return 0;
}
internal U64
count_bits_set32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
count_bits_set64(U64 val)
{
NotImplemented;
return 0;
}
internal U64
ctz32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
clz32(U32 val)
{
NotImplemented;
return 0;
}
internal U64
clz64(U64 val)
{
NotImplemented;
return 0;
}
#else
# error "bits not defined for this target"
#endif
+18
View File
@@ -0,0 +1,18 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_BITS_H
#define BASE_BITS_H
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
internal U64 count_bits_set16(U16 val);
internal U64 count_bits_set32(U32 val);
internal U64 count_bits_set64(U64 val);
internal U64 ctz32(U32 val);
internal U64 ctz64(U64 val);
internal U64 clz32(U32 val);
internal U64 clz64(U64 val);
#endif // BASE_BITS_H
+60 -59
View File
@@ -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/)
////////////////////////////////
//~ 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 **
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;
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;
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->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->value_strings = values;
StringJoin join = {0};
@@ -71,26 +82,26 @@ internal CmdLine
cmd_line_from_string_list(Arena *arena, String8List command_line)
{
CmdLine parsed = {0};
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 first_passthrough = 1;
for(String8Node *node = command_line.first->next, *next = 0; node != 0; 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;
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))
{
after_passthrough_option = 1;
@@ -104,79 +115,69 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
{
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
{
is_option = 0;
}
}
else
{
is_option = 0;
}
//- rjf: string is an option
// NOTE(rjf): This string is an option.
if(is_option)
{
// rjf: unpack option prefix
B32 has_values = 0;
U64 value_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
U64 value_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
U64 value_signifier_position = Min(value_signifier_position1, value_signifier_position2);
String8 value_portion_this_string = str8_skip(option_name, value_signifier_position+1);
if(value_signifier_position < option_name.size)
B32 has_arguments = 0;
U64 arg_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 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
if(arg_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 values = {0};
if(has_values)
String8List arguments = {0};
// NOTE(rjf): Parse arguments.
if(has_arguments)
{
for(String8Node *n = node; n; n = n->next)
{
next = n->next;
String8 string = n->string;
if(n == node)
{
string = value_portion_this_string;
string = arg_portion_this_string;
}
U8 splits[] = { ',' };
String8List values_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)
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
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) &&
(n != node || value_portion_this_string.size != 0))
(n != node || arg_portion_this_string.size != 0))
{
break;
}
}
}
// rjf: store
cmd_line_insert_opt(arena, &parsed, option_name, values);
// NOTE(rjf): Register config variable.
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
}
//- rjf: default path - treat as a passthrough input
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
// 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))
{
str8_list_push(arena, &parsed.inputs, node->string);
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;
after_passthrough_option = 1;
}
}
@@ -217,12 +218,12 @@ internal B32
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
{
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
return (var != 0);
return(var != 0);
}
internal B32
cmd_line_has_argument(CmdLine *cmd_line, String8 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);
}
+3 -5
View File
@@ -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/)
#ifndef BASE_COMMAND_LINE_H
@@ -29,18 +29,16 @@ struct CmdLineOptList
typedef struct CmdLine CmdLine;
struct CmdLine
{
String8 exe_name;
CmdLineOptList options;
String8List inputs;
U64 option_table_size;
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_opt_from_slot(CmdLineOpt **slot, String8 string);
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
+16 -167
View File
@@ -1,12 +1,9 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_CONTEXT_CRACKING_H
#define BASE_CONTEXT_CRACKING_H
////////////////////////////////
//~ rjf: Clang OS/Arch Cracking
#if defined(__clang__)
# define COMPILER_CLANG 1
@@ -18,7 +15,7 @@
# elif defined(__APPLE__) && defined(__MACH__)
# define OS_MAC 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
@@ -30,40 +27,17 @@
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# endif
////////////////////////////////
//~ rjf: MSVC OS/Arch Cracking
#elif defined(_MSC_VER)
# define COMPILER_MSVC 1
# if _MSC_VER >= 1920
# define COMPILER_MSVC_YEAR 2019
# elif _MSC_VER >= 1910
# define COMPILER_MSVC_YEAR 2017
# elif _MSC_VER >= 1900
# define COMPILER_MSVC_YEAR 2015
# elif _MSC_VER >= 1800
# define COMPILER_MSVC_YEAR 2013
# elif _MSC_VER >= 1700
# define COMPILER_MSVC_YEAR 2012
# elif _MSC_VER >= 1600
# define COMPILER_MSVC_YEAR 2010
# elif _MSC_VER >= 1500
# define COMPILER_MSVC_YEAR 2008
# elif _MSC_VER >= 1400
# define COMPILER_MSVC_YEAR 2005
# else
# define COMPILER_MSVC_YEAR 0
# endif
# define COMPILER_CL 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(_M_AMD64)
@@ -75,12 +49,9 @@
# elif defined(_M_ARM)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# endif
////////////////////////////////
//~ rjf: GCC OS/Arch Cracking
#elif defined(__GNUC__) || defined(__GNUG__)
# define COMPILER_GCC 1
@@ -88,7 +59,7 @@
# if defined(__gnu_linux__) || defined(__linux__)
# define OS_LINUX 1
# else
# error This compiler/OS combo is not supported.
# error This compiler/platform combo is not supported yet
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
@@ -100,100 +71,26 @@
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Architecture not supported.
# error architecture not supported yet
# endif
#else
# error Compiler not supported.
# error This compiler is not supported yet
#endif
////////////////////////////////
//~ rjf: Arch Cracking
#if defined(ARCH_X64)
# define ARCH_64BIT 1
#elif defined(ARCH_X86)
# define ARCH_32BIT 1
#endif
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
# define ARCH_LITTLE_ENDIAN 1
#else
# error Endianness of this architecture not understood by context cracker.
#endif
////////////////////////////////
//~ rjf: Language Cracking
#if defined(__cplusplus)
# define LANG_CPP 1
#else
# define LANG_C 1
#endif
////////////////////////////////
//~ rjf: Build Option Cracking
#if !defined(BUILD_DEBUG)
# define BUILD_DEBUG 1
#endif
#if !defined(BUILD_TESTS)
# define BUILD_TESTS 0
#endif
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
# define BUILD_SUPPLEMENTARY_UNIT 0
#endif
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
# define BUILD_ENTRY_DEFINING_UNIT 1
#endif
#if !defined(BUILD_CONSOLE_INTERFACE)
# define BUILD_CONSOLE_INTERFACE 0
#endif
#if !defined(BUILD_VERSION_MAJOR)
# define BUILD_VERSION_MAJOR 0
#endif
#if !defined(BUILD_VERSION_MINOR)
# define BUILD_VERSION_MINOR 9
#endif
#if !defined(BUILD_VERSION_PATCH)
# define BUILD_VERSION_PATCH 28
#endif
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
#if BUILD_DEBUG
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
#else
# define BUILD_MODE_STRING_LITERAL_APPEND ""
#endif
#if defined(BUILD_GIT_HASH)
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
#else
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
#endif
#if !defined(BUILD_TITLE)
# define BUILD_TITLE "Untitled"
#endif
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#endif
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/raddebugger/issues"
#endif
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
////////////////////////////////
//~ rjf: Zero All Undefined Options
// zeroify
#if !defined(ARCH_32BIT)
# define ARCH_32BIT 0
@@ -213,8 +110,8 @@
#if !defined(ARCH_ARM32)
# define ARCH_ARM32 0
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#if !defined(COMPILER_CL)
# define COMPILER_CL 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
@@ -238,58 +135,10 @@
# define LANG_C 0
#endif
////////////////////////////////
//~ rjf: Unsupported Errors
#if ARCH_X86
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
#endif
#if !ARCH_X64
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#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
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
# define ARCH_LITTLE_ENDIAN 1
#else
# error Endianness of this architecture not understood by context cracker
#endif
#endif // BASE_CONTEXT_CRACKING_H
-809
View File
@@ -1,809 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Safe Casts
internal U16
safe_cast_u16(U32 x)
{
AssertAlways(x <= max_U16);
U16 result = (U16)x;
return result;
}
internal U32
safe_cast_u32(U64 x)
{
AssertAlways(x <= max_U32);
U32 result = (U32)x;
return result;
}
internal S32
safe_cast_s32(S64 x)
{
AssertAlways(x <= max_S32);
S32 result = (S32)x;
return result;
}
////////////////////////////////
//~ rjf: Large Base Type Functions
internal U128
u128_zero(void)
{
U128 v = {0};
return v;
}
internal U128
u128_make(U64 v0, U64 v1)
{
U128 v = { .u64 = { v0, v1 }};
return v;
}
internal B32
u128_match(U128 a, U128 b)
{
return MemoryMatchStruct(&a, &b);
}
////////////////////////////////
//~ rjf: Bit Patterns
internal U32
u32_from_u64_saturate(U64 x){
U32 x32 = (x > max_U32)?max_U32:(U32)x;
return(x32);
}
internal U64
u64_up_to_pow2(U64 x){
if (x == 0){
x = 1;
}
else{
x -= 1;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x += 1;
}
return(x);
}
internal S32
extend_sign32(U32 x, U32 size)
{
U32 n = size * 8;
U32 m = (U32)1 << (n - 1);
S32 r = (S32)((x ^ m) - m);
return r;
}
internal S64
extend_sign64(U64 x, U64 size)
{
U64 n = size * 8;
U64 m = (U64)1 << (n - 1);
S64 r = (S64)((x ^ m) - m);
return r;
}
internal F32
inf32(void){
union { U32 u; F32 f; } x;
x.u = exponent32;
return(x.f);
}
internal F32
neg_inf32(void){
union { U32 u; F32 f; } x;
x.u = sign32 | exponent32;
return(x.f);
}
internal U16
bswap_u16(U16 x)
{
U16 result = (((x & 0xFF00) >> 8) |
((x & 0x00FF) << 8));
return result;
}
internal U32
bswap_u32(U32 x)
{
U32 result = (((x & 0xFF000000) >> 24) |
((x & 0x00FF0000) >> 8) |
((x & 0x0000FF00) << 8) |
((x & 0x000000FF) << 24));
return result;
}
internal U64
bswap_u64(U64 x)
{
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x00000000000000FFULL) << 56));
return result;
}
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
internal U64
count_bits_set32(U32 val)
{
return __popcnt(val);
}
internal U64
count_bits_set64(U64 val)
{
return __popcnt64(val);
}
internal U64
ctz32(U32 mask)
{
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
internal U64
ctz64(U64 mask)
{
unsigned long idx;
_BitScanForward64(&idx, mask);
return idx;
}
internal U64
clz32(U32 mask)
{
unsigned long idx;
_BitScanReverse(&idx, mask);
return 31 - idx;
}
internal U64
clz64(U64 mask)
{
unsigned long idx;
_BitScanReverse64(&idx, mask);
return 63 - idx;
}
#elif COMPILER_CLANG || COMPILER_GCC
internal U64
count_bits_set32(U32 val)
{
return __builtin_popcount(val);
}
internal U64
count_bits_set64(U64 val)
{
return __builtin_popcountll(val);
}
internal U64
ctz32(U32 val)
{
return __builtin_ctz(val);
}
internal U64
clz32(U32 val)
{
return __builtin_clz(val);
}
internal U64
ctz64(U64 val)
{
return __builtin_ctzll(val);
}
internal U64
clz64(U64 val)
{
return __builtin_clzll(val);
}
#else
# error "Bit intrinsic functions not defined for this compiler."
#endif
////////////////////////////////
//~ rjf: Enum -> Sign
internal S32
sign_from_side_S32(Side side){
return((side == Side_Min)?-1:1);
}
internal F32
sign_from_side_F32(Side side){
return((side == Side_Min)?-1.f:1.f);
}
////////////////////////////////
//~ rjf: Memory Functions
internal B32
memory_is_zero(void *ptr, U64 size)
{
B32 result = 1;
// break down size
U64 extra = (size&0x7);
U64 count8 = (size >> 3);
// check with 8-byte stride
U64 *p64 = (U64*)ptr;
if(result)
{
for(U64 i = 0; i < count8; i += 1, p64 += 1)
{
if(*p64 != 0)
{
result = 0;
goto done;
}
}
}
// check extra
if(result)
{
U8 *p8 = (U8*)p64;
for(U64 i = 0; i < extra; i += 1, p8 += 1)
{
if(*p8 != 0)
{
result = 0;
goto done;
}
}
}
done:;
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;
}
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
internal TxtPt
txt_pt(S64 line, S64 column)
{
TxtPt p = {0};
p.line = line;
p.column = column;
return p;
}
internal B32
txt_pt_match(TxtPt a, TxtPt b)
{
return a.line == b.line && a.column == b.column;
}
internal B32
txt_pt_less_than(TxtPt a, TxtPt b)
{
B32 result = 0;
if(a.line < b.line)
{
result = 1;
}
else if(a.line == b.line)
{
result = a.column < b.column;
}
return result;
}
internal TxtPt
txt_pt_min(TxtPt a, TxtPt b)
{
TxtPt result = b;
if(txt_pt_less_than(a, b))
{
result = a;
}
return result;
}
internal TxtPt
txt_pt_max(TxtPt a, TxtPt b)
{
TxtPt result = a;
if(txt_pt_less_than(a, b))
{
result = b;
}
return result;
}
internal TxtRng
txt_rng(TxtPt min, TxtPt max)
{
TxtRng range = {0};
if(txt_pt_less_than(min, max))
{
range.min = min;
range.max = max;
}
else
{
range.min = max;
range.max = min;
}
return range;
}
internal TxtRng
txt_rng_intersect(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_max(a.min, b.min);
result.max = txt_pt_min(a.max, b.max);
if(txt_pt_less_than(result.max, result.min))
{
MemoryZeroStruct(&result);
}
return result;
}
internal TxtRng
txt_rng_union(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_min(a.min, b.min);
result.max = txt_pt_max(a.max, b.max);
return result;
}
internal B32
txt_rng_contains(TxtRng r, TxtPt pt)
{
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) &&
txt_pt_less_than(pt, r.max));
return result;
}
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
internal U64
bit_size_from_arch(Arch arch)
{
// TODO(rjf): metacode
U64 arch_bitsize = 0;
switch(arch)
{
case Arch_x64: arch_bitsize = 64; break;
case Arch_x86: arch_bitsize = 32; break;
case Arch_arm64: arch_bitsize = 64; break;
case Arch_arm32: arch_bitsize = 32; break;
default: break;
}
return arch_bitsize;
}
internal U64
byte_size_from_arch(Arch 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
return 64;
}
////////////////////////////////
//~ rjf: Time Functions
internal DenseTime
dense_time_from_date_time(DateTime date_time){
DenseTime result = 0;
result += date_time.year;
result *= 12;
result += date_time.mon;
result *= 31;
result += date_time.day;
result *= 24;
result += date_time.hour;
result *= 60;
result += date_time.min;
result *= 61;
result += date_time.sec;
result *= 1000;
result += date_time.msec;
return(result);
}
internal DateTime
date_time_from_dense_time(DenseTime time){
DateTime result = {0};
result.msec = time%1000;
time /= 1000;
result.sec = time%61;
time /= 61;
result.min = time%60;
time /= 60;
result.hour = time%24;
time /= 24;
result.day = time%31;
time /= 31;
result.mon = time%12;
time /= 12;
Assert(time <= max_U32);
result.year = (U32)time;
return(result);
}
internal DateTime
date_time_from_micro_seconds(U64 time){
DateTime result = {0};
result.micro_sec = time%1000;
time /= 1000;
result.msec = time%1000;
time /= 1000;
result.sec = time%60;
time /= 60;
result.min = time%60;
time /= 60;
result.hour = time%24;
time /= 24;
result.day = time%31;
time /= 31;
result.mon = time%12;
time /= 12;
Assert(time <= max_U32);
result.year = (U32)time;
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
internal U64
wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
{
Assert(src_data_size <= ring_size);
{
U64 ring_off = ring_pos%ring_size;
U64 bytes_before_split = ring_size-ring_off;
U64 pre_split_bytes = Min(bytes_before_split, src_data_size);
U64 pst_split_bytes = src_data_size-pre_split_bytes;
void *pre_split_data = src_data;
void *pst_split_data = ((U8 *)src_data + pre_split_bytes);
MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes);
MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes);
}
return src_data_size;
}
internal U64
wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
{
Assert(read_size <= ring_size);
{
U64 ring_off = ring_pos%ring_size;
U64 bytes_before_split = ring_size-ring_off;
U64 pre_split_bytes = Min(bytes_before_split, read_size);
U64 pst_split_bytes = read_size-pre_split_bytes;
MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes);
MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes);
}
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,
};
-1135
View File
File diff suppressed because it is too large Load Diff
-20
View File
@@ -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
-249
View File
@@ -1,249 +0,0 @@
// 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
main_thread_base_entry_point(int arguments_count, char **arguments)
{
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
local_persist char tm_data[MB(64)];
tmLoadLibrary(TM_RELEASE);
tmSetMaxThreadCount(256);
tmInitialize(sizeof(tm_data), tm_data);
#endif
//- rjf: set up spall
#if PROFILE_SPALL
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
#endif
//- 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);
//- rjf: begin captures
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
if(capture)
{
ProfBeginCapture(arguments[0]);
ProfMsg(BUILD_TITLE);
}
//- rjf: initialize all included layers
#if defined(HTTP_H) && !defined(HTTP_INIT_MANUAL)
http_init();
#endif
#if defined(SYMBOL_SERVER_H) && !defined(SMSV_INIT_MANUAL)
smsv_init();
#endif
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
ac_init();
#endif
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
c_init();
#endif
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
fs_init();
#endif
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
mtx_init();
#endif
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
di_init(&cmdline);
#endif
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
dmn_init();
#endif
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
d_init();
#endif
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
wm_init();
#endif
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
fp_init();
#endif
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
r_init(&cmdline);
#endif
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
fnt_init();
#endif
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
rd_init(&cmdline);
#endif
//- rjf: launch async threads
#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
U64 num_async_threads = get_system_info()->logical_processor_count;
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
num_async_threads -= num_main_threads_clamped;
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
if(num_async_threads_string.size != 0)
{
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
//- rjf: call into entry point
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)
{
ProfEndCapture();
}
scratch_end(scratch);
}
internal void
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
{
TCTX *tctx = tctx_alloc();
tctx_select(tctx);
entry_point(params);
tctx_release(tctx);
}
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;
}
}
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ENTRY_POINT_H
#define BASE_ENTRY_POINT_H
internal void main_thread_base_entry_point(int argc, char **argv);
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
internal U64 update_tick_idx(void);
internal B32 update(void);
internal void async_thread_entry_point(void *params);
#endif // BASE_ENTRY_POINT_H
-169
View File
@@ -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;
}
-102
View File
@@ -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
-50
View File
@@ -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;
}
-48
View File
@@ -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
+8 -29
View File
@@ -1,39 +1,18 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Base Includes
#undef LAYER_COLOR
#define LAYER_COLOR 0x3399ccff
#undef RADDBG_LAYER_COLOR
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
#include "base_core.c"
#include "base_profile.c"
#include "base_memory.c"
#include "base_types.c"
#include "base_markup.c"
#include "base_arena.c"
#include "base_math.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_string.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_markup.c"
#include "base_meta.c"
#include "base_log.c"
#include "base_test.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
#include "base_arena_dev.c"
#include "base_bits.c"
+8 -28
View File
@@ -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/)
#ifndef BASE_INC_H
@@ -8,36 +8,16 @@
//~ rjf: Base Includes
#include "base_context_cracking.h"
#include "base_core.h"
#include "base_profile.h"
#include "base_memory.h"
#include "base_types.h"
#include "base_markup.h"
#include "base_ins.h"
#include "base_linked_lists.h"
#include "base_arena.h"
#include "base_math.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_string.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_markup.h"
#include "base_meta.h"
#include "base_log.h"
#include "base_test.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
#include "base_arena_dev.h"
#include "base_bits.h"
#endif // BASE_INC_H
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_INS_H
#define BASE_INS_H
////////////////////////////////
// NOTE(allen): Implementations of Intrinsics
#if OS_WINDOWS
# include <windows.h>
# include <tmmintrin.h>
# include <wmmintrin.h>
# include <intrin.h>
# if ARCH_X64
# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0)
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
# endif
#elif OS_LINUX
# if ARCH_X64
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
# endif
#else
// TODO(allen):
#endif
////////////////////////////////
// NOTE(allen): Intrinsic Checks
#if ARCH_X64
# if !defined(ins_atomic_u64_inc_eval)
# error missing: ins_atomic_u64_inc_eval
# endif
#else
# error the intrinsic set for this arch is not developed
#endif
#endif //BASE_INS_H
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_LINKED_LIST_H
#define BASE_LINKED_LIST_H
////////////////////////////////
//~ rjf: Helpers
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((p) = nil)
////////////////////////////////
//~ rjf: Base Macros
//- rjf: Base Doubly-Linked-List Macros
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
CheckNil(nil,p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
((p)==(l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
((n) == (l) ? (l) = (l)->prev : (0)),\
(CheckNil(nil,(n)->prev) ? (0) :\
((n)->prev->next = (n)->next)),\
(CheckNil(nil,(n)->next) ? (0) :\
((n)->next->prev = (n)->prev)))
//- rjf: Base Singly-Linked-List Queue Macros
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
((f)=(l)=(n),SetNil(nil,(n)->next)):\
((n)->next=(f),(f)=(n)))
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
(SetNil(nil,f),SetNil(nil,l)):\
((f)=(f)->next))
//- rjf: Base Singly-Linked-List Stack Macros
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define SLLStackPop_N(f,next) ((f)=(f)->next)
////////////////////////////////
//~ rjf: Convenience Wrappers
//- rjf: Doubly-Linked-List Wrappers
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
//- rjf: Singly-Linked-List Queue Wrappers
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
//- rjf: Singly-Linked-List Stack Wrappers
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
#define SLLStackPop(f) SLLStackPop_N(f,next)
#endif //BASE_LINKED_LIST_H
-105
View File
@@ -1,105 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Globals/Thread-Locals
C_LINKAGE thread_static Log *log_active;
#if !BUILD_SUPPLEMENTARY_UNIT
C_LINKAGE thread_static Log *log_active = 0;
#endif
String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
internal Log *
log_alloc(void)
{
Arena *arena = arena_alloc();
Log *log = push_array(arena, Log, 1);
log->arena = arena;
return log;
}
internal void
log_release(Log *log)
{
arena_release(log->arena);
}
internal void
log_select(Log *log)
{
log_active = log;
}
////////////////////////////////
//~ rjf: Log Building/Clearing
internal void
log_msg(LogMsgKind kind, String8 string)
{
if(log_active != 0 && log_active->top_scope != 0)
{
String8 string_copy = push_str8_copy(log_active->arena, string);
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
}
}
internal void
log_msgf(LogMsgKind kind, char *fmt, ...)
{
if(log_active != 0)
{
Temp scratch = scratch_begin(0, 0);
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
log_msg(kind, string);
va_end(args);
scratch_end(scratch);
}
}
////////////////////////////////
//~ rjf: Log Scopes
internal void
log_scope_begin(void)
{
if(log_active != 0)
{
U64 pos = arena_pos(log_active->arena);
LogScope *scope = push_array(log_active->arena, LogScope, 1);
scope->pos = pos;
SLLStackPush(log_active->top_scope, scope);
}
}
internal LogScopeResult
log_scope_end(Arena *arena)
{
LogScopeResult result = {0};
if(log_active != 0)
{
LogScope *scope = log_active->top_scope;
if(scope != 0)
{
SLLStackPop(log_active->top_scope);
if(arena != 0)
{
for EachEnumVal(LogMsgKind, kind)
{
Temp scratch = scratch_begin(&arena, 1);
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);
}
}
return result;
}
-70
View File
@@ -1,70 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_LOG_H
#define BASE_LOG_H
////////////////////////////////
//~ rjf: Log Types
typedef enum LogMsgKind
{
LogMsgKind_Info,
LogMsgKind_UserError,
LogMsgKind_COUNT
}
LogMsgKind;
typedef struct LogScope LogScope;
struct LogScope
{
LogScope *next;
U64 pos;
String8List strings[LogMsgKind_COUNT];
};
typedef struct LogScopeResult LogScopeResult;
struct LogScopeResult
{
String8 strings[LogMsgKind_COUNT];
};
typedef struct Log Log;
struct Log
{
Arena *arena;
LogScope *top_scope;
};
////////////////////////////////
// Globals
extern String8 g_logs_folder;
////////////////////////////////
//~ rjf: Log Creation/Selection
internal Log *log_alloc(void);
internal void log_release(Log *log);
internal void log_select(Log *log);
////////////////////////////////
//~ rjf: Log Building
internal void log_msg(LogMsgKind kind, String8 string);
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
#define log_info(s) log_msg(LogMsgKind_Info, (s))
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __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
internal void log_scope_begin(void);
internal LogScopeResult log_scope_end(Arena *arena);
#endif // BASE_LOG_H
+1 -1
View File
@@ -1,2 +1,2 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
+69 -10
View File
@@ -1,20 +1,79 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_MARKUP_H
#define BASE_MARKUP_H
#define RADDBG_MARKUP_IMPLEMENTATION
#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf
#if OS_LINUX
# define RADDBG_MARKUP_STUBS
#endif
#include "lib_raddbg_markup/raddbg_markup.h"
////////////////////////////////
//~ rjf: Zero Settings
#if !defined(LAYER_COLOR)
# define LAYER_COLOR 0x404040ff
#if !defined(PROFILE_TELEMETRY)
# define PROFILE_TELEMETRY 0
#endif
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
#if !defined(MARKUP_LAYER_COLOR)
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
#endif
////////////////////////////////
//~ rjf: Third Party Includes
#if PROFILE_TELEMETRY
# include "rad_tm.h"
# if OS_WINDOWS
# pragma comment(lib, "rad_tm_win64.lib")
# endif
#endif
////////////////////////////////
//~ rjf: Telemetry Profile Defines
#if PROFILE_TELEMETRY
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
# define ProfTick(...) tmTick(0)
# define ProfIsCapturing(...) tmRunning()
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
# define ProfEndCapture(...) tmClose(0)
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
# define ProfEndLockWait(...) tmEndWaitForLock(0)
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
# define ProfColor(color) tmZoneColorSticky(color)
#endif
////////////////////////////////
//~ rjf: Zeroify Undefined Defines
#if !defined(ProfBegin)
# define ProfBegin(...) (0)
# define ProfBeginDynamic(...) (0)
# define ProfEnd(...) (0)
# define ProfTick(...) (0)
# define ProfIsCapturing(...) (0)
# define ProfBeginCapture(...) (0)
# define ProfEndCapture(...) (0)
# define ProfThreadName(...) (0)
# define ProfMsg(...) (0)
# define ProfBeginLockWait(...) (0)
# define ProfEndLockWait(...) (0)
# define ProfLockTake(...) (0)
# define ProfLockDrop(...) (0)
# define ProfColor(...) (0)
#endif
////////////////////////////////
//~ rjf: Helper Wrappers
#define ProfBeginFunction(...) ProfBegin(this_function_name)
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
////////////////////////////////
//~ rjf: General Markup
#define ThreadName(...) (ProfThreadName(__VA_ARGS__))
#endif // BASE_MARKUP_H
+22 -255
View File
@@ -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/)
////////////////////////////////
//~ rjf: Scalar Math Ops
//~ rjf: Scalar Ops
internal F32
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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;}
////////////////////////////////
@@ -389,50 +386,15 @@ derotate_4x4f32(Mat4x4F32 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
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 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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
@@ -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 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 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 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;}
////////////////////////////////
//~ rjf: Color Operations
//- rjf: hsv <-> rgb
//~ rjf: Miscellaneous Ops
internal Vec3F32
hsv_from_rgb(Vec3F32 rgb)
@@ -607,102 +567,16 @@ rgba_from_hsva(Vec4F32 hsva)
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
linear_from_srgba(Vec4F32 srgba)
rgba_from_u32(U32 hex)
{
Vec4F32 result;
result.xyz = linear_from_srgb(srgba.xyz);
result.w = srgba.w;
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;
}
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
u32_from_rgba(Vec4F32 rgba)
{
@@ -714,99 +588,9 @@ u32_from_rgba(Vec4F32 rgba)
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
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
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
{
@@ -830,20 +614,3 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list)
}
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
View File
@@ -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/)
#ifndef BASE_MATH_H
@@ -177,28 +177,6 @@ struct Mat4x4F32
//- 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;
union Rng1U32
{
@@ -349,29 +327,7 @@ union Rng2S64
};
////////////////////////////////
//~ rjf: Range 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;
};
//~ rjf: List Types
typedef struct Rng1S64Node Rng1S64Node;
struct Rng1S64Node
@@ -396,20 +352,19 @@ struct Rng1S64Array
};
////////////////////////////////
//~ rjf: Scalar Math Ops
//~ rjf: Scalar Ops
#define abs_s64(v) (S64)llabs(v)
#define sqrt_f32(v) sqrtf(v)
#define cbrt_f32(v) cbrtf(v)
#define mod_f32(a, b) fmodf((a), (b))
#define pow_f32(b, e) powf((b), (e))
#define ceil_f32(v) ceilf(v)
#define floor_f32(v) floorf(v)
#define round_f32(v) roundf(v)
#define abs_f32(v) fabsf(v)
#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f))
#define turns_from_radians_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 degrees_from_turns_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)))
@@ -419,15 +374,14 @@ struct Rng1S64Array
#define tan_f32(v) tanf(radians_from_turns_f32(v))
#define sqrt_f64(v) sqrt(v)
#define cbrt_f64(v) cbrt(v)
#define mod_f64(a, b) fmod((a), (b))
#define pow_f64(b, e) pow((b), (e))
#define ceil_f64(v) ceil(v)
#define floor_f64(v) floor(v)
#define round_f64(v) round(v)
#define abs_f64(v) fabs(v)
#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897))
#define turns_from_radians_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 degrees_from_turns_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)))
@@ -465,6 +419,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
internal S64 length_squared_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);
#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 length_squared_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);
#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 length_squared_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);
#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 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
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))
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 length_squared_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 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 length_squared_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);
////////////////////////////////
@@ -563,37 +521,11 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
////////////////////////////////
//~ 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 r1u32s(min, size) rng_1u32((min), (min)+(size))
internal Rng1U32 rng_1u32(U32 min, U32 max);
internal Rng1U32 shift_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);
#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 shift_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);
#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 shift_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);
#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 shift_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);
#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 shift_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);
#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)))
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
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);
#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)))
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
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);
#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)))
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
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);
#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)))
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
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);
////////////////////////////////
//~ rjf: Color Operations
//~ rjf: Miscellaneous Ops
//- rjf: hsv <-> rgb
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
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 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 }
////////////////////////////////
//~ 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 Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
////////////////////////////////
//~ 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
#endif // BASE_MATH_H
-20
View File
@@ -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
-56
View File
@@ -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;
}
-39
View File
@@ -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
-421
View File
@@ -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 = &params->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 = &params->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;
}
-297
View File
@@ -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
-115
View File
@@ -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(&params);
// 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;
}
-91
View File
@@ -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
-31
View File
@@ -1,31 +0,0 @@
// Copyright (c) Epic Games Tools
// 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
-126
View File
@@ -1,126 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_PROFILE_H
#define BASE_PROFILE_H
////////////////////////////////
//~ rjf: Zero Settings
#if !defined(PROFILE_TELEMETRY)
# define PROFILE_TELEMETRY 0
#endif
#if !defined(PROFILE_SPALL)
# define PROFILE_SPALL 0
#endif
////////////////////////////////
//~ rjf: Third Party Includes
#if PROFILE_TELEMETRY
# include "rad_tm.h"
# if OS_WINDOWS
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "rad_tm_win64.lib")
# endif
#elif PROFILE_SPALL
# include "spall.h"
#endif
////////////////////////////////
//~ rjf: Telemetry Profile Defines
#if PROFILE_TELEMETRY
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
# define ProfTick(...) tmTick(0)
# define ProfIsCapturing(...) tmRunning()
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
# define ProfEndCapture(...) tmClose(0)
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
# define ProfEndLockWait(...) tmEndWaitForLock(0)
# define ProfLockTake(...) tmAcquiredLock(0, 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 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
////////////////////////////////
//~ rjf: Zeroify Undefined Defines
#if !defined(ProfBegin)
# define ProfBegin(...) (0)
# define ProfBeginDynamic(...) (0)
# define ProfEnd(...) (0)
# define ProfTick(...) (0)
# define ProfIsCapturing(...) (0)
# define ProfBeginCapture(...) (0)
# define ProfEndCapture(...) (0)
# define ProfThreadName(...) (0)
# define ProfMsg(...) (0)
# define ProfBeginLockWait(...) (0)
# define ProfEndLockWait(...) (0)
# define ProfLockTake(...) (0)
# define ProfLockDrop(...) (0)
# define ProfColor(...) (0)
# define ProfBeginV(...) (0)
# define ProfNoteV(...) (0)
#endif
////////////////////////////////
//~ rjf: Helper Wrappers
#define ProfBeginFunction(...) ProfBegin(this_function_name)
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
#endif // BASE_PROFILE_H
-139
View File
@@ -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;
}
-56
View File
@@ -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
-2
View File
@@ -1,2 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-22
View File
@@ -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
File diff suppressed because it is too large Load Diff
@@ -1,8 +1,14 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_STRINGS_H
#define BASE_STRINGS_H
#ifndef BASE_STRING_H
#define BASE_STRING_H
////////////////////////////////
//~ rjf: Third Party Includes
#define STB_SPRINTF_DECORATE(name) raddbg_##name
#include "third_party/stb/stb_sprintf.h"
////////////////////////////////
//~ rjf: String Types
@@ -38,6 +44,13 @@ struct String8Node
String8 string;
};
typedef struct String8MetaNode String8MetaNode;
struct String8MetaNode
{
String8MetaNode *next;
String8Node *node;
};
typedef struct String8List String8List;
struct String8List
{
@@ -50,9 +63,8 @@ struct String8List
typedef struct String8Array String8Array;
struct String8Array
{
String8 *v;
String8 *strings;
U64 count;
U64 total_size;
};
////////////////////////////////
@@ -74,7 +86,6 @@ enum
typedef enum PathStyle
{
PathStyle_Null,
PathStyle_Relative,
PathStyle_WindowsAbsolute,
PathStyle_UnixAbsolute,
@@ -84,7 +95,7 @@ typedef enum PathStyle
#elif OS_LINUX
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
#else
# error Absolute path style is undefined for this OS.
# error "absolute path style is undefined for this OS"
#endif
}
PathStyle;
@@ -146,9 +157,9 @@ internal B32 char_is_lower(U8 c);
internal B32 char_is_alpha(U8 c);
internal B32 char_is_slash(U8 c);
internal B32 char_is_digit(U8 c, U32 base);
internal U8 lower_from_char(U8 c);
internal U8 upper_from_char(U8 c);
internal U8 correct_slash_from_char(U8 c);
internal U8 char_to_lower(U8 c);
internal U8 char_to_upper(U8 c);
internal U8 char_to_correct_slash(U8 c);
////////////////////////////////
//~ rjf: C-String Measurement
@@ -160,11 +171,8 @@ internal U64 cstring32_length(U32 *c);
////////////////////////////////
//~ rjf: String Constructors
#define s(S) str8_lit(S)
#define str8_lit(S) str8((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_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 String32 str32_cstring(U32 *c);
internal String8 str8_cstring_capped(void *cstr, void *cap);
internal String16 str16_cstring_capped(void *cstr, void *cap);
////////////////////////////////
//~ rjf: String Stylization
@@ -196,17 +203,9 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
////////////////////////////////
//~ 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);
#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_reverse(String8 string, U64 start_pos, String8 needle, 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))
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
////////////////////////////////
//~ 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_postfix(String8 str, U64 size);
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_slashes(String8 string);
////////////////////////////////
//~ rjf: String Formatting & Copying
internal String8 str8_cat(Arena *arena, String8 s1, String8 s2);
internal String8 str8_copy(Arena *arena, String8 s);
internal String8 str8fv(Arena *arena, char *fmt, va_list args);
internal String8 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.
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
internal String8 push_str8_copy(Arena *arena, String8 s);
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
internal String8 push_str8f(Arena *arena, char *fmt, ...);
////////////////////////////////
//~ rjf: String <=> Integer Conversions
@@ -240,19 +231,13 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn
//- rjf: string -> integer
internal S64 sign_from_str8(String8 string, String8 *string_tail);
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 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_s64_from_str8_c_rules(String8 string, S64 *x);
//- rjf: integer -> string
internal String8 str8_from_memory_size(Arena *arena, U64 size);
internal String8 str8_from_count(Arena *arena, U64 count);
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
internal String8 str8_from_memory_size(Arena *arena, U64 z);
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);
@@ -264,19 +249,17 @@ internal F64 f64_from_str8(String8 string);
////////////////////////////////
//~ rjf: String List Construction Functions
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_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(Arena *arena, String8List *list, String8 string);
internal String8Node *str8_list_push_front(Arena *arena, String8List *list, String8 string);
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_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(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 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_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_substr(Arena *arena, String8List list, Rng1U64 range);
#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_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);
////////////////////////////////
//~ rjf: Basic Data Stringification Helpers
internal String8List numeric_str8_list_from_data(Arena *arena, U32 radix, String8 data, U64 stride);
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
////////////////////////////////
//~ rjf; String Arrays
internal String8Array str8_array_zero(void);
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
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
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_skip_last_slash(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);
////////////////////////////////
//~ 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
@@ -366,6 +299,7 @@ internal UnicodeDecode utf8_decode(U8 *str, U64 max);
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
internal U32 utf8_encode(U8 *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
@@ -376,42 +310,22 @@ internal String8 str8_from_32(Arena *arena, String32 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_side(Side side);
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_month(Month month);
internal String8 string_from_date_time(Arena *arena, DateTime *date_time);
internal String8 string_from_date_time__file_name(Arena *arena, DateTime *date_time);
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
////////////////////////////////
//~ rjf: String <-> Globally Unique IDs
internal String8 string_from_guid(Arena *arena, Guid guid);
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
internal Guid guid_from_string(String8 string);
////////////////////////////////
//~ rjf: Basic Text Indentation
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);
////////////////////////////////
//~ rjf: String <-> Color
@@ -434,12 +348,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_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_u64(Arena *arena, String8List *srl, U64 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_u8(Arena *arena, String8List *srl, U8 x);
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_u64(Arena *arena, String8List *srl, U64 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_u8(Arena *arena, String8List *srl, U8 x);
internal void str8_serial_push_cstr(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_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
@@ -448,33 +362,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_find_first_match(String8 string, U64 off, U16 scan_val);
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 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_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);
#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)
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);
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
////////////////////////////////
//~ 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_STRING_H
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-22
View File
@@ -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
-51
View File
@@ -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
-101
View File
@@ -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
+31 -187
View File
@@ -1,234 +1,78 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// 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;
#if !BUILD_SUPPLEMENTARY_UNIT
C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
C_LINKAGE thread_static TCTX* tctx_thread_local;
#if !SUPPLEMENT_UNIT
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
#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
tctx_release(TCTX *tctx)
{
arena_release(tctx->arenas[1]);
arena_release(tctx->arenas[0]);
}
internal void
tctx_select(TCTX *tctx)
{
tctx_init_and_equip(TCTX *tctx){
MemoryZeroStruct(tctx);
Arena **arena_ptr = tctx->arenas;
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
*arena_ptr = arena_alloc();
}
tctx_thread_local = tctx;
}
internal TCTX *
tctx_selected(void)
{
return tctx_thread_local;
internal TCTX*
tctx_get_equipped(void){
return(tctx_thread_local);
}
//- rjf: scratch arenas
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 **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;
B32 has_conflict = 0;
for(U64 j = 0; j < count; j += 1, conflict_ptr += 1)
{
if(*arena_ptr == *conflict_ptr)
{
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
if (*arena_ptr == *conflict_ptr){
has_conflict = 1;
break;
}
}
if(!has_conflict)
{
if (!has_conflict){
result = *arena_ptr;
break;
}
}
return result;
}
//- rjf: lane metadata
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;
return(result);
}
internal void
tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx)
{
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();
tctx_set_thread_name(String8 string){
TCTX *tctx = tctx_get_equipped();
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
MemoryCopy(tctx->thread_name, string.str, size);
tctx->thread_name_size = size;
}
internal String8
tctx_get_thread_name(void)
{
TCTX *tctx = tctx_selected();
tctx_get_thread_name(void){
TCTX *tctx = tctx_get_equipped();
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
return result;
return(result);
}
//- rjf: thread source-locations
internal void
tctx_write_srcloc(char *file_name, U64 line_number)
{
TCTX *tctx = tctx_selected();
tctx_write_srcloc(char *file_name, U64 line_number){
TCTX *tctx = tctx_get_equipped();
tctx->file_name = file_name;
tctx->line_number = line_number;
}
internal void
tctx_read_srcloc(char **file_name, U64 *line_number)
{
TCTX *tctx = tctx_selected();
tctx_read_srcloc(char **file_name, U64 *line_number){
TCTX *tctx = tctx_get_equipped();
*file_name = tctx->file_name;
*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;
}
+15 -107
View File
@@ -1,132 +1,40 @@
// Copyright (c) Epic Games Tools
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_THREAD_CONTEXT_H
#define BASE_THREAD_CONTEXT_H
////////////////////////////////
//~ rjf: Lane 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
// NOTE(allen): Thread Context
typedef struct TCTX TCTX;
struct TCTX
{
// rjf: scratch arenas
Arena *arenas[2];
// rjf: thread name
U8 thread_name[32];
U64 thread_name_size;
// rjf: lane context
LaneCtx lane_ctx;
// rjf: source location info
char *file_name;
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 TCTX *tctx_alloc(void);
internal void tctx_release(TCTX *tctx);
internal void tctx_select(TCTX *tctx);
internal TCTX *tctx_selected(void);
internal void tctx_init_and_equip(TCTX *tctx);
internal TCTX* tctx_get_equipped(void);
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
internal void tctx_set_thread_name(String8 name);
internal String8 tctx_get_thread_name(void);
internal void tctx_write_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__)
//- rjf: scratch arenas
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 String8 tctx_get_thread_name(void);
//- rjf: thread source-locations
internal void tctx_write_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__)
//- rjf: access scopes
internal Access *access_open(void);
internal void access_close(Access *access);
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
//- rjf: access points
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
#endif //BASE_THREAD_CONTEXT_H
-204
View File
@@ -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);
}
-159
View File
@@ -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
+454
View File
@@ -0,0 +1,454 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ Safe Casts
internal U16
safe_cast_u16(U32 x)
{
AssertAlways(x <= max_U16);
U16 result = (U16)x;
return result;
}
internal U32
safe_cast_u32(U64 x)
{
AssertAlways(x <= max_U32);
U32 result = (U32)x;
return result;
}
internal S32
safe_cast_s32(S64 x)
{
AssertAlways(x <= max_S32);
S32 result = (S32)x;
return result;
}
////////////////////////////////
//~ rjf: Large Base Type Functions
internal U128
u128_zero(void)
{
U128 v = {0};
return v;
}
internal U128
u128_make(U64 v0, U64 v1)
{
U128 v = {v0, v1};
return v;
}
internal B32
u128_match(U128 a, U128 b)
{
return MemoryMatchStruct(&a, &b);
}
////////////////////////////////
//~ rjf: Bit Patterns
internal U32
u32_from_u64_saturate(U64 x){
U32 x32 = (x > max_U32)?max_U32:(U32)x;
return(x32);
}
internal U64
u64_up_to_pow2(U64 x){
if (x == 0){
x = 1;
}
else{
x -= 1;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x += 1;
}
return(x);
}
internal S32
extend_sign32(U32 x, U32 size){
U32 high_bit = size * 8;
U32 shift = 32 - high_bit;
S32 result = ((S32)x << shift) >> shift;
return result;
}
internal S64
extend_sign64(U64 x, U64 size){
U64 high_bit = size * 8;
U64 shift = 64 - high_bit;
S64 result = ((S64)x << shift) >> shift;
return result;
}
internal F32
inf32(void){
union { U32 u; F32 f; } x;
x.u = exponent32;
return(x.f);
}
internal F32
neg_inf32(void){
union { U32 u; F32 f; } x;
x.u = sign32 | exponent32;
return(x.f);
}
internal U16
bswap_u16(U16 x)
{
U16 result = (((x & 0xFF00) >> 8) |
((x & 0x00FF) << 8));
return result;
}
internal U32
bswap_u32(U32 x)
{
U32 result = (((x & 0xFF000000) >> 24) |
((x & 0x00FF0000) >> 8) |
((x & 0x0000FF00) << 8) |
((x & 0x000000FF) << 24));
return result;
}
internal U64
bswap_u64(U64 x)
{
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x00000000000000FFULL) << 56));
return result;
}
////////////////////////////////
//~ rjf: Enum -> Sign
internal S32
sign_from_side_S32(Side side){
return((side == Side_Min)?-1:1);
}
internal F32
sign_from_side_F32(Side side){
return((side == Side_Min)?-1.f:1.f);
}
////////////////////////////////
//~ rjf: Memory Functions
internal B32
memory_is_zero(void *ptr, U64 size){
B32 result = 1;
// break down size
U64 extra = (size&0x7);
U64 count8 = (size >> 3);
// check with 8-byte stride
U64 *p64 = (U64*)ptr;
if(result)
{
for (U64 i = 0; i < count8; i += 1, p64 += 1){
if (*p64 != 0){
result = 0;
goto done;
}
}
}
// check extra
if(result)
{
U8 *p8 = (U8*)p64;
for (U64 i = 0; i < extra; i += 1, p8 += 1){
if (*p8 != 0){
result = 0;
goto done;
}
}
}
done:;
return(result);
}
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
internal TxtPt
txt_pt(S64 line, S64 column)
{
TxtPt p = {0};
p.line = line;
p.column = column;
return p;
}
internal B32
txt_pt_match(TxtPt a, TxtPt b)
{
return a.line == b.line && a.column == b.column;
}
internal B32
txt_pt_less_than(TxtPt a, TxtPt b)
{
B32 result = 0;
if(a.line < b.line)
{
result = 1;
}
else if(a.line == b.line)
{
result = a.column < b.column;
}
return result;
}
internal TxtPt
txt_pt_min(TxtPt a, TxtPt b)
{
TxtPt result = b;
if(txt_pt_less_than(a, b))
{
result = a;
}
return result;
}
internal TxtPt
txt_pt_max(TxtPt a, TxtPt b)
{
TxtPt result = a;
if(txt_pt_less_than(a, b))
{
result = b;
}
return result;
}
internal TxtRng
txt_rng(TxtPt min, TxtPt max)
{
TxtRng range = {0};
if(txt_pt_less_than(min, max))
{
range.min = min;
range.max = max;
}
else
{
range.min = max;
range.max = min;
}
return range;
}
internal TxtRng
txt_rng_intersect(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_max(a.min, b.min);
result.max = txt_pt_min(a.max, b.max);
if(txt_pt_less_than(result.max, result.min))
{
MemoryZeroStruct(&result);
}
return result;
}
internal TxtRng
txt_rng_union(TxtRng a, TxtRng b)
{
TxtRng result = {0};
result.min = txt_pt_min(a.min, b.min);
result.max = txt_pt_max(a.max, b.max);
return result;
}
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
internal U64
bit_size_from_arch(Architecture arch)
{
// TODO(rjf): metacode
U64 arch_bitsize = 0;
switch(arch)
{
case Architecture_x64: arch_bitsize = 64; break;
case Architecture_x86: arch_bitsize = 32; break;
case Architecture_arm64: arch_bitsize = 64; break;
case Architecture_arm32: arch_bitsize = 32; break;
default: break;
}
return arch_bitsize;
}
internal U64
max_instruction_size_from_arch(Architecture arch)
{
// TODO(rjf): make this real
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_CL
compiler = Compiler_cl;
#elif COMPILER_GCC
compiler = Compiler_gcc;
#elif COMPILER_CLANG
compiler = Compiler_clang;
#endif
return compiler;
}
////////////////////////////////
//~ rjf: Time Functions
internal DenseTime
dense_time_from_date_time(DateTime date_time){
DenseTime result = 0;
result += date_time.year;
result *= 12;
result += date_time.mon;
result *= 31;
result += date_time.day;
result *= 24;
result += date_time.hour;
result *= 60;
result += date_time.min;
result *= 61;
result += date_time.sec;
result *= 1000;
result += date_time.msec;
return(result);
}
internal DateTime
date_time_from_dense_time(DenseTime time){
DateTime result = {0};
result.msec = time%1000;
time /= 1000;
result.sec = time%61;
time /= 61;
result.min = time%60;
time /= 60;
result.hour = time%24;
time /= 24;
result.day = time%31;
time /= 31;
result.mon = time%12;
time /= 12;
Assert(time <= max_U32);
result.year = (U32)time;
return(result);
}
internal DateTime
date_time_from_micro_seconds(U64 time){
DateTime result = {0};
result.micro_sec = time%1000;
time /= 1000;
result.msec = time%1000;
time /= 1000;
result.sec = time%60;
time /= 60;
result.min = time%60;
time /= 60;
result.hour = time%24;
time /= 24;
result.day = time%31;
time /= 31;
result.mon = time%12;
time /= 12;
Assert(time <= max_U32);
result.year = (U32)time;
return(result);
}
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
internal U64
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
{
Assert(src_data_size <= ring_size);
{
U64 ring_off = ring_pos%ring_size;
U64 bytes_before_split = ring_size-ring_off;
U64 pre_split_bytes = Min(bytes_before_split, src_data_size);
U64 pst_split_bytes = src_data_size-pre_split_bytes;
void *pre_split_data = src_data;
void *pst_split_data = ((U8 *)src_data + pre_split_bytes);
MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes);
MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes);
}
return src_data_size;
}
internal U64
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
{
Assert(read_size <= ring_size);
{
U64 ring_off = ring_pos%ring_size;
U64 bytes_before_split = ring_size-ring_off;
U64 pre_split_bytes = Min(bytes_before_split, read_size);
U64 pst_split_bytes = read_size-pre_split_bytes;
MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes);
MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes);
}
return read_size;
}
+680
View File
@@ -0,0 +1,680 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_TYPES_H
#define BASE_TYPES_H
////////////////////////////////
//~ rjf: Foreign Includes
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
////////////////////////////////
//~ rjf: Build Configuration
#if !defined(ENABLE_DEV)
# define ENABLE_DEV 0
#endif
#if !defined(SUPPLEMENT_UNIT)
# define SUPPLEMENT_UNIT 0
#endif
////////////////////////////////
//~ rjf: Codebase Keywords
#define internal static
#define global static
#define local_persist static
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
# pragma section(".rdata$", read)
# define read_only __declspec(allocate(".rdata$"))
#elif (COMPILER_CLANG && OS_LINUX)
# define read_only __attribute__((section(".rodata")))
#else
// NOTE(rjf): I don't know of a useful way to do this in GCC land.
// __attribute__((section(".rodata"))) looked promising, but it introduces a
// strange warning about malformed section attributes, and it doesn't look
// like writing to that section reliably produces access violations, strangely
// enough. (It does on Clang)
# define read_only
#endif
////////////////////////////////
//~ rjf: Memory Operation Macros
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, byte, size) memset((dst), (byte), (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 MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
#define MemoryZero(s,z) memset((s),0,(z))
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
#define MemoryZeroArray(a) MemoryZero((a),sizeof(a))
#define MemoryZeroTyped(m,c) MemoryZero((m),sizeof(*(m))*(c))
#define MemoryMatch(a,b,z) (MemoryCompare((a),(b),(z)) == 0)
#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a)))
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
#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: Units
#define KB(n) (((U64)(n)) << 10)
#define MB(n) (((U64)(n)) << 20)
#define GB(n) (((U64)(n)) << 30)
#define TB(n) (((U64)(n)) << 40)
#define Thousand(n) ((n)*1000)
#define Million(n) ((n)*1000000)
#define Billion(n) ((n)*1000000000)
////////////////////////////////
//~ rjf: Asserts
#if COMPILER_CL
# define Trap() __debugbreak()
#elif COMPILER_CLANG || COMPILER_GCC
# define Trap() __builtin_trap()
# else
# error "undefined trap"
#endif
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
#if !defined(NDEBUG)
# define Assert(x) AssertAlways(x)
#else
# define Assert(x) (void)(x)
#endif
#define AssertImplies(a,b) Assert(!(a) || b)
#define AssertIff(a,b) Assert(!!(a) == !!(b))
#define InvalidPath Assert(!"Invalid Path!")
#define NotImplemented Assert(!"Not Implemented!")
#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1]
////////////////////////////////
//~ rjf: Branch Predictor Hints
#if defined(__clang__)
# define Expect(expr, val) __builtin_expect((expr), (val))
#else
# define Expect(expr, val) (expr)
#endif
#define Likely(expr) Expect(expr,1)
#define Unlikely(expr) Expect(expr,0)
////////////////////////////////
//~ rjf: Misc. Helper Macros
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
#define Stmnt(S) do{ S }while(0)
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
#define Glue_(A,B) A##B
#define Glue(A,B) Glue_(A,B)
#define Min(A,B) ( ((A)<(B))?(A):(B) )
#define Max(A,B) ( ((A)>(B))?(A):(B) )
#define ClampTop(A,X) Min(A,X)
#define ClampBot(X,B) Max(X,B)
#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) )
#define PtrClampTop(A,X) ClampTop(A,X)
#define PtrClampBot(X,B) ClampBot(X,B)
#define PtrClamp(A,X,B) Clamp(A,X,B)
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; )
#if ARCH_64BIT
# define IntFromPtr(ptr) ((U64)(ptr))
#elif ARCH_32BIT
# define IntFromPtr(ptr) ((U32)(ptr))
#else
# error missing ptr cast for this architecture
#endif
#define PtrFromInt(i) (void*)((U8*)0 + (i))
#define Member(T,m) (((T*)0)->m)
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
#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))
#if LANG_CPP
# define zero_struct {}
#else
# define zero_struct {0}
#endif
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
# define this_function_name "unknown"
#else
# define this_function_name __func__
#endif
#if LANG_CPP
# define C_LINKAGE_BEGIN extern "C"{
# define C_LINKAGE_END }
# define C_LINKAGE extern "C"
#else
# define C_LINKAGE_BEGIN
# define C_LINKAGE_END
# define C_LINKAGE
#endif
#if COMPILER_CL
# define thread_static __declspec(thread)
#elif COMPILER_CLANG || COMPILER_GCC
# define thread_static __thread
#endif
#if OS_WINDOWS
# define shared_function C_LINKAGE __declspec(dllexport)
#else
# define shared_function C_LINKAGE
#endif
////////////////////////////////
//~ ASAN
#if COMPILER_CL
# if defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# define NO_ASAN __declspec(no_sanitize_address)
# else
# define NO_ASAN
# endif
#elif COMPILER_CLANG
# if defined(__has_feature)
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# define ASAN_ENABLED 1
# endif
# endif
# define NO_ASAN __attribute__((no_sanitize("address")))
#else
# error "NO_ASAN is not defined"
#endif
#if ASAN_ENABLED
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
C_LINKAGE_BEGIN
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
C_LINKAGE_END
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
#else
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
#endif
////////////////////////////////
//~ rjf: Base Types
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef float F32;
typedef double F64;
////////////////////////////////
//~ rjf: Large Base Types
typedef struct U128 U128;
struct U128
{
U64 u64[2];
};
////////////////////////////////
//~ rjf: Basic Types & Spaces
typedef void VoidProc(void);
typedef enum Dimension
{
Dimension_X,
Dimension_Y,
Dimension_Z,
Dimension_W,
}
Dimension;
typedef enum Side
{
Side_Invalid = -1,
Side_Min,
Side_Max,
Side_COUNT,
}
Side;
#define side_flip(s) ((Side)(!(s)))
typedef enum Axis2
{
Axis2_Invalid = -1,
Axis2_X,
Axis2_Y,
Axis2_COUNT,
}
Axis2;
#define axis2_flip(a) ((Axis2)(!(a)))
typedef enum Corner
{
Corner_Invalid = -1,
Corner_00,
Corner_01,
Corner_10,
Corner_11,
Corner_COUNT
}
Corner;
////////////////////////////////
//~ rjf: Toolchain/Environment Enums
typedef enum OperatingSystem
{
OperatingSystem_Null,
OperatingSystem_Windows,
OperatingSystem_Linux,
OperatingSystem_Mac,
OperatingSystem_COUNT,
}
OperatingSystem;
typedef enum Architecture
{
Architecture_Null,
Architecture_x64,
Architecture_x86,
Architecture_arm64,
Architecture_arm32,
Architecture_COUNT,
}
Architecture;
typedef enum Compiler
{
Compiler_Null,
Compiler_cl,
Compiler_gcc,
Compiler_clang,
Compiler_COUNT,
}
Compiler;
////////////////////////////////
//~ rjf: Text 2D Coordinates & Ranges
typedef struct TxtPt TxtPt;
struct TxtPt
{
S64 line;
S64 column;
};
typedef struct TxtRng TxtRng;
struct TxtRng
{
TxtPt min;
TxtPt max;
};
////////////////////////////////
//~ NOTE(allen): Constants
global U32 sign32 = 0x80000000;
global U32 exponent32 = 0x7F800000;
global U32 mantissa32 = 0x007FFFFF;
global F32 big_golden32 = 1.61803398875f;
global F32 small_golden32 = 0.61803398875f;
global F32 pi32 = 3.1415926535897f;
global F64 machine_epsilon64 = 4.94065645841247e-324;
global U64 max_U64 = 0xffffffffffffffffull;
global U32 max_U32 = 0xffffffff;
global U16 max_U16 = 0xffff;
global U8 max_U8 = 0xff;
global S64 max_S64 = (S64)0x7fffffffffffffffull;
global S32 max_S32 = (S32)0x7fffffff;
global S16 max_S16 = (S16)0x7fff;
global S8 max_S8 = (S8)0x7f;
global S64 min_S64 = (S64)0xffffffffffffffffull;
global S32 min_S32 = (S32)0xffffffff;
global S16 min_S16 = (S16)0xffff;
global S8 min_S8 = (S8)0xff;
global const U32 bitmask1 = 0x00000001;
global const U32 bitmask2 = 0x00000003;
global const U32 bitmask3 = 0x00000007;
global const U32 bitmask4 = 0x0000000f;
global const U32 bitmask5 = 0x0000001f;
global const U32 bitmask6 = 0x0000003f;
global const U32 bitmask7 = 0x0000007f;
global const U32 bitmask8 = 0x000000ff;
global const U32 bitmask9 = 0x000001ff;
global const U32 bitmask10 = 0x000003ff;
global const U32 bitmask11 = 0x000007ff;
global const U32 bitmask12 = 0x00000fff;
global const U32 bitmask13 = 0x00001fff;
global const U32 bitmask14 = 0x00003fff;
global const U32 bitmask15 = 0x00007fff;
global const U32 bitmask16 = 0x0000ffff;
global const U32 bitmask17 = 0x0001ffff;
global const U32 bitmask18 = 0x0003ffff;
global const U32 bitmask19 = 0x0007ffff;
global const U32 bitmask20 = 0x000fffff;
global const U32 bitmask21 = 0x001fffff;
global const U32 bitmask22 = 0x003fffff;
global const U32 bitmask23 = 0x007fffff;
global const U32 bitmask24 = 0x00ffffff;
global const U32 bitmask25 = 0x01ffffff;
global const U32 bitmask26 = 0x03ffffff;
global const U32 bitmask27 = 0x07ffffff;
global const U32 bitmask28 = 0x0fffffff;
global const U32 bitmask29 = 0x1fffffff;
global const U32 bitmask30 = 0x3fffffff;
global const U32 bitmask31 = 0x7fffffff;
global const U32 bitmask32 = 0xffffffff;
global const U64 bitmask33 = 0x00000001ffffffffull;
global const U64 bitmask34 = 0x00000003ffffffffull;
global const U64 bitmask35 = 0x00000007ffffffffull;
global const U64 bitmask36 = 0x0000000fffffffffull;
global const U64 bitmask37 = 0x0000001fffffffffull;
global const U64 bitmask38 = 0x0000003fffffffffull;
global const U64 bitmask39 = 0x0000007fffffffffull;
global const U64 bitmask40 = 0x000000ffffffffffull;
global const U64 bitmask41 = 0x000001ffffffffffull;
global const U64 bitmask42 = 0x000003ffffffffffull;
global const U64 bitmask43 = 0x000007ffffffffffull;
global const U64 bitmask44 = 0x00000fffffffffffull;
global const U64 bitmask45 = 0x00001fffffffffffull;
global const U64 bitmask46 = 0x00003fffffffffffull;
global const U64 bitmask47 = 0x00007fffffffffffull;
global const U64 bitmask48 = 0x0000ffffffffffffull;
global const U64 bitmask49 = 0x0001ffffffffffffull;
global const U64 bitmask50 = 0x0003ffffffffffffull;
global const U64 bitmask51 = 0x0007ffffffffffffull;
global const U64 bitmask52 = 0x000fffffffffffffull;
global const U64 bitmask53 = 0x001fffffffffffffull;
global const U64 bitmask54 = 0x003fffffffffffffull;
global const U64 bitmask55 = 0x007fffffffffffffull;
global const U64 bitmask56 = 0x00ffffffffffffffull;
global const U64 bitmask57 = 0x01ffffffffffffffull;
global const U64 bitmask58 = 0x03ffffffffffffffull;
global const U64 bitmask59 = 0x07ffffffffffffffull;
global const U64 bitmask60 = 0x0fffffffffffffffull;
global const U64 bitmask61 = 0x1fffffffffffffffull;
global const U64 bitmask62 = 0x3fffffffffffffffull;
global const U64 bitmask63 = 0x7fffffffffffffffull;
global const U64 bitmask64 = 0xffffffffffffffffull;
global const U32 bit1 = (1<<0);
global const U32 bit2 = (1<<1);
global const U32 bit3 = (1<<2);
global const U32 bit4 = (1<<3);
global const U32 bit5 = (1<<4);
global const U32 bit6 = (1<<5);
global const U32 bit7 = (1<<6);
global const U32 bit8 = (1<<7);
global const U32 bit9 = (1<<8);
global const U32 bit10 = (1<<9);
global const U32 bit11 = (1<<10);
global const U32 bit12 = (1<<11);
global const U32 bit13 = (1<<12);
global const U32 bit14 = (1<<13);
global const U32 bit15 = (1<<14);
global const U32 bit16 = (1<<15);
global const U32 bit17 = (1<<16);
global const U32 bit18 = (1<<17);
global const U32 bit19 = (1<<18);
global const U32 bit20 = (1<<19);
global const U32 bit21 = (1<<20);
global const U32 bit22 = (1<<21);
global const U32 bit23 = (1<<22);
global const U32 bit24 = (1<<23);
global const U32 bit25 = (1<<24);
global const U32 bit26 = (1<<25);
global const U32 bit27 = (1<<26);
global const U32 bit28 = (1<<27);
global const U32 bit29 = (1<<28);
global const U32 bit30 = (1<<29);
global const U32 bit31 = (1<<30);
global const U32 bit32 = (1<<31);
global const U64 bit33 = (1ull<<32);
global const U64 bit34 = (1ull<<33);
global const U64 bit35 = (1ull<<34);
global const U64 bit36 = (1ull<<35);
global const U64 bit37 = (1ull<<36);
global const U64 bit38 = (1ull<<37);
global const U64 bit39 = (1ull<<38);
global const U64 bit40 = (1ull<<39);
global const U64 bit41 = (1ull<<40);
global const U64 bit42 = (1ull<<41);
global const U64 bit43 = (1ull<<42);
global const U64 bit44 = (1ull<<43);
global const U64 bit45 = (1ull<<44);
global const U64 bit46 = (1ull<<45);
global const U64 bit47 = (1ull<<46);
global const U64 bit48 = (1ull<<47);
global const U64 bit49 = (1ull<<48);
global const U64 bit50 = (1ull<<49);
global const U64 bit51 = (1ull<<50);
global const U64 bit52 = (1ull<<51);
global const U64 bit53 = (1ull<<52);
global const U64 bit54 = (1ull<<53);
global const U64 bit55 = (1ull<<54);
global const U64 bit56 = (1ull<<55);
global const U64 bit57 = (1ull<<56);
global const U64 bit58 = (1ull<<57);
global const U64 bit59 = (1ull<<58);
global const U64 bit60 = (1ull<<59);
global const U64 bit61 = (1ull<<60);
global const U64 bit62 = (1ull<<61);
global const U64 bit63 = (1ull<<62);
global const U64 bit64 = (1ull<<63);
////////////////////////////////
//~ allen: Time
typedef enum WeekDay
{
WeekDay_Sun,
WeekDay_Mon,
WeekDay_Tue,
WeekDay_Wed,
WeekDay_Thu,
WeekDay_Fri,
WeekDay_Sat,
WeekDay_COUNT,
}
WeekDay;
typedef enum Month
{
Month_Jan,
Month_Feb,
Month_Mar,
Month_Apr,
Month_May,
Month_Jun,
Month_Jul,
Month_Aug,
Month_Sep,
Month_Oct,
Month_Nov,
Month_Dec,
Month_COUNT,
}
Month;
typedef struct DateTime DateTime;
struct DateTime
{
U16 micro_sec; // [0,999]
U16 msec; // [0,999]
U16 sec; // [0,60]
U16 min; // [0,59]
U16 hour; // [0,24]
U16 day; // [0,30]
union{
WeekDay week_day;
U32 wday;
};
union{
Month month;
U32 mon;
};
U32 year; // 1 = 1 CE, 0 = 1 BC
};
typedef U64 DenseTime;
////////////////////////////////
//~ allen: Files
typedef U32 FilePropertyFlags;
enum
{
FilePropertyFlag_IsFolder = (1 << 0),
};
typedef struct FileProperties FileProperties;
struct FileProperties
{
U64 size;
DenseTime modified;
DenseTime created;
FilePropertyFlags flags;
};
////////////////////////////////
//~ Safe Casts
internal U16 safe_cast_u16(U32 x);
internal U32 safe_cast_u32(U64 x);
internal S32 safe_cast_s32(S64 x);
////////////////////////////////
//~ rjf: Large Base Type Functions
internal U128 u128_zero(void);
internal U128 u128_make(U64 v0, U64 v1);
internal B32 u128_match(U128 a, U128 b);
////////////////////////////////
//~ rjf: Bit Patterns
internal U32 u32_from_u64_saturate(U64 x);
internal U64 u64_up_to_pow2(U64 x);
internal S32 extend_sign32(U32 x, U32 size);
internal S64 extend_sign64(U64 x, U64 size);
internal F32 inf32(void);
internal F32 neg_inf32(void);
internal U16 bswap_u16(U16 x);
internal U32 bswap_u32(U32 x);
internal U64 bswap_u64(U64 x);
////////////////////////////////
//~ rjf: Enum -> Sign
internal S32 sign_from_side_S32(Side side);
internal F32 sign_from_side_F32(Side side);
////////////////////////////////
//~ rjf: Memory Functions
internal B32 memory_is_zero(void *ptr, U64 size);
////////////////////////////////
//~ rjf: Text 2D Coordinate/Range Functions
internal TxtPt txt_pt(S64 line, S64 column);
internal B32 txt_pt_match(TxtPt a, TxtPt b);
internal B32 txt_pt_less_than(TxtPt a, TxtPt b);
internal TxtPt txt_pt_min(TxtPt a, TxtPt b);
internal TxtPt txt_pt_max(TxtPt a, TxtPt b);
internal TxtRng txt_rng(TxtPt min, TxtPt max);
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
////////////////////////////////
//~ rjf: Toolchain/Environment Enum Functions
internal U64 bit_size_from_arch(Architecture arch);
internal U64 max_instruction_size_from_arch(Architecture arch);
internal OperatingSystem operating_system_from_context(void);
internal Architecture architecture_from_context(void);
internal Compiler compiler_from_context(void);
////////////////////////////////
//~ rjf: Time Functions
internal DenseTime dense_time_from_date_time(DateTime date_time);
internal DateTime date_time_from_dense_time(DenseTime time);
internal DateTime date_time_from_micro_seconds(U64 time);
////////////////////////////////
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
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)))
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
#endif // BASE_TYPES_H
-340
View File
@@ -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);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-630
View File
@@ -1,630 +0,0 @@
////////////////////////////////
//~ rjf: CV Numerics
@table(name val)
CV_NumericKindTable:
{
{CHAR 0x8000}
{SHORT 0x8001}
{USHORT 0x8002}
{LONG 0x8003}
{ULONG 0x8004}
{FLOAT32 0x8005}
{FLOAT64 0x8006}
{FLOAT80 0x8007}
{FLOAT128 0x8008}
{QUADWORD 0x8009}
{UQUADWORD 0x800a}
{FLOAT48 0x800b}
{COMPLEX32 0x800c}
{COMPLEX64 0x800d}
{COMPLEX80 0x800e}
{COMPLEX128 0x800f}
{VARSTRING 0x8010}
{OCTWORD 0x8017}
{UOCTWORD 0x8018}
{DECIMAL 0x8019}
{DATE 0x801a}
{UTF8STRING 0x801b}
{FLOAT16 0x801c}
}
@enum(U16) CV_NumericKind:
{
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_NumericKind)
cv_string_from_numeric_kind:
{
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
////////////////////////////////
//~ rjf: CV Architectures
@table(name val)
CV_ArchTable:
{
{8080 0x00}
{8086 0x01}
{80286 0x02}
{80386 0x03}
{80486 0x04}
{PENTIUM 0x05}
{PENTIUMII 0x06}
{PENTIUMIII 0x07}
{MIPS 0x10}
{MIPS16 0x11}
{MIPS32 0x12}
{MIPS64 0x13}
{MIPSI 0x14}
{MIPSII 0x15}
{MIPSIII 0x16}
{MIPSIV 0x17}
{MIPSV 0x18}
{M68000 0x20}
{M68010 0x21}
{M68020 0x22}
{M68030 0x23}
{M68040 0x24}
{ALPHA 0x30}
{ALPHA_21164 0x31}
{ALPHA_21164A 0x32}
{ALPHA_21264 0x33}
{ALPHA_21364 0x34}
{PPC601 0x40}
{PPC603 0x41}
{PPC604 0x42}
{PPC620 0x43}
{PPCFP 0x44}
{PPCBE 0x45}
{SH3 0x50}
{SH3E 0x51}
{SH3DSP 0x52}
{SH4 0x53}
{SHMEDIA 0x54}
{ARM3 0x60}
{ARM4 0x61}
{ARM4T 0x62}
{ARM5 0x63}
{ARM5T 0x64}
{ARM6 0x65}
{ARM_XMAC 0x66}
{ARM_WMMX 0x67}
{ARM7 0x68}
{OMNI 0x70}
{IA64_1 0x80}
{IA64_2 0x81}
{CEE 0x90}
{AM33 0xA0}
{M32R 0xB0}
{TRICORE 0xC0}
{X64 0xD0}
{EBC 0xE0}
{THUMB 0xF0}
{ARMNT 0xF4}
{ARM64 0xF6}
{D3D11_SHADER 0x100}
}
@enum(U16) CV_Arch:
{
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
`IA64 = CV_Arch_IA64_1`,
`PENTIUMPRO = CV_Arch_PENTIUMII`,
`MIPSR4000 = CV_Arch_MIPS`,
`ALPHA_21064 = CV_Arch_ALPHA`,
`AMD64 = CV_Arch_X64`,
}
@enum2string_switch(CV_Arch)
cv_string_from_arch:
{
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
////////////////////////////////
//~ rjf: CV Registers
@table(name val) CV_AllRegTable:
{
{ERR 30000}
{TEB 30001}
{TIMER 30002}
{EFAD1 30003}
{EFAD2 30004}
{EFAD3 30005}
{VFRAME 30006}
{HANDLE 30007}
{PARAMS 30008}
{LOCALS 30009}
{TID 30010}
{ENV 30011}
{CMDLN 30012}
}
@enum(U16) CV_AllReg:
{
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
}
////////////////////////////////
//~ rjf: CV Sym Kinds
@table(name header_type_name val) CV_SymKindTable:
{
{COMPILE Compile 0x0001}
{REGISTER_16t - 0x0002}
{CONSTANT_16t - 0x0003}
{UDT_16t - 0x0004}
{SSEARCH StartSearch 0x0005}
{END - 0x0006}
{SKIP - 0x0007}
{CVRESERVE - 0x0008}
{OBJNAME_ST - 0x0009}
{ENDARG - 0x000a}
{COBOLUDT_16t - 0x000b}
{MANYREG_16t - 0x000c}
{RETURN Return 0x000d}
{ENTRYTHIS - 0x000e}
{BPREL16 - 0x0100}
{LDATA16 - 0x0101}
{GDATA16 - 0x0102}
{PUB16 - 0x0103}
{LPROC16 - 0x0104}
{GPROC16 - 0x0105}
{THUNK16 - 0x0106}
{BLOCK16 - 0x0107}
{WITH16 - 0x0108}
{LABEL16 - 0x0109}
{CEXMODEL16 - 0x010a}
{VFTABLE16 - 0x010b}
{REGREL16 - 0x010c}
{BPREL32_16t - 0x0200}
{LDATA32_16t - 0x0201}
{GDATA32_16t - 0x0202}
{PUB32_16t - 0x0203}
{LPROC32_16t - 0x0204}
{GPROC32_16t - 0x0205}
{THUNK32_ST - 0x0206}
{BLOCK32_ST - 0x0207}
{WITH32_ST - 0x0208}
{LABEL32_ST - 0x0209}
{CEXMODEL32 - 0x020a}
{VFTABLE32_16t - 0x020b}
{REGREL32_16t - 0x020c}
{LTHREAD32_16t - 0x020d}
{GTHREAD32_16t - 0x020e}
{SLINK32 SLink32 0x020f}
{LPROCMIPS_16t - 0x0300}
{GPROCMIPS_16t - 0x0301}
{PROCREF_ST - 0x0400}
{DATAREF_ST - 0x0401}
{ALIGN - 0x0402}
{LPROCREF_ST - 0x0403}
{OEM OEM 0x0404}
{TI16_MAX - 0x1000}
{CONSTANT_ST - 0x1002}
{UDT_ST - 0x1003}
{COBOLUDT_ST - 0x1004}
{MANYREG_ST - 0x1005}
{BPREL32_ST - 0x1006}
{LDATA32_ST - 0x1007}
{GDATA32_ST - 0x1008}
{PUB32_ST - 0x1009}
{LPROC32_ST - 0x100a}
{GPROC32_ST - 0x100b}
{VFTABLE32 VPath32 0x100c}
{REGREL32_ST - 0x100d}
{LTHREAD32_ST - 0x100e}
{GTHREAD32_ST - 0x100f}
{LPROCMIPS_ST - 0x1010}
{GPROCMIPS_ST - 0x1011}
{FRAMEPROC Frameproc 0x1012}
{COMPILE2_ST - 0x1013}
{MANYREG2_ST - 0x1014}
{LPROCIA64_ST - 0x1015}
{GPROCIA64_ST - 0x1016}
{LOCALSLOT_ST - 0x1017}
{PARAMSLOT_ST - 0x1018}
{ANNOTATION Annotation 0x1019}
{GMANPROC_ST - 0x101a}
{LMANPROC_ST - 0x101b}
{RESERVED1 - 0x101c}
{RESERVED2 - 0x101d}
{RESERVED3 - 0x101e}
{RESERVED4 - 0x101f}
{LMANDATA_ST - 0x1020}
{GMANDATA_ST - 0x1021}
{MANFRAMEREL_ST - 0x1022}
{MANREGISTER_ST - 0x1023}
{MANSLOT_ST - 0x1024}
{MANMANYREG_ST - 0x1025}
{MANREGREL_ST - 0x1026}
{MANMANYREG2_ST - 0x1027}
{MANTYPREF - 0x1028}
{UNAMESPACE_ST - 0x1029}
{ST_MAX - 0x1100}
{OBJNAME ObjName 0x1101}
{THUNK32 Thunk32 0x1102}
{BLOCK32 Block32 0x1103}
{WITH32 - 0x1104}
{LABEL32 Label32 0x1105}
{REGISTER Register 0x1106}
{CONSTANT Constant 0x1107}
{UDT UDT 0x1108}
{COBOLUDT - 0x1109}
{MANYREG Manyreg 0x110a}
{BPREL32 BPRel32 0x110b}
{LDATA32 Data32 0x110c}
{GDATA32 Data32 0x110d}
{PUB32 Pub32 0x110e}
{LPROC32 Proc32 0x110f}
{GPROC32 Proc32 0x1110}
{REGREL32 Regrel32 0x1111}
{LTHREAD32 Thread32 0x1112}
{GTHREAD32 Thread32 0x1113}
{LPROCMIPS - 0x1114}
{GPROCMIPS - 0x1115}
{COMPILE2 Compile2 0x1116}
{MANYREG2 Manyreg2 0x1117}
{LPROCIA64 - 0x1118}
{GPROCIA64 - 0x1119}
{LOCALSLOT Slot 0x111a}
{PARAMSLOT - 0x111b}
{LMANDATA - 0x111c}
{GMANDATA - 0x111d}
{MANFRAMEREL AttrFrameRel 0x111e}
{MANREGISTER AttrReg 0x111f}
{MANSLOT - 0x1120}
{MANMANYREG AttrManyReg 0x1121}
{MANREGREL AttrRegRel 0x1122}
{MANMANYREG2 - 0x1123}
{UNAMESPACE UNamespace 0x1124}
{PROCREF Ref2 0x1125}
{DATAREF Ref2 0x1126}
{LPROCREF Ref2 0x1127}
{ANNOTATIONREF - 0x1128}
{TOKENREF - 0x1129}
{GMANPROC - 0x112a}
{LMANPROC - 0x112b}
{TRAMPOLINE Trampoline 0x112c}
{MANCONSTANT - 0x112d}
{ATTR_FRAMEREL AttrFrameRel 0x112e}
{ATTR_REGISTER AttrReg 0x112f}
{ATTR_REGREL AttrRegRel 0x1130}
{ATTR_MANYREG AttrManyReg 0x1131}
{SEPCODE Sepcode 0x1132}
{DEFRANGE_2005 - 0x1134}
{DEFRANGE2_2005 - 0x1135}
{SECTION Section 0x1136}
{COFFGROUP CoffGroup 0x1137}
{EXPORT Export 0x1138}
{CALLSITEINFO CallSiteInfo 0x1139}
{FRAMECOOKIE FrameCookie 0x113a}
{DISCARDED Discarded 0x113b}
{COMPILE3 Compile3 0x113c}
{ENVBLOCK EnvBlock 0x113d}
{LOCAL Local 0x113e}
{DEFRANGE - 0x113f}
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
{LPROC32_ID - 0x1146}
{GPROC32_ID - 0x1147}
{LPROCMIPS_ID - 0x1148}
{GPROCMIPS_ID - 0x1149}
{LPROCIA64_ID - 0x114a}
{GPROCIA64_ID - 0x114b}
{BUILDINFO BuildInfo 0x114c}
{INLINESITE InlineSite 0x114d}
{INLINESITE_END - 0x114e}
{PROC_ID_END - 0x114f}
{DEFRANGE_HLSL - 0x1150}
{GDATA_HLSL - 0x1151}
{LDATA_HLSL - 0x1152}
{FILESTATIC FileStatic 0x1153}
{LPROC32_DPC - 0x1155}
{LPROC32_DPC_ID - 0x1156}
{DEFRANGE_DPC_PTR_TAG - 0x1157}
{DPC_SYM_TAG_MAP - 0x1158}
{ARMSWITCHTABLE - 0x1159}
{CALLEES FunctionList 0x115a}
{CALLERS FunctionList 0x115b}
{POGODATA PogoInfo 0x115c}
{INLINESITE2 InlineSite2 0x115d}
{HEAPALLOCSITE HeapAllocSite 0x115e}
{MOD_TYPEREF ModTypeRef 0x115f}
{REF_MINIPDB RefMiniPdb 0x1160}
{PDBMAP - 0x1161}
{GDATA_HLSL32 - 0x1162}
{LDATA_HLSL32 - 0x1163}
{GDATA_HLSL32_EX - 0x1164}
{LDATA_HLSL32_EX - 0x1165}
{FASTLINK FastLink 0x1167}
{INLINEES Inlinees 0x1168}
}
@enum(U16) CV_SymKind:
{
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_SymKind)
cv_string_from_sym_kind:
{
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
@gen(functions)
{
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
}
@gen(functions) @c_file
{
`internal U64`;
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
`{`;
`U64 result = 0;`;
`switch(v)`;
`{`;
`default:{}break;`;
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
`}`;
`return result;`;
`}`;
}
////////////////////////////////
//~ rjf: CV Basic Types
@table(name val type_name)
CV_BasicTypeTable:
{
{NOTYPE 0x00 "" }
{ABS 0x01 "" }
{SEGMENT 0x02 "" }
{VOID 0x03 "void" }
{CURRENCY 0x04 "" }
{NBASICSTR 0x05 "" }
{FBASICSTR 0x06 "" }
{NOTTRANS 0x07 "" }
{HRESULT 0x08 "HRESULT" }
{CHAR 0x10 "CHAR" }
{SHORT 0x11 "SHORT" }
{LONG 0x12 "LONG" }
{QUAD 0x13 "QUAD" }
{OCT 0x14 "OCT" }
{UCHAR 0x20 "UCHAR" }
{USHORT 0x21 "USHORT" }
{ULONG 0x22 "ULONG" }
{UQUAD 0x23 "UQUAD" }
{UOCT 0x24 "UOCT" }
{BOOL8 0x30 "BOOL8" }
{BOOL16 0x31 "BOOL16" }
{BOOL32 0x32 "BOOL32" }
{BOOL64 0x33 "BOOL64" }
{FLOAT32 0x40 "FLOAT32" }
{FLOAT64 0x41 "FLOAT64" }
{FLOAT80 0x42 "FLOAT80" }
{FLOAT128 0x43 "FLOAT128" }
{FLOAT48 0x44 "FLOAT48" }
{FLOAT32PP 0x45 "FLOAT32PP" }
{FLOAT16 0x46 "FLOAT16" }
{COMPLEX32 0x50 "ComplexF32" }
{COMPLEX64 0x51 "ComplexF64" }
{COMPLEX80 0x52 "ComplexF80" }
{COMPLEX128 0x53 "ComplexF128" }
{BIT 0x60 "" }
{PASCHAR 0x61 "" }
{BOOL32FF 0x62 "BOOL32FF" }
{INT8 0x68 "int8" }
{UINT8 0x69 "uint8" }
{RCHAR 0x70 "char" }
{WCHAR 0x71 "WCHAR" }
{INT16 0x72 "int16" }
{UINT16 0x73 "uint16" }
{INT32 0x74 "int32" }
{UINT32 0x75 "uint32" }
{INT64 0x76 "int64" }
{UINT64 0x77 "uint64" }
{INT128 0x78 "int128" }
{UINT128 0x79 "uint128" }
{CHAR16 0x7a "char16" }
{CHAR32 0x7b "char32" }
{CHAR8 0x7c "char" }
{PTR 0xf0 "PTR" }
}
@enum(U8) CV_BasicType:
{
@expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)`
}
@enum2string_switch(CV_BasicType) cv_string_from_basic_type:
{
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break`
}
@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type:
{
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break`
}
////////////////////////////////
//~ rjf: CV Leaf Kinds
@table(name header_type_name val)
CV_LeafKindTable:
{
{NOTYPE - 0x0000}
{MODIFIER_16t - 0x0001}
{POINTER_16t - 0x0002}
{ARRAY_16t - 0x0003}
{CLASS_16t - 0x0004}
{STRUCTURE_16t - 0x0005}
{UNION_16t - 0x0006}
{ENUM_16t - 0x0007}
{PROCEDURE_16t - 0x0008}
{MFUNCTION_16t - 0x0009}
{VTSHAPE VTShape 0x000a}
{COBOL0_16t - 0x000b}
{COBOL1 - 0x000c}
{BARRAY_16t - 0x000d}
{LABEL Label 0x000e}
{NULL - 0x000f}
{NOTTRAN - 0x0010}
{DIMARRAY_16t - 0x0011}
{VFTPATH_16t - 0x0012}
{PRECOMP_16t - 0x0013}
{ENDPRECOMP - 0x0014}
{OEM_16t - 0x0015}
{TYPESERVER_ST - 0x0016}
{SKIP_16t - 0x0200}
{ARGLIST_16t - 0x0201}
{DEFARG_16t - 0x0202}
{LIST - 0x0203}
{FIELDLIST_16t - 0x0204}
{DERIVED_16t - 0x0205}
{BITFIELD_16t - 0x0206}
{METHODLIST_16t - 0x0207}
{DIMCONU_16t - 0x0208}
{DIMCONLU_16t - 0x0209}
{DIMVARU_16t - 0x020a}
{DIMVARLU_16t - 0x020b}
{REFSYM - 0x020c}
{BCLASS_16t - 0x0400}
{VBCLASS_16t - 0x0401}
{IVBCLASS_16t - 0x0402}
{ENUMERATE_ST - 0x0403}
{FRIENDFCN_16t - 0x0404}
{INDEX_16t - 0x0405}
{MEMBER_16t - 0x0406}
{STMEMBER_16t - 0x0407}
{METHOD_16t - 0x0408}
{NESTTYPE_16t - 0x0409}
{VFUNCTAB_16t - 0x040a}
{FRIENDCLS_16t - 0x040b}
{ONEMETHOD_16t - 0x040c}
{VFUNCOFF_16t - 0x040d}
{TI16_MAX - 0x1000}
{MODIFIER Modifier 0x1001}
{POINTER Pointer 0x1002}
{ARRAY_ST - 0x1003}
{CLASS_ST - 0x1004}
{STRUCTURE_ST - 0x1005}
{UNION_ST - 0x1006}
{ENUM_ST - 0x1007}
{PROCEDURE Procedure 0x1008}
{MFUNCTION MFunction 0x1009}
{COBOL0 - 0x100a}
{BARRAY - 0x100b}
{DIMARRAY_ST - 0x100c}
{VFTPATH VFPath 0x100d}
{PRECOMP_ST - 0x100e}
{OEM - 0x100f}
{ALIAS_ST - 0x1010}
{OEM2 - 0x1011}
{SKIP Skip 0x1200}
{ARGLIST ArgList 0x1201}
{DEFARG_ST - 0x1202}
{FIELDLIST - 0x1203}
{DERIVED - 0x1204}
{BITFIELD BitField 0x1205}
{METHODLIST MethodListMember 0x1206}
{DIMCONU - 0x1207}
{DIMCONLU - 0x1208}
{DIMVARU - 0x1209}
{DIMVARLU - 0x120a}
{BCLASS BClass 0x1400}
{VBCLASS VBClass 0x1401}
{IVBCLASS - 0x1402}
{FRIENDFCN_ST - 0x1403}
{INDEX Index 0x1404}
{MEMBER_ST - 0x1405}
{STMEMBER_ST - 0x1406}
{METHOD_ST - 0x1407}
{NESTTYPE_ST - 0x1408}
{VFUNCTAB VFuncTab 0x1409}
{FRIENDCLS - 0x140a}
{ONEMETHOD_ST - 0x140b}
{VFUNCOFF VFuncOff 0x140c}
{NESTTYPEEX_ST - 0x140d}
{MEMBERMODIFY_ST - 0x140e}
{MANAGED_ST - 0x140f}
{ST_MAX - 0x1500}
{TYPESERVER TypeServer 0x1501}
{ENUMERATE Enumerate 0x1502}
{ARRAY Array 0x1503}
{CLASS Struct 0x1504}
{STRUCTURE Struct 0x1505}
{UNION Union 0x1506}
{ENUM Enum 0x1507}
{DIMARRAY - 0x1508}
{PRECOMP PreComp 0x1509}
{ALIAS Alias 0x150a}
{DEFARG - 0x150b}
{FRIENDFCN - 0x150c}
{MEMBER Member 0x150d}
{STMEMBER StMember 0x150e}
{METHOD Method 0x150f}
{NESTTYPE NestType 0x1510}
{ONEMETHOD OneMethod 0x1511}
{NESTTYPEEX NestTypeEx 0x1512}
{MEMBERMODIFY - 0x1513}
{MANAGED - 0x1514}
{TYPESERVER2 TypeServer2 0x1515}
{STRIDED_ARRAY - 0x1516}
{HLSL - 0x1517}
{MODIFIER_EX - 0x1518}
{INTERFACE Struct 0x1519}
{BINTERFACE - 0x151a}
{VECTOR - 0x151b}
{MATRIX - 0x151c}
{VFTABLE - 0x151d}
{FUNC_ID FuncId 0x1601}
{MFUNC_ID MFuncId 0x1602}
{BUILDINFO BuildInfo 0x1603}
{SUBSTR_LIST SubstrList 0x1604}
{STRING_ID StringId 0x1605}
{UDT_SRC_LINE UDTSrcLine 0x1606}
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
{CLASS2 Struct2 0x1608}
{STRUCT2 Struct2 0x1609}
}
@enum(U16) CV_LeafKind:
{
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
}
@enum2string_switch(CV_LeafKind)
cv_string_from_leaf_kind:
{
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
}
@gen(functions)
{
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
}
@gen(functions) @c_file
{
`internal U64`;
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
`{`;
`U64 result = 0;`;
`switch(v)`;
`{`;
`default:{}break;`;
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
`}`;
`return result;`;
`}`;
}
-24
View File
@@ -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;
}
-9
View File
@@ -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

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