mirror of
https://github.com/golang/go
synced 2024-10-06 08:00:07 +00:00
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
This commit is contained in:
parent
c6f7c176a3
commit
613383c765
|
@ -254,7 +254,6 @@ cgen(Node *n, Node *res)
|
||||||
case OOR:
|
case OOR:
|
||||||
case OXOR:
|
case OXOR:
|
||||||
case OADD:
|
case OADD:
|
||||||
case OADDPTR:
|
|
||||||
case OMUL:
|
case OMUL:
|
||||||
a = optoas(n->op, nl->type);
|
a = optoas(n->op, nl->type);
|
||||||
goto sbop;
|
goto sbop;
|
||||||
|
|
|
@ -1599,7 +1599,6 @@ optoas(int op, Type *t)
|
||||||
case CASE(OADD, TINT32):
|
case CASE(OADD, TINT32):
|
||||||
case CASE(OADD, TUINT32):
|
case CASE(OADD, TUINT32):
|
||||||
case CASE(OADD, TPTR32):
|
case CASE(OADD, TPTR32):
|
||||||
case CASE(OADDPTR, TPTR32):
|
|
||||||
a = AADD;
|
a = AADD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,6 @@ cgen(Node *n, Node *res)
|
||||||
case OOR:
|
case OOR:
|
||||||
case OXOR:
|
case OXOR:
|
||||||
case OADD:
|
case OADD:
|
||||||
case OADDPTR:
|
|
||||||
case OMUL:
|
case OMUL:
|
||||||
a = optoas(n->op, nl->type);
|
a = optoas(n->op, nl->type);
|
||||||
if(a == AIMULB) {
|
if(a == AIMULB) {
|
||||||
|
|
|
@ -1537,14 +1537,12 @@ optoas(int op, Type *t)
|
||||||
case CASE(OADD, TINT32):
|
case CASE(OADD, TINT32):
|
||||||
case CASE(OADD, TUINT32):
|
case CASE(OADD, TUINT32):
|
||||||
case CASE(OADD, TPTR32):
|
case CASE(OADD, TPTR32):
|
||||||
case CASE(OADDPTR, TPTR32):
|
|
||||||
a = AADDL;
|
a = AADDL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CASE(OADD, TINT64):
|
case CASE(OADD, TINT64):
|
||||||
case CASE(OADD, TUINT64):
|
case CASE(OADD, TUINT64):
|
||||||
case CASE(OADD, TPTR64):
|
case CASE(OADD, TPTR64):
|
||||||
case CASE(OADDPTR, TPTR64):
|
|
||||||
a = AADDQ;
|
a = AADDQ;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -242,7 +242,6 @@ cgen(Node *n, Node *res)
|
||||||
case OOR:
|
case OOR:
|
||||||
case OXOR:
|
case OXOR:
|
||||||
case OADD:
|
case OADD:
|
||||||
case OADDPTR:
|
|
||||||
case OMUL:
|
case OMUL:
|
||||||
a = optoas(n->op, nl->type);
|
a = optoas(n->op, nl->type);
|
||||||
if(a == AIMULB) {
|
if(a == AIMULB) {
|
||||||
|
|
|
@ -430,7 +430,6 @@ optoas(int op, Type *t)
|
||||||
case CASE(OADD, TINT32):
|
case CASE(OADD, TINT32):
|
||||||
case CASE(OADD, TUINT32):
|
case CASE(OADD, TUINT32):
|
||||||
case CASE(OADD, TPTR32):
|
case CASE(OADD, TPTR32):
|
||||||
case CASE(OADDPTR, TPTR32):
|
|
||||||
a = AADDL;
|
a = AADDL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1153,7 +1153,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||||
case Csend:
|
case Csend:
|
||||||
return fmtprint(f, "chan<- %N", n->left);
|
return fmtprint(f, "chan<- %N", n->left);
|
||||||
default:
|
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);
|
return fmtprint(f, "chan (%N)", n->left);
|
||||||
else
|
else
|
||||||
return fmtprint(f, "chan %N", n->left);
|
return fmtprint(f, "chan %N", n->left);
|
||||||
|
|
|
@ -806,7 +806,8 @@ cgen_eface(Node *n, Node *res)
|
||||||
void
|
void
|
||||||
cgen_slice(Node *n, Node *res)
|
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;
|
cap = n->list->n;
|
||||||
len = n->list->next->n;
|
len = n->list->next->n;
|
||||||
|
@ -823,6 +824,11 @@ cgen_slice(Node *n, Node *res)
|
||||||
// garbage collector can see.
|
// garbage collector can see.
|
||||||
|
|
||||||
base = temp(types[TUINTPTR]);
|
base = temp(types[TUINTPTR]);
|
||||||
|
tmplen = temp(types[TINT]);
|
||||||
|
if(n->op != OSLICESTR)
|
||||||
|
tmpcap = temp(types[TINT]);
|
||||||
|
else
|
||||||
|
tmpcap = tmplen;
|
||||||
|
|
||||||
if(isnil(n->left)) {
|
if(isnil(n->left)) {
|
||||||
tempname(&src, n->left->type);
|
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);
|
fatal("slicearr is supposed to work on pointer: %+N\n", n);
|
||||||
cgen(&src, base);
|
cgen(&src, base);
|
||||||
cgen_checknil(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 {
|
} else {
|
||||||
src.type = types[tptr];
|
src.type = types[tptr];
|
||||||
add = nod(OADDPTR, &src, offs);
|
cgen(&src, base);
|
||||||
typecheck(&add, Erv);
|
|
||||||
cgen(add, base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// committed to the update
|
// committed to the update
|
||||||
gvardef(res);
|
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.array = src.array [ + lo *width ]
|
||||||
dst = *res;
|
dst = *res;
|
||||||
dst.xoffset += Array_array;
|
dst.xoffset += Array_array;
|
||||||
dst.type = types[tptr];
|
dst.type = types[tptr];
|
||||||
|
|
||||||
cgen(base, &dst);
|
cgen(base, &dst);
|
||||||
|
|
||||||
// dst.len = hi [ - lo ]
|
// dst.len = hi [ - lo ]
|
||||||
dst = *res;
|
dst = *res;
|
||||||
dst.xoffset += Array_nel;
|
dst.xoffset += Array_nel;
|
||||||
dst.type = types[simtype[TUINT]];
|
dst.type = types[simtype[TUINT]];
|
||||||
cgen(len, &dst);
|
cgen(tmplen, &dst);
|
||||||
|
|
||||||
if(n->op != OSLICESTR) {
|
if(n->op != OSLICESTR) {
|
||||||
// dst.cap = cap [ - lo ]
|
// dst.cap = cap [ - lo ]
|
||||||
dst = *res;
|
dst = *res;
|
||||||
dst.xoffset += Array_cap;
|
dst.xoffset += Array_cap;
|
||||||
dst.type = types[simtype[TUINT]];
|
dst.type = types[simtype[TUINT]];
|
||||||
cgen(cap, &dst);
|
cgen(tmpcap, &dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -447,7 +447,6 @@ enum
|
||||||
OSUB, // x - y
|
OSUB, // x - y
|
||||||
OOR, // x | y
|
OOR, // x | y
|
||||||
OXOR, // x ^ y
|
OXOR, // x ^ y
|
||||||
OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
|
|
||||||
OADDSTR, // s + "foo"
|
OADDSTR, // s + "foo"
|
||||||
OADDR, // &x
|
OADDR, // &x
|
||||||
OANDAND, // b0 && b1
|
OANDAND, // b0 && b1
|
||||||
|
|
|
@ -1113,8 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
|
||||||
// struct { byte *str; intgo len; }
|
// struct { byte *str; intgo len; }
|
||||||
if((*xoffset & (widthptr-1)) != 0)
|
if((*xoffset & (widthptr-1)) != 0)
|
||||||
fatal("twobitwalktype1: invalid alignment, %T", t);
|
fatal("twobitwalktype1: invalid alignment, %T", t);
|
||||||
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
|
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
|
||||||
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string
|
|
||||||
*xoffset += t->width;
|
*xoffset += t->width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1145,9 +1144,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
|
||||||
// struct { byte *array; uintgo len; uintgo cap; }
|
// struct { byte *array; uintgo len; uintgo cap; }
|
||||||
if((*xoffset & (widthptr-1)) != 0)
|
if((*xoffset & (widthptr-1)) != 0)
|
||||||
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
|
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
|
||||||
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
|
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
|
||||||
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1);
|
|
||||||
bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice
|
|
||||||
*xoffset += t->width;
|
*xoffset += t->width;
|
||||||
} else
|
} else
|
||||||
for(i = 0; i < t->bound; i++)
|
for(i = 0; i < t->bound; i++)
|
||||||
|
|
|
@ -1516,8 +1516,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
|
||||||
*xoffset += t->width;
|
*xoffset += t->width;
|
||||||
break;
|
break;
|
||||||
case TSTRING:
|
case TSTRING:
|
||||||
proggendata(g, BitsMultiWord);
|
proggendata(g, BitsPointer);
|
||||||
proggendata(g, BitsString);
|
proggendata(g, BitsScalar);
|
||||||
*xoffset += t->width;
|
*xoffset += t->width;
|
||||||
break;
|
break;
|
||||||
case TINTER:
|
case TINTER:
|
||||||
|
@ -1530,8 +1530,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
|
||||||
break;
|
break;
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
if(isslice(t)) {
|
if(isslice(t)) {
|
||||||
proggendata(g, BitsMultiWord);
|
proggendata(g, BitsPointer);
|
||||||
proggendata(g, BitsSlice);
|
proggendata(g, BitsScalar);
|
||||||
proggendata(g, BitsScalar);
|
proggendata(g, BitsScalar);
|
||||||
} else {
|
} else {
|
||||||
t1 = t->type;
|
t1 = t->type;
|
||||||
|
|
|
@ -656,11 +656,15 @@ maptype(Type *key, Type *val)
|
||||||
{
|
{
|
||||||
Type *t;
|
Type *t;
|
||||||
Type *bad;
|
Type *bad;
|
||||||
int atype;
|
int atype, mtype;
|
||||||
|
|
||||||
if(key != nil) {
|
if(key != nil) {
|
||||||
atype = algtype1(key, &bad);
|
atype = algtype1(key, &bad);
|
||||||
switch(bad == T ? key->etype : bad->etype) {
|
if(bad == T)
|
||||||
|
mtype = key->etype;
|
||||||
|
else
|
||||||
|
mtype = bad->etype;
|
||||||
|
switch(mtype) {
|
||||||
default:
|
default:
|
||||||
if(atype == ANOEQ)
|
if(atype == ANOEQ)
|
||||||
yyerror("invalid map key type %T", key);
|
yyerror("invalid map key type %T", key);
|
||||||
|
|
|
@ -525,19 +525,6 @@ reswitch:
|
||||||
op = n->etype;
|
op = n->etype;
|
||||||
goto arith;
|
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 OADD:
|
||||||
case OAND:
|
case OAND:
|
||||||
case OANDAND:
|
case OANDAND:
|
||||||
|
|
|
@ -2875,14 +2875,14 @@ sliceany(Node* n, NodeList **init)
|
||||||
lb = N;
|
lb = N;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
|
// Checking src[lb:hb:cb] or src[lb:hb].
|
||||||
// generate
|
// if chk0 || chk1 || chk2 { panicslice() }
|
||||||
// if hb > bound || lb > hb { panicslice() }
|
|
||||||
chk = N;
|
chk = N;
|
||||||
chk0 = N;
|
chk0 = N; // cap(src) < cb
|
||||||
chk1 = N;
|
chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
|
||||||
chk2 = N;
|
chk2 = N; // hb < lb
|
||||||
|
|
||||||
|
// All comparisons are unsigned to avoid testing < 0.
|
||||||
bt = types[simtype[TUINT]];
|
bt = types[simtype[TUINT]];
|
||||||
if(cb != N && cb->type->width > 4)
|
if(cb != N && cb->type->width > 4)
|
||||||
bt = types[TUINT64];
|
bt = types[TUINT64];
|
||||||
|
|
|
@ -2494,6 +2494,15 @@ func TestSlice(t *testing.T) {
|
||||||
if vs != s[3:5] {
|
if vs != s[3:5] {
|
||||||
t.Errorf("s.Slice(3, 5) = %q; expected %q", 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) {
|
func TestSlice3(t *testing.T) {
|
||||||
|
@ -2532,6 +2541,15 @@ func TestSlice3(t *testing.T) {
|
||||||
s := "hello world"
|
s := "hello world"
|
||||||
rv = ValueOf(&s).Elem()
|
rv = ValueOf(&s).Elem()
|
||||||
shouldPanic(func() { rv.Slice3(1, 2, 3) })
|
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) {
|
func TestSetLenCap(t *testing.T) {
|
||||||
|
|
|
@ -1746,9 +1746,14 @@ func (v Value) Slice(i, j int) Value {
|
||||||
|
|
||||||
// Reinterpret as *sliceHeader to edit.
|
// Reinterpret as *sliceHeader to edit.
|
||||||
s := (*sliceHeader)(unsafe.Pointer(&x))
|
s := (*sliceHeader)(unsafe.Pointer(&x))
|
||||||
s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
|
|
||||||
s.Len = j - i
|
s.Len = j - i
|
||||||
s.Cap = cap - 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
|
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
|
||||||
return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
|
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.
|
// Reinterpret as *sliceHeader to edit.
|
||||||
s := (*sliceHeader)(unsafe.Pointer(&x))
|
s := (*sliceHeader)(unsafe.Pointer(&x))
|
||||||
s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
|
|
||||||
s.Len = j - i
|
s.Len = j - i
|
||||||
s.Cap = k - 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
|
fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
|
||||||
return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
|
return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func TestGCInfo(t *testing.T) {
|
func TestGCInfo(t *testing.T) {
|
||||||
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
|
verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
|
||||||
verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
|
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 string", &bssString, nonStackInfo(infoString))
|
||||||
verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
|
verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
|
||||||
verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
|
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 ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
|
||||||
verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
|
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 string", &dataString, nonStackInfo(infoString))
|
||||||
verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
|
verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
|
||||||
verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
|
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 ScalarPtr", new(ScalarPtr), infoScalarPtr)
|
||||||
verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
|
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 string", new(string), infoString)
|
||||||
verifyGCInfo(t, "stack slice", new([]string), infoSlice)
|
verifyGCInfo(t, "stack slice", new([]string), infoSlice)
|
||||||
verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
|
verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
|
||||||
|
@ -39,7 +39,7 @@ func TestGCInfo(t *testing.T) {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
|
verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
|
||||||
verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
|
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 string", escape(new(string)), nonStackInfo(infoString))
|
||||||
verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
|
verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
|
||||||
verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
|
verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
|
||||||
|
@ -88,8 +88,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BitsString = iota
|
BitsString = iota // unused
|
||||||
BitsSlice
|
BitsSlice // unused
|
||||||
BitsIface
|
BitsIface
|
||||||
BitsEface
|
BitsEface
|
||||||
)
|
)
|
||||||
|
@ -116,7 +116,7 @@ type PtrScalar struct {
|
||||||
|
|
||||||
var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
|
var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
|
||||||
|
|
||||||
type Complex struct {
|
type BigStruct struct {
|
||||||
q *int
|
q *int
|
||||||
w byte
|
w byte
|
||||||
e [17]byte
|
e [17]byte
|
||||||
|
@ -127,27 +127,31 @@ type Complex struct {
|
||||||
i string
|
i string
|
||||||
}
|
}
|
||||||
|
|
||||||
func infoComplex() []byte {
|
func infoBigStruct() []byte {
|
||||||
switch runtime.GOARCH {
|
switch runtime.GOARCH {
|
||||||
case "386", "arm":
|
case "386", "arm":
|
||||||
return []byte{
|
return []byte{
|
||||||
BitsPointer, BitsScalar, BitsScalar, BitsScalar,
|
BitsPointer, // q *int
|
||||||
BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
|
BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
|
||||||
BitsDead, BitsScalar, BitsScalar, BitsScalar,
|
BitsPointer, BitsDead, BitsDead, // r []byte
|
||||||
BitsScalar, BitsMultiWord, BitsString,
|
BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
|
||||||
|
BitsPointer, BitsDead, // i string
|
||||||
}
|
}
|
||||||
case "amd64":
|
case "amd64":
|
||||||
return []byte{
|
return []byte{
|
||||||
BitsPointer, BitsScalar, BitsScalar, BitsScalar,
|
BitsPointer, // q *int
|
||||||
BitsMultiWord, BitsSlice, BitsDead, BitsScalar,
|
BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
|
||||||
BitsScalar, BitsScalar, BitsMultiWord, BitsString,
|
BitsPointer, BitsDead, BitsDead, // r []byte
|
||||||
|
BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
|
||||||
|
BitsPointer, BitsDead, // i string
|
||||||
}
|
}
|
||||||
case "amd64p32":
|
case "amd64p32":
|
||||||
return []byte{
|
return []byte{
|
||||||
BitsPointer, BitsScalar, BitsScalar, BitsScalar,
|
BitsPointer, // q *int
|
||||||
BitsScalar, BitsScalar, BitsMultiWord, BitsSlice,
|
BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
|
||||||
BitsDead, BitsScalar, BitsScalar, BitsDead,
|
BitsPointer, BitsDead, BitsDead, // r []byte
|
||||||
BitsScalar, BitsScalar, BitsMultiWord, BitsString,
|
BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
|
||||||
|
BitsPointer, BitsDead, // i string
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown arch")
|
panic("unknown arch")
|
||||||
|
@ -167,7 +171,7 @@ var (
|
||||||
// BSS
|
// BSS
|
||||||
bssScalarPtr ScalarPtr
|
bssScalarPtr ScalarPtr
|
||||||
bssPtrScalar PtrScalar
|
bssPtrScalar PtrScalar
|
||||||
bssComplex Complex
|
bssBigStruct BigStruct
|
||||||
bssString string
|
bssString string
|
||||||
bssSlice []string
|
bssSlice []string
|
||||||
bssEface interface{}
|
bssEface interface{}
|
||||||
|
@ -176,14 +180,14 @@ var (
|
||||||
// DATA
|
// DATA
|
||||||
dataScalarPtr = ScalarPtr{q: 1}
|
dataScalarPtr = ScalarPtr{q: 1}
|
||||||
dataPtrScalar = PtrScalar{w: 1}
|
dataPtrScalar = PtrScalar{w: 1}
|
||||||
dataComplex = Complex{w: 1}
|
dataBigStruct = BigStruct{w: 1}
|
||||||
dataString = "foo"
|
dataString = "foo"
|
||||||
dataSlice = []string{"foo"}
|
dataSlice = []string{"foo"}
|
||||||
dataEface interface{} = 42
|
dataEface interface{} = 42
|
||||||
dataIface Iface = IfaceImpl(42)
|
dataIface Iface = IfaceImpl(42)
|
||||||
|
|
||||||
infoString = []byte{BitsMultiWord, BitsString}
|
infoString = []byte{BitsPointer, BitsDead}
|
||||||
infoSlice = []byte{BitsMultiWord, BitsSlice, BitsDead}
|
infoSlice = []byte{BitsPointer, BitsDead, BitsDead}
|
||||||
infoEface = []byte{BitsMultiWord, BitsEface}
|
infoEface = []byte{BitsMultiWord, BitsEface}
|
||||||
infoIface = []byte{BitsMultiWord, BitsIface}
|
infoIface = []byte{BitsMultiWord, BitsIface}
|
||||||
)
|
)
|
||||||
|
|
|
@ -260,16 +260,8 @@ dumpbv(BitVector *bv, uintptr offset)
|
||||||
break;
|
break;
|
||||||
case BitsMultiWord:
|
case BitsMultiWord:
|
||||||
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
|
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
|
||||||
case BitsString:
|
default:
|
||||||
dumpint(FieldKindString);
|
runtime·throw("unexpected garbage collection bits");
|
||||||
dumpint(offset + i / BitsPerPointer * PtrSize);
|
|
||||||
i += BitsPerPointer;
|
|
||||||
break;
|
|
||||||
case BitsSlice:
|
|
||||||
dumpint(FieldKindSlice);
|
|
||||||
dumpint(offset + i / BitsPerPointer * PtrSize);
|
|
||||||
i += 2 * BitsPerPointer;
|
|
||||||
break;
|
|
||||||
case BitsIface:
|
case BitsIface:
|
||||||
dumpint(FieldKindIface);
|
dumpint(FieldKindIface);
|
||||||
dumpint(offset + i / BitsPerPointer * PtrSize);
|
dumpint(offset + i / BitsPerPointer * PtrSize);
|
||||||
|
@ -495,13 +487,13 @@ dumproots(void)
|
||||||
dumpint(TagData);
|
dumpint(TagData);
|
||||||
dumpint((uintptr)data);
|
dumpint((uintptr)data);
|
||||||
dumpmemrange(data, edata - data);
|
dumpmemrange(data, edata - data);
|
||||||
dumpfields((BitVector){(edata - data)*8, (uint32*)runtime·gcdatamask});
|
dumpfields(runtime·gcdatamask);
|
||||||
|
|
||||||
// bss segment
|
// bss segment
|
||||||
dumpint(TagBss);
|
dumpint(TagBss);
|
||||||
dumpint((uintptr)bss);
|
dumpint((uintptr)bss);
|
||||||
dumpmemrange(bss, ebss - bss);
|
dumpmemrange(bss, ebss - bss);
|
||||||
dumpfields((BitVector){(ebss - bss)*8, (uint32*)runtime·gcbssmask});
|
dumpfields(runtime·gcdatamask);
|
||||||
|
|
||||||
// MSpan.types
|
// MSpan.types
|
||||||
allspans = runtime·mheap.allspans;
|
allspans = runtime·mheap.allspans;
|
||||||
|
@ -802,13 +794,11 @@ dumpbvtypes(BitVector *bv, byte *base)
|
||||||
if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
|
if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
|
||||||
continue;
|
continue;
|
||||||
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
|
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
|
||||||
case BitsString:
|
default:
|
||||||
|
runtime·throw("unexpected garbage collection bits");
|
||||||
case BitsIface:
|
case BitsIface:
|
||||||
i += BitsPerPointer;
|
i += BitsPerPointer;
|
||||||
break;
|
break;
|
||||||
case BitsSlice:
|
|
||||||
i += 2 * BitsPerPointer;
|
|
||||||
break;
|
|
||||||
case BitsEface:
|
case BitsEface:
|
||||||
dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
|
dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
|
||||||
i += BitsPerPointer;
|
i += BitsPerPointer;
|
||||||
|
|
|
@ -303,7 +303,6 @@ extern int8 runtime·size_to_class8[1024/8 + 1];
|
||||||
extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
|
extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
|
||||||
extern void runtime·InitSizes(void);
|
extern void runtime·InitSizes(void);
|
||||||
|
|
||||||
|
|
||||||
typedef struct MCacheList MCacheList;
|
typedef struct MCacheList MCacheList;
|
||||||
struct MCacheList
|
struct MCacheList
|
||||||
{
|
{
|
||||||
|
@ -581,6 +580,9 @@ struct StackMap
|
||||||
// (the index is encoded in PCDATA_StackMapIndex).
|
// (the index is encoded in PCDATA_StackMapIndex).
|
||||||
BitVector runtime·stackmapdata(StackMap *stackmap, int32 n);
|
BitVector runtime·stackmapdata(StackMap *stackmap, int32 n);
|
||||||
|
|
||||||
|
extern BitVector runtime·gcdatamask;
|
||||||
|
extern BitVector runtime·gcbssmask;
|
||||||
|
|
||||||
// defined in mgc0.go
|
// defined in mgc0.go
|
||||||
void runtime·gc_m_ptr(Eface*);
|
void runtime·gc_m_ptr(Eface*);
|
||||||
void runtime·gc_g_ptr(Eface*);
|
void runtime·gc_g_ptr(Eface*);
|
||||||
|
|
|
@ -172,8 +172,8 @@ static FinBlock *finc; // cache of free blocks
|
||||||
static FinBlock *allfin; // list of all blocks
|
static FinBlock *allfin; // list of all blocks
|
||||||
bool runtime·fingwait;
|
bool runtime·fingwait;
|
||||||
bool runtime·fingwake;
|
bool runtime·fingwake;
|
||||||
byte* runtime·gcdatamask;
|
BitVector runtime·gcdatamask;
|
||||||
byte* runtime·gcbssmask;
|
BitVector runtime·gcbssmask;
|
||||||
|
|
||||||
static Lock gclock;
|
static Lock gclock;
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ static void gchelperstart(void);
|
||||||
static void flushallmcaches(void);
|
static void flushallmcaches(void);
|
||||||
static bool scanframe(Stkframe *frame, void *unused);
|
static bool scanframe(Stkframe *frame, void *unused);
|
||||||
static void scanstack(G *gp);
|
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 runfinqv = {runfinq};
|
||||||
static FuncVal bgsweepv = {bgsweep};
|
static FuncVal bgsweepv = {bgsweep};
|
||||||
|
@ -221,8 +221,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
|
||||||
uintptr i, nobj, size, idx, x, off, scanbufpos;
|
uintptr i, nobj, size, idx, x, off, scanbufpos;
|
||||||
intptr ncached;
|
intptr ncached;
|
||||||
Workbuf *wbuf;
|
Workbuf *wbuf;
|
||||||
String *str;
|
|
||||||
Slice *slice;
|
|
||||||
Iface *iface;
|
Iface *iface;
|
||||||
Eface *eface;
|
Eface *eface;
|
||||||
Type *typ;
|
Type *typ;
|
||||||
|
@ -346,6 +344,10 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
|
||||||
obj = *(byte**)(b+i);
|
obj = *(byte**)(b+i);
|
||||||
goto markobj;
|
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.
|
// Find the next pair of bits.
|
||||||
if(ptrmask == nil) {
|
if(ptrmask == nil) {
|
||||||
if(ncached <= 0) {
|
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;
|
bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
|
||||||
|
|
||||||
switch(bits) {
|
switch(bits) {
|
||||||
case BitsString:
|
default:
|
||||||
str = (String*)(b+i);
|
runtime·throw("unexpected garbage collection bits");
|
||||||
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;
|
|
||||||
case BitsIface:
|
case BitsIface:
|
||||||
iface = (Iface*)(b+i);
|
iface = (Iface*)(b+i);
|
||||||
if(iface->tab != nil) {
|
if(iface->tab != nil) {
|
||||||
|
@ -392,21 +380,9 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bits == BitsSlice) {
|
i += PtrSize;
|
||||||
i += 2*PtrSize;
|
cached >>= gcBits;
|
||||||
if(ncached == 2)
|
ncached--;
|
||||||
ncached = 0;
|
|
||||||
else if(ptrmask == nil) {
|
|
||||||
// Refill cache and consume one quadruple.
|
|
||||||
cached = *--ptrbitp;
|
|
||||||
cached >>= gcBits;
|
|
||||||
ncached = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i += PtrSize;
|
|
||||||
cached >>= gcBits;
|
|
||||||
ncached--;
|
|
||||||
}
|
|
||||||
|
|
||||||
markobj:
|
markobj:
|
||||||
// At this point we have extracted the next potential pointer.
|
// 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.
|
// Note: if you add a case here, please also update heapdump.c:dumproots.
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case RootData:
|
case RootData:
|
||||||
scanblock(data, edata - data, runtime·gcdatamask);
|
scanblock(data, edata - data, (byte*)runtime·gcdatamask.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RootBss:
|
case RootBss:
|
||||||
scanblock(bss, ebss - bss, runtime·gcbssmask);
|
scanblock(bss, ebss - bss, (byte*)runtime·gcbssmask.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RootFinalizers:
|
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.
|
// Unrolls GC program prog for data/bss, returns dense GC mask.
|
||||||
static byte*
|
static BitVector
|
||||||
unrollglobgcprog(byte *prog, uintptr size)
|
unrollglobgcprog(byte *prog, uintptr size)
|
||||||
{
|
{
|
||||||
byte *mask;
|
byte *mask;
|
||||||
|
@ -1872,7 +1848,7 @@ unrollglobgcprog(byte *prog, uintptr size)
|
||||||
runtime·throw("unrollglobgcprog: program does not end with insEnd");
|
runtime·throw("unrollglobgcprog: program does not end with insEnd");
|
||||||
if(mask[masksize] != 0xa1)
|
if(mask[masksize] != 0xa1)
|
||||||
runtime·throw("unrollglobgcprog: overflow");
|
runtime·throw("unrollglobgcprog: overflow");
|
||||||
return mask;
|
return (BitVector){masksize*8, (uint32*)mask};
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2062,7 +2038,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
|
||||||
*mask = runtime·mallocgc(*len, nil, 0);
|
*mask = runtime·mallocgc(*len, nil, 0);
|
||||||
for(i = 0; i < n; i += PtrSize) {
|
for(i = 0; i < n; i += PtrSize) {
|
||||||
off = (p+i-data)/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;
|
(*mask)[i/PtrSize] = bits;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2074,7 +2050,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
|
||||||
*mask = runtime·mallocgc(*len, nil, 0);
|
*mask = runtime·mallocgc(*len, nil, 0);
|
||||||
for(i = 0; i < n; i += PtrSize) {
|
for(i = 0; i < n; i += PtrSize) {
|
||||||
off = (p+i-bss)/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;
|
(*mask)[i/PtrSize] = bits;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -50,8 +50,8 @@ enum {
|
||||||
BitsMultiWord = 3,
|
BitsMultiWord = 3,
|
||||||
// BitsMultiWord will be set for the first word of a multi-word item.
|
// 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.
|
// When it is set, one of the following will be set for the second word.
|
||||||
BitsString = 0,
|
// NOT USED ANYMORE: BitsString = 0,
|
||||||
BitsSlice = 1,
|
// NOT USED ANYMORE: BitsSlice = 1,
|
||||||
BitsIface = 2,
|
BitsIface = 2,
|
||||||
BitsEface = 3,
|
BitsEface = 3,
|
||||||
|
|
||||||
|
|
|
@ -762,8 +762,6 @@ extern uint32 runtime·cpuid_ecx;
|
||||||
extern uint32 runtime·cpuid_edx;
|
extern uint32 runtime·cpuid_edx;
|
||||||
extern DebugVars runtime·debug;
|
extern DebugVars runtime·debug;
|
||||||
extern uintptr runtime·maxstacksize;
|
extern uintptr runtime·maxstacksize;
|
||||||
extern byte* runtime·gcdatamask;
|
|
||||||
extern byte* runtime·gcbssmask;
|
|
||||||
extern Note runtime·signote;
|
extern Note runtime·signote;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -592,19 +592,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
|
||||||
break;
|
break;
|
||||||
case BitsMultiWord:
|
case BitsMultiWord:
|
||||||
switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
|
switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
|
||||||
case BitsString:
|
default:
|
||||||
// string referents are never on the stack, never need to be adjusted
|
runtime·throw("unexpected garbage collection bits");
|
||||||
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;
|
|
||||||
case BitsEface:
|
case BitsEface:
|
||||||
t = (Type*)scanp[i];
|
t = (Type*)scanp[i];
|
||||||
if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
|
if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
|
||||||
|
|
|
@ -147,9 +147,13 @@ func checkSlice(desc string, f func() []byte, xbase, xlen, xcap int) {
|
||||||
println(desc, "=", base, len, cap, "want panic")
|
println(desc, "=", base, len, cap, "want panic")
|
||||||
return
|
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()
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
90
test/slicecap.go
Normal file
90
test/slicecap.go
Normal file
|
@ -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:])
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue