github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/runtime/gcinfo_test.go (about) 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 )