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