Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boehm GC support #4385

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/nix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Pull musl
- name: Pull musl, bdwgc
run: |
git submodule update --init lib/musl
git submodule update --init lib/musl lib/bdwgc
- name: Restore LLVM source cache
uses: actions/cache/restore@v4
id: cache-llvm-source
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@
[submodule "lib/wasi-cli"]
path = lib/wasi-cli
url = https://github.com/WebAssembly/wasi-cli
[submodule "lib/bdwgc"]
path = lib/bdwgc
url = https://github.com/ivmai/bdwgc.git
7 changes: 7 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ wasmtest:

build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binaryen)
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/bdwgc
@mkdir -p build/release/tinygo/lib/clang/include
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
Expand All @@ -871,6 +872,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
ifneq ($(USE_SYSTEM_BINARYEN),1)
@cp -p build/wasm-opt$(EXE) build/release/tinygo/bin
endif
@cp -rp lib/bdwgc/* build/release/tinygo/lib/bdwgc
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
Expand All @@ -884,9 +886,11 @@ endif
@cp -rp lib/musl/crt/crt1.c build/release/tinygo/lib/musl/crt
@cp -rp lib/musl/COPYRIGHT build/release/tinygo/lib/musl
@cp -rp lib/musl/include build/release/tinygo/lib/musl
@cp -rp lib/musl/src/ctype build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/env build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/errno build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/exit build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/fcntl build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
Expand All @@ -895,9 +899,12 @@ endif
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/misc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/sched build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/stdlib build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/thread build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/time build/release/tinygo/lib/musl/src
Expand Down
71 changes: 71 additions & 0 deletions builder/bdwgc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package builder

// The well-known conservative Boehm-Demers-Weiser GC.
// This file provides a way to compile this GC for use with TinyGo.

import (
"path/filepath"

"github.com/tinygo-org/tinygo/goenv"
)

var BoehmGC = Library{
name: "bdwgc",
cflags: func(target, headerPath string) []string {
libdir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
return []string{
// use a modern environment
"-DUSE_MMAP", // mmap is available
"-DUSE_MUNMAP", // return memory to the OS using munmap
"-DGC_BUILTIN_ATOMIC", // use compiler intrinsics for atomic operations
"-DNO_EXECUTE_PERMISSION", // don't make the heap executable

// specific flags for TinyGo
"-DALL_INTERIOR_POINTERS", // scan interior pointers (needed for Go)
"-DIGNORE_DYNAMIC_LOADING", // we don't support dynamic loading at the moment
"-DNO_GETCONTEXT", // musl doesn't support getcontext()

// Special flag to work around the lack of __data_start in ld.lld.
// TODO: try to fix this in LLVM/lld directly so we don't have to
// work around it anymore.
"-DGC_DONT_REGISTER_MAIN_STATIC_DATA",

// Do not scan the stack. We have our own mechanism to do this.
"-DSTACK_NOT_SCANNED",

// Assertions can be enabled while debugging GC issues.
//"-DGC_ASSERTIONS",

// Threading is not yet supported, so these are disabled.
//"-DGC_THREADS",
//"-DTHREAD_LOCAL_ALLOC",

"-I" + libdir + "/include",
}
},
sourceDir: func() string {
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
},
librarySources: func(target string) ([]string, error) {
return []string{
"allchblk.c",
"alloc.c",
"blacklst.c",
"dbg_mlc.c",
"dyn_load.c",
"finalize.c",
"headers.c",
"mach_dep.c",
"malloc.c",
"mark.c",
"mark_rts.c",
"misc.c",
"new_hblk.c",
"obj_map.c",
"os_dep.c",
"pthread_stop_world.c",
"pthread_support.c",
"reclaim.c",
}, nil
},
}
29 changes: 22 additions & 7 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,22 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// the libc needs them.
root := goenv.Get("TINYGOROOT")
var libcDependencies []*compileJob
var libcJob *compileJob
switch config.Target.Libc {
case "darwin-libSystem":
job := makeDarwinLibSystemJob(config, tmpdir)
libcDependencies = append(libcDependencies, job)
case "musl":
job, unlock, err := libMusl.load(config, tmpdir)
var unlock func()
libcJob, unlock, err = libMusl.load(config, tmpdir, nil)
if err != nil {
return BuildResult{}, err
}
defer unlock()
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(job.result), "crt1.o")))
libcDependencies = append(libcDependencies, job)
libcDependencies = append(libcDependencies, dummyCompileJob(filepath.Join(filepath.Dir(libcJob.result), "crt1.o")))
libcDependencies = append(libcDependencies, libcJob)
case "picolibc":
libcJob, unlock, err := libPicolibc.load(config, tmpdir)
libcJob, unlock, err := libPicolibc.load(config, tmpdir, nil)
if err != nil {
return BuildResult{}, err
}
Expand All @@ -169,14 +171,14 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
libcDependencies = append(libcDependencies, dummyCompileJob(path))
case "wasmbuiltins":
libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir)
libcJob, unlock, err := libWasmBuiltins.load(config, tmpdir, nil)
if err != nil {
return BuildResult{}, err
}
defer unlock()
libcDependencies = append(libcDependencies, libcJob)
case "mingw-w64":
job, unlock, err := libMinGW.load(config, tmpdir)
job, unlock, err := libMinGW.load(config, tmpdir, nil)
if err != nil {
return BuildResult{}, err
}
Expand Down Expand Up @@ -652,14 +654,27 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Add compiler-rt dependency if needed. Usually this is a simple load from
// a cache.
if config.Target.RTLib == "compiler-rt" {
job, unlock, err := libCompilerRT.load(config, tmpdir)
job, unlock, err := libCompilerRT.load(config, tmpdir, nil)
if err != nil {
return result, err
}
defer unlock()
linkerDependencies = append(linkerDependencies, job)
}

// The Boehm collector is stored in a separate C library.
if config.GC() == "boehm" {
if libcJob == nil {
return BuildResult{}, fmt.Errorf("boehm GC isn't supported with libc %s", config.Target.Libc)
}
job, unlock, err := BoehmGC.load(config, tmpdir, libcJob)
if err != nil {
return BuildResult{}, err
}
defer unlock()
linkerDependencies = append(linkerDependencies, job)
}

// Add jobs to compile extra files. These files are in C or assembly and
// contain things like the interrupt vector table and low level operations
// such as stack switching.
Expand Down
25 changes: 20 additions & 5 deletions builder/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ type Library struct {
// output archive file, it is expected to be removed after use.
// As a side effect, this call creates the library header files if they didn't
// exist yet.
func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJob, abortLock func(), err error) {
// The provided libc job (if not null) will cause this libc to be added as a
// dependency for all C compiler jobs, and adds libc headers for the given
// target config. In other words, pass this libc if the library needs a libc to
// compile.
func (l *Library) load(config *compileopts.Config, tmpdir string, libc *compileJob) (job *compileJob, abortLock func(), err error) {
outdir, precompiled := config.LibcPath(l.name)
archiveFilePath := filepath.Join(outdir, "lib.a")
if precompiled {
Expand Down Expand Up @@ -181,6 +185,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
args = append(args, "-mfpu=vfpv2")
}
}
if libc != nil {
args = append(args, config.LibcCFlags()...)
}

var once sync.Once

Expand Down Expand Up @@ -233,7 +240,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
objpath := filepath.Join(dir, cleanpath+".o")
os.MkdirAll(filepath.Dir(objpath), 0o777)
objs = append(objs, objpath)
job.dependencies = append(job.dependencies, &compileJob{
objfile := &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
var compileArgs []string
Expand All @@ -248,7 +255,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
return nil
},
})
}
if libc != nil {
objfile.dependencies = append(objfile.dependencies, libc)
}
job.dependencies = append(job.dependencies, objfile)
}

// Create crt1.o job, if needed.
Expand All @@ -257,7 +268,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// won't make much of a difference in speed).
if l.crt1Source != "" {
srcpath := filepath.Join(sourceDir, l.crt1Source)
job.dependencies = append(job.dependencies, &compileJob{
crt1Job := &compileJob{
description: "compile " + srcpath,
run: func(*compileJob) error {
var compileArgs []string
Expand All @@ -277,7 +288,11 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
}
return os.Rename(tmpfile.Name(), filepath.Join(outdir, "crt1.o"))
},
})
}
if libc != nil {
crt1Job.dependencies = append(crt1Job.dependencies, libc)
}
job.dependencies = append(job.dependencies, crt1Job)
}

ok = true
Expand Down
8 changes: 8 additions & 0 deletions builder/musl.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,23 +113,31 @@ var libMusl = Library{
librarySources: func(target string) ([]string, error) {
arch := compileopts.MuslArchitecture(target)
globs := []string{
"ctype/*.c",
"env/*.c",
"errno/*.c",
"exit/*.c",
"fcntl/*.c",
"internal/defsysinfo.c",
"internal/intscan.c",
"internal/libc.c",
"internal/shgetc.c",
"internal/syscall_ret.c",
"internal/vdso.c",
"legacy/*.c",
"locale/*.c",
"linux/*.c",
"locale/*.c",
"malloc/*.c",
"malloc/mallocng/*.c",
"mman/*.c",
"math/*.c",
"misc/*.c",
"multibyte/*.c",
"sched/*.c",
"signal/*.c",
"stdio/*.c",
"stdlib/*.c",
"string/*.c",
"thread/" + arch + "/*.s",
"thread/*.c",
Expand Down
Loading
Loading