build: implement GOEXPERIMENT again in runtime, and add to liblink

For Austin's framepointer experiment.

Change-Id: I81b6f414943b3578924f853300b9193684f79bf4
Reviewed-on: https://go-review.googlesource.com/2994
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 9e4d1e3..82c2273 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -576,7 +576,6 @@
 		"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/lib9.a",
 	}},
 	{"runtime", []string{
-		"zaexperiment.h",
 		"zversion.go",
 	}},
 }
@@ -601,7 +600,6 @@
 	{"anames9.c", mkanames},
 	{"zdefaultcc.go", mkzdefaultcc},
 	{"zversion.go", mkzversion},
-	{"zaexperiment.h", mkzexperiment},
 
 	// not generated anymore, but delete the file if we see it
 	{"enam.c", nil},
@@ -937,8 +935,8 @@
 				)
 			}
 
-			// gc/lex.c records the GOEXPERIMENT setting used during the build.
-			if name == "lex.c" {
+			// liblink/go.c records the GOEXPERIMENT setting used during the build.
+			if name == "go.c" {
 				compile = append(compile,
 					"-D", fmt.Sprintf("GOEXPERIMENT=%q", os.Getenv("GOEXPERIMENT")))
 			}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index 1e6ae82..d659234 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -27,21 +27,8 @@
 			"\n"+
 			"const defaultGoroot = `%s`\n"+
 			"const theVersion = `%s`\n"+
-			"\n"+
-			"var buildVersion = theVersion\n", goroot_final, goversion)
-
-	writefile(out, file, 0)
-}
-
-// mkzexperiment writes zaexperiment.h (sic):
-//
-//	#define GOEXPERIMENT "experiment string"
-//
-func mkzexperiment(dir, file string) {
-	out := fmt.Sprintf(
-		"// auto generated by go tool dist\n"+
-			"\n"+
-			"#define GOEXPERIMENT \"%s\"\n", os.Getenv("GOEXPERIMENT"))
+			"const goexperiment = `%s`\n"+
+			"var buildVersion = theVersion\n", goroot_final, goversion, os.Getenv("GOEXPERIMENT"))
 
 	writefile(out, file, 0)
 }
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 21cf8b8..5a2b774 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -994,8 +994,6 @@
 EXTERN	Link*	ctxt;
 
 EXTERN	int	nointerface;
-EXTERN	int	fieldtrack_enabled;
-EXTERN	int	precisestack_enabled;
 EXTERN	int	writearchive;
 
 EXTERN	Biobuf	bstdout;
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 006ded2..29fb2e1 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -33,19 +33,6 @@
 
 #define	BOM	0xFEFF
 
-// Compiler experiments.
-// These are controlled by the GOEXPERIMENT environment
-// variable recorded when the compiler is built.
-static struct {
-	char *name;
-	int *val;
-} exper[] = {
-//	{"rune32", &rune32},
-	{"fieldtrack", &fieldtrack_enabled},
-	{"precisestack", &precisestack_enabled},
-	{nil, nil},
-};
-
 // Debug arguments.
 // These can be specified with the -d flag, as in "-d nil"
 // to set the debug_checknil variable. In general the list passed
@@ -55,55 +42,8 @@
 	int *val;
 } debugtab[] = {
 	{"nil", &debug_checknil},
-	{nil, nil},
 };
 
-static void
-addexp(char *s)
-{
-	int i;
-
-	for(i=0; exper[i].name != nil; i++) {
-		if(strcmp(exper[i].name, s) == 0) {
-			*exper[i].val = 1;
-			return;
-		}
-	}
-	
-	print("unknown experiment %s\n", s);
-	exits("unknown experiment");
-}
-
-static void
-setexp(void)
-{
-	char *f[20];
-	int i, nf;
-
-	precisestack_enabled = 1; // on by default
-
-	// cmd/dist #defines GOEXPERIMENT for us.
-	nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
-	for(i=0; i<nf; i++)
-		addexp(f[i]);
-}
-
-char*
-expstring(void)
-{
-	int i;
-	static char buf[512];
-
-	strcpy(buf, "X");
-	for(i=0; exper[i].name != nil; i++)
-		if(*exper[i].val)
-			seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
-	if(strlen(buf) == 1)
-		strcpy(buf, "X,none");
-	buf[1] = ':';
-	return buf;
-}
-
 // Our own isdigit, isspace, isalpha, isalnum that take care 
 // of EOF and other out of range arguments.
 static int
@@ -272,8 +212,6 @@
 	if(nacl)
 		flag_largemodel = 1;
 
-	setexp();
-	
 	fmtstrinit(&pragcgobuf);
 	quotefmtinstall();
 
@@ -344,13 +282,14 @@
 		
 		nf = getfields(debugstr, f, nelem(f), 1, ",");
 		for(i=0; i<nf; i++) {
-			for(j=0; debugtab[j].name != nil; j++) {
+			for(j=0; j<nelem(debugtab); j++) {
 				if(strcmp(debugtab[j].name, f[i]) == 0) {
-					*debugtab[j].val = 1;
+					if(debugtab[j].val != nil)
+						*debugtab[j].val = 1;
 					break;
 				}
 			}
-			if(debugtab[j].name == nil)
+			if(j >= nelem(debugtab))
 				sysfatal("unknown debug information -d '%s'\n", f[i]);
 		}
 	}
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
index 3bfa69b..e22d756 100644
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -1487,25 +1487,21 @@
 				// Annotate ambiguously live variables so that they can
 				// be zeroed at function entry.
 				// livein and liveout are dead here and used as temporaries.
-				// For now, only enabled when using GOEXPERIMENT=precisestack
-				// during make.bash / all.bash.
-				if(precisestack_enabled) {
-					bvresetall(livein);
-					bvandnot(liveout, any, all);
-					if(!bvisempty(liveout)) {
-						for(pos = 0; pos < liveout->n; pos++) {
-							if(!bvget(liveout, pos))
-								continue;
-							bvset(all, pos); // silence future warnings in this block
-							n = *(Node**)arrayget(lv->vars, pos);
-							if(!n->needzero) {
-								n->needzero = 1;
-								if(debuglive >= 1)
-									warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
-								// Record in 'ambiguous' bitmap.
-								xoffset = n->xoffset + stkptrsize;
-								twobitwalktype1(n->type, &xoffset, ambig);
-							}
+				bvresetall(livein);
+				bvandnot(liveout, any, all);
+				if(!bvisempty(liveout)) {
+					for(pos = 0; pos < liveout->n; pos++) {
+						if(!bvget(liveout, pos))
+							continue;
+						bvset(all, pos); // silence future warnings in this block
+						n = *(Node**)arrayget(lv->vars, pos);
+						if(!n->needzero) {
+							n->needzero = 1;
+							if(debuglive >= 1)
+								warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
+							// Record in 'ambiguous' bitmap.
+							xoffset = n->xoffset + stkptrsize;
+							twobitwalktype1(n->type, &xoffset, ambig);
 						}
 					}
 				}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 48dd17a..1d2dcf7 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2521,9 +2521,9 @@
 		v = t->nname;
 		if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
 			v = N;
-		// In precisestack mode, the garbage collector assumes results
+		// For precise stacks, the garbage collector assumes results
 		// are always live, so zero them always.
-		if(out && (precisestack_enabled || (v == N && hasdefer))) {
+		if(out) {
 			// Defer might stop a panic and show the
 			// return values as they exist at the time of panic.
 			// Make sure to zero them on entry to the function.
diff --git a/src/liblink/go.c b/src/liblink/go.c
index 9f5a423..e31c71a 100644
--- a/src/liblink/go.c
+++ b/src/liblink/go.c
@@ -9,6 +9,66 @@
 #include <bio.h>
 #include <link.h>
 
+int framepointer_enabled;
+int fieldtrack_enabled;
+
+// Toolchain experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the toolchain is built.
+// This list is also known to cmd/gc.
+static struct {
+	char *name;
+	int *val;
+} exper[] = {
+	{"fieldtrack", &fieldtrack_enabled},
+	{"basepointer", &framepointer_enabled}, 
+};
+
+static void
+addexp(char *s)
+{
+	int i;
+
+	for(i=0; i < nelem(exper); i++ ) {
+		if(strcmp(exper[i].name, s) == 0) {
+			if(exper[i].val != nil)
+				*exper[i].val = 1;
+			return;
+		}
+	}
+	
+	print("unknown experiment %s\n", s);
+	exits("unknown experiment");
+}
+
+void
+linksetexp(void)
+{
+	char *f[20];
+	int i, nf;
+
+	// cmd/dist #defines GOEXPERIMENT for us.
+	nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
+	for(i=0; i<nf; i++)
+		addexp(f[i]);
+}
+
+char*
+expstring(void)
+{
+	int i;
+	static char buf[512];
+
+	strcpy(buf, "X");
+	for(i=0; i<nelem(exper); i++)
+		if(*exper[i].val)
+			seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
+	if(strlen(buf) == 1)
+		strcpy(buf, "X,none");
+	buf[1] = ':';
+	return buf;
+}
+
 // replace all "". with pkg.
 char*
 expandpkg(char *t0, char *pkg)
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
index e068371..35b88f4 100644
--- a/src/liblink/sym.c
+++ b/src/liblink/sym.c
@@ -90,6 +90,7 @@
 	char *p;
 	char buf[1024];
 
+	linksetexp();
 	nuxiinit(arch);
 	
 	ctxt = emallocz(sizeof *ctxt);
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 6fa407f..1950403 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -3163,8 +3163,6 @@
 	return
 }
 
-var goexperiment string = "GOEXPERIMENT" // TODO: defined in zaexperiment.h
-
 func haveexperiment(name string) bool {
 	x := goexperiment
 	for x != "" {