github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/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  )