github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/runtime/slice.go (about)

     1  // Copyright 2009 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
     6  
     7  import (
     8  	"unsafe"
     9  )
    10  
    11  type slice struct {
    12  	array unsafe.Pointer
    13  	len   int
    14  	cap   int
    15  }
    16  
    17  // TODO: take uintptrs instead of int64s?
    18  func makeslice(t *slicetype, len64, cap64 int64) slice {
    19  	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
    20  	// but it produces a 'len out of range' error instead of a 'cap out of range' error
    21  	// when someone does make([]T, bignumber). 'cap out of range' is true too,
    22  	// but since the cap is only being supplied implicitly, saying len is clearer.
    23  	// See issue 4085.
    24  	len := int(len64)
    25  	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/t.elem.size {
    26  		panic(errorString("makeslice: len out of range"))
    27  	}
    28  	cap := int(cap64)
    29  	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/t.elem.size {
    30  		panic(errorString("makeslice: cap out of range"))
    31  	}
    32  	p := newarray(t.elem, uintptr(cap))
    33  	return slice{p, len, cap}
    34  }
    35  
    36  // growslice handles slice growth during append.
    37  // It is passed the slice type, the old slice, and the desired new minimum capacity,
    38  // and it returns a new slice with at least that capacity, with the old data
    39  // copied into it.
    40  func growslice(t *slicetype, old slice, cap int) slice {
    41  	if raceenabled {
    42  		callerpc := getcallerpc(unsafe.Pointer(&t))
    43  		racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice))
    44  	}
    45  	if msanenabled {
    46  		msanread(old.array, uintptr(old.len*int(t.elem.size)))
    47  	}
    48  
    49  	et := t.elem
    50  	if et.size == 0 {
    51  		if cap < old.cap {
    52  			panic(errorString("growslice: cap out of range"))
    53  		}
    54  		// append should not create a slice with nil pointer but non-zero len.
    55  		// We assume that append doesn't need to preserve old.array in this case.
    56  		return slice{unsafe.Pointer(&zerobase), old.len, cap}
    57  	}
    58  
    59  	newcap := old.cap
    60  	doublecap := newcap + newcap
    61  	if cap > doublecap {
    62  		newcap = cap
    63  	} else {
    64  		if old.len < 1024 {
    65  			newcap = doublecap
    66  		} else {
    67  			for newcap < cap {
    68  				newcap += newcap / 4
    69  			}
    70  		}
    71  	}
    72  
    73  	var lenmem, capmem, maxcap uintptr
    74  	const ptrSize = unsafe.Sizeof((*byte)(nil))
    75  	switch et.size {
    76  	case 1:
    77  		lenmem = uintptr(old.len)
    78  		capmem = roundupsize(uintptr(newcap))
    79  		newcap = int(capmem)
    80  		maxcap = _MaxMem
    81  	case ptrSize:
    82  		lenmem = uintptr(old.len) * ptrSize
    83  		capmem = roundupsize(uintptr(newcap) * ptrSize)
    84  		newcap = int(capmem / ptrSize)
    85  		maxcap = _MaxMem / ptrSize
    86  	default:
    87  		lenmem = uintptr(old.len) * et.size
    88  		capmem = roundupsize(uintptr(newcap) * et.size)
    89  		newcap = int(capmem / et.size)
    90  		maxcap = _MaxMem / et.size
    91  	}
    92  
    93  	if cap < old.cap || uintptr(newcap) > maxcap {
    94  		panic(errorString("growslice: cap out of range"))
    95  	}
    96  
    97  	var p unsafe.Pointer
    98  	if et.kind&kindNoPointers != 0 {
    99  		p = rawmem(capmem)
   100  		memmove(p, old.array, lenmem)
   101  		memclr(add(p, lenmem), capmem-lenmem)
   102  	} else {
   103  		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
   104  		p = newarray(et, uintptr(newcap))
   105  		if !writeBarrier.enabled {
   106  			memmove(p, old.array, lenmem)
   107  		} else {
   108  			for i := uintptr(0); i < lenmem; i += et.size {
   109  				typedmemmove(et, add(p, i), add(old.array, i))
   110  			}
   111  		}
   112  	}
   113  
   114  	return slice{p, old.len, newcap}
   115  }
   116  
   117  func slicecopy(to, fm slice, width uintptr) int {
   118  	if fm.len == 0 || to.len == 0 {
   119  		return 0
   120  	}
   121  
   122  	n := fm.len
   123  	if to.len < n {
   124  		n = to.len
   125  	}
   126  
   127  	if width == 0 {
   128  		return n
   129  	}
   130  
   131  	if raceenabled {
   132  		callerpc := getcallerpc(unsafe.Pointer(&to))
   133  		pc := funcPC(slicecopy)
   134  		racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
   135  		racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
   136  	}
   137  	if msanenabled {
   138  		msanwrite(to.array, uintptr(n*int(width)))
   139  		msanread(fm.array, uintptr(n*int(width)))
   140  	}
   141  
   142  	size := uintptr(n) * width
   143  	if size == 1 { // common case worth about 2x to do here
   144  		// TODO: is this still worth it with new memmove impl?
   145  		*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
   146  	} else {
   147  		memmove(to.array, fm.array, size)
   148  	}
   149  	return n
   150  }
   151  
   152  func slicestringcopy(to []byte, fm string) int {
   153  	if len(fm) == 0 || len(to) == 0 {
   154  		return 0
   155  	}
   156  
   157  	n := len(fm)
   158  	if len(to) < n {
   159  		n = len(to)
   160  	}
   161  
   162  	if raceenabled {
   163  		callerpc := getcallerpc(unsafe.Pointer(&to))
   164  		pc := funcPC(slicestringcopy)
   165  		racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
   166  	}
   167  	if msanenabled {
   168  		msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
   169  	}
   170  
   171  	memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
   172  	return n
   173  }