...
Run Format

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

View as plain text