summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-10-30 10:16:03 -0400
committerRuss Cox <rsc@golang.org>2014-10-30 10:16:03 -0400
commitf65bb028c5ceb4fb213b103f24a85f17cf67ac39 (patch)
tree1cd04bf33dc052ad80d0559fb1789fcebaac7682 /src/cmd
parent710efc5a3085f55968c120abb25206fb72c05d46 (diff)
downloadgo-f65bb028c5ceb4fb213b103f24a85f17cf67ac39.tar.gz
[dev.garbage] cmd/gc, runtime: implement write barriers in terms of writebarrierptr
This CL implements the many multiword write barriers by calling writebarrierptr, so that only writebarrierptr needs the actual barrier. In lieu of an actual barrier, writebarrierptr checks that the value being copied is not a small non-zero integer. This is enough to shake out bugs where the barrier is being called when it should not (for non-pointer values). It also found a few tests in sync/atomic that were being too clever. This CL adds a write barrier for the memory moved during the builtin copy function, which I forgot when inserting barriers for Go 1.4. This CL re-enables some write barriers that were disabled for Go 1.4. Those were disabled because it is possible to change the generated code so that they are unnecessary most of the time, but we have not changed the generated code yet. For safety they must be enabled. None of this is terribly efficient. We are aiming for correct first. LGTM=rlh R=rlh CC=golang-codereviews https://codereview.appspot.com/168770043
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/api/goapi.go1
-rw-r--r--src/cmd/gc/builtin.c29
-rw-r--r--src/cmd/gc/runtime.go31
-rw-r--r--src/cmd/gc/typecheck.c6
-rw-r--r--src/cmd/gc/walk.c46
5 files changed, 95 insertions, 18 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 5a8c87603..e49ba33bb 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -405,6 +405,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" note struct{};" +
" p struct{};" +
" parfor struct{};" +
+ " slice struct{};" +
" slicetype struct{};" +
" stkframe struct{};" +
" sudog struct{};" +
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index fbca4ee5f..bd3fca167 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -86,10 +86,33 @@ char *runtimeimport =
"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
- "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
- "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+ "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
+ "func @\"\".writebarriercopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n"
"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 0fb15c265..38bf6abb6 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -115,10 +115,35 @@ func writebarrieriface(dst *any, src any)
// The unused *byte argument makes sure that src is 2-pointer-aligned,
// which is the maximum alignment on NaCl amd64p32
// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
-func writebarrierfat2(dst *any, _ *byte, src any)
-func writebarrierfat3(dst *any, _ *byte, src any)
-func writebarrierfat4(dst *any, _ *byte, src any)
+// The bitmap in the name tells which words being copied are pointers.
+func writebarrierfat01(dst *any, _ *byte, src any)
+func writebarrierfat10(dst *any, _ *byte, src any)
+func writebarrierfat11(dst *any, _ *byte, src any)
+func writebarrierfat001(dst *any, _ *byte, src any)
+func writebarrierfat010(dst *any, _ *byte, src any)
+func writebarrierfat011(dst *any, _ *byte, src any)
+func writebarrierfat100(dst *any, _ *byte, src any)
+func writebarrierfat101(dst *any, _ *byte, src any)
+func writebarrierfat110(dst *any, _ *byte, src any)
+func writebarrierfat111(dst *any, _ *byte, src any)
+func writebarrierfat0001(dst *any, _ *byte, src any)
+func writebarrierfat0010(dst *any, _ *byte, src any)
+func writebarrierfat0011(dst *any, _ *byte, src any)
+func writebarrierfat0100(dst *any, _ *byte, src any)
+func writebarrierfat0101(dst *any, _ *byte, src any)
+func writebarrierfat0110(dst *any, _ *byte, src any)
+func writebarrierfat0111(dst *any, _ *byte, src any)
+func writebarrierfat1000(dst *any, _ *byte, src any)
+func writebarrierfat1001(dst *any, _ *byte, src any)
+func writebarrierfat1010(dst *any, _ *byte, src any)
+func writebarrierfat1011(dst *any, _ *byte, src any)
+func writebarrierfat1100(dst *any, _ *byte, src any)
+func writebarrierfat1101(dst *any, _ *byte, src any)
+func writebarrierfat1110(dst *any, _ *byte, src any)
+func writebarrierfat1111(dst *any, _ *byte, src any)
+
func writebarrierfat(typ *byte, dst *any, src *any)
+func writebarriercopy(typ *byte, dst any, src any) int
func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 714c66268..f05d8022d 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -2891,7 +2891,8 @@ typecheckas(Node *n)
case OSLICE3:
case OSLICESTR:
// For x = x[0:y], x can be updated in place, without touching pointer.
- if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
+ // TODO(rsc): Reenable once it is actually updated in place without touching the pointer.
+ if(0 && samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
n->right->reslice = 1;
break;
@@ -2899,7 +2900,8 @@ typecheckas(Node *n)
// For x = append(x, ...), x can be updated in place when there is capacity,
// without touching the pointer; otherwise the emitted code to growslice
// can take care of updating the pointer, and only in that case.
- if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
+ // TODO(rsc): Reenable once the emitted code does update the pointer.
+ if(0 && n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
n->right->reslice = 1;
break;
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index d4d0f449c..7b502eb60 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -6,6 +6,7 @@
#include <libc.h>
#include "go.h"
#include "../ld/textflag.h"
+#include "../../runtime/mgc0.h"
static Node* walkprint(Node*, NodeList**);
static Node* writebarrierfn(char*, Type*, Type*);
@@ -1988,14 +1989,15 @@ applywritebarrier(Node *n, NodeList **init)
{
Node *l, *r;
Type *t;
+ vlong x;
+ static Bvec *bv;
+ char name[32];
if(n->left && n->right && needwritebarrier(n->left, n->right)) {
t = n->left->type;
l = nod(OADDR, n->left, N);
l->etype = 1; // addr does not escape
if(t->width == widthptr) {
- n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
- l, n->right);
} else if(t->etype == TSTRING) {
n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
l, n->right);
@@ -2005,14 +2007,33 @@ applywritebarrier(Node *n, NodeList **init)
} else if(isinter(t)) {
n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
l, n->right);
- } else if(t->width == 2*widthptr) {
- n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
- l, nodnil(), n->right);
- } else if(t->width == 3*widthptr) {
- n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
- l, nodnil(), n->right);
- } else if(t->width == 4*widthptr) {
- n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
+ } else if(t->width <= 4*widthptr) {
+ x = 0;
+ if(bv == nil)
+ bv = bvalloc(BitsPerPointer*4);
+ bvresetall(bv);
+ twobitwalktype1(t, &x, bv);
+ // The bvgets are looking for BitsPointer in successive slots.
+ enum {
+ PtrBit = 1,
+ };
+ if(BitsPointer != (1<<PtrBit))
+ fatal("wrong PtrBit");
+ switch(t->width/widthptr) {
+ case 2:
+ snprint(name, sizeof name, "writebarrierfat%d%d",
+ bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit));
+ break;
+ case 3:
+ snprint(name, sizeof name, "writebarrierfat%d%d%d",
+ bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit));
+ break;
+ case 4:
+ snprint(name, sizeof name, "writebarrierfat%d%d%d%d",
+ bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit), bvget(bv, 3*BitsPerPointer+PtrBit));
+ break;
+ }
+ n = mkcall1(writebarrierfn(name, t, n->right->type), T, init,
l, nodnil(), n->right);
} else {
r = n->right;
@@ -2874,6 +2895,11 @@ copyany(Node *n, NodeList **init, int runtimecall)
{
Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
NodeList *l;
+
+ if(haspointers(n->left->type->type)) {
+ fn = writebarrierfn("writebarriercopy", n->left->type, n->right->type);
+ return mkcall1(fn, n->type, init, typename(n->left->type->type), n->left, n->right);
+ }
if(runtimecall) {
if(n->right->type->etype == TSTRING)