Skip to content

Add -gc=custom option #3302

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

Merged
merged 14 commits into from
Jan 28, 2023
Merged
2 changes: 1 addition & 1 deletion compileopts/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (c *Config) GC() string {
// that can be traced by the garbage collector.
func (c *Config) NeedsStackObjects() bool {
switch c.GC() {
case "conservative", "precise":
case "conservative", "custom", "precise":
for _, tag := range c.BuildTags() {
if tag == "tinygo.wasm" {
return true
Expand Down
2 changes: 1 addition & 1 deletion compileopts/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

var (
validGCOptions = []string{"none", "leaking", "conservative", "precise"}
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
validSerialOptions = []string{"none", "uart", "usb"}
validPrintSizeOptions = []string{"none", "short", "full"}
Expand Down
8 changes: 7 additions & 1 deletion compileopts/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestVerifyOptions(t *testing.T) {

expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, precise`)
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`)
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
Expand Down Expand Up @@ -48,6 +48,12 @@ func TestVerifyOptions(t *testing.T) {
GC: "conservative",
},
},
{
name: "GCOptionCustom",
opts: compileopts.Options{
GC: "custom",
},
},
{
name: "InvalidSchedulerOption",
opts: compileopts.Options{
Expand Down
2 changes: 1 addition & 1 deletion src/internal/task/gc_stack_chain.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build (gc.conservative || gc.precise) && tinygo.wasm
//go:build (gc.conservative || gc.custom || gc.precise) && tinygo.wasm

package task

Expand Down
2 changes: 1 addition & 1 deletion src/internal/task/gc_stack_noop.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !(gc.conservative || gc.precise) || !tinygo.wasm
//go:build !(gc.conservative || gc.custom || gc.precise) || !tinygo.wasm

package task

Expand Down
55 changes: 55 additions & 0 deletions src/runtime/gc_custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//go:build gc.custom
// +build gc.custom

package runtime

// This GC strategy allows an external GC to be plugged in instead of the builtin
// implementations.
//
// The interface defined in this file is not stable and can be broken at anytime, even
// across minor versions.
//
// runtime.markStack() must be called at the beginning of any GC cycle. //go:linkname
// on a function without a body can be used to access this internal function.
//
// The custom implementation must provide the following functions in the runtime package
// using the go:linkname directive:
//
// - func initHeap()
// - func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
// - func free(ptr unsafe.Pointer)
// - func markRoots(start, end uintptr)
// - func GC()
//
//
// In addition, if targeting wasi, the following functions should be exported for interoperability
// with wasi libraries that use them. Note, this requires the export directive, not go:linkname.
//
// - func malloc(size uintptr) unsafe.Pointer
// - func free(ptr unsafe.Pointer)
// - func calloc(nmemb, size uintptr) unsafe.Pointer
// - func realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer
Comment on lines +25 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are normally defined by the runtime, and call runtime.alloc/runtime.free as needed. Would it be possible to keep it that way and let the custom GC only provide the functions above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added the custommalloc build tag and this intends to replace it with just the concept of a custom GC.

Replacing malloc with an implementation that doesn't delegate to Go GC (in my case mimalloc) had a dramatic improvement in performance and is important for allowing high performance. I'd be fine with keeping the current tag though if it seems better.


import (
"unsafe"
)

// initHeap is called when the heap is first initialized at program start.
func initHeap()

// alloc is called to allocate memory. layout is currently not used.
func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer

// free is called to explicitly free a previously allocated pointer.
func free(ptr unsafe.Pointer)

// markRoots is called with the start and end addresses to scan for references.
// It is currently only called with the top and bottom of the stack.
func markRoots(start, end uintptr)

// GC is called to explicitly run garbage collection.
func GC()

func setHeapEnd(newHeapEnd uintptr) {
// Heap is in custom GC so ignore for when called from wasm initialization.
}
2 changes: 1 addition & 1 deletion src/runtime/gc_stack_portable.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build (gc.conservative || gc.precise) && tinygo.wasm
//go:build (gc.conservative || gc.custom || gc.precise) && tinygo.wasm

package runtime

Expand Down