Home | History | Annotate | Download | only in runtime
      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
      6 
      7 import (
      8 	"unsafe"
      9 )
     10 
     11 // The constant is known to the compiler.
     12 // There is no fundamental theory behind this number.
     13 const tmpStringBufSize = 32
     14 
     15 type tmpBuf [tmpStringBufSize]byte
     16 
     17 // concatstrings implements a Go string concatenation x+y+z+...
     18 // The operands are passed in the slice a.
     19 // If buf != nil, the compiler has determined that the result does not
     20 // escape the calling function, so the string data can be stored in buf
     21 // if small enough.
     22 func concatstrings(buf *tmpBuf, a []string) string {
     23 	idx := 0
     24 	l := 0
     25 	count := 0
     26 	for i, x := range a {
     27 		n := len(x)
     28 		if n == 0 {
     29 			continue
     30 		}
     31 		if l+n < l {
     32 			throw("string concatenation too long")
     33 		}
     34 		l += n
     35 		count++
     36 		idx = i
     37 	}
     38 	if count == 0 {
     39 		return ""
     40 	}
     41 
     42 	// If there is just one string and either it is not on the stack
     43 	// or our result does not escape the calling frame (buf != nil),
     44 	// then we can return that string directly.
     45 	if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
     46 		return a[idx]
     47 	}
     48 	s, b := rawstringtmp(buf, l)
     49 	l = 0
     50 	for _, x := range a {
     51 		copy(b[l:], x)
     52 		l += len(x)
     53 	}
     54 	return s
     55 }
     56 
     57 func concatstring2(buf *tmpBuf, a [2]string) string {
     58 	return concatstrings(buf, a[:])
     59 }
     60 
     61 func concatstring3(buf *tmpBuf, a [3]string) string {
     62 	return concatstrings(buf, a[:])
     63 }
     64 
     65 func concatstring4(buf *tmpBuf, a [4]string) string {
     66 	return concatstrings(buf, a[:])
     67 }
     68 
     69 func concatstring5(buf *tmpBuf, a [5]string) string {
     70 	return concatstrings(buf, a[:])
     71 }
     72 
     73 // Buf is a fixed-size buffer for the result,
     74 // it is not nil if the result does not escape.
     75 func slicebytetostring(buf *tmpBuf, b []byte) string {
     76 	l := len(b)
     77 	if l == 0 {
     78 		// Turns out to be a relatively common case.
     79 		// Consider that you want to parse out data between parens in "foo()bar",
     80 		// you find the indices and convert the subslice to string.
     81 		return ""
     82 	}
     83 	if raceenabled && l > 0 {
     84 		racereadrangepc(unsafe.Pointer(&b[0]),
     85 			uintptr(l),
     86 			getcallerpc(unsafe.Pointer(&b)),
     87 			funcPC(slicebytetostring))
     88 	}
     89 	s, c := rawstringtmp(buf, l)
     90 	copy(c, b)
     91 	return s
     92 }
     93 
     94 // stringDataOnStack reports whether the string's data is
     95 // stored on the current goroutine's stack.
     96 func stringDataOnStack(s string) bool {
     97 	ptr := uintptr((*stringStruct)(unsafe.Pointer(&s)).str)
     98 	stk := getg().stack
     99 	return stk.lo <= ptr && ptr < stk.hi
    100 }
    101 
    102 func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
    103 	if buf != nil && l <= len(buf) {
    104 		b = buf[:l]
    105 		s = slicebytetostringtmp(b)
    106 	} else {
    107 		s, b = rawstring(l)
    108 	}
    109 	return
    110 }
    111 
    112 func slicebytetostringtmp(b []byte) string {
    113 	// Return a "string" referring to the actual []byte bytes.
    114 	// This is only for use by internal compiler optimizations
    115 	// that know that the string form will be discarded before
    116 	// the calling goroutine could possibly modify the original
    117 	// slice or synchronize with another goroutine.
    118 	// First such case is a m[string(k)] lookup where
    119 	// m is a string-keyed map and k is a []byte.
    120 	// Second such case is "<"+string(b)+">" concatenation where b is []byte.
    121 	// Third such case is string(b)=="foo" comparison where b is []byte.
    122 
    123 	if raceenabled && len(b) > 0 {
    124 		racereadrangepc(unsafe.Pointer(&b[0]),
    125 			uintptr(len(b)),
    126 			getcallerpc(unsafe.Pointer(&b)),
    127 			funcPC(slicebytetostringtmp))
    128 	}
    129 	return *(*string)(unsafe.Pointer(&b))
    130 }
    131 
    132 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
    133 	var b []byte
    134 	if buf != nil && len(s) <= len(buf) {
    135 		b = buf[:len(s)]
    136 	} else {
    137 		b = rawbyteslice(len(s))
    138 	}
    139 	copy(b, s)
    140 	return b
    141 }
    142 
    143 func stringtoslicebytetmp(s string) []byte {
    144 	// Return a slice referring to the actual string bytes.
    145 	// This is only for use by internal compiler optimizations
    146 	// that know that the slice won't be mutated.
    147 	// The only such case today is:
    148 	// for i, c := range []byte(str)
    149 
    150 	str := (*stringStruct)(unsafe.Pointer(&s))
    151 	ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}
    152 	return *(*[]byte)(unsafe.Pointer(&ret))
    153 }
    154 
    155 func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
    156 	// two passes.
    157 	// unlike slicerunetostring, no race because strings are immutable.
    158 	n := 0
    159 	t := s
    160 	for len(s) > 0 {
    161 		_, k := charntorune(s)
    162 		s = s[k:]
    163 		n++
    164 	}
    165 	var a []rune
    166 	if buf != nil && n <= len(buf) {
    167 		a = buf[:n]
    168 	} else {
    169 		a = rawruneslice(n)
    170 	}
    171 	n = 0
    172 	for len(t) > 0 {
    173 		r, k := charntorune(t)
    174 		t = t[k:]
    175 		a[n] = r
    176 		n++
    177 	}
    178 	return a
    179 }
    180 
    181 func slicerunetostring(buf *tmpBuf, a []rune) string {
    182 	if raceenabled && len(a) > 0 {
    183 		racereadrangepc(unsafe.Pointer(&a[0]),
    184 			uintptr(len(a))*unsafe.Sizeof(a[0]),
    185 			getcallerpc(unsafe.Pointer(&a)),
    186 			funcPC(slicerunetostring))
    187 	}
    188 	var dum [4]byte
    189 	size1 := 0
    190 	for _, r := range a {
    191 		size1 += runetochar(dum[:], r)
    192 	}
    193 	s, b := rawstringtmp(buf, size1+3)
    194 	size2 := 0
    195 	for _, r := range a {
    196 		// check for race
    197 		if size2 >= size1 {
    198 			break
    199 		}
    200 		size2 += runetochar(b[size2:], r)
    201 	}
    202 	return s[:size2]
    203 }
    204 
    205 type stringStruct struct {
    206 	str unsafe.Pointer
    207 	len int
    208 }
    209 
    210 func intstring(buf *[4]byte, v int64) string {
    211 	var s string
    212 	var b []byte
    213 	if buf != nil {
    214 		b = buf[:]
    215 		s = slicebytetostringtmp(b)
    216 	} else {
    217 		s, b = rawstring(4)
    218 	}
    219 	n := runetochar(b, rune(v))
    220 	return s[:n]
    221 }
    222 
    223 // stringiter returns the index of the next
    224 // rune after the rune that starts at s[k].
    225 func stringiter(s string, k int) int {
    226 	if k >= len(s) {
    227 		// 0 is end of iteration
    228 		return 0
    229 	}
    230 
    231 	c := s[k]
    232 	if c < runeself {
    233 		return k + 1
    234 	}
    235 
    236 	// multi-char rune
    237 	_, n := charntorune(s[k:])
    238 	return k + n
    239 }
    240 
    241 // stringiter2 returns the rune that starts at s[k]
    242 // and the index where the next rune starts.
    243 func stringiter2(s string, k int) (int, rune) {
    244 	if k >= len(s) {
    245 		// 0 is end of iteration
    246 		return 0, 0
    247 	}
    248 
    249 	c := s[k]
    250 	if c < runeself {
    251 		return k + 1, rune(c)
    252 	}
    253 
    254 	// multi-char rune
    255 	r, n := charntorune(s[k:])
    256 	return k + n, r
    257 }
    258 
    259 // rawstring allocates storage for a new string. The returned
    260 // string and byte slice both refer to the same storage.
    261 // The storage is not zeroed. Callers should use
    262 // b to set the string contents and then drop b.
    263 func rawstring(size int) (s string, b []byte) {
    264 	p := mallocgc(uintptr(size), nil, flagNoScan|flagNoZero)
    265 
    266 	(*stringStruct)(unsafe.Pointer(&s)).str = p
    267 	(*stringStruct)(unsafe.Pointer(&s)).len = size
    268 
    269 	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
    270 
    271 	for {
    272 		ms := maxstring
    273 		if uintptr(size) <= uintptr(ms) || casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), uintptr(ms), uintptr(size)) {
    274 			return
    275 		}
    276 	}
    277 }
    278 
    279 // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
    280 func rawbyteslice(size int) (b []byte) {
    281 	cap := roundupsize(uintptr(size))
    282 	p := mallocgc(cap, nil, flagNoScan|flagNoZero)
    283 	if cap != uintptr(size) {
    284 		memclr(add(p, uintptr(size)), cap-uintptr(size))
    285 	}
    286 
    287 	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
    288 	return
    289 }
    290 
    291 // rawruneslice allocates a new rune slice. The rune slice is not zeroed.
    292 func rawruneslice(size int) (b []rune) {
    293 	if uintptr(size) > _MaxMem/4 {
    294 		throw("out of memory")
    295 	}
    296 	mem := roundupsize(uintptr(size) * 4)
    297 	p := mallocgc(mem, nil, flagNoScan|flagNoZero)
    298 	if mem != uintptr(size)*4 {
    299 		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
    300 	}
    301 
    302 	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
    303 	return
    304 }
    305 
    306 // used by cmd/cgo
    307 func gobytes(p *byte, n int) []byte {
    308 	if n == 0 {
    309 		return make([]byte, 0)
    310 	}
    311 	x := make([]byte, n)
    312 	memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n))
    313 	return x
    314 }
    315 
    316 func gostring(p *byte) string {
    317 	l := findnull(p)
    318 	if l == 0 {
    319 		return ""
    320 	}
    321 	s, b := rawstring(l)
    322 	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
    323 	return s
    324 }
    325 
    326 func gostringn(p *byte, l int) string {
    327 	if l == 0 {
    328 		return ""
    329 	}
    330 	s, b := rawstring(l)
    331 	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
    332 	return s
    333 }
    334 
    335 func index(s, t string) int {
    336 	if len(t) == 0 {
    337 		return 0
    338 	}
    339 	for i := 0; i < len(s); i++ {
    340 		if s[i] == t[0] && hasprefix(s[i:], t) {
    341 			return i
    342 		}
    343 	}
    344 	return -1
    345 }
    346 
    347 func contains(s, t string) bool {
    348 	return index(s, t) >= 0
    349 }
    350 
    351 func hasprefix(s, t string) bool {
    352 	return len(s) >= len(t) && s[:len(t)] == t
    353 }
    354 
    355 func atoi(s string) int {
    356 	n := 0
    357 	for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
    358 		n = n*10 + int(s[0]) - '0'
    359 		s = s[1:]
    360 	}
    361 	return n
    362 }
    363