summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-12 00:18:20 -0400
committerRuss Cox <rsc@golang.org>2014-09-12 00:18:20 -0400
commit01cc50951b57fd695075fa8a7e53025cf6115da0 (patch)
tree470703fc67a92851fd65b76afa1e16a390a2ee59 /src/cmd/gc
parenta6669fa5e7d26c7e5f9d61a389450d2c1ef79f1c (diff)
downloadgo-01cc50951b57fd695075fa8a7e53025cf6115da0.tar.gz
cmd/gc: turn Go prototypes into ptr liveness maps for assembly functions
The goal here is to allow assembly functions to appear in the middle of a Go stack (having called other code) and still record enough information about their pointers so that stack copying and garbage collection can handle them precisely. Today, these frames are handled only conservatively. If you write func myfunc(x *float64) (y *int) (with no body, an 'extern' declaration), then the Go compiler now emits a liveness bitmap for use from the assembly definition of myfunc. The bitmap symbol is myfunc.args_stackmap and it contains two bitmaps. The first bitmap, in effect at function entry, marks all inputs as live. The second bitmap, not in effect at function entry, marks the outputs live as well. In funcdata.h, define new assembly macros: GO_ARGS opts in to using the Go compiler-generated liveness bitmap for the current function. GO_RESULTS_INITIALIZED indicates that the results have been initialized and need to be kept live for the remainder of the function; it causes a switch to the second generated bitmap for the assembly code that follows. NO_LOCAL_POINTERS indicates that there are no pointers in the local variables being stored in the function's stack frame. LGTM=khr R=khr CC=golang-codereviews https://codereview.appspot.com/137520043
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/pgen.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index ec50ada5b..50c03788e 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -14,6 +14,7 @@
#include "../../runtime/funcdata.h"
static void allocauto(Prog* p);
+static void emitptrargsmap(void);
static Sym*
makefuncdatasym(char *namefmt, int64 funcdatakind)
@@ -173,9 +174,15 @@ compile(Node *fn)
lno = setlineno(fn);
+ curfn = fn;
+ dowidth(curfn->type);
+
if(fn->nbody == nil) {
- if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0)
+ if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
yyerror("missing function body", fn);
+ goto ret;
+ }
+ emitptrargsmap();
goto ret;
}
@@ -184,9 +191,6 @@ compile(Node *fn)
// set up domain for labels
clearlabels();
- curfn = fn;
- dowidth(curfn->type);
-
if(curfn->type->outnamed) {
// add clearing of the output parameters
t = structfirst(&save, getoutarg(curfn->type));
@@ -329,6 +333,43 @@ ret:
lineno = lno;
}
+static void
+emitptrargsmap(void)
+{
+ int nptr, nbitmap, j, off;
+ vlong xoffset;
+ Bvec *bv;
+ Sym *sym;
+
+ sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
+
+ nptr = curfn->type->argwid / widthptr;
+ bv = bvalloc(nptr*2);
+ nbitmap = 1;
+ if(curfn->type->outtuple > 0)
+ nbitmap = 2;
+ off = duint32(sym, 0, nbitmap);
+ off = duint32(sym, off, bv->n);
+ if(curfn->type->thistuple > 0) {
+ xoffset = 0;
+ twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
+ }
+ if(curfn->type->intuple > 0) {
+ xoffset = 0;
+ twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
+ }
+ for(j = 0; j < bv->n; j += 32)
+ off = duint32(sym, off, bv->b[j/32]);
+ if(curfn->type->outtuple > 0) {
+ xoffset = 0;
+ twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
+ for(j = 0; j < bv->n; j += 32)
+ off = duint32(sym, off, bv->b[j/32]);
+ }
+ ggloblsym(sym, off, RODATA);
+ free(bv);
+}
+
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.