summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-12-01 07:52:09 -0800
committerKeith Randall <khr@golang.org>2014-12-01 07:52:09 -0800
commitae637f5f9923cb1b798695597cdd0d0f4dea9464 (patch)
treeda207f9e6285ae49659c97c96e9d41c63102f13c
parent66be71687665f9511c060208dacf6e56adcd3bce (diff)
downloadgo-ae637f5f9923cb1b798695597cdd0d0f4dea9464.tar.gz
reflect: Fix reflect.funcLayout. The GC bitmap has two bits per
pointer, not one. Fixes issue 9179 LGTM=iant, rsc R=golang-codereviews, iant, rsc CC=golang-codereviews https://codereview.appspot.com/182160043
-rw-r--r--src/reflect/all_test.go101
-rw-r--r--src/reflect/export_test.go19
-rw-r--r--src/reflect/type.go4
3 files changed, 122 insertions, 2 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 268a9e319..7a01c95d8 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 0778ad37f..caaf51a50 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 572e611fa..c0ddfcad0 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)