Commit 557a61d2 authored by Russ Cox's avatar Russ Cox

cmd/gc: add //go:nowritebarrier to diagnose unintended write barriers

//go:nowritebarrier can only be used in package runtime.
It does not disable write barriers; it is an assertion, checked
by the compiler, that the following function needs no write
barriers.

Change-Id: Id7978b779b66dc1feea39ee6bda9fd4d80280b7c
Reviewed-on: https://go-review.googlesource.com/1224Reviewed-by: default avatarRick Hudson <rlh@golang.org>
parent 2fa657c5
...@@ -271,6 +271,7 @@ struct Node ...@@ -271,6 +271,7 @@ struct Node
uchar noescape; // func arguments do not escape uchar noescape; // func arguments do not escape
uchar nosplit; // func should not execute on separate stack uchar nosplit; // func should not execute on separate stack
uchar builtin; // built-in name, like len or close uchar builtin; // built-in name, like len or close
uchar nowritebarrier; // emit compiler error instead of write barrier
uchar walkdef; uchar walkdef;
uchar typecheck; uchar typecheck;
uchar local; uchar local;
...@@ -987,6 +988,7 @@ EXTERN int flag_race; ...@@ -987,6 +988,7 @@ EXTERN int flag_race;
EXTERN int flag_largemodel; EXTERN int flag_largemodel;
EXTERN int noescape; EXTERN int noescape;
EXTERN int nosplit; EXTERN int nosplit;
EXTERN int nowritebarrier;
EXTERN int debuglive; EXTERN int debuglive;
EXTERN Link* ctxt; EXTERN Link* ctxt;
......
...@@ -1319,6 +1319,7 @@ xfndcl: ...@@ -1319,6 +1319,7 @@ xfndcl:
$$->endlineno = lineno; $$->endlineno = lineno;
$$->noescape = noescape; $$->noescape = noescape;
$$->nosplit = nosplit; $$->nosplit = nosplit;
$$->nowritebarrier = nowritebarrier;
funcbody($$); funcbody($$);
} }
...@@ -1502,6 +1503,7 @@ xdcl_list: ...@@ -1502,6 +1503,7 @@ xdcl_list:
nointerface = 0; nointerface = 0;
noescape = 0; noescape = 0;
nosplit = 0; nosplit = 0;
nowritebarrier = 0;
} }
vardcl_list: vardcl_list:
......
...@@ -1655,6 +1655,12 @@ go: ...@@ -1655,6 +1655,12 @@ go:
nosplit = 1; nosplit = 1;
goto out; goto out;
} }
if(strcmp(lexbuf, "go:nowritebarrier") == 0) {
if(!compiling_runtime)
yyerror("//go:nowritebarrier only allowed in runtime");
nowritebarrier = 1;
goto out;
}
out: out:
return c; return c;
......
...@@ -2010,6 +2010,8 @@ applywritebarrier(Node *n, NodeList **init) ...@@ -2010,6 +2010,8 @@ applywritebarrier(Node *n, NodeList **init)
char name[32]; char name[32];
if(n->left && n->right && needwritebarrier(n->left, n->right)) { if(n->left && n->right && needwritebarrier(n->left, n->right)) {
if(curfn && curfn->nowritebarrier)
yyerror("write barrier prohibited");
t = n->left->type; t = n->left->type;
l = nod(OADDR, n->left, N); l = nod(OADDR, n->left, N);
l->etype = 1; // addr does not escape l->etype = 1; // addr does not escape
......
This diff is collapsed.
This diff is collapsed.
...@@ -1577,6 +1577,7 @@ func goexit0(gp *g) { ...@@ -1577,6 +1577,7 @@ func goexit0(gp *g) {
} }
//go:nosplit //go:nosplit
//go:nowritebarrier
func save(pc, sp uintptr) { func save(pc, sp uintptr) {
_g_ := getg() _g_ := getg()
...@@ -1585,7 +1586,7 @@ func save(pc, sp uintptr) { ...@@ -1585,7 +1586,7 @@ func save(pc, sp uintptr) {
_g_.sched.lr = 0 _g_.sched.lr = 0
_g_.sched.ret = 0 _g_.sched.ret = 0
_g_.sched.ctxt = nil _g_.sched.ctxt = nil
// write as uintptr to avoid write barrier, which will smash _g_.sched. // _g_.sched.g = _g_, but avoid write barrier, which smashes _g_.sched
*(*uintptr)(unsafe.Pointer(&_g_.sched.g)) = uintptr(unsafe.Pointer(_g_)) *(*uintptr)(unsafe.Pointer(&_g_.sched.g)) = uintptr(unsafe.Pointer(_g_))
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment