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