github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/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 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info. 14 func TestGCInfo(t *testing.T) { 15 verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr)) 16 verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar)) 17 verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct())) 18 verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString)) 19 verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice)) 20 verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface)) 21 verifyGCInfo(t, "bss iface", &bssIface, nonStackInfo(infoIface)) 22 23 verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr)) 24 verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar)) 25 verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct())) 26 verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString)) 27 verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice)) 28 verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface)) 29 verifyGCInfo(t, "data iface", &dataIface, nonStackInfo(infoIface)) 30 31 verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr) 32 verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar) 33 verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct()) 34 verifyGCInfo(t, "stack string", new(string), infoString) 35 verifyGCInfo(t, "stack slice", new([]string), infoSlice) 36 verifyGCInfo(t, "stack eface", new(interface{}), infoEface) 37 verifyGCInfo(t, "stack iface", new(Iface), infoIface) 38 39 for i := 0; i < 10; i++ { 40 verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr)) 41 verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar)) 42 verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct())) 43 verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString)) 44 verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface)) 45 verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface)) 46 } 47 48 } 49 50 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) { 51 mask := runtime.GCMask(p) 52 if len(mask) > len(mask0) { 53 mask0 = append(mask0, typeDead) 54 mask = mask[:len(mask0)] 55 } 56 if bytes.Compare(mask, mask0) != 0 { 57 t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask) 58 return 59 } 60 } 61 62 func nonStackInfo(mask []byte) []byte { 63 // typeDead is replaced with typeScalar everywhere except stacks. 64 mask1 := make([]byte, len(mask)) 65 for i, v := range mask { 66 if v == typeDead { 67 v = typeScalar 68 } 69 mask1[i] = v 70 } 71 return mask1 72 } 73 74 var gcinfoSink interface{} 75 76 func escape(p interface{}) interface{} { 77 gcinfoSink = p 78 return p 79 } 80 81 const ( 82 typeDead = iota 83 typeScalar 84 typePointer 85 ) 86 87 const ( 88 BitsString = iota // unused 89 BitsSlice // unused 90 BitsIface 91 BitsEface 92 ) 93 94 type ScalarPtr struct { 95 q int 96 w *int 97 e int 98 r *int 99 t int 100 y *int 101 } 102 103 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer} 104 105 type PtrScalar struct { 106 q *int 107 w int 108 e *int 109 r int 110 t *int 111 y int 112 } 113 114 var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar} 115 116 type BigStruct struct { 117 q *int 118 w byte 119 e [17]byte 120 r []byte 121 t int 122 y uint16 123 u uint64 124 i string 125 } 126 127 func infoBigStruct() []byte { 128 switch runtime.GOARCH { 129 case "386", "arm": 130 return []byte{ 131 typePointer, // q *int 132 typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte 133 typePointer, typeDead, typeDead, // r []byte 134 typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64 135 typePointer, typeDead, // i string 136 } 137 case "arm64", "amd64", "ppc64", "ppc64le": 138 return []byte{ 139 typePointer, // q *int 140 typeScalar, typeScalar, typeScalar, // w byte; e [17]byte 141 typePointer, typeDead, typeDead, // r []byte 142 typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64 143 typePointer, typeDead, // i string 144 } 145 case "amd64p32": 146 return []byte{ 147 typePointer, // q *int 148 typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte 149 typePointer, typeDead, typeDead, // r []byte 150 typeScalar, typeScalar, typeDead, typeScalar, typeScalar, // t int; y uint16; u uint64 151 typePointer, typeDead, // i string 152 } 153 default: 154 panic("unknown arch") 155 } 156 } 157 158 type Iface interface { 159 f() 160 } 161 162 type IfaceImpl int 163 164 func (IfaceImpl) f() { 165 } 166 167 var ( 168 // BSS 169 bssScalarPtr ScalarPtr 170 bssPtrScalar PtrScalar 171 bssBigStruct BigStruct 172 bssString string 173 bssSlice []string 174 bssEface interface{} 175 bssIface Iface 176 177 // DATA 178 dataScalarPtr = ScalarPtr{q: 1} 179 dataPtrScalar = PtrScalar{w: 1} 180 dataBigStruct = BigStruct{w: 1} 181 dataString = "foo" 182 dataSlice = []string{"foo"} 183 dataEface interface{} = 42 184 dataIface Iface = IfaceImpl(42) 185 186 infoString = []byte{typePointer, typeDead} 187 infoSlice = []byte{typePointer, typeDead, typeDead} 188 infoEface = []byte{typePointer, typePointer} 189 infoIface = []byte{typePointer, typePointer} 190 )