From 4e7aac54137bb77a0b821b1cf24dcc3f42588a7d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 Oct 2011 10:03:37 -0400 Subject: [PATCH] reflect: make unsafe use of SliceHeader gc-friendly Revert workaround in compiler and revert test for compiler workaround. Tested that the 386 build continues to fail if the gc change is made without the reflect change. R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/5312041 --- src/cmd/gc/reflect.c | 2 +- src/pkg/reflect/value.go | 29 +++++++++++----- src/pkg/runtime/gc_test.go | 71 -------------------------------------- 3 files changed, 21 insertions(+), 81 deletions(-) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 4ce16957929..ca7d08e511a 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -516,6 +516,7 @@ haspointers(Type *t) case TUINT32: case TINT64: case TUINT64: + case TUINTPTR: case TFLOAT32: case TFLOAT64: case TBOOL: @@ -533,7 +534,6 @@ haspointers(Type *t) case TPTR32: case TPTR64: case TUNSAFEPTR: - case TUINTPTR: case TINTER: case TCHAN: case TMAP: diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index 056704f7972..9ddbee0e2e1 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -1424,11 +1424,17 @@ func (v Value) Slice(beg, end int) Value { typ = iv.typ.toType() base = (*SliceHeader)(iv.addr).Data } - s := new(SliceHeader) + + // Declare slice so that gc can see the base pointer in it. + var x []byte + + // Reinterpret as *SliceHeader to edit. + s := (*SliceHeader)(unsafe.Pointer(&x)) s.Data = base + uintptr(beg)*typ.Elem().Size() s.Len = end - beg - s.Cap = cap - beg - return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(s)) + s.Cap = end - beg + + return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(&x)) } // String returns the string v's underlying value, as a string. @@ -1654,12 +1660,17 @@ func MakeSlice(typ Type, len, cap int) Value { if typ.Kind() != Slice { panic("reflect: MakeSlice of non-slice type") } - s := &SliceHeader{ - Data: uintptr(unsafe.NewArray(typ.Elem(), cap)), - Len: len, - Cap: cap, - } - return valueFromAddr(0, typ, unsafe.Pointer(s)) + + // Declare slice so that gc can see the base pointer in it. + var x []byte + + // Reinterpret as *SliceHeader to edit. + s := (*SliceHeader)(unsafe.Pointer(&x)) + s.Data = uintptr(unsafe.NewArray(typ.Elem(), cap)) + s.Len = len + s.Cap = cap + + return valueFromAddr(0, typ, unsafe.Pointer(&x)) } // MakeChan creates a new channel with the specified type and buffer size. diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go index c299ba20e7a..fad60a36804 100644 --- a/src/pkg/runtime/gc_test.go +++ b/src/pkg/runtime/gc_test.go @@ -3,7 +3,6 @@ package runtime_test import ( "runtime" "testing" - "unsafe" ) func TestGcSys(t *testing.T) { @@ -23,73 +22,3 @@ func TestGcSys(t *testing.T) { func workthegc() []byte { return make([]byte, 1029) } - -func TestGcUintptr(t *testing.T) { - p1 := unsafe.Pointer(new(int)) - *(*int)(unsafe.Pointer(p1)) = 42 - p2 := uintptr(unsafe.Pointer(new(int))) - *(*int)(unsafe.Pointer(p2)) = 42 - var a1 [1]unsafe.Pointer - a1[0] = unsafe.Pointer(new(int)) - *(*int)(unsafe.Pointer(a1[0])) = 42 - var a2 [1]uintptr - a2[0] = uintptr(unsafe.Pointer(new(int))) - *(*int)(unsafe.Pointer(a2[0])) = 42 - s1 := make([]unsafe.Pointer, 1) - s1[0] = unsafe.Pointer(new(int)) - *(*int)(unsafe.Pointer(s1[0])) = 42 - s2 := make([]uintptr, 1) - s2[0] = uintptr(unsafe.Pointer(new(int))) - *(*int)(unsafe.Pointer(s2[0])) = 42 - m1 := make(map[int]unsafe.Pointer) - m1[0] = unsafe.Pointer(new(int)) - *(*int)(unsafe.Pointer(m1[0])) = 42 - m2 := make(map[int]uintptr) - m2[0] = uintptr(unsafe.Pointer(new(int))) - *(*int)(unsafe.Pointer(m2[0])) = 42 - c1 := make(chan unsafe.Pointer, 1) - func() { - p := new(int) - *p = 42 - c1 <- unsafe.Pointer(p) - }() - c2 := make(chan uintptr, 1) - func() { - p := new(int) - *p = 42 - c2 <- uintptr(unsafe.Pointer(p)) - }() - - runtime.GC() - - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(p1))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("p1 is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(p2))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("p2 is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(a1[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("a1[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(a2[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("a2[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(s1[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("s1[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(s2[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("s2[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(m1[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("m1[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(m2[0]))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("m2[0] is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(<-c1))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("<-c1 is freed") - } - if p, _ := runtime.Lookup((*byte)(unsafe.Pointer(<-c2))); p == nil || *(*int)(unsafe.Pointer(p)) != 42 { - t.Fatalf("<-c2 is freed") - } -}