Skip to content

Commit 3cb1da9

Browse files
committed
all: add -unwind= flag to select unwinder
The current options are: - simple: a setjmp/longjmp like unwinder strategy - none: no unwinding supported at all (recover() is a no-op) This can be useful to control binary size. The default stays at -unwind=simple for supported architectures but it's now possible to disable unwinding (and therefore recover) using -unwind=none.
1 parent a422394 commit 3cb1da9

File tree

7 files changed

+41
-12
lines changed

7 files changed

+41
-12
lines changed

builder/build.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
139139
SizeLevel: sizeLevel,
140140

141141
Scheduler: config.Scheduler(),
142+
Unwinder: config.Unwinder(),
142143
FuncImplementation: config.FuncImplementation(),
143144
AutomaticStackSize: config.AutomaticStackSize(),
144145
DefaultStackSize: config.Target.DefaultStackSize,

compileopts/config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,30 @@ func (c *Config) PanicStrategy() string {
191191
return c.Options.PanicStrategy
192192
}
193193

194+
// Unwinder returns the unwinder used. It can be "simple" or "none".
195+
// If no unwinder has been specified on the command line, an appropriate unwind
196+
// strategy for the target architecture is chosen.
197+
func (c *Config) Unwinder() string {
198+
unwinder := c.Options.Unwinder
199+
if unwinder == "" {
200+
arch := strings.Split(c.Triple(), "-")[0]
201+
switch arch {
202+
case "wasm32":
203+
// Probably needs to be implemented using the exception handling
204+
// proposal of WebAssembly:
205+
// https://github.com/WebAssembly/exception-handling
206+
unwinder = "none"
207+
case "avr", "riscv64", "xtensa":
208+
// TODO: add support for these architectures
209+
unwinder = "none"
210+
default:
211+
unwinder = "simple"
212+
}
213+
214+
}
215+
return unwinder
216+
}
217+
194218
// AutomaticStackSize returns whether goroutine stack sizes should be determined
195219
// automatically at compile time, if possible. If it is false, no attempt is
196220
// made.

compileopts/options.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
var (
1010
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
1111
validSchedulerOptions = []string{"none", "tasks", "coroutines", "asyncify"}
12+
validUnwinderOptions = []string{"none", "simple"}
1213
validSerialOptions = []string{"none", "uart", "usb"}
1314
validPrintSizeOptions = []string{"none", "short", "full"}
1415
validPanicStrategyOptions = []string{"print", "trap"}
@@ -27,6 +28,7 @@ type Options struct {
2728
GC string
2829
PanicStrategy string
2930
Scheduler string
31+
Unwinder string
3032
Serial string
3133
PrintIR bool
3234
DumpSSA bool
@@ -93,6 +95,14 @@ func (o *Options) Verify() error {
9395
}
9496
}
9597

98+
if o.Unwinder != "" {
99+
if !isInArray(validUnwinderOptions, o.Unwinder) {
100+
return fmt.Errorf("invalid flag -unwind=%#v: valid values are %s",
101+
o.Unwinder,
102+
strings.Join(validUnwinderOptions, ", "))
103+
}
104+
}
105+
96106
if o.Opt != "" {
97107
if !isInArray(validOptOptions, o.Opt) {
98108
return fmt.Errorf("invalid -opt=%s: valid values are %s", o.Opt, strings.Join(validOptOptions, ", "))

compiler/compiler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type Config struct {
5252

5353
// Various compiler options that determine how code is generated.
5454
Scheduler string
55+
Unwinder string
5556
FuncImplementation string
5657
AutomaticStackSize bool
5758
DefaultStackSize uint64

compiler/compiler_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ func TestCompiler(t *testing.T) {
108108
CodeModel: config.CodeModel(),
109109
RelocationModel: config.RelocationModel(),
110110
Scheduler: config.Scheduler(),
111+
Unwinder: config.Unwinder(),
111112
FuncImplementation: config.FuncImplementation(),
112113
AutomaticStackSize: config.AutomaticStackSize(),
113114
DefaultStackSize: config.Target.DefaultStackSize,

compiler/defer.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,7 @@ import (
2525
// supportsRecover returns whether the compiler supports the recover() builtin
2626
// for the current architecture.
2727
func (b *builder) supportsRecover() bool {
28-
switch b.archFamily() {
29-
case "wasm32":
30-
// Probably needs to be implemented using the exception handling
31-
// proposal of WebAssembly:
32-
// https://github.com/WebAssembly/exception-handling
33-
return false
34-
case "avr", "riscv64", "xtensa":
35-
// TODO: add support for these architectures
36-
return false
37-
default:
38-
return true
39-
}
28+
return b.Unwinder != "none"
4029
}
4130

4231
// hasDeferFrame returns whether the current function needs to catch panics and

main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,7 @@ func main() {
11411141
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
11421142
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
11431143
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks, asyncify)")
1144+
unwinder := flag.String("unwind", "", "which unwind strategy to use (none, simple)")
11441145
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
11451146
printIR := flag.Bool("printir", false, "print LLVM IR")
11461147
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
@@ -1223,6 +1224,7 @@ func main() {
12231224
GC: *gc,
12241225
PanicStrategy: *panicStrategy,
12251226
Scheduler: *scheduler,
1227+
Unwinder: *unwinder,
12261228
Serial: *serial,
12271229
PrintIR: *printIR,
12281230
DumpSSA: *dumpSSA,
@@ -1431,6 +1433,7 @@ func main() {
14311433
fmt.Printf("build tags: %s\n", strings.Join(config.BuildTags(), " "))
14321434
fmt.Printf("garbage collector: %s\n", config.GC())
14331435
fmt.Printf("scheduler: %s\n", config.Scheduler())
1436+
fmt.Printf("unwinder: %s\n", config.Unwinder())
14341437
fmt.Printf("cached GOROOT: %s\n", cachedGOROOT)
14351438
case "list":
14361439
config, err := builder.NewConfig(options)

0 commit comments

Comments
 (0)