1
0
mirror of https://github.com/golang/go synced 2024-11-19 05:44:40 -07:00

reflect: generated unrolled GC bitmask directly

The code for a generated type is already generating an
unrolled GC bitmask.  Rather than unrolling the the source
type bitmasks and copying them, just generate the required
bitmask directly.  Don't mark it as an unrolled GC program,
since there is no need to do so.

Fixes #8917.

LGTM=rsc
R=dvyukov, rsc
CC=golang-codereviews
https://golang.org/cl/156930044
This commit is contained in:
Ian Lance Taylor 2014-10-13 10:01:34 -07:00
parent 7c74850d76
commit 3cf9acccae
2 changed files with 43 additions and 19 deletions

View File

@ -4018,3 +4018,9 @@ func TestInvalid(t *testing.T) {
t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind())
}
}
// Issue 8917.
func TestLargeGCProg(t *testing.T) {
fv := ValueOf(func([256]*byte) {})
fv.Call([]Value{ValueOf([256]*byte{})})
}

View File

@ -1514,20 +1514,36 @@ func (gc *gcProg) appendProg(t *rtype) {
gc.size += t.size
return
}
nptr := t.size / unsafe.Sizeof(uintptr(0))
var prog []byte
if t.kind&kindGCProg != 0 {
// Ensure that the runtime has unrolled GC program.
// TODO(rsc): Do not allocate.
unsafe_New(t)
// The program is stored in t.gc[0], skip unroll flag.
prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:]
} else {
// The mask is linked directly in t.gc.
prog = (*[2 * ptrSize]byte)(unsafe.Pointer(t.gc[0]))[:]
}
for i := uintptr(0); i < nptr; i++ {
gc.appendWord(extractGCWord(prog, i))
switch t.Kind() {
default:
panic("reflect: non-pointer type marked as having pointers")
case Ptr, UnsafePointer, Chan, Func, Map:
gc.appendWord(bitsPointer)
case Slice:
gc.appendWord(bitsPointer)
gc.appendWord(bitsScalar)
gc.appendWord(bitsScalar)
case String:
gc.appendWord(bitsPointer)
gc.appendWord(bitsScalar)
case Array:
c := t.Len()
e := t.Elem().common()
for i := 0; i < c; i++ {
gc.appendProg(e)
}
case Interface:
gc.appendWord(bitsMultiWord)
if t.NumMethod() == 0 {
gc.appendWord(bitsEface)
} else {
gc.appendWord(bitsIface)
}
case Struct:
c := t.NumField()
for i := 0; i < c; i++ {
gc.appendProg(t.Field(i).Type.common())
}
}
}
@ -1562,7 +1578,6 @@ func (gc *gcProg) finalize() unsafe.Pointer {
gc.appendWord(extractGCWord(gc.gc, i))
}
}
gc.gc = append([]byte{1}, gc.gc...) // prepend unroll flag
return unsafe.Pointer(&gc.gc[0])
}
@ -1574,9 +1589,14 @@ func (gc *gcProg) align(a uintptr) {
gc.size = align(gc.size, a)
}
// These constants must stay in sync with ../runtime/mgc0.h.
const (
bitsScalar = 1
bitsPointer = 2
bitsScalar = 1
bitsPointer = 2
bitsMultiWord = 3
bitsIface = 2
bitsEface = 3
)
// Make sure these routines stay in sync with ../../runtime/hashmap.go!
@ -1619,7 +1639,6 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
b := new(rtype)
b.size = gc.size
b.gc[0] = gc.finalize()
b.kind |= kindGCProg
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
@ -1821,7 +1840,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
x := new(rtype)
x.size = gc.size
x.gc[0] = gc.finalize()
x.kind |= kindGCProg
var s string
if rcvr != nil {
s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"