Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1137c3e
Add symgc as git submodule
kinke May 12, 2025
104ec17
CI: Integrate symgc in shared druntime on Linux x86_64
kinke May 12, 2025
3e210c7
[integrate symgc in static druntime too]
kinke May 12, 2025
ff0ea5c
[fix CI - must compile symgc with new compiler]
kinke May 12, 2025
93176ba
[revise compiler flags and work around missing dub on Alpine]
kinke May 12, 2025
496f383
[always use LLVM with disabled assertions]
kinke May 12, 2025
161c699
GHA: Disable *branch* workflows for symgc branch
kinke May 12, 2025
db365c3
druntime: Drag in symgc automatically at link-time
kinke May 12, 2025
9fd0b9f
druntime: Enable DRT_* environment variables support by default iff. …
kinke May 12, 2025
3545b11
Bump symgc to fix copy paste error.
schveiguy May 13, 2025
e14368c
Bump symgc to fix off-by-one finalizer issue
schveiguy May 13, 2025
ea9a2af
Add a hook to the GC to allow it access to any thread that is starting
schveiguy Apr 22, 2025
5bf1f3a
Change default threadInit function pointer to null, handle in proto gc.
schveiguy Apr 27, 2025
cb8f1ff
Update symgc to deal with updated thread gc hooks.
schveiguy May 14, 2025
52b1dcd
CI: Enable symgc on Alpine too
kinke May 15, 2025
7a9e56a
Update symgc: Zero tail of slab slots when allocating with pointers
kinke May 16, 2025
69e72ec
Bump symgc submodule (incl. preliminary Windows support now etc.)
kinke May 20, 2025
f8a7b5c
Work around undefined core.time symbols for druntime unittest runner
kinke May 19, 2025
cd6e2d7
Integrate symgc in Windows x64 druntime too (#5)
kinke May 20, 2025
4b4a3bc
Phobos: std.uni: Hack out invalid access of GC-managed data from CowA…
kinke May 21, 2025
ba37367
Fix issue dlang/dmd!21397 - Refcounting with Throwable is unsound (dl…
schveiguy May 22, 2025
26b9693
Bump symgc branch to add inFinalizer support
schveiguy May 22, 2025
8c5bad9
Phobos: Cherry-pick std.uni.CowArray dtor fix
kinke May 22, 2025
7e07260
Update symgc to handle race condition when pausing threads on Windows
schveiguy May 23, 2025
23c0d51
Bump symgc to latest master
kinke Jun 23, 2025
a6a5f25
Bump symgc to try and fix high memory usage
schveiguy Jun 24, 2025
4790943
avoid counting scan threads when doing arena association.
schveiguy Jun 25, 2025
f2d7d93
Bump to symgc to update init message.
schveiguy Jun 25, 2025
c3229df
Bump symgc to fix NOHUGEPAGE issue
schveiguy Jul 2, 2025
e40300c
Ninja actions repository was deleted, but ninja now included in all G…
schveiguy Jul 2, 2025
b5d16f4
Symgc - include fix for random segfaults based on incorrect metadata …
schveiguy Jul 9, 2025
6b7b8b4
Fix dlang/dmd!21615 - The GC expandArrayUsed has pathological behavio…
schveiguy Jul 29, 2025
3309030
Windows: Adapt to curl.se not providing any official 32-bit builds an…
kinke Sep 15, 2025
24c8ab6
Bump symgc to 0.0.5 (arm64 support), make symgc the default on platfo…
schveiguy Sep 26, 2025
439b39d
CI: Default to conservative GC to overcome testsuite failures
kinke Sep 26, 2025
1fd6fc1
Update symgc to v0.0.6 to fix windows huge alloc issue.
schveiguy Oct 8, 2025
b108e25
Fix race condition of GC thread cleanup from external GC after the
schveiguy Nov 7, 2025
b8ba0d2
Bump to symgc 0.0.7 to fix some stop-the-world races.
schveiguy Nov 9, 2025
14e94a3
*shared* druntime: Avoid aborting with '_handleToDSO not in sync with…
kinke Jan 21, 2026
6d671af
GHA: Bump macOS x86_64 job image to macos-15-intel
kinke Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions .github/actions/1-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,9 @@ runs:

arch='${{ inputs.arch }}'

# use assertions for untagged builds
assertsSuffix="-withAsserts"
if [[ '${{ github.ref }}' = refs/tags/* ]]; then
assertsSuffix=""
fi

if [[ '${{ runner.os }}' == Windows ]]; then
curl -fL --retry 3 --max-time 300 -o llvm.7z \
https://github.com/ldc-developers/llvm-project/releases/download/$tag/llvm-$version-windows-$arch$assertsSuffix.7z
https://github.com/ldc-developers/llvm-project/releases/download/$tag/llvm-$version-windows-$arch.7z
mkdir llvm
cd llvm
7z x ../llvm.7z >/dev/null
Expand All @@ -103,7 +97,7 @@ runs:
os=osx
fi
curl -fL --retry 3 --max-time 300 -o llvm.tar.xz \
https://github.com/ldc-developers/llvm-project/releases/download/$tag/llvm-$version-$os-$arch$assertsSuffix.tar.xz
https://github.com/ldc-developers/llvm-project/releases/download/$tag/llvm-$version-$os-$arch.tar.xz
mkdir llvm
tar -xf llvm.tar.xz --strip 1 -C llvm
rm llvm.tar.xz
Expand All @@ -119,8 +113,8 @@ runs:
sudo ln -sf ld.lld /usr/bin/ld
ld --version

- name: Install ninja v1.12.1
uses: Ahajha/gha-setup-ninja@69595b0cf872acdad8ce599142fbdc88724b9a2b
# - name: Install ninja v1.12.1
# uses: Ahajha/gha-setup-ninja@69595b0cf872acdad8ce599142fbdc88724b9a2b

- name: Install D host compiler
uses: dlang-community/setup-dlang@v1
Expand All @@ -136,7 +130,7 @@ runs:
run: |
set -euxo pipefail
python3 --version
if [[ '${{ runner.os }}-${{ inputs.arch }}' == 'macOS-arm64' ]]; then
if [[ '${{ runner.os }}' == 'macOS' ]]; then
brew install lit
else
python3 -m pip install --user lit psutil
Expand Down Expand Up @@ -164,7 +158,8 @@ runs:

url='https://curl.se/windows/latest.cgi?p=win64-mingw.zip'
if [[ '${{ inputs.arch }}' == x86 ]]; then
url='https://curl.se/windows/latest.cgi?p=win32-mingw.zip'
# this is the latest *official* 32-bit build
url='https://curl.se/windows/dl-8.15.0_5/curl-8.15.0_5-win32-mingw.zip'
fi

curl -fL --retry 3 --max-time 60 -o libcurl.zip "$url"
Expand Down
23 changes: 23 additions & 0 deletions .github/actions/3-build-native/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ runs:
using: composite
steps:

- name: 'Linux(aarch64/x86_64) & Windows(x86_64): Build symgc'
if: (runner.os == 'Linux' && (inputs.arch == 'x86_64' || inputs.arch == 'aarch64')) || (runner.os == 'Windows' && inputs.arch == 'x64')
shell: bash
run: |
set -eux
cd runtime/symgc
# FIXME: hitting LLVM assertion with -g
DFLAGS="-O -g -singleobj -linkonce-templates" dub build -v --compiler=$PWD/../../../bootstrap-ldc/bin/ldc2
# extract single object file as symgc.o[bj]
if [[ '${{ runner.os }}' == Linux ]]; then
ls -l libsymgc.a
ar x libsymgc.a
mv *.o symgc.o
ls -l symgc.o
else
ls -l symgc.lib
#obj=$(lib.exe /nologo /list symgc.lib)
#lib.exe /nologo symgc.lib /extract:"$obj" /out:symgc.obj
llvm-ar x symgc.lib
mv *.obj symgc.obj
ls -l symgc.obj
fi

- name: 'Posix: Build mimalloc'
if: runner.os != 'Windows'
uses: ./.github/actions/helper-mimalloc
Expand Down
4 changes: 4 additions & 0 deletions .github/actions/4d-test-libs/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ runs:
if [[ '${{ runner.os }}' == macOS ]]; then
# FIXME: https://github.com/dlang/phobos/issues/10730
excludes+='|^std.experimental.allocator.building_blocks.allocator_list'
if [[ '${{ inputs.arch }}' == x86_64 ]]; then
# FIXME: regressed with image bump from macos-13 to macos-15-intel, apparently wrt. getpwnam_r() setting unexpected errno
excludes+='|^std.path'
fi
fi

ctest -j$N --output-on-failure -E "$excludes" --timeout 120
Expand Down
12 changes: 11 additions & 1 deletion .github/actions/6-integration-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,29 @@ runs:

- name: Generate hello.d
shell: bash
run: echo 'void main() { import std.stdio; writefln("Hello world, %d bits", size_t.sizeof * 8); }' > ../hello.d
run: echo 'void main() { import std.stdio; writefln("Hello world, %d bits", size_t.sizeof * 8); auto dummyAlloc = new int; }' > ../hello.d

- name: Run hello-world integration test with shared libs
shell: bash
run: |
set -eux
symgc=0
if [[ -f runtime/symgc/symgc.o || -f runtime/symgc/symgc.obj ]]; then
symgc=1
fi
cd ..
if [[ '${{ runner.os }}' == Windows ]]; then
# add druntime/Phobos DLL dir to PATH
export PATH="$PWD/installed/bin:$PATH"
fi
installed/bin/ldc2 hello.d -link-defaultlib-shared
./hello
if [[ $symgc == 1 ]]; then
./hello --DRT-gcopt="gc:sdc"
installed/bin/ldc2 hello.d
./hello --DRT-gcopt="gc:sdc"
DRT_GCOPT="gc:sdc" ./hello
fi
if [[ -d installed/lib32 ]]; then
installed/bin/ldc2 hello.d -m32 -link-defaultlib-shared
./hello
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/merge-windows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ runs:
ldc2-multilib\bin\ldc2 -link-defaultlib-shared -m32 -run hello.d || exit /b

# preliminary arm64 cross-compilation support
- name: Install ninja v1.12.1
uses: Ahajha/gha-setup-ninja@69595b0cf872acdad8ce599142fbdc88724b9a2b
# - name: Install ninja v1.12.1
# uses: Ahajha/gha-setup-ninja@69595b0cf872acdad8ce599142fbdc88724b9a2b
- name: Set VSDIR env variable
shell: bash
run: echo "VSDIR=$(vswhere -latest -property installationPath)" >> $GITHUB_ENV
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
push:
branches-ignore:
- 'merge-*' # don't run on pushes to merge-X.Y.Z branches, they are usually PRs
- 'symgc*'
tags: # explicitly needed to run for all tags, due to the branches filter above
- '**'

Expand All @@ -15,6 +16,7 @@ concurrency:

env:
LLVM_VERSION: 20.1.5
DRT_GCOPT: gc:conservative

jobs:
build-native:
Expand Down Expand Up @@ -71,7 +73,7 @@ jobs:
with_pgo: true

- job_name: macOS x86_64
os: macos-13
os: macos-15-intel
arch: x86_64
# https://github.com/ldc-developers/ldc/issues/4462:
# When using LTO, we need to explicitly export ~all symbols for plugin support via `ld64 -exported_symbol '__*'`.
Expand Down Expand Up @@ -132,7 +134,7 @@ jobs:
else
# set up Alpine container
apk add \
git cmake ninja-is-really-ninja g++ clang ldc lld llvm-dev llvm-static compiler-rt \
git cmake ninja-is-really-ninja g++ clang ldc dub lld llvm-dev llvm-static compiler-rt \
libxml2-static zstd-static zlib-static \
bash grep diffutils make curl 7zip perl
# create missing 7za symlink
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/supported_llvm_versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
push:
branches-ignore:
- 'merge-*' # don't run on pushes to merge-X.Y.Z branches, they are usually PRs
- 'symgc*'
tags: # explicitly needed to run for all tags, due to the branches filter above
- '**'

Expand Down Expand Up @@ -54,8 +55,8 @@ jobs:
with:
submodules: true
fetch-depth: 50
- name: Install ninja
uses: symmetryinvestments/gha-setup-ninja@v2
# - name: Install ninja
# uses: symmetryinvestments/gha-setup-ninja@v2
- name: Install D host compiler
uses: dlang-community/setup-dlang@v1
with:
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "phobos"]
path = runtime/phobos
url = https://github.com/ldc-developers/phobos.git
url = https://github.com/symmetryinvestments/phobos.git
[submodule "runtime/symgc"]
path = runtime/symgc
url = https://github.com/symmetryinvestments/symgc.git
5 changes: 3 additions & 2 deletions dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -6763,8 +6763,9 @@ ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp
}
// Little sanity check to make sure it's really a Throwable
ClassReferenceExp boss = oldest.thrown;
const next = 5; // index of Throwable.next
assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
const next = 5; // index of Throwable._nextInChainPtr
with ((*boss.value.elements)[next].type) // Throwable._nextInChainPtr
assert(ty == Tpointer || ty == Tclass);
ClassReferenceExp collateral = newest.thrown;
if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
{
Expand Down
12 changes: 11 additions & 1 deletion runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -537,16 +537,26 @@ macro(compile_druntime d_flags lib_suffix path_suffix emit_bc all_at_once single
else()
set(single_obj_name "")
endif()
set(symgc_version "")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/symgc/symgc${CMAKE_C_OUTPUT_EXTENSION}" AND "${path_suffix}" STREQUAL "${LIB_SUFFIX}") # not for 32-bit druntime with MULTILIB=ON
set(symgc_version "-d-version=With_symgc")
endif()
dc("${DRUNTIME_D}"
"${RUNTIME_DIR}/src"
"-conf=;${d_flags};${DRUNTIME_EXTRA_FLAGS};-I${RUNTIME_DIR}/src"
"-conf=;${d_flags};${symgc_version};${DRUNTIME_EXTRA_FLAGS};-I${RUNTIME_DIR}/src"
"${PROJECT_BINARY_DIR}/objects${target_suffix}"
"${emit_bc}"
"${all_at_once}"
"${single_obj_name}"
${outlist_o}
${outlist_bc}
)
if(symgc_version)
list(APPEND ${outlist_o} ${CMAKE_CURRENT_SOURCE_DIR}/symgc/symgc${CMAKE_C_OUTPUT_EXTENSION})
if(${emit_bc})
list(APPEND ${outlist_bc} ${CMAKE_CURRENT_SOURCE_DIR}/symgc/symgc${CMAKE_C_OUTPUT_EXTENSION})
endif()
endif()
endmacro()

# Sets up the targets for building the Phobos D object files, appending the
Expand Down
14 changes: 11 additions & 3 deletions runtime/druntime/src/core/gc/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ import core.stdc.stdio : printf;

__gshared Config config;

private __gshared bool _initialized;

struct Config
{
bool disable; // start disabled
bool fork = false; // optional concurrent behaviour
ubyte profile; // enable profiling with summary when terminating program
string gc = "conservative"; // select gc implementation conservative|precise|manual
version (With_symgc)
string gc = "sdcq"; // pick the symgc in quiet mode by default.
else
string gc = "conservative"; // select gc implementation conservative|precise|manual

@MemVal size_t initReserve; // initial reserve (bytes)
@MemVal size_t minPoolSize = 1 << 20; // initial and minimum pool size (bytes)
Expand All @@ -31,7 +36,9 @@ struct Config

bool initialize()
{
return initConfigOptions(this, "gcopt");
if (!_initialized)
_initialized = initConfigOptions(this, "gcopt");
return _initialized;
}

void help() @nogc nothrow
Expand All @@ -52,7 +59,7 @@ struct Config
auto _minPoolSize = minPoolSize.bytes2prettyStruct;
auto _maxPoolSize = maxPoolSize.bytes2prettyStruct;
auto _incPoolSize = incPoolSize.bytes2prettyStruct;
printf(" - select gc implementation (default = conservative)
printf(" - select gc implementation (default = %.*s)

initReserve:N - initial memory to reserve in MB (%lld%c)
minPoolSize:N - initial and minimum pool size in MB (%lld%c)
Expand All @@ -64,6 +71,7 @@ struct Config

Memory-related values can use B, K, M or G suffixes.
".ptr,
cast(int)gc.length, gc.ptr,
_initReserve.v, _initReserve.u,
_minPoolSize.v, _minPoolSize.u,
_maxPoolSize.v, _maxPoolSize.u,
Expand Down
30 changes: 30 additions & 0 deletions runtime/druntime/src/core/gc/gcinterface.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/
module core.gc.gcinterface;

import core.thread.threadbase : ThreadBase;

static import core.memory;
alias BlkAttr = core.memory.GC.BlkAttr;
alias BlkInfo = core.memory.GC.BlkInfo;
Expand Down Expand Up @@ -270,4 +272,32 @@ interface GC
* Returns: true if successful.
*/
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow;

/**
* Prepare a thread for use with the GC after the GC is initialized. Note
* that you can register an initThread function to call before the GC is
* initialized, see core.gc.registry.
*
* This function is always called *from* the thread as it is being started,
* before any static initializers. The thread object parameter may not yet
* be registered as `ThreadBase.getThis()`, as this is called before that
* happens.
*/
void initThread(ThreadBase thread) nothrow @nogc;

/**
* Clean up any GC related data from the thread before it exits. There is
* no equivalent of this function as a hook before the GC is initialized.
* That is, the thread init function called before the GC is initialized
* (from the registry hook) should assume this function may not be called
* on termination if the GC is never initialized.
*
* Most times, this is called from the thread that is the given thread
* reference, but it's possible the `thread` parameter is not the same as
* the current thread.
*
* There is no guarantee the thread is still registered as
* `ThreadBase.getThis()`.
*/
void cleanupThread(ThreadBase thread) nothrow @nogc;
}
Loading
Loading