8000 all: add the Boehm-Demers-Weiser GC on Linux · tinygo-org/tinygo@965702f · GitHub
[go: up one dir, main page]

Skip to content

Commit 965702f

Browse files
committed
all: add the Boehm-Demers-Weiser GC on Linux
This adds support for the well-known Boehm GC. It's significantly faster than our own naive GC and could be used as an alternative on bigger systems. In the future, this GC might also be supported on WebAssembly with some extra work. Right now it's Linux only (though Windows/MacOS shouldn't be too difficult to add).
1 parent 3a94c90 commit 965702f

File tree

17 files changed

+377
-55
lines changed
  • compileopts
  • lib
  • src/runtime
  • 17 files changed

    +377
    -55
    lines changed

    .github/workflows/nix.yml

    Lines changed: 2 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -17,9 +17,9 @@ jobs:
    1717
    steps:
    1818
    - name: Checkout
    1919
    uses: actions/checkout@v4
    20-
    - name: Pull musl
    20+
    - name: Pull musl, bdwgc
    2121
    run: |
    22-
    git submodule update --init lib/musl
    22+
    git submodule update --init lib/musl lib/bdwgc
    2323
    - name: Restore LLVM source cache
    2424
    uses: actions/cache/restore@v4
    2525
    id: cache-llvm-source

    .gitmodules

    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -42,3 +42,6 @@
    4242
    [submodule "lib/wasi-cli"]
    4343
    path = lib/wasi-cli
    4444
    url = https://github.com/WebAssembly/wasi-cli
    45+
    [submodule "lib/bdwgc"]
    46+
    path = lib/bdwgc
    47+
    url = https://github.com/ivmai/bdwgc.git

    GNUmakefile

    Lines changed: 7 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -850,6 +850,7 @@ wasmtest:
    850850

    851851
    build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
    852852
    @mkdir -p build/release/tinygo/bin
    853+
    @mkdir -p build/release/tinygo/lib/bdwgc
    853854
    @mkdir -p build/release/tinygo/lib/clang/include
    854855
    @mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
    855856
    @mkdir -p build/release/tinygo/lib/macos-minimal-sdk
    @@ -871,6 +872,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
    871872
    ifneq ($(USE_SYSTEM_BINARYEN),1)
    872873
    @cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
    873874
    endif
    875+
    @cp -rp lib/bdwgc/* build/release/tinygo/lib/bdwgc
    874876
    @cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
    875877
    @cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
    876878
    @cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
    @@ -884,9 +886,11 @@ endif
    884886
    @cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt
    885887
    @cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl
    886888
    @cp -rp lib/musl/include build/release/tinygo/lib/musl
    889+
    @cp -rp lib/musl/src/ctype build/release/tinygo/lib/musl/src
    887890
    @cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
    888891
    @cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
    889892
    @cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
    893+
    @cp -rp lib/musl/src/fcntl build/release/tinygo/lib/musl/src
    890894
    @cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
    891895
    @cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
    892896
    @cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
    @@ -895,9 +899,12 @@ endif
    895899
    @cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
    896900
    @cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
    897901
    @cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
    902+
    @cp -rp lib/musl/src/misc build/release/tinygo/lib/musl/src
    898903
    @cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
    904+
    @cp -rp lib/musl/src/sched build/release/tinygo/lib/musl/src
    899905
    @cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
    900906
    @cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
    907+
    @cp -rp lib/musl/src/stdlib build/release/tinygo/lib/musl/src
    901908
    @cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
    902909
    @cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
    903910
    @cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src

    builder/bdwgc.go

    Lines changed: 71 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,71 @@
    1+
    package builder
    2+
    3+
    // The well-known conservative Boehm-Demers-Weiser GC.
    4+
    // This file provides a way to compile this GC for use with TinyGo.
    5+
    6+
    import (
    7+
    "path/filepath"
    8+
    9+
    "github.com/tinygo-org/tinygo/goenv"
    10+
    )
    11+
    12+
    var BoehmGC = Library{
    13+
    name: "bdwgc",
    14+
    cflags: func(target, headerPath string) []string {
    15+
    libdir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
    16+
    return []string{
    17+
    // use a modern environment
    18+
    "-DUSE_MMAP", // mmap is available
    19+
    "-DUSE_MUNMAP", // return memory to the OS using munmap
    20+
    "-DGC_BUILTIN_ATOMIC", // use compiler intrinsics for atomic operations
    21+
    "-DNO_EXECUTE_PERMISSION", // don't make the heap executable
    22+
    23+
    // specific flags for TinyGo
    24+
    "-DALL_INTERIOR_POINTERS", // scan interior pointers (needed for Go)
    25+
    "-DIGNORE_DYNAMIC_LOADING", // we don't support dynamic loading at the moment
    26+
    "-DNO_GETCONTEXT", // musl doesn't support getcontext()
    27+
    28+
    // Special flag to work around the lack of __data_start in ld.lld.
    29+
    // TODO: try to fix this in LLVM/lld directly so we don't have to
    30+
    // work around it anymore.
    31+
    "-DGC_DONT_REGISTER_MAIN_STATIC_DATA",
    32+
    33+
    // Do not scan the stack. We have our own mechanism to do this.
    34+
    "-DSTACK_NOT_SCANNED",
    35+
    36+
    // Assertions can be enabled while debugging GC issues.
    37+
    //"-DGC_ASSERTIONS",
    38+
    39+
    // Threading is not yet supported, so these are disabled.
    40+
    //"-DGC_THREADS",
    41+
    //"-DTHREAD_LOCAL_ALLOC",
    42+
    43+
    "-I" + libdir + "/include",
    44+
    }
    45+
    },
    46+
    sourceDir: func() string {
    47+
    return filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
    48+
    },
    49+
    librarySources: func(target string) ([]string, error) {
    50+
    return []string{
    51+
    "allchblk.c",
    52+
    "alloc.c",
    53+
    "blacklst.c",
    54+
    "dbg_mlc.c",
    55+
    "dyn_load.c",
    56+
    "finalize.c",
    57+
    "headers.c",
    58+
    "mach_dep.c",
    59+
    "malloc.c",
    60+
    "mark.c",
    61+
    "mark_rts.c",
    62+
    "misc.c",
    63+
    "new_hblk.c",
    64+
    "obj_map.c",
    65+
    "os_dep.c",
    66+
    "pthread_stop_world.c",
    67+
    "pthread_support.c",
    68+
    "reclaim.c",
    69+
    }, nil
    70+
    },
    71+
    }

    builder/build.go

    Lines changed: 22 additions & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -143,20 +143,22 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
    143143
    // the libc needs them.
    144144
    root := goenv.Get("TINYGOROOT")
    145145
    var libcDependencies []*compileJob
    146+
    var libcJob *compileJob
    146147
    switch config.Target.Libc {
    147148
    case "darwin-libSystem":
    148149
    job := makeDarwinLibSystemJob(config, tmpdir)
    149150
    libcDependencies = append(libcDependencies, job)
    150151
    case "musl":
    151-
    job, unlock, err := libMusl.load(config, tmpdir)
    152+
    var unlock func()
    153+
    libcJob, unlock, err = libMusl.load(config, tmpdir, nil)
    152154
    if err != nil {
    153155
    return BuildResult{}, err
    154156
    }
    155157
    defer unlock()
    156-
    libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
    157-
    libcDependencies = append(libcDependencies, job)
    158+
    libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(libcJob.result), "crt1.o")))
    159+
    libcDependencies = append(libcDependencies, libcJob)
    158160
    case "picolibc":
    159-
    libcJob, unlock, err := libPicolibc.load(config, tmpdir)
    161+
    libcJob, unlock, err := libPicolibc.load(config, tmpdir, nil)
    160162
    if err != nil {
    161163
    return BuildResult{}, err
    162164
    }
    @@ -169,14 +171,14 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
    169171
    }
    170172
    libcDependencies = append(libcDependencies, dummyCompileJob(path))
    171173
    case "wasmbuiltins":
    172-
    libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir)
    174+
    libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir, nil)
    173175
    if err != nil {
    174176
    return BuildResult{}, err
    175177
    }
    176178
    defer unlock()
    177179
    libcDependencies = append(libcDependencies, libcJob)
    178180
    case "mingw-w64":
    179-
    job, unlock, err := libMinGW.load(config, tmpdir)
    181+
    job, unlock, err := libMinGW.load(config, tmpdir, nil)
    180182
    if err != nil {
    181183
    return BuildResult{}, err
    182184
    }
    @@ -652,14 +654,27 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
    652654
    // Add compiler-rt dependency if needed. Usually this is a simple load from
    653655
    // a cache.
    654656
    if config.Target.RTLib == "compiler-rt" {
    655-
    job, unlock, err := libCompilerRT.load(config, tmpdir)
    657+
    job, unlock, err := libCompilerRT.load(config, tmpdir, nil)
    656658
    if err != nil {
    657659
    return result, err
    658660
    }
    659661
    defer unlock()
    660662
    linkerDependencies = append(linkerDependencies, job)
    661663
    }
    662664

    665+
    // The Boehm collector is stored in a separate C library.
    666+
    if config.GC() == "boehm" {
    667+
    if libcJob == nil {
    668+
    return BuildResult{}, fmt.Errorf("boehm GC isn't supported with libc %s", config.Target.Libc)
    669+
    }
    670+
    job, unlock, err := BoehmGC.load(config, tmpdir, libcJob)
    671+
    if err != nil {
    672+
    return BuildResult{}, err
    673+
    }
    674+
    defer unlock()
    675+
    linkerDependencies = append(linkerDependencies, job)
    676+
    }
    677+
    663678
    // Add jobs to compile extra files. These files are in C or assembly and
    664679
    // contain things like the interrupt vector table and low level operations
    665680
    // such as stack switching.

    builder/library.go

    Lines changed: 20 additions & 5 deletions
    Original file line numberDiff line numberDiff line change
    @@ -43,7 +43,11 @@ type Library struct {
    4343
    // output archive file, it is expected to be removed after use.
    4444
    // As a side effect, this call creates the library header files if they didn't
    4545
    // exist yet.
    46-
    func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
    46+
    // The provided libc job (if not null) will cause this libc to be added as a
    47+
    // dependency for all C compiler jobs, and adds libc headers for the given
    48+
    // target config. In other words, pass this libc if the library needs a libc to
    49+
    // compile.
    50+
    func (l *Library) load(config *compileopts.Config, tmpdir string, libc *compileJob) (job *compileJob, abortLock func(), err error) {
    4751
    outdir, precompiled := config.LibcPath(l.name)
    4852
    archiveFilePath := filepath.Join(outdir, "lib.a")
    4953
    if precompiled {
    @@ -181,6 +185,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
    181185
    args = append(args, "-mfpu=vfpv2")
    182186
    }
    183187
    }
    188+
    if libc != nil {
    189+
    args = append(args, config.LibcCFlags()...)
    190+
    }
    184191

    185192
    var once sync.Once
    186193

    @@ -233,7 +240,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
    233240
    objpath := filepath.Join(dir, cleanpath+".o")
    234241
    os.MkdirAll(filepath.Dir(objpath), 0o777)
    235242
    objs = append(objs, objpath)
    236-
    job.dependencies = append(job.dependencies, &compileJob{
    243+
    objfile := &compileJob{
    237244
    description: "compile " + srcpath,
    238245
    run: func(*compileJob) error {
    239246
    var compileArgs []string
    @@ -248,7 +255,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
    248255
    }
    249256
    return nil
    250257
    },
    251-
    })
    258+
    }
    259+
    if libc != nil {
    260+
    objfile.dependencies = append(objfile.dependencies, libc)
    261+
    }
    262+
    job.dependencies = append(job.dependencies, objfile)
    252263
    }
    253264

    254265
    // Create crt1.o job, if needed.
    @@ -257,7 +268,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
    257268
    // won't make much of a difference in speed).
    258269
    if l.crt1Source != "" {
    259270
    srcpath := filepath.Join(sourceDir, l.crt1Source)
    260-
    job.dependencies = append(job.dependencies, &compileJob{
    271+
    crt1Job := &compileJob{
    261272
    description: "compile " + srcpath,
    262273
    run: func(*compileJob) error {
    263274
    var compileArgs []string
    @@ -277,7 +288,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
    277288
    }
    278289
    return os.Rename(tmpfile.Name(), filepath.Join(outdir, "crt1.o"))
    279290
    },
    280-
    })
    291+
    }
    292+
    if libc != nil {
    293+
    crt1Job.dependencies = append(crt1Job.dependencies, libc)
    294+
    }
    295+
    job.dependencies = append(job.dependencies, crt1Job)
    281296
    }
    282297

    283298
    ok = true

    builder/musl.go

    Lines changed: 8 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -113,23 +113,31 @@ var libMusl = Library{
    113113
    librarySources: func(target string) ([]string, error) {
    114114
    arch := compileopts.MuslArchitecture(target)
    115115
    globs := []string{
    116+
    "ctype/*.c",
    116117
    "env/*.c",
    117118
    "errno/*.c",
    118119
    "exit/*.c",
    120+
    "fcntl/*.c& 27A9 quot;,
    119121
    "internal/defsysinfo.c",
    122+
    "internal/intscan.c",
    120123
    "internal/libc.c",
    124+
    "internal/shgetc.c",
    121125
    "internal/syscall_ret.c",
    122126
    "internal/vdso.c",
    123127
    "legacy/*.c",
    124128
    "locale/*.c",
    125129
    "linux/*.c",
    130+
    "locale/*.c",
    126131
    "malloc/*.c",
    127132
    "malloc/mallocng/*.c",
    128133
    "mman/*.c",
    129134
    "math/*.c",
    135+
    "misc/*.c",
    130136
    "multibyte/*.c",
    137+
    "sched/*.c",
    131138
    "signal/*.c",
    132139
    "stdio/*.c",
    140+
    "stdlib/*.c",
    133141
    "string/*.c",
    134142
    "thread/" + arch + "/*.s",
    135143
    "thread/*.c",

    0 commit comments

    Comments
     (0)
    0