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