Black Lives Matter. Support the Equal Justice Initiative.

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, a [2]string) string {
    59  	return concatstrings(buf, a[:])
    60  }
    61  
    62  func concatstring3(buf *tmpBuf, a [3]string) string {
    63  	return concatstrings(buf, a[:])
    64  }
    65  
    66  func concatstring4(buf *tmpBuf, a [4]string) string {
    67  	return concatstrings(buf, a[:])
    68  }
    69  
    70  func concatstring5(buf *tmpBuf, a [5]string) string {
    71  	return concatstrings(buf, a[:])
    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 index(s, t string) int {
   339  	if len(t) == 0 {
   340  		return 0
   341  	}
   342  	for i := 0; i < len(s); i++ {
   343  		if s[i] == t[0] && hasPrefix(s[i:], t) {
   344  			return i
   345  		}
   346  	}
   347  	return -1
   348  }
   349  
   350  func contains(s, t string) bool {
   351  	return index(s, t) >= 0
   352  }
   353  
   354  func hasPrefix(s, prefix string) bool {
   355  	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
   356  }
   357  
   358  const (
   359  	maxUint = ^uint(0)
   360  	maxInt  = int(maxUint >> 1)
   361  )
   362  
   363  // atoi parses an int from a string s.
   364  // The bool result reports whether s is a number
   365  // representable by a value of type int.
   366  func atoi(s string) (int, bool) {
   367  	if s == "" {
   368  		return 0, false
   369  	}
   370  
   371  	neg := false
   372  	if s[0] == '-' {
   373  		neg = true
   374  		s = s[1:]
   375  	}
   376  
   377  	un := uint(0)
   378  	for i := 0; i < len(s); i++ {
   379  		c := s[i]
   380  		if c < '0' || c > '9' {
   381  			return 0, false
   382  		}
   383  		if un > maxUint/10 {
   384  			// overflow
   385  			return 0, false
   386  		}
   387  		un *= 10
   388  		un1 := un + uint(c) - '0'
   389  		if un1 < un {
   390  			// overflow
   391  			return 0, false
   392  		}
   393  		un = un1
   394  	}
   395  
   396  	if !neg && un > uint(maxInt) {
   397  		return 0, false
   398  	}
   399  	if neg && un > uint(maxInt)+1 {
   400  		return 0, false
   401  	}
   402  
   403  	n := int(un)
   404  	if neg {
   405  		n = -n
   406  	}
   407  
   408  	return n, true
   409  }
   410  
   411  // atoi32 is like atoi but for integers
   412  // that fit into an int32.
   413  func atoi32(s string) (int32, bool) {
   414  	if n, ok := atoi(s); n == int(int32(n)) {
   415  		return int32(n), ok
   416  	}
   417  	return 0, false
   418  }
   419  
   420  //go:nosplit
   421  func findnull(s *byte) int {
   422  	if s == nil {
   423  		return 0
   424  	}
   425  
   426  	// Avoid IndexByteString on Plan 9 because it uses SSE instructions
   427  	// on x86 machines, and those are classified as floating point instructions,
   428  	// which are illegal in a note handler.
   429  	if GOOS == "plan9" {
   430  		p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
   431  		l := 0
   432  		for p[l] != 0 {
   433  			l++
   434  		}
   435  		return l
   436  	}
   437  
   438  	// pageSize is the unit we scan at a time looking for NULL.
   439  	// It must be the minimum page size for any architecture Go
   440  	// runs on. It's okay (just a minor performance loss) if the
   441  	// actual system page size is larger than this value.
   442  	const pageSize = 4096
   443  
   444  	offset := 0
   445  	ptr := unsafe.Pointer(s)
   446  	// IndexByteString uses wide reads, so we need to be careful
   447  	// with page boundaries. Call IndexByteString on
   448  	// [ptr, endOfPage) interval.
   449  	safeLen := int(pageSize - uintptr(ptr)%pageSize)
   450  
   451  	for {
   452  		t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
   453  		// Check one page at a time.
   454  		if i := bytealg.IndexByteString(t, 0); i != -1 {
   455  			return offset + i
   456  		}
   457  		// Move to next page
   458  		ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
   459  		offset += safeLen
   460  		safeLen = pageSize
   461  	}
   462  }
   463  
   464  func findnullw(s *uint16) int {
   465  	if s == nil {
   466  		return 0
   467  	}
   468  	p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
   469  	l := 0
   470  	for p[l] != 0 {
   471  		l++
   472  	}
   473  	return l
   474  }
   475  
   476  //go:nosplit
   477  func gostringnocopy(str *byte) string {
   478  	ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
   479  	s := *(*string)(unsafe.Pointer(&ss))
   480  	return s
   481  }
   482  
   483  func gostringw(strw *uint16) string {
   484  	var buf [8]byte
   485  	str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
   486  	n1 := 0
   487  	for i := 0; str[i] != 0; i++ {
   488  		n1 += encoderune(buf[:], rune(str[i]))
   489  	}
   490  	s, b := rawstring(n1 + 4)
   491  	n2 := 0
   492  	for i := 0; str[i] != 0; i++ {
   493  		// check for race
   494  		if n2 >= n1 {
   495  			break
   496  		}
   497  		n2 += encoderune(b[n2:], rune(str[i]))
   498  	}
   499  	b[n2] = 0 // for luck
   500  	return s[:n2]
   501  }
   502  
   503  // parseRelease parses a dot-separated version number. It follows the
   504  // semver syntax, but allows the minor and patch versions to be
   505  // elided.
   506  func parseRelease(rel string) (major, minor, patch int, ok bool) {
   507  	// Strip anything after a dash or plus.
   508  	for i := 0; i < len(rel); i++ {
   509  		if rel[i] == '-' || rel[i] == '+' {
   510  			rel = rel[:i]
   511  			break
   512  		}
   513  	}
   514  
   515  	next := func() (int, bool) {
   516  		for i := 0; i < len(rel); i++ {
   517  			if rel[i] == '.' {
   518  				ver, ok := atoi(rel[:i])
   519  				rel = rel[i+1:]
   520  				return ver, ok
   521  			}
   522  		}
   523  		ver, ok := atoi(rel)
   524  		rel = ""
   525  		return ver, ok
   526  	}
   527  	if major, ok = next(); !ok || rel == "" {
   528  		return
   529  	}
   530  	if minor, ok = next(); !ok || rel == "" {
   531  		return
   532  	}
   533  	patch, ok = next()
   534  	return
   535  }
   536  

View as plain text