]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc, runtime: treat slices and strings like pointers in garbage collection
authorRuss Cox <rsc@golang.org>
Mon, 25 Aug 2014 18:38:19 +0000 (14:38 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 25 Aug 2014 18:38:19 +0000 (14:38 -0400)
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

25 files changed:
src/cmd/5g/cgen.c
src/cmd/5g/gsubr.c
src/cmd/6g/cgen.c
src/cmd/6g/gsubr.c
src/cmd/8g/cgen.c
src/cmd/8g/gsubr.c
src/cmd/gc/fmt.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/plive.c
src/cmd/gc/reflect.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/pkg/reflect/all_test.go
src/pkg/reflect/value.go
src/pkg/runtime/gcinfo_test.go
src/pkg/runtime/heapdump.c
src/pkg/runtime/malloc.h
src/pkg/runtime/mgc0.c
src/pkg/runtime/mgc0.h
src/pkg/runtime/runtime.h
src/pkg/runtime/stack.c
test/slice3.go
test/slicecap.go [new file with mode: 0644]

index a9c597cdc819152dca466da0bf68b02a0889725c..5fae7a564cda9010a2c6554c4d5ac9c65c398eab 100644 (file)
@@ -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;
index 1241a23ea653fe892de41c3a96dcf00cab252aed..5a70fcddaffcbbd4ec30106854eeb09d62d87354 100644 (file)
@@ -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;
 
index bff2350621783212191cf66f4c58616b8f687951..592e81542ce212ff3513bfeb8d2b69ddfcf2bc2d 100644 (file)
@@ -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) {
index 4ac2e9207957000e7109eec09ce699e1072d9fa5..a451d7d62471889aaf0b8365fbfcf00587495c8d 100644 (file)
@@ -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;
 
index bdf728dbbc6e62e432aa1de1cdabb9180acafadf..f3093bc26e67beb5b1ebf09cc769e14528574569 100644 (file)
@@ -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) {
index 66d5b8d6963cfc2431ad524e68e0e674f89655d5..9ee418cb7834371cdf5c9bb4622c6629ae435b17 100644 (file)
@@ -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;
 
index 951170aeff2271797aa48aaeb8fba1657440c58a..98556a658f3f2b88aae8d2f26b2b7ca2af133a5a 100644 (file)
@@ -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);
index 908a5e53d980627c793e469807b483a674a27206..86acd882598321a1c2b7934b03cf49a162edd47c 100644 (file)
@@ -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);
        }
 }
 
index 61bb7bd6e4c0042964ceb8f8310f73ee93820ec4..12c1e98539aab11701d6f473a45124b69d83db0a 100644 (file)
@@ -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
index e67b0af757b484ec26d357548c5e5e93258ce44d..0ad700e82fa609acf6b5348b40aea0d4b312ae5d 100644 (file)
@@ -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++)
index 66efac07d07cdf1ff6d602310964c628b50e1708..05bf2d6521d2456ed17a5797d6e4a4d9af9db4f6 100644 (file)
@@ -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;
index 081c373a889cc4f85d903350ed9305f8746b08d2..d62d55e773980c0f660793208b51de2a9894b185 100644 (file)
@@ -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);
index c295cf6d21e0fc5ff6564853dde7a7358cbf7364..746feb4d1b544c6b9c507cd5c89a6c6362c024b1 100644 (file)
@@ -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:
index f3886cf73af3b823b8ea99024cd12ed61e1a4d8a..c251af660e5c4c38a85916a078d406dedf1ffcb0 100644 (file)
@@ -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];
index d9781699e037717b438207fba17de966d7153c6c..9a2a9f266899d49b238fdf4a4596dbf18058e7fa 100644 (file)
@@ -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) {
index dda852a3ec4cc514a22c988a70913f84c987f66e..4394ed07396f2b3b6a9f2a32ddc750cb4b95f4c3 100644 (file)
@@ -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}
index 16764c948736c0b8c18306bcda2df2caca65afb7..88f6703f97df8f21d3a12c9b4c8fafa6c1cf007d 100644 (file)
@@ -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}
 )
index 1a38087c8d4ee0161d4687c56932b36fae4209b2..61f6fc2d954533f265fa5f61874070597c7e0ff6 100644 (file)
@@ -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;
index f5a2b2a42d05abface013fe5fb13d21e86330211..eafabb364aecc07a23e506c5af5b313679d8f773 100644 (file)
@@ -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*);
index d931e31525542008ed7bacc1f4c971db8fc130cf..db89f6036f946151a1664f00ba0499a742a91b8e 100644 (file)
@@ -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;
index a7292effd31ce98388c630f0973a57d230e17903..d04b5cab8feda5a780760c5c04c724d09e0f9aa2 100644 (file)
@@ -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,
 
index df2999bbd98a2e86e4a7a70249ea167903ae2a17..4f63fdf71849f2121609cdc263c790392ed42891 100644 (file)
@@ -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;
 
 /*
index fc11d98c9b67edad7bd17fcb410c19c6ccdf1015..61205bd478218f738ab5fc287dba8bdd188fd7be 100644 (file)
@@ -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)) {
index 3cf34b57e75c284b9d6482e0a16e3bf17988983d..857eaf3a093e0c7215576e606c5b1316f38783b5 100644 (file)
@@ -19,10 +19,10 @@ var bout *bufio.Writer
 
 func main() {
        bout = bufio.NewWriter(os.Stdout)
-       
+
        fmt.Fprintf(bout, "%s", programTop)
        fmt.Fprintf(bout, "func main() {\n")
-       
+
        index := []string{
                "0",
                "1",
@@ -38,7 +38,7 @@ func main() {
                "v10",
                "v20",
        }
-       
+
        parse := func(s string) (n int, isconst bool) {
                if s == "vminus1" {
                        return -1, false
@@ -69,7 +69,7 @@ func main() {
                                                iconst && kconst && iv > kv,
                                                iconst && base == "array" && iv > Cap,
                                                jconst && base == "array" && jv > Cap,
-                                               kconst && base == "array" && kv > Cap:                          
+                                               kconst && base == "array" && kv > Cap:
                                                continue
                                        }
 
@@ -82,7 +82,7 @@ func main() {
                                                xlen = jv - iv
                                                xcap = kv - iv
                                        }
-                                       fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap)                                                                 
+                                       fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap)
                                }
                        }
                }
@@ -147,9 +147,13 @@ func checkSlice(desc string, f func() []byte, xbase, xlen, xcap int) {
                println(desc, "=", base, len, cap, "want panic")
                return
        }
-       if base != uintptr(xbase) || len != uintptr(xlen) || cap != uintptr(xcap) {
+       if cap != 0 && base != uintptr(xbase) || base >= 10 || len != uintptr(xlen) || cap != uintptr(xcap) {
                notOK()
-               println(desc, "=", base, len, cap, "want", xbase, xlen, xcap)
+               if cap == 0 {
+                       println(desc, "=", base, len, cap, "want", "0-9", xlen, xcap)
+               } else {
+                       println(desc, "=", base, len, cap, "want", xbase, xlen, xcap)
+               }
        }
 }
 
diff --git a/test/slicecap.go b/test/slicecap.go
new file mode 100644 (file)
index 0000000..dceb7e2
--- /dev/null
@@ -0,0 +1,90 @@
+// run
+
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var (
+       hello = "hello"
+       bytes = []byte{1, 2, 3, 4, 5}
+       ints  = []int32{1, 2, 3, 4, 5}
+
+       five = 5
+
+       ok = true
+)
+
+func notOK() {
+       if ok {
+               println("BUG:")
+               ok = false
+       }
+}
+
+func checkString(desc, s string) {
+       p1 := *(*uintptr)(unsafe.Pointer(&s))
+       p2 := *(*uintptr)(unsafe.Pointer(&hello))
+       if p1-p2 >= 5 {
+               notOK()
+               println("string", desc, "has invalid base")
+       }
+}
+
+func checkBytes(desc string, s []byte) {
+       p1 := *(*uintptr)(unsafe.Pointer(&s))
+       p2 := *(*uintptr)(unsafe.Pointer(&bytes))
+       if p1-p2 >= 5 {
+               println("byte slice", desc, "has invalid base")
+       }
+}
+
+func checkInts(desc string, s []int32) {
+       p1 := *(*uintptr)(unsafe.Pointer(&s))
+       p2 := *(*uintptr)(unsafe.Pointer(&ints))
+       if p1-p2 >= 5*4 {
+               println("int slice", desc, "has invalid base")
+       }
+}
+
+func main() {
+       {
+               x := hello
+               checkString("x", x)
+               checkString("x[5:]", x[5:])
+               checkString("x[five:]", x[five:])
+               checkString("x[5:five]", x[5:five])
+               checkString("x[five:5]", x[five:5])
+               checkString("x[five:five]", x[five:five])
+               checkString("x[1:][2:][2:]", x[1:][2:][2:])
+               y := x[4:]
+               checkString("y[1:]", y[1:])
+       }
+       {
+               x := bytes
+               checkBytes("x", x)
+               checkBytes("x[5:]", x[5:])
+               checkBytes("x[five:]", x[five:])
+               checkBytes("x[5:five]", x[5:five])
+               checkBytes("x[five:5]", x[five:5])
+               checkBytes("x[five:five]", x[five:five])
+               checkBytes("x[1:][2:][2:]", x[1:][2:][2:])
+               y := x[4:]
+               checkBytes("y[1:]", y[1:])
+       }
+       {
+               x := ints
+               checkInts("x", x)
+               checkInts("x[5:]", x[5:])
+               checkInts("x[five:]", x[five:])
+               checkInts("x[5:five]", x[5:five])
+               checkInts("x[five:5]", x[five:5])
+               checkInts("x[five:five]", x[five:five])
+               checkInts("x[1:][2:][2:]", x[1:][2:][2:])
+               y := x[4:]
+               checkInts("y[1:]", y[1:])
+       }
+}