Home | History | Annotate | Download | only in runtime
      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/uintptr(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/uintptr(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_n is a variant of growslice that takes the number of new elements
     37 // instead of the new minimum capacity.
     38 // TODO(rsc): This is used by append(slice, slice...).
     39 // The compiler should change that code to use growslice directly (issue #11419).
     40 func growslice_n(t *slicetype, old slice, n int) slice {
     41 	if n < 1 {
     42 		panic(errorString("growslice: invalid n"))
     43 	}
     44 	return growslice(t, old, old.cap+n)
     45 }
     46 
     47 // growslice handles slice growth during append.
     48 // It is passed the slice type, the old slice, and the desired new minimum capacity,
     49 // and it returns a new slice with at least that capacity, with the old data
     50 // copied into it.
     51 func growslice(t *slicetype, old slice, cap int) slice {
     52 	if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
     53 		panic(errorString("growslice: cap out of range"))
     54 	}
     55 
     56 	if raceenabled {
     57 		callerpc := getcallerpc(unsafe.Pointer(&t))
     58 		racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice))
     59 	}
     60 
     61 	et := t.elem
     62 	if et.size == 0 {
     63 		// append should not create a slice with nil pointer but non-zero len.
     64 		// We assume that append doesn't need to preserve old.array in this case.
     65 		return slice{unsafe.Pointer(&zerobase), old.len, cap}
     66 	}
     67 
     68 	newcap := old.cap
     69 	if newcap+newcap < cap {
     70 		newcap = cap
     71 	} else {
     72 		for {
     73 			if old.len < 1024 {
     74 				newcap += newcap
     75 			} else {
     76 				newcap += newcap / 4
     77 			}
     78 			if newcap >= cap {
     79 				break
     80 			}
     81 		}
     82 	}
     83 
     84 	if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
     85 		panic(errorString("growslice: cap out of range"))
     86 	}
     87 	lenmem := uintptr(old.len) * uintptr(et.size)
     88 	capmem := roundupsize(uintptr(newcap) * uintptr(et.size))
     89 	newcap = int(capmem / uintptr(et.size))
     90 	var p unsafe.Pointer
     91 	if et.kind&kindNoPointers != 0 {
     92 		p = rawmem(capmem)
     93 		memmove(p, old.array, lenmem)
     94 		memclr(add(p, lenmem), capmem-lenmem)
     95 	} else {
     96 		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
     97 		p = newarray(et, uintptr(newcap))
     98 		if !writeBarrierEnabled {
     99 			memmove(p, old.array, lenmem)
    100 		} else {
    101 			for i := uintptr(0); i < lenmem; i += et.size {
    102 				typedmemmove(et, add(p, i), add(old.array, i))
    103 			}
    104 		}
    105 	}
    106 
    107 	return slice{p, old.len, newcap}
    108 }
    109 
    110 func slicecopy(to, fm slice, width uintptr) int {
    111 	if fm.len == 0 || to.len == 0 {
    112 		return 0
    113 	}
    114 
    115 	n := fm.len
    116 	if to.len < n {
    117 		n = to.len
    118 	}
    119 
    120 	if width == 0 {
    121 		return n
    122 	}
    123 
    124 	if raceenabled {
    125 		callerpc := getcallerpc(unsafe.Pointer(&to))
    126 		pc := funcPC(slicecopy)
    127 		racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
    128 		racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
    129 	}
    130 
    131 	size := uintptr(n) * width
    132 	if size == 1 { // common case worth about 2x to do here
    133 		// TODO: is this still worth it with new memmove impl?
    134 		*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
    135 	} else {
    136 		memmove(to.array, fm.array, size)
    137 	}
    138 	return int(n)
    139 }
    140 
    141 func slicestringcopy(to []byte, fm string) int {
    142 	if len(fm) == 0 || len(to) == 0 {
    143 		return 0
    144 	}
    145 
    146 	n := len(fm)
    147 	if len(to) < n {
    148 		n = len(to)
    149 	}
    150 
    151 	if raceenabled {
    152 		callerpc := getcallerpc(unsafe.Pointer(&to))
    153 		pc := funcPC(slicestringcopy)
    154 		racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
    155 	}
    156 
    157 	memmove(unsafe.Pointer(&to[0]), unsafe.Pointer((*stringStruct)(unsafe.Pointer(&fm)).str), uintptr(n))
    158 	return n
    159 }
    160