...

Source file src/runtime/string.go

Documentation: 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  	"internal/bytealg"
		 9  	"runtime/internal/sys"
		10  	"unsafe"
		11  )
		12  
		13  // The constant is known to the compiler.
		14  // There is no fundamental theory behind this number.
		15  const tmpStringBufSize = 32
		16  
		17  type tmpBuf [tmpStringBufSize]byte
		18  
		19  // concatstrings implements a Go string concatenation x+y+z+...
		20  // The operands are passed in the slice a.
		21  // If buf != nil, the compiler has determined that the result does not
		22  // escape the calling function, so the string data can be stored in buf
		23  // if small enough.
		24  func concatstrings(buf *tmpBuf, a []string) string {
		25  	idx := 0
		26  	l := 0
		27  	count := 0
		28  	for i, x := range a {
		29  		n := len(x)
		30  		if n == 0 {
		31  			continue
		32  		}
		33  		if l+n < l {
		34  			throw("string concatenation too long")
		35  		}
		36  		l += n
		37  		count++
		38  		idx = i
		39  	}
		40  	if count == 0 {
		41  		return ""
		42  	}
		43  
		44  	// If there is just one string and either it is not on the stack
		45  	// or our result does not escape the calling frame (buf != nil),
		46  	// then we can return that string directly.
		47  	if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
		48  		return a[idx]
		49  	}
		50  	s, b := rawstringtmp(buf, l)
		51  	for _, x := range a {
		52  		copy(b, x)
		53  		b = b[len(x):]
		54  	}
		55  	return s
		56  }
		57  
		58  func concatstring2(buf *tmpBuf, a0, a1 string) string {
		59  	return concatstrings(buf, []string{a0, a1})
		60  }
		61  
		62  func concatstring3(buf *tmpBuf, a0, a1, a2 string) string {
		63  	return concatstrings(buf, []string{a0, a1, a2})
		64  }
		65  
		66  func concatstring4(buf *tmpBuf, a0, a1, a2, a3 string) string {
		67  	return concatstrings(buf, []string{a0, a1, a2, a3})
		68  }
		69  
		70  func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string {
		71  	return concatstrings(buf, []string{a0, a1, a2, a3, a4})
		72  }
		73  
		74  // slicebytetostring converts a byte slice to a string.
		75  // It is inserted by the compiler into generated code.
		76  // ptr is a pointer to the first element of the slice;
		77  // n is the length of the slice.
		78  // Buf is a fixed-size buffer for the result,
		79  // it is not nil if the result does not escape.
		80  func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
		81  	if n == 0 {
		82  		// Turns out to be a relatively common case.
		83  		// Consider that you want to parse out data between parens in "foo()bar",
		84  		// you find the indices and convert the subslice to string.
		85  		return ""
		86  	}
		87  	if raceenabled {
		88  		racereadrangepc(unsafe.Pointer(ptr),
		89  			uintptr(n),
		90  			getcallerpc(),
		91  			funcPC(slicebytetostring))
		92  	}
		93  	if msanenabled {
		94  		msanread(unsafe.Pointer(ptr), uintptr(n))
		95  	}
		96  	if n == 1 {
		97  		p := unsafe.Pointer(&staticuint64s[*ptr])
		98  		if sys.BigEndian {
		99  			p = add(p, 7)
	 100  		}
	 101  		stringStructOf(&str).str = p
	 102  		stringStructOf(&str).len = 1
	 103  		return
	 104  	}
	 105  
	 106  	var p unsafe.Pointer
	 107  	if buf != nil && n <= len(buf) {
	 108  		p = unsafe.Pointer(buf)
	 109  	} else {
	 110  		p = mallocgc(uintptr(n), nil, false)
	 111  	}
	 112  	stringStructOf(&str).str = p
	 113  	stringStructOf(&str).len = n
	 114  	memmove(p, unsafe.Pointer(ptr), uintptr(n))
	 115  	return
	 116  }
	 117  
	 118  // stringDataOnStack reports whether the string's data is
	 119  // stored on the current goroutine's stack.
	 120  func stringDataOnStack(s string) bool {
	 121  	ptr := uintptr(stringStructOf(&s).str)
	 122  	stk := getg().stack
	 123  	return stk.lo <= ptr && ptr < stk.hi
	 124  }
	 125  
	 126  func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
	 127  	if buf != nil && l <= len(buf) {
	 128  		b = buf[:l]
	 129  		s = slicebytetostringtmp(&b[0], len(b))
	 130  	} else {
	 131  		s, b = rawstring(l)
	 132  	}
	 133  	return
	 134  }
	 135  
	 136  // slicebytetostringtmp returns a "string" referring to the actual []byte bytes.
	 137  //
	 138  // Callers need to ensure that the returned string will not be used after
	 139  // the calling goroutine modifies the original slice or synchronizes with
	 140  // another goroutine.
	 141  //
	 142  // The function is only called when instrumenting
	 143  // and otherwise intrinsified by the compiler.
	 144  //
	 145  // Some internal compiler optimizations use this function.
	 146  // - Used for m[T1{... Tn{..., string(k), ...} ...}] and m[string(k)]
	 147  //	 where k is []byte, T1 to Tn is a nesting of struct and array literals.
	 148  // - Used for "<"+string(b)+">" concatenation where b is []byte.
	 149  // - Used for string(b)=="foo" comparison where b is []byte.
	 150  func slicebytetostringtmp(ptr *byte, n int) (str string) {
	 151  	if raceenabled && n > 0 {
	 152  		racereadrangepc(unsafe.Pointer(ptr),
	 153  			uintptr(n),
	 154  			getcallerpc(),
	 155  			funcPC(slicebytetostringtmp))
	 156  	}
	 157  	if msanenabled && n > 0 {
	 158  		msanread(unsafe.Pointer(ptr), uintptr(n))
	 159  	}
	 160  	stringStructOf(&str).str = unsafe.Pointer(ptr)
	 161  	stringStructOf(&str).len = n
	 162  	return
	 163  }
	 164  
	 165  func stringtoslicebyte(buf *tmpBuf, s string) []byte {
	 166  	var b []byte
	 167  	if buf != nil && len(s) <= len(buf) {
	 168  		*buf = tmpBuf{}
	 169  		b = buf[:len(s)]
	 170  	} else {
	 171  		b = rawbyteslice(len(s))
	 172  	}
	 173  	copy(b, s)
	 174  	return b
	 175  }
	 176  
	 177  func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
	 178  	// two passes.
	 179  	// unlike slicerunetostring, no race because strings are immutable.
	 180  	n := 0
	 181  	for range s {
	 182  		n++
	 183  	}
	 184  
	 185  	var a []rune
	 186  	if buf != nil && n <= len(buf) {
	 187  		*buf = [tmpStringBufSize]rune{}
	 188  		a = buf[:n]
	 189  	} else {
	 190  		a = rawruneslice(n)
	 191  	}
	 192  
	 193  	n = 0
	 194  	for _, r := range s {
	 195  		a[n] = r
	 196  		n++
	 197  	}
	 198  	return a
	 199  }
	 200  
	 201  func slicerunetostring(buf *tmpBuf, a []rune) string {
	 202  	if raceenabled && len(a) > 0 {
	 203  		racereadrangepc(unsafe.Pointer(&a[0]),
	 204  			uintptr(len(a))*unsafe.Sizeof(a[0]),
	 205  			getcallerpc(),
	 206  			funcPC(slicerunetostring))
	 207  	}
	 208  	if msanenabled && len(a) > 0 {
	 209  		msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
	 210  	}
	 211  	var dum [4]byte
	 212  	size1 := 0
	 213  	for _, r := range a {
	 214  		size1 += encoderune(dum[:], r)
	 215  	}
	 216  	s, b := rawstringtmp(buf, size1+3)
	 217  	size2 := 0
	 218  	for _, r := range a {
	 219  		// check for race
	 220  		if size2 >= size1 {
	 221  			break
	 222  		}
	 223  		size2 += encoderune(b[size2:], r)
	 224  	}
	 225  	return s[:size2]
	 226  }
	 227  
	 228  type stringStruct struct {
	 229  	str unsafe.Pointer
	 230  	len int
	 231  }
	 232  
	 233  // Variant with *byte pointer type for DWARF debugging.
	 234  type stringStructDWARF struct {
	 235  	str *byte
	 236  	len int
	 237  }
	 238  
	 239  func stringStructOf(sp *string) *stringStruct {
	 240  	return (*stringStruct)(unsafe.Pointer(sp))
	 241  }
	 242  
	 243  func intstring(buf *[4]byte, v int64) (s string) {
	 244  	var b []byte
	 245  	if buf != nil {
	 246  		b = buf[:]
	 247  		s = slicebytetostringtmp(&b[0], len(b))
	 248  	} else {
	 249  		s, b = rawstring(4)
	 250  	}
	 251  	if int64(rune(v)) != v {
	 252  		v = runeError
	 253  	}
	 254  	n := encoderune(b, rune(v))
	 255  	return s[:n]
	 256  }
	 257  
	 258  // rawstring allocates storage for a new string. The returned
	 259  // string and byte slice both refer to the same storage.
	 260  // The storage is not zeroed. Callers should use
	 261  // b to set the string contents and then drop b.
	 262  func rawstring(size int) (s string, b []byte) {
	 263  	p := mallocgc(uintptr(size), nil, false)
	 264  
	 265  	stringStructOf(&s).str = p
	 266  	stringStructOf(&s).len = size
	 267  
	 268  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
	 269  
	 270  	return
	 271  }
	 272  
	 273  // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
	 274  func rawbyteslice(size int) (b []byte) {
	 275  	cap := roundupsize(uintptr(size))
	 276  	p := mallocgc(cap, nil, false)
	 277  	if cap != uintptr(size) {
	 278  		memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
	 279  	}
	 280  
	 281  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
	 282  	return
	 283  }
	 284  
	 285  // rawruneslice allocates a new rune slice. The rune slice is not zeroed.
	 286  func rawruneslice(size int) (b []rune) {
	 287  	if uintptr(size) > maxAlloc/4 {
	 288  		throw("out of memory")
	 289  	}
	 290  	mem := roundupsize(uintptr(size) * 4)
	 291  	p := mallocgc(mem, nil, false)
	 292  	if mem != uintptr(size)*4 {
	 293  		memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
	 294  	}
	 295  
	 296  	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
	 297  	return
	 298  }
	 299  
	 300  // used by cmd/cgo
	 301  func gobytes(p *byte, n int) (b []byte) {
	 302  	if n == 0 {
	 303  		return make([]byte, 0)
	 304  	}
	 305  
	 306  	if n < 0 || uintptr(n) > maxAlloc {
	 307  		panic(errorString("gobytes: length out of range"))
	 308  	}
	 309  
	 310  	bp := mallocgc(uintptr(n), nil, false)
	 311  	memmove(bp, unsafe.Pointer(p), uintptr(n))
	 312  
	 313  	*(*slice)(unsafe.Pointer(&b)) = slice{bp, n, n}
	 314  	return
	 315  }
	 316  
	 317  // This is exported via linkname to assembly in syscall (for Plan9).
	 318  //go:linkname gostring
	 319  func gostring(p *byte) string {
	 320  	l := findnull(p)
	 321  	if l == 0 {
	 322  		return ""
	 323  	}
	 324  	s, b := rawstring(l)
	 325  	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
	 326  	return s
	 327  }
	 328  
	 329  func gostringn(p *byte, l int) string {
	 330  	if l == 0 {
	 331  		return ""
	 332  	}
	 333  	s, b := rawstring(l)
	 334  	memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
	 335  	return s
	 336  }
	 337  
	 338  func hasPrefix(s, prefix string) bool {
	 339  	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
	 340  }
	 341  
	 342  const (
	 343  	maxUint = ^uint(0)
	 344  	maxInt	= int(maxUint >> 1)
	 345  )
	 346  
	 347  // atoi parses an int from a string s.
	 348  // The bool result reports whether s is a number
	 349  // representable by a value of type int.
	 350  func atoi(s string) (int, bool) {
	 351  	if s == "" {
	 352  		return 0, false
	 353  	}
	 354  
	 355  	neg := false
	 356  	if s[0] == '-' {
	 357  		neg = true
	 358  		s = s[1:]
	 359  	}
	 360  
	 361  	un := uint(0)
	 362  	for i := 0; i < len(s); i++ {
	 363  		c := s[i]
	 364  		if c < '0' || c > '9' {
	 365  			return 0, false
	 366  		}
	 367  		if un > maxUint/10 {
	 368  			// overflow
	 369  			return 0, false
	 370  		}
	 371  		un *= 10
	 372  		un1 := un + uint(c) - '0'
	 373  		if un1 < un {
	 374  			// overflow
	 375  			return 0, false
	 376  		}
	 377  		un = un1
	 378  	}
	 379  
	 380  	if !neg && un > uint(maxInt) {
	 381  		return 0, false
	 382  	}
	 383  	if neg && un > uint(maxInt)+1 {
	 384  		return 0, false
	 385  	}
	 386  
	 387  	n := int(un)
	 388  	if neg {
	 389  		n = -n
	 390  	}
	 391  
	 392  	return n, true
	 393  }
	 394  
	 395  // atoi32 is like atoi but for integers
	 396  // that fit into an int32.
	 397  func atoi32(s string) (int32, bool) {
	 398  	if n, ok := atoi(s); n == int(int32(n)) {
	 399  		return int32(n), ok
	 400  	}
	 401  	return 0, false
	 402  }
	 403  
	 404  //go:nosplit
	 405  func findnull(s *byte) int {
	 406  	if s == nil {
	 407  		return 0
	 408  	}
	 409  
	 410  	// Avoid IndexByteString on Plan 9 because it uses SSE instructions
	 411  	// on x86 machines, and those are classified as floating point instructions,
	 412  	// which are illegal in a note handler.
	 413  	if GOOS == "plan9" {
	 414  		p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
	 415  		l := 0
	 416  		for p[l] != 0 {
	 417  			l++
	 418  		}
	 419  		return l
	 420  	}
	 421  
	 422  	// pageSize is the unit we scan at a time looking for NULL.
	 423  	// It must be the minimum page size for any architecture Go
	 424  	// runs on. It's okay (just a minor performance loss) if the
	 425  	// actual system page size is larger than this value.
	 426  	const pageSize = 4096
	 427  
	 428  	offset := 0
	 429  	ptr := unsafe.Pointer(s)
	 430  	// IndexByteString uses wide reads, so we need to be careful
	 431  	// with page boundaries. Call IndexByteString on
	 432  	// [ptr, endOfPage) interval.
	 433  	safeLen := int(pageSize - uintptr(ptr)%pageSize)
	 434  
	 435  	for {
	 436  		t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
	 437  		// Check one page at a time.
	 438  		if i := bytealg.IndexByteString(t, 0); i != -1 {
	 439  			return offset + i
	 440  		}
	 441  		// Move to next page
	 442  		ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
	 443  		offset += safeLen
	 444  		safeLen = pageSize
	 445  	}
	 446  }
	 447  
	 448  func findnullw(s *uint16) int {
	 449  	if s == nil {
	 450  		return 0
	 451  	}
	 452  	p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
	 453  	l := 0
	 454  	for p[l] != 0 {
	 455  		l++
	 456  	}
	 457  	return l
	 458  }
	 459  
	 460  //go:nosplit
	 461  func gostringnocopy(str *byte) string {
	 462  	ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
	 463  	s := *(*string)(unsafe.Pointer(&ss))
	 464  	return s
	 465  }
	 466  
	 467  func gostringw(strw *uint16) string {
	 468  	var buf [8]byte
	 469  	str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
	 470  	n1 := 0
	 471  	for i := 0; str[i] != 0; i++ {
	 472  		n1 += encoderune(buf[:], rune(str[i]))
	 473  	}
	 474  	s, b := rawstring(n1 + 4)
	 475  	n2 := 0
	 476  	for i := 0; str[i] != 0; i++ {
	 477  		// check for race
	 478  		if n2 >= n1 {
	 479  			break
	 480  		}
	 481  		n2 += encoderune(b[n2:], rune(str[i]))
	 482  	}
	 483  	b[n2] = 0 // for luck
	 484  	return s[:n2]
	 485  }
	 486  

View as plain text