aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-08-25 14:38:19 -0400
committerRuss Cox <rsc@golang.org>2014-08-25 14:38:19 -0400
commit613383c7651d490aae045eb70cd515b151735766 (patch)
treec77f23bff111b953d23cb7a3bf288116dcca137f /src
parentc6f7c176a3a46ff87d72c4b744bbadf02df1890e (diff)
downloadgo-613383c7651d490aae045eb70cd515b151735766.tar.xz
cmd/gc, runtime: treat slices and strings like pointers in garbage collection
Before, a slice with cap=0 or a string with len=0 might have its base pointer pointing beyond the actual slice/string data into the next block. The collector had to ignore slices and strings with cap=0 in order to avoid misinterpreting the base pointer. Now, a slice with cap=0 or a string with len=0 still has a base pointer pointing into the actual slice/string data, no matter what. The collector can now always scan the pointer, which means strings and slices are no longer special. Fixes #8404. LGTM=khr, josharian R=josharian, khr, dvyukov CC=golang-codereviews https://golang.org/cl/112570044
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5g/cgen.c1
-rw-r--r--src/cmd/5g/gsubr.c1
-rw-r--r--src/cmd/6g/cgen.c1
-rw-r--r--src/cmd/6g/gsubr.c2
-rw-r--r--src/cmd/8g/cgen.c1
-rw-r--r--src/cmd/8g/gsubr.c1
-rw-r--r--src/cmd/gc/fmt.c2
-rw-r--r--src/cmd/gc/gen.c55
-rw-r--r--src/cmd/gc/go.h1
-rw-r--r--src/cmd/gc/plive.c7
-rw-r--r--src/cmd/gc/reflect.c8
-rw-r--r--src/cmd/gc/subr.c8
-rw-r--r--src/cmd/gc/typecheck.c13
-rw-r--r--src/cmd/gc/walk.c12
-rw-r--r--src/pkg/reflect/all_test.go18
-rw-r--r--src/pkg/reflect/value.go14
-rw-r--r--src/pkg/runtime/gcinfo_test.go50
-rw-r--r--src/pkg/runtime/heapdump.c22
-rw-r--r--src/pkg/runtime/malloc.h4
-rw-r--r--src/pkg/runtime/mgc0.c60
-rw-r--r--src/pkg/runtime/mgc0.h4
-rw-r--r--src/pkg/runtime/runtime.h2
-rw-r--r--src/pkg/runtime/stack.c15
23 files changed, 147 insertions, 155 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index a9c597cdc8..5fae7a564c 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -254,7 +254,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
goto sbop;
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 1241a23ea6..5a70fcddaf 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1599,7 +1599,6 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADD;
break;
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index bff2350621..592e81542c 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -247,7 +247,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 4ac2e92079..a451d7d624 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -1537,14 +1537,12 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
case CASE(OADD, TINT64):
case CASE(OADD, TUINT64):
case CASE(OADD, TPTR64):
- case CASE(OADDPTR, TPTR64):
a = AADDQ;
break;
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index bdf728dbbc..f3093bc26e 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -242,7 +242,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 66d5b8d696..9ee418cb78 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -430,7 +430,6 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index 951170aeff..98556a658f 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -1153,7 +1153,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case Csend:
return fmtprint(f, "chan<- %N", n->left);
default:
- if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv)
+ if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv)
return fmtprint(f, "chan (%N)", n->left);
else
return fmtprint(f, "chan %N", n->left);
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 908a5e53d9..86acd88259 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -806,7 +806,8 @@ cgen_eface(Node *n, Node *res)
void
cgen_slice(Node *n, Node *res)
{
- Node src, dst, *cap, *len, *offs, *add, *base;
+ Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con;
+ Prog *p1, *p2;
cap = n->list->n;
len = n->list->next->n;
@@ -823,6 +824,11 @@ cgen_slice(Node *n, Node *res)
// garbage collector can see.
base = temp(types[TUINTPTR]);
+ tmplen = temp(types[TINT]);
+ if(n->op != OSLICESTR)
+ tmpcap = temp(types[TINT]);
+ else
+ tmpcap = tmplen;
if(isnil(n->left)) {
tempname(&src, n->left->type);
@@ -837,43 +843,62 @@ cgen_slice(Node *n, Node *res)
fatal("slicearr is supposed to work on pointer: %+N\n", n);
cgen(&src, base);
cgen_checknil(base);
- if(offs != N) {
- add = nod(OADD, base, offs);
- typecheck(&add, Erv);
- cgen(add, base);
- }
- } else if(offs == N) {
- src.type = types[tptr];
- cgen(&src, base);
} else {
src.type = types[tptr];
- add = nod(OADDPTR, &src, offs);
- typecheck(&add, Erv);
- cgen(add, base);
+ cgen(&src, base);
}
// committed to the update
gvardef(res);
+ // compute len and cap.
+ // len = n-i, cap = m-i, and offs = i*width.
+ // computing offs last lets the multiply overwrite i.
+ cgen(len, tmplen);
+ if(n->op != OSLICESTR)
+ cgen(cap, tmpcap);
+
+ // if new cap != 0 { base += add }
+ // This avoids advancing base past the end of the underlying array/string,
+ // so that it cannot point at the next object in memory.
+ // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
+ // In essence we are replacing x[i:j:k] where i == j == k
+ // or x[i:j] where i == j == cap(x) with x[0:0:0].
+ if(offs != N) {
+ p1 = gjmp(P);
+ p2 = gjmp(P);
+ patch(p1, pc);
+
+ nodconst(&con, tmpcap->type, 0);
+ cmp = nod(OEQ, tmpcap, &con);
+ typecheck(&cmp, Erv);
+ bgen(cmp, 1, -1, p2);
+
+ add = nod(OADD, base, offs);
+ typecheck(&add, Erv);
+ cgen(add, base);
+
+ patch(p2, pc);
+ }
+
// dst.array = src.array [ + lo *width ]
dst = *res;
dst.xoffset += Array_array;
dst.type = types[tptr];
-
cgen(base, &dst);
// dst.len = hi [ - lo ]
dst = *res;
dst.xoffset += Array_nel;
dst.type = types[simtype[TUINT]];
- cgen(len, &dst);
+ cgen(tmplen, &dst);
if(n->op != OSLICESTR) {
// dst.cap = cap [ - lo ]
dst = *res;
dst.xoffset += Array_cap;
dst.type = types[simtype[TUINT]];
- cgen(cap, &dst);
+ cgen(tmpcap, &dst);
}
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 61bb7bd6e4..12c1e98539 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -447,7 +447,6 @@ enum
OSUB, // x - y
OOR, // x | y
OXOR, // x ^ y
- OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
OADDSTR, // s + "foo"
OADDR, // &x
OANDAND, // b0 && b1
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
index e67b0af757..0ad700e82f 100644
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -1113,8 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *str; intgo len; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
*xoffset += t->width;
break;
@@ -1145,9 +1144,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *array; uintgo len; uintgo cap; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
*xoffset += t->width;
} else
for(i = 0; i < t->bound; i++)
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 66efac07d0..05bf2d6521 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -1516,8 +1516,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
*xoffset += t->width;
break;
case TSTRING:
- proggendata(g, BitsMultiWord);
- proggendata(g, BitsString);
+ proggendata(g, BitsPointer);
+ proggendata(g, BitsScalar);
*xoffset += t->width;
break;
case TINTER:
@@ -1530,8 +1530,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
break;
case TARRAY:
if(isslice(t)) {
- proggendata(g, BitsMultiWord);
- proggendata(g, BitsSlice);
+ proggendata(g, BitsPointer);
+ proggendata(g, BitsScalar);
proggendata(g, BitsScalar);
} else {
t1 = t->type;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 081c373a88..d62d55e773 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -656,11 +656,15 @@ maptype(Type *key, Type *val)
{
Type *t;
Type *bad;
- int atype;
+ int atype, mtype;
if(key != nil) {
atype = algtype1(key, &bad);
- switch(bad == T ? key->etype : bad->etype) {
+ if(bad == T)
+ mtype = key->etype;
+ else
+ mtype = bad->etype;
+ switch(mtype) {
default:
if(atype == ANOEQ)
yyerror("invalid map key type %T", key);
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index c295cf6d21..746feb4d1b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -525,19 +525,6 @@ reswitch:
op = n->etype;
goto arith;
- case OADDPTR:
- ok |= Erv;
- l = typecheck(&n->left, Erv);
- r = typecheck(&n->right, Erv);
- if(l->type == T || r->type == T)
- goto error;
- if(l->type->etype != tptr)
- fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left);
- if(r->type->etype != TUINTPTR)
- fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right);
- n->type = types[tptr];
- goto ret;
-
case OADD:
case OAND:
case OANDAND:
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index f3886cf73a..c251af660e 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2875,14 +2875,14 @@ sliceany(Node* n, NodeList **init)
lb = N;
}
- // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
- // generate
- // if hb > bound || lb > hb { panicslice() }
+ // Checking src[lb:hb:cb] or src[lb:hb].
+ // if chk0 || chk1 || chk2 { panicslice() }
chk = N;
- chk0 = N;
- chk1 = N;
- chk2 = N;
+ chk0 = N; // cap(src) < cb
+ chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
+ chk2 = N; // hb < lb
+ // All comparisons are unsigned to avoid testing < 0.
bt = types[simtype[TUINT]];
if(cb != N && cb->type->width > 4)
bt = types[TUINT64];
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index d9781699e0..9a2a9f2668 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -2494,6 +2494,15 @@ func TestSlice(t *testing.T) {
if vs != s[3:5] {
t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5])
}
+
+ rv := ValueOf(&xs).Elem()
+ rv = rv.Slice(3, 4)
+ ptr2 := rv.Pointer()
+ rv = rv.Slice(5, 5)
+ ptr3 := rv.Pointer()
+ if ptr3 != ptr2 {
+ t.Errorf("xs.Slice(3,4).Slice3(5,5).Pointer() = %#x, want %#x", ptr3, ptr2)
+ }
}
func TestSlice3(t *testing.T) {
@@ -2532,6 +2541,15 @@ func TestSlice3(t *testing.T) {
s := "hello world"
rv = ValueOf(&s).Elem()
shouldPanic(func() { rv.Slice3(1, 2, 3) })
+
+ rv = ValueOf(&xs).Elem()
+ rv = rv.Slice3(3, 5, 7)
+ ptr2 := rv.Pointer()
+ rv = rv.Slice3(4, 4, 4)
+ ptr3 := rv.Pointer()
+ if ptr3 != ptr2 {
+ t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).Pointer() = %#x, want %#x", ptr3, ptr2)
+ }
}
func TestSetLenCap(t *testing.T) {
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index dda852a3ec..4394ed0739 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -1746,9 +1746,14 @@ func (v Value) Slice(i, j int) Value {
// Reinterpret as *sliceHeader to edit.
s := (*sliceHeader)(unsafe.Pointer(&x))
- s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = cap - i
+ if cap-i > 0 {
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+ } else {
+ // do not advance pointer, to avoid pointing beyond end of slice
+ s.Data = base
+ }
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
@@ -1793,9 +1798,14 @@ func (v Value) Slice3(i, j, k int) Value {
// Reinterpret as *sliceHeader to edit.
s := (*sliceHeader)(unsafe.Pointer(&x))
- s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
s.Len = j - i
s.Cap = k - i
+ if k-i > 0 {
+ s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+ } else {
+ // do not advance pointer, to avoid pointing beyond end of slice
+ s.Data = base
+ }
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
diff --git a/src/pkg/runtime/gcinfo_test.go b/src/pkg/runtime/gcinfo_test.go
index 16764c9487..88f6703f97 100644
--- a/src/pkg/runtime/gcinfo_test.go
+++ b/src/pkg/runtime/gcinfo_test.go
@@ -14,7 +14,7 @@ import (
func TestGCInfo(t *testing.T) {
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
- verifyGCInfo(t, "bss Complex", &bssComplex, nonStackInfo(infoComplex()))
+ verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct()))
verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString))
verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
@@ -22,7 +22,7 @@ func TestGCInfo(t *testing.T) {
verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
- verifyGCInfo(t, "data Complex", &dataComplex, nonStackInfo(infoComplex()))
+ verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct()))
verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString))
verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
@@ -30,7 +30,7 @@ func TestGCInfo(t *testing.T) {
verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
- verifyGCInfo(t, "stack Complex", new(Complex), infoComplex())
+ verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
verifyGCInfo(t, "stack string", new(string), infoString)
verifyGCInfo(t, "stack slice", new([]string), infoSlice)
verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
@@ -39,7 +39,7 @@ func TestGCInfo(t *testing.T) {
for i := 0; i < 10; i++ {
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
- verifyGCInfo(t, "heap Complex", escape(new(Complex)), nonStackInfo(infoComplex()))
+ verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct()))
verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString))
verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
@@ -88,8 +88,8 @@ const (
)
const (
- BitsString = iota
- BitsSlice
+ BitsString = iota // unused
+ BitsSlice // unused
BitsIface
BitsEface
)
@@ -116,7 +116,7 @@ type PtrScalar struct {
var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
-type Complex struct {
+type BigStruct struct {
q *int
w byte
e [17]byte
@@ -127,27 +127,31 @@ type Complex struct {
i string
}
-func infoComplex() []byte {
+func infoBigStruct() []byte {
switch runtime.GOARCH {
case "386", "arm":
return []byte{
- BitsPointer, BitsScalar, BitsScalar, BitsScalar,
- BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
- BitsDead, BitsScalar, BitsScalar, BitsScalar,
- BitsScalar, BitsMultiWord, BitsString,
+ BitsPointer, // q *int
+ BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+ BitsPointer, BitsDead, BitsDead, // r []byte
+ BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+ BitsPointer, BitsDead, // i string
}
case "amd64":
return []byte{
- BitsPointer, BitsScalar, BitsScalar, BitsScalar,
- BitsMultiWord, BitsSlice, BitsDead, BitsScalar,
- BitsScalar, BitsScalar, BitsMultiWord, BitsString,
+ BitsPointer, // q *int
+ BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+ BitsPointer, BitsDead, BitsDead, // r []byte
+ BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+ BitsPointer, BitsDead, // i string
}
case "amd64p32":
return []byte{
- BitsPointer, BitsScalar, BitsScalar, BitsScalar,
- BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
- BitsDead, BitsScalar, BitsScalar, BitsDead,
- BitsScalar, BitsScalar, BitsMultiWord, BitsString,
+ BitsPointer, // q *int
+ BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+ BitsPointer, BitsDead, BitsDead, // r []byte
+ BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+ BitsPointer, BitsDead, // i string
}
default:
panic("unknown arch")
@@ -167,7 +171,7 @@ var (
// BSS
bssScalarPtr ScalarPtr
bssPtrScalar PtrScalar
- bssComplex Complex
+ bssBigStruct BigStruct
bssString string
bssSlice []string
bssEface interface{}
@@ -176,14 +180,14 @@ var (
// DATA
dataScalarPtr = ScalarPtr{q: 1}
dataPtrScalar = PtrScalar{w: 1}
- dataComplex = Complex{w: 1}
+ dataBigStruct = BigStruct{w: 1}
dataString = "foo"
dataSlice = []string{"foo"}
dataEface interface{} = 42
dataIface Iface = IfaceImpl(42)
- infoString = []byte{BitsMultiWord, BitsString}
- infoSlice = []byte{BitsMultiWord, BitsSlice, BitsDead}
+ infoString = []byte{BitsPointer, BitsDead}
+ infoSlice = []byte{BitsPointer, BitsDead, BitsDead}
infoEface = []byte{BitsMultiWord, BitsEface}
infoIface = []byte{BitsMultiWord, BitsIface}
)
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
index 1a38087c8d..61f6fc2d95 100644
--- a/src/pkg/runtime/heapdump.c
+++ b/src/pkg/runtime/heapdump.c
@@ -260,16 +260,8 @@ dumpbv(BitVector *bv, uintptr offset)
break;
case BitsMultiWord:
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
- case BitsString:
- dumpint(FieldKindString);
- dumpint(offset + i / BitsPerPointer * PtrSize);
- i += BitsPerPointer;
- break;
- case BitsSlice:
- dumpint(FieldKindSlice);
- dumpint(offset + i / BitsPerPointer * PtrSize);
- i += 2 * BitsPerPointer;
- break;
+ default:
+ runtime·throw("unexpected garbage collection bits");
case BitsIface:
dumpint(FieldKindIface);
dumpint(offset + i / BitsPerPointer * PtrSize);
@@ -495,13 +487,13 @@ dumproots(void)
dumpint(TagData);
dumpint((uintptr)data);
dumpmemrange(data, edata - data);
- dumpfields((BitVector){(edata - data)*8, (uint32*)runtime·gcdatamask});
+ dumpfields(runtime·gcdatamask);
// bss segment
dumpint(TagBss);
dumpint((uintptr)bss);
dumpmemrange(bss, ebss - bss);
- dumpfields((BitVector){(ebss - bss)*8, (uint32*)runtime·gcbssmask});
+ dumpfields(runtime·gcdatamask);
// MSpan.types
allspans = runtime·mheap.allspans;
@@ -802,13 +794,11 @@ dumpbvtypes(BitVector *bv, byte *base)
if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
continue;
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
- case BitsString:
+ default:
+ runtime·throw("unexpected garbage collection bits");
case BitsIface:
i += BitsPerPointer;
break;
- case BitsSlice:
- i += 2 * BitsPerPointer;
- break;
case BitsEface:
dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
i += BitsPerPointer;
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index f5a2b2a42d..eafabb364a 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -303,7 +303,6 @@ extern int8 runtime·size_to_class8[1024/8 + 1];
extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
extern void runtime·InitSizes(void);
-
typedef struct MCacheList MCacheList;
struct MCacheList
{
@@ -581,6 +580,9 @@ struct StackMap
// (the index is encoded in PCDATA_StackMapIndex).
BitVector runtime·stackmapdata(StackMap *stackmap, int32 n);
+extern BitVector runtime·gcdatamask;
+extern BitVector runtime·gcbssmask;
+
// defined in mgc0.go
void runtime·gc_m_ptr(Eface*);
void runtime·gc_g_ptr(Eface*);
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index d931e31525..db89f6036f 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -172,8 +172,8 @@ static FinBlock *finc; // cache of free blocks
static FinBlock *allfin; // list of all blocks
bool runtime·fingwait;
bool runtime·fingwake;
-byte* runtime·gcdatamask;
-byte* runtime·gcbssmask;
+BitVector runtime·gcdatamask;
+BitVector runtime·gcbssmask;
static Lock gclock;
@@ -187,7 +187,7 @@ static void gchelperstart(void);
static void flushallmcaches(void);
static bool scanframe(Stkframe *frame, void *unused);
static void scanstack(G *gp);
-static byte* unrollglobgcprog(byte *prog, uintptr size);
+static BitVector unrollglobgcprog(byte *prog, uintptr size);
static FuncVal runfinqv = {runfinq};
static FuncVal bgsweepv = {bgsweep};
@@ -221,8 +221,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
uintptr i, nobj, size, idx, x, off, scanbufpos;
intptr ncached;
Workbuf *wbuf;
- String *str;
- Slice *slice;
Iface *iface;
Eface *eface;
Type *typ;
@@ -346,6 +344,10 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
obj = *(byte**)(b+i);
goto markobj;
}
+
+ // With those three out of the way, must be multi-word.
+ if(bits != BitsMultiWord)
+ runtime·throw("unexpected garbage collection bits");
// Find the next pair of bits.
if(ptrmask == nil) {
if(ncached <= 0) {
@@ -358,22 +360,8 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
switch(bits) {
- case BitsString:
- str = (String*)(b+i);
- if(str->len > 0)
- obj = str->str;
- break;
- case BitsSlice:
- slice = (Slice*)(b+i);
- if(Debug && slice->cap < slice->len) {
- g->m->traceback = 2;
- runtime·printf("bad slice in object %p: %p/%p/%p\n",
- b, slice->array, slice->len, slice->cap);
- runtime·throw("bad slice in heap object");
- }
- if(slice->cap > 0)
- obj = slice->array;
- break;
+ default:
+ runtime·throw("unexpected garbage collection bits");
case BitsIface:
iface = (Iface*)(b+i);
if(iface->tab != nil) {
@@ -392,21 +380,9 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
break;
}
- if(bits == BitsSlice) {
- i += 2*PtrSize;
- if(ncached == 2)
- ncached = 0;
- else if(ptrmask == nil) {
- // Refill cache and consume one quadruple.
- cached = *--ptrbitp;
- cached >>= gcBits;
- ncached = 1;
- }
- } else {
- i += PtrSize;
- cached >>= gcBits;
- ncached--;
- }
+ i += PtrSize;
+ cached >>= gcBits;
+ ncached--;
markobj:
// At this point we have extracted the next potential pointer.
@@ -513,11 +489,11 @@ markroot(ParFor *desc, uint32 i)
// Note: if you add a case here, please also update heapdump.c:dumproots.
switch(i) {
case RootData:
- scanblock(data, edata - data, runtime·gcdatamask);
+ scanblock(data, edata - data, (byte*)runtime·gcdatamask.data);
break;
case RootBss:
- scanblock(bss, ebss - bss, runtime·gcbssmask);
+ scanblock(bss, ebss - bss, (byte*)runtime·gcbssmask.data);
break;
case RootFinalizers:
@@ -1852,7 +1828,7 @@ unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse)
}
// Unrolls GC program prog for data/bss, returns dense GC mask.
-static byte*
+static BitVector
unrollglobgcprog(byte *prog, uintptr size)
{
byte *mask;
@@ -1872,7 +1848,7 @@ unrollglobgcprog(byte *prog, uintptr size)
runtime·throw("unrollglobgcprog: program does not end with insEnd");
if(mask[masksize] != 0xa1)
runtime·throw("unrollglobgcprog: overflow");
- return mask;
+ return (BitVector){masksize*8, (uint32*)mask};
}
void
@@ -2062,7 +2038,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
*mask = runtime·mallocgc(*len, nil, 0);
for(i = 0; i < n; i += PtrSize) {
off = (p+i-data)/PtrSize;
- bits = (runtime·gcdatamask[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+ bits = (((byte*)runtime·gcdatamask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
(*mask)[i/PtrSize] = bits;
}
return;
@@ -2074,7 +2050,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
*mask = runtime·mallocgc(*len, nil, 0);
for(i = 0; i < n; i += PtrSize) {
off = (p+i-bss)/PtrSize;
- bits = (runtime·gcbssmask[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+ bits = (((byte*)runtime·gcbssmask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
(*mask)[i/PtrSize] = bits;
}
return;
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
index a7292effd3..d04b5cab8f 100644
--- a/src/pkg/runtime/mgc0.h
+++ b/src/pkg/runtime/mgc0.h
@@ -50,8 +50,8 @@ enum {
BitsMultiWord = 3,
// BitsMultiWord will be set for the first word of a multi-word item.
// When it is set, one of the following will be set for the second word.
- BitsString = 0,
- BitsSlice = 1,
+ // NOT USED ANYMORE: BitsString = 0,
+ // NOT USED ANYMORE: BitsSlice = 1,
BitsIface = 2,
BitsEface = 3,
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index df2999bbd9..4f63fdf718 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -762,8 +762,6 @@ extern uint32 runtime·cpuid_ecx;
extern uint32 runtime·cpuid_edx;
extern DebugVars runtime·debug;
extern uintptr runtime·maxstacksize;
-extern byte* runtime·gcdatamask;
-extern byte* runtime·gcbssmask;
extern Note runtime·signote;
/*
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index fc11d98c9b..61205bd478 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -592,19 +592,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
break;
case BitsMultiWord:
switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
- case BitsString:
- // string referents are never on the stack, never need to be adjusted
- i++; // skip len
- break;
- case BitsSlice:
- p = scanp[i];
- if(minp <= p && p < maxp) {
- if(StackDebug >= 3)
- runtime·printf("adjust slice %p\n", p);
- scanp[i] = p + delta;
- }
- i += 2; // skip len, cap
- break;
+ default:
+ runtime·throw("unexpected garbage collection bits");
case BitsEface:
t = (Type*)scanp[i];
if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {