From 3cf9acccae4686ebb1dbaece4056eca58b8392b2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 13 Oct 2014 10:01:34 -0700 Subject: [PATCH] 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 --- src/reflect/all_test.go | 6 +++++ src/reflect/type.go | 56 +++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index f0cd6a4128..6bdc9be9dd 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -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{})}) +} diff --git a/src/reflect/type.go b/src/reflect/type.go index a36c0ba604..821b60412e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -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 + ")" -- 2.51.0