From: Russ Cox Date: Mon, 1 Dec 2014 16:18:47 +0000 (-0500) Subject: [release-branch.go1.4] reflect: Fix reflect.funcLayout. The GC bitmap has two bits per X-Git-Tag: go1.4rc2~2 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=95e92ac420ca0edaa9dabdbe76583affbc1015a0;p=gostls13.git [release-branch.go1.4] reflect: Fix reflect.funcLayout. The GC bitmap has two bits per ««« CL 182160043 / 321d04dea9d6 reflect: Fix reflect.funcLayout. The GC bitmap has two bits per pointer, not one. Fixes #9179 LGTM=iant, rsc R=golang-codereviews, iant, rsc CC=golang-codereviews https://golang.org/cl/182160043 »»» TBR=khr CC=golang-codereviews https://golang.org/cl/180440044 --- diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 268a9e319f..7a01c95d86 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4055,3 +4055,104 @@ func TestLargeGCProg(t *testing.T) { fv := ValueOf(func([256]*byte) {}) fv.Call([]Value{ValueOf([256]*byte{})}) } + +// Issue 9179. +func TestCallGC(t *testing.T) { + f := func(a, b, c, d, e string) { + } + g := func(in []Value) []Value { + runtime.GC() + return nil + } + typ := ValueOf(f).Type() + f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string)) + f2("four", "five5", "six666", "seven77", "eight888") +} + +type funcLayoutTest struct { + rcvr, t Type + argsize, retOffset uintptr + stack []byte +} + +var funcLayoutTests []funcLayoutTest + +func init() { + var argAlign = PtrSize + if runtime.GOARCH == "amd64p32" { + argAlign = 2 * PtrSize + } + roundup := func(x uintptr, a uintptr) uintptr { + return (x + a - 1) / a * a + } + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a, b string) string { return "" }).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsPointer, BitsScalar, BitsPointer}, + }) + + var r []byte + if PtrSize == 4 { + r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer} + } else { + r = []byte{BitsScalar, BitsScalar, BitsPointer} + } + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(), + roundup(3*4, PtrSize) + PtrSize + 2, + roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign), + r, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer}, + }) + + type S struct { + a, b uintptr + c, d *byte + } + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a S) {}).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer}, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + ValueOf((*byte)(nil)).Type(), + ValueOf(func(a uintptr, b *int) {}).Type(), + 3 * PtrSize, + roundup(3*PtrSize, argAlign), + []byte{BitsPointer, BitsScalar, BitsPointer}, + }) +} + +func TestFuncLayout(t *testing.T) { + for _, lt := range funcLayoutTests { + _, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr) + if argsize != lt.argsize { + t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize) + } + if retOffset != lt.retOffset { + t.Errorf("funcLayout(%v, %v).retOffset=%d, want %d", lt.t, lt.rcvr, retOffset, lt.retOffset) + } + if !bytes.Equal(stack, lt.stack) { + t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack) + } + } +} diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 0778ad37f5..caaf51a50f 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -17,3 +17,22 @@ func IsRO(v Value) bool { var ArrayOf = arrayOf var CallGC = &callGC + +const PtrSize = ptrSize +const BitsPointer = bitsPointer +const BitsScalar = bitsScalar + +func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) { + var ft *rtype + var s *bitVector + if rcvr != nil { + ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype)) + } else { + ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil) + } + frametype = ft + for i := uint32(0); i < s.n; i += 2 { + stack = append(stack, s.data[i/8]>>(i%8)&3) + } + return +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 572e611fa9..c0ddfcad0a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1894,14 +1894,14 @@ func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { switch Kind(t.kind & kindMask) { case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < uint32(*offset/uintptr(ptrSize)) { + for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { bv.append2(bitsScalar) } bv.append2(bitsPointer) case Interface: // 2 pointers - for bv.n < uint32(*offset/uintptr(ptrSize)) { + for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { bv.append2(bitsScalar) } bv.append2(bitsPointer)