diff --git a/compiler/compiler.go b/compiler/compiler.go index 8c47dda8..83527c31 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -32,6 +32,7 @@ func init() { // Configure the compiler. type Config struct { Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default) + GC string // garbage collection strategy DumpSSA bool // dump Go SSA, for compiler debugging Debug bool // add debug symbols for gdb RootDir string // GOROOT for TinyGo @@ -170,6 +171,15 @@ func (c *Compiler) TargetData() llvm.TargetData { return c.targetData } +// selectGC picks an appropriate GC strategy if none was provided. +func (c *Compiler) selectGC() string { + gc := c.GC + if gc == "" { + gc = "dumb" + } + return gc +} + // Compile the given package path or .go file path. Return an error when this // fails (in any stage). func (c *Compiler) Compile(mainPath string) error { @@ -200,7 +210,7 @@ func (c *Compiler) Compile(mainPath string) error { CgoEnabled: true, UseAllFiles: false, Compiler: "gc", // must be one of the recognized compilers - BuildTags: append([]string{"tinygo"}, c.BuildTags...), + BuildTags: append([]string{"tinygo", "gc." + c.selectGC()}, c.BuildTags...), }, ParserMode: parser.ParseComments, } diff --git a/main.go b/main.go index bec5d6c9..3858b213 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ var commands = map[string]string{ type BuildConfig struct { opt string + gc string printIR bool dumpSSA bool debug bool @@ -36,6 +37,7 @@ type BuildConfig struct { func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, action func(string) error) error { compilerConfig := compiler.Config{ Triple: spec.Triple, + GC: config.gc, Debug: config.debug, DumpSSA: config.dumpSSA, RootDir: sourceDir(), @@ -433,6 +435,7 @@ func handleCompilerError(err error) { func main() { outpath := flag.String("o", "", "output filename") opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z") + gc := flag.String("gc", "dumb", "garbage collector to use (dumb)") printIR := flag.Bool("printir", false, "print LLVM IR") dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA") target := flag.String("target", "", "LLVM target") @@ -452,6 +455,7 @@ func main() { flag.CommandLine.Parse(os.Args[2:]) config := &BuildConfig{ opt: *opt, + gc: *gc, printIR: *printIR, dumpSSA: *dumpSSA, debug: !*nodebug, diff --git a/src/runtime/gc.go b/src/runtime/gc_dumb.go similarity index 73% rename from src/runtime/gc.go rename to src/runtime/gc_dumb.go index 10cdc704..34fbfda3 100644 --- a/src/runtime/gc.go +++ b/src/runtime/gc_dumb.go @@ -1,5 +1,11 @@ +// +build gc.dumb + package runtime +// This GC implementation is the simplest useful memory allocator possible: it +// only allocates memory and never frees it. For some constrained systems, it +// may be the only memory allocator possible. + import ( "unsafe" ) @@ -22,11 +28,11 @@ func alloc(size uintptr) unsafe.Pointer { } func free(ptr unsafe.Pointer) { - // TODO: use a GC + // Memory is never freed. } func GC() { - // Unimplemented. + // No-op. } func KeepAlive(x interface{}) {