1
0
mirror of https://github.com/golang/go synced 2024-11-20 10:14:43 -07:00

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
This commit is contained in:
Russ Cox 2011-10-18 10:03:37 -04:00
parent 313c8224d5
commit 4e7aac5413
3 changed files with 21 additions and 81 deletions

View File

@ -516,6 +516,7 @@ haspointers(Type *t)
case TUINT32: case TUINT32:
case TINT64: case TINT64:
case TUINT64: case TUINT64:
case TUINTPTR:
case TFLOAT32: case TFLOAT32:
case TFLOAT64: case TFLOAT64:
case TBOOL: case TBOOL:
@ -533,7 +534,6 @@ haspointers(Type *t)
case TPTR32: case TPTR32:
case TPTR64: case TPTR64:
case TUNSAFEPTR: case TUNSAFEPTR:
case TUINTPTR:
case TINTER: case TINTER:
case TCHAN: case TCHAN:
case TMAP: case TMAP:

View File

@ -1424,11 +1424,17 @@ func (v Value) Slice(beg, end int) Value {
typ = iv.typ.toType() typ = iv.typ.toType()
base = (*SliceHeader)(iv.addr).Data 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.Data = base + uintptr(beg)*typ.Elem().Size()
s.Len = end - beg s.Len = end - beg
s.Cap = cap - beg s.Cap = end - beg
return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(s))
return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(&x))
} }
// String returns the string v's underlying value, as a string. // 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 { if typ.Kind() != Slice {
panic("reflect: MakeSlice of non-slice type") panic("reflect: MakeSlice of non-slice type")
} }
s := &SliceHeader{
Data: uintptr(unsafe.NewArray(typ.Elem(), cap)), // Declare slice so that gc can see the base pointer in it.
Len: len, var x []byte
Cap: cap,
} // Reinterpret as *SliceHeader to edit.
return valueFromAddr(0, typ, unsafe.Pointer(s)) 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. // MakeChan creates a new channel with the specified type and buffer size.

View File

@ -3,7 +3,6 @@ package runtime_test
import ( import (
"runtime" "runtime"
"testing" "testing"
"unsafe"
) )
func TestGcSys(t *testing.T) { func TestGcSys(t *testing.T) {
@ -23,73 +22,3 @@ func TestGcSys(t *testing.T) {
func workthegc() []byte { func workthegc() []byte {
return make([]byte, 1029) 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")
}
}