Skip to content

Commit b5dffc8

Browse files
committed
generalize "lists" GC
1 parent c8cce62 commit b5dffc8

16 files changed

+66
-38
lines changed

compileopts/config.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ func (c *Config) GOARCH() string {
7979

8080
// BuildTags returns the complete list of build tags used during this build.
8181
func (c *Config) BuildTags() []string {
82-
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler()}...)
82+
gc := c.GC()
83+
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + gc, "scheduler." + c.Scheduler()}...)
84+
switch gc {
85+
case "list", "blocks", "extalloc":
86+
tags = append(tags, "gc.conservative")
87+
}
8388
for i := 1; i <= c.GoMinorVersion; i++ {
8489
tags = append(tags, fmt.Sprintf("go1.%d", i))
8590
}
@@ -96,7 +101,7 @@ func (c *Config) CgoEnabled() bool {
96101
}
97102

98103
// GC returns the garbage collection strategy in use on this platform. Valid
99-
// values are "none", "leaking", "extalloc", and "conservative".
104+
// values are "none", "leaking", "list", "extalloc", and "blocks".
100105
func (c *Config) GC() string {
101106
if c.Options.GC != "" {
102107
return c.Options.GC
@@ -106,7 +111,7 @@ func (c *Config) GC() string {
106111
}
107112
for _, tag := range c.Target.BuildTags {
108113
if tag == "baremetal" || tag == "wasm" {
109-
return "conservative"
114+
return "blocks"
110115
}
111116
}
112117
return "extalloc"
@@ -116,7 +121,7 @@ func (c *Config) GC() string {
116121
// that can be traced by the garbage collector.
117122
func (c *Config) NeedsStackObjects() bool {
118123
switch c.GC() {
119-
case "conservative", "extalloc":
124+
case "list", "blocks", "extalloc":
120125
for _, tag := range c.BuildTags() {
121126
if tag == "baremetal" {
122127
return false

compileopts/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
var (
9-
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
9+
validGCOptions = []string{"none", "leaking", "list", "extalloc", "blocks"}
1010
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
1111
validPrintSizeOptions = []string{"none", "short", "full"}
1212
validPanicStrategyOptions = []string{"print", "trap"}

compileopts/options_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestVerifyOptions(t *testing.T) {
1111

12-
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
12+
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, list, extalloc, blocks`)
1313
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines`)
1414
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
1515
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
@@ -42,16 +42,22 @@ func TestVerifyOptions(t *testing.T) {
4242
GC: "leaking",
4343
},
4444
},
45+
{
46+
name: "GCOptionList",
47+
opts: compileopts.Options{
48+
GC: "list",
49+
},
50+
},
4551
{
4652
name: "GCOptionExtalloc",
4753
opts: compileopts.Options{
4854
GC: "extalloc",
4955
},
5056
},
5157
{
52-
name: "GCOptionConservative",
58+
name: "GCOptionBlocks",
5359
opts: compileopts.Options{
54-
GC: "conservative",
60+
GC: "blocks",
5561
},
5662
},
5763
{

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ func main() {
787787

788788
outpath := flag.String("o", "", "output filename")
789789
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
790-
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
790+
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, blocks, list)")
791791
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
792792
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)")
793793
printIR := flag.Bool("printir", false, "print LLVM IR")

src/runtime/gc_conservative.go renamed to src/runtime/gc_blocks.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// +build gc.conservative
2-
// +build !avr
1+
// +build gc.blocks
32

43
package runtime
54

src/runtime/gc_globals_conservative.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build gc.conservative gc.extalloc
1+
// +build gc.conservative
22
// +build baremetal
33

44
package runtime

src/runtime/gc_globals_precise.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build gc.conservative gc.extalloc
1+
// +build gc.conservative
22
// +build !baremetal
33

44
package runtime

src/runtime/gc_avr.go renamed to src/runtime/gc_list.go

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
// +build gc.conservative
2-
// +build avr
1+
// +build gc.list
32

43
package runtime
54

65
// This memory manager is partially inspired by the memory allocator included in avr-libc.
76
// Unlike avr-libc malloc, this memory manager stores an allocation list instead of a free list.
8-
// This gives an overhead of 4 bytes/allocation (up from avr-libc's 2 bytes/allocation).
7+
// This gives an overhead of 2 pointers/allocation (up from avr-libc's 1 pointer-width/allocation).
98
// The allocation list is stored in ascending address order.
109
// The set of free spans is implicitly derived from the gaps between allocations.
1110
// This allocator has an effective allocation complexity of O(n) and worst-case GC complexity of O(n^2).
12-
// Due to architectural quirks of AVR, as well as tiny heaps, this should almost always be faster than the standard conservative collector.
11+
// Due to architectural quirks, as well as tiny heaps, this should almost always be faster than the standard conservative collector on AVR.
1312

1413
import "unsafe"
1514

@@ -73,20 +72,6 @@ func markAddr(addr uintptr) {
7372
}
7473
}
7574

76-
// markMem scans a memory region for pointers and marks anything that is pointed to.
77-
func markMem(start, end uintptr) {
78-
if start >= end {
79-
return
80-
}
81-
prevByte := *(*byte)(unsafe.Pointer(start))
82-
for ; start != end; start++ {
83-
b := *(*byte)(unsafe.Pointer(start))
84-
addr := (uintptr(b) << 8) | uintptr(prevByte)
85-
markAddr(addr)
86-
prevByte = b
87-
}
88-
}
89-
9075
// GC runs a garbage collection cycle.
9176
func GC() {
9277
// Mark phase: mark all reachable objects, recursively.
@@ -172,7 +157,7 @@ searchLoop:
172157
// That was the last free region.
173158
break searchLoop
174159
}
175-
start = uintptr(unsafe.Pointer(&node.base)) + node.len
160+
start = align(uintptr(unsafe.Pointer(&node.base)) + node.len)
176161
dst = &node.next
177162
}
178163

src/runtime/gc_list_avr.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// +build gc.list,avr
2+
3+
package runtime
4+
5+
import "unsafe"
6+
7+
// markMem scans a memory region for pointers and marks anything that is pointed to.
8+
func markMem(start, end uintptr) {
9+
if start >= end {
10+
return
11+
}
12+
prevByte := *(*byte)(unsafe.Pointer(start))
13+
for ; start != end; start++ {
14+
b := *(*byte)(unsafe.Pointer(start))
15+
addr := (uintptr(b) << 8) | uintptr(prevByte)
16+
markAddr(addr)
17+
prevByte = b
18+
}
19+
}

src/runtime/gc_list_generic.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// +build gc.list,!avr
2+
3+
package runtime
4+
5+
import "unsafe"
6+
7+
// markMem scans a memory region for pointers and marks anything that is pointed to.
8+
func markMem(start, end uintptr) {
9+
start = align(start)
10+
end &^= unsafe.Alignof(unsafe.Pointer(nil)) - 1
11+
for ; start < end; start += unsafe.Alignof(unsafe.Pointer(nil)) - 1 {
12+
markAddr(*(*uintptr)(unsafe.Pointer(start)))
13+
}
14+
}

0 commit comments

Comments
 (0)