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.Compare(mask, mask0) != 0 {
     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 until the third 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 	return mask
     85 }
     86 
     87 var gcinfoSink interface{}
     88 
     89 func escape(p interface{}) interface{} {
     90 	gcinfoSink = p
     91 	return p
     92 }
     93 
     94 var infoPtr = []byte{typePointer}
     95 
     96 type Ptr struct {
     97 	*byte
     98 }
     99 
    100 var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
    101 
    102 type ScalarPtr struct {
    103 	q int
    104 	w *int
    105 	e int
    106 	r *int
    107 	t int
    108 	y *int
    109 }
    110 
    111 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
    112 
    113 var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
    114 
    115 type PtrScalar struct {
    116 	q *int
    117 	w int
    118 	e *int
    119 	r int
    120 	t *int
    121 	y int
    122 }
    123 
    124 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
    125 
    126 type BigStruct struct {
    127 	q *int
    128 	w byte
    129 	e [17]byte
    130 	r []byte
    131 	t int
    132 	y uint16
    133 	u uint64
    134 	i string
    135 }
    136 
    137 func infoBigStruct() []byte {
    138 	switch runtime.GOARCH {
    139 	case "386", "arm":
    140 		return []byte{
    141 			typePointer,                                                // q *int
    142 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    143 			typePointer, typeScalar, typeScalar, // r []byte
    144 			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    145 			typePointer, typeScalar, // i string
    146 		}
    147 	case "arm64", "amd64", "ppc64", "ppc64le":
    148 		return []byte{
    149 			typePointer,                        // q *int
    150 			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    151 			typePointer, typeScalar, typeScalar, // r []byte
    152 			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    153 			typePointer, typeScalar, // i string
    154 		}
    155 	case "amd64p32":
    156 		return []byte{
    157 			typePointer,                                                // q *int
    158 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
    159 			typePointer, typeScalar, typeScalar, // r []byte
    160 			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
    161 			typePointer, typeScalar, // i string
    162 		}
    163 	default:
    164 		panic("unknown arch")
    165 	}
    166 }
    167 
    168 type Iface interface {
    169 	f()
    170 }
    171 
    172 type IfaceImpl int
    173 
    174 func (IfaceImpl) f() {
    175 }
    176 
    177 var (
    178 	// BSS
    179 	bssPtr       Ptr
    180 	bssScalarPtr ScalarPtr
    181 	bssPtrScalar PtrScalar
    182 	bssBigStruct BigStruct
    183 	bssString    string
    184 	bssSlice     []string
    185 	bssEface     interface{}
    186 	bssIface     Iface
    187 
    188 	// DATA
    189 	dataPtr                   = Ptr{new(byte)}
    190 	dataScalarPtr             = ScalarPtr{q: 1}
    191 	dataPtrScalar             = PtrScalar{w: 1}
    192 	dataBigStruct             = BigStruct{w: 1}
    193 	dataString                = "foo"
    194 	dataSlice                 = []string{"foo"}
    195 	dataEface     interface{} = 42
    196 	dataIface     Iface       = IfaceImpl(42)
    197 
    198 	infoString = []byte{typePointer, typeScalar}
    199 	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
    200 	infoEface  = []byte{typePointer, typePointer}
    201 	infoIface  = []byte{typePointer, typePointer}
    202 )
    203