Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package runtime_test
      6 
      7 import (
      8 	"bytes"
      9 	"runtime"
     10 	"testing"
     11 )
     12 
     13 const (
     14 	typeScalar  = 0
     15 	typePointer = 1
     16 )
     17 
     18 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
     19 func TestGCInfo(t *testing.T) {
     20 	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
     21 	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
     22 	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
     23 	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
     24 	verifyGCInfo(t, "bss string", &bssString, infoString)
     25 	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
     26 	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
     27 	verifyGCInfo(t, "bss iface", &bssIface, infoIface)
     28 
     29 	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
     30 	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
     31 	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
     32 	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
     33 	verifyGCInfo(t, "data string", &dataString, infoString)
     34 	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
     35 	verifyGCInfo(t, "data eface", &dataEface, infoEface)
     36 	verifyGCInfo(t, "data iface", &dataIface, infoIface)
     37 
     38 	verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr)
     39 	verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
     40 	verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
     41 	verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
     42 	verifyGCInfo(t, "stack string", new(string), infoString)
     43 	verifyGCInfo(t, "stack slice", new([]string), infoSlice)
     44 	verifyGCInfo(t, "stack eface", new(interface{}), infoEface)
     45 	verifyGCInfo(t, "stack iface", new(Iface), infoIface)
     46 
     47 	for i := 0; i < 10; i++ {
     48 		verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr)))
     49 		verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
     50 		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
     51 		verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
     52 		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), trimDead(infoPtrScalar))
     53 		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), trimDead(infoBigStruct()))
     54 		verifyGCInfo(t, "heap string", escape(new(string)), trimDead(infoString))
     55 		verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
     56 		verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
     57 	}
     58 }
     59 
     60 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
     61 	mask := runtime.GCMask(p)
     62 	if !bytes.Equal(mask, mask0) {
     63 		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
     64 		return
     65 	}
     66 }
     67 
     68 func padDead(mask []byte) []byte {
     69 	// Because the dead bit isn't encoded in the second word,
     70 	// and because on 32-bit systems a one-word allocation
     71 	// uses a two-word block, the pointer info for a one-word
     72 	// object needs to be expanded to include an extra scalar
     73 	// on 32-bit systems to match the heap bitmap.
     74 	if runtime.PtrSize == 4 && len(mask) == 1 {
     75 		return []byte{mask[0], 0}
     76 	}
     77 	return mask
     78 }
     79 
     80 func trimDead(mask []byte) []byte {
     81 	for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
     82 		mask = mask[:len(mask)-1]
     83 	}
     84 	if len(mask) == 2 && mask[0] == typeScalar && mask[1] == typeScalar {
     85 		mask = mask[:0]
     86 	}
     87 	return mask
     88 }
     89 
     90 var gcinfoSink interface{}
     91 
     92 func escape(p interface{}) interface{} {
     93 	gcinfoSink = p
     94 	return p
     95 }
     96 
     97 var infoPtr = []byte{typePointer}
     98 
     99 type Ptr struct {
    100 	*byte
    101 }
    102 
    103 var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
    104 
    105 type ScalarPtr struct {
    106 	q int
    107 	w *int
    108 	e int
    109 	r *int
    110 	t int
    111 	y *int
    112 }
    113 
    114 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
    115 
    116 var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
    117 
    118 type PtrScalar struct {
    119 	q *int
    120 	w int
    121 	e *int
    122 	r int
    123 	t *int
    124 	y int
    125 }
    126 
    127 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
    128 
    129 type BigStruct struct {
    130 	q *int
    131 	w byte
    132 	e [17]byte
    133 	r []byte
    134 	t int
    135 	y uint16
    136 	u uint64
    137 	i string
    138 }
    139 
    140 func infoBigStruct() []byte {
    141 	switch runtime.GOARCH {
    142 	case "386", "arm", "mips", "mipsle":
    143 		return []byte{
    144 			typePointer,                                                // q *int
    145 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    146 			typePointer, typeScalar, typeScalar, // r []byte
    147 			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    148 			typePointer, typeScalar, // i string
    149 		}
    150 	case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le", "s390x":
    151 		return []byte{
    152 			typePointer,                        // q *int
    153 			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    154 			typePointer, typeScalar, typeScalar, // r []byte
    155 			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    156 			typePointer, typeScalar, // i string
    157 		}
    158 	case "amd64p32":
    159 		return []byte{
    160 			typePointer,                                                // q *int
    161 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    162 			typePointer, typeScalar, typeScalar, // r []byte
    163 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    164 			typePointer, typeScalar, // i string
    165 		}
    166 	default:
    167 		panic("unknown arch")
    168 	}
    169 }
    170 
    171 type Iface interface {
    172 	f()
    173 }
    174 
    175 type IfaceImpl int
    176 
    177 func (IfaceImpl) f() {
    178 }
    179 
    180 var (
    181 	// BSS
    182 	bssPtr       Ptr
    183 	bssScalarPtr ScalarPtr
    184 	bssPtrScalar PtrScalar
    185 	bssBigStruct BigStruct
    186 	bssString    string
    187 	bssSlice     []string
    188 	bssEface     interface{}
    189 	bssIface     Iface
    190 
    191 	// DATA
    192 	dataPtr                   = Ptr{new(byte)}
    193 	dataScalarPtr             = ScalarPtr{q: 1}
    194 	dataPtrScalar             = PtrScalar{w: 1}
    195 	dataBigStruct             = BigStruct{w: 1}
    196 	dataString                = "foo"
    197 	dataSlice                 = []string{"foo"}
    198 	dataEface     interface{} = 42
    199 	dataIface     Iface       = IfaceImpl(42)
    200 
    201 	infoString = []byte{typePointer, typeScalar}
    202 	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
    203 	infoEface  = []byte{typePointer, typePointer}
    204 	infoIface  = []byte{typePointer, typePointer}
    205 )
    206