// Copyright 2014 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package runtimeimport ()// The constant is known to the compiler.// There is no fundamental theory behind this number.const tmpStringBufSize = 32type tmpBuf [tmpStringBufSize]byte// concatstrings implements a Go string concatenation x+y+z+...// The operands are passed in the slice a.// If buf != nil, the compiler has determined that the result does not// escape the calling function, so the string data can be stored in buf// if small enough.func concatstrings( *tmpBuf, []string) string { := 0 := 0 := 0for , := range { := len()if == 0 {continue }if + < {throw("string concatenation too long") } += ++ = }if == 0 {return"" }// If there is just one string and either it is not on the stack // or our result does not escape the calling frame (buf != nil), // then we can return that string directly.if == 1 && ( != nil || !stringDataOnStack([])) {return [] } , := rawstringtmp(, )for , := range {copy(, ) = [len():] }return}func concatstring2( *tmpBuf, , string) string {returnconcatstrings(, []string{, })}func concatstring3( *tmpBuf, , , string) string {returnconcatstrings(, []string{, , })}func concatstring4( *tmpBuf, , , , string) string {returnconcatstrings(, []string{, , , })}func concatstring5( *tmpBuf, , , , , string) string {returnconcatstrings(, []string{, , , , })}// slicebytetostring converts a byte slice to a string.// It is inserted by the compiler into generated code.// ptr is a pointer to the first element of the slice;// n is the length of the slice.// Buf is a fixed-size buffer for the result,// it is not nil if the result does not escape.//// slicebytetostring should be an internal detail,// but widely used packages access it using linkname.// Notable members of the hall of shame include:// - github.com/cloudwego/frugal//// Do not remove or change the type signature.// See go.dev/issue/67401.////go:linkname slicebytetostringfunc slicebytetostring( *tmpBuf, *byte, int) string {if == 0 {// Turns out to be a relatively common case. // Consider that you want to parse out data between parens in "foo()bar", // you find the indices and convert the subslice to string.return"" }ifraceenabled {racereadrangepc(unsafe.Pointer(),uintptr(),getcallerpc(),abi.FuncPCABIInternal()) }ifmsanenabled {msanread(unsafe.Pointer(), uintptr()) }ifasanenabled {asanread(unsafe.Pointer(), uintptr()) }if == 1 { := unsafe.Pointer(&staticuint64s[*])ifgoarch.BigEndian { = add(, 7) }returnunsafe.String((*byte)(), 1) }varunsafe.Pointerif != nil && <= len() { = unsafe.Pointer() } else { = mallocgc(uintptr(), nil, false) }memmove(, unsafe.Pointer(), uintptr())returnunsafe.String((*byte)(), )}// stringDataOnStack reports whether the string's data is// stored on the current goroutine's stack.func stringDataOnStack( string) bool { := uintptr(unsafe.Pointer(unsafe.StringData())) := getg().stackreturn .lo <= && < .hi}func rawstringtmp( *tmpBuf, int) ( string, []byte) {if != nil && <= len() { = [:] = slicebytetostringtmp(&[0], len()) } else { , = rawstring() }return}// slicebytetostringtmp returns a "string" referring to the actual []byte bytes.//// Callers need to ensure that the returned string will not be used after// the calling goroutine modifies the original slice or synchronizes with// another goroutine.//// The function is only called when instrumenting// and otherwise intrinsified by the compiler.//// Some internal compiler optimizations use this function.// - Used for m[T1{... Tn{..., string(k), ...} ...}] and m[string(k)]// where k is []byte, T1 to Tn is a nesting of struct and array literals.// - Used for "<"+string(b)+">" concatenation where b is []byte.// - Used for string(b)=="foo" comparison where b is []byte.func slicebytetostringtmp( *byte, int) string {ifraceenabled && > 0 {racereadrangepc(unsafe.Pointer(),uintptr(),getcallerpc(),abi.FuncPCABIInternal()) }ifmsanenabled && > 0 {msanread(unsafe.Pointer(), uintptr()) }ifasanenabled && > 0 {asanread(unsafe.Pointer(), uintptr()) }returnunsafe.String(, )}func stringtoslicebyte( *tmpBuf, string) []byte {var []byteif != nil && len() <= len() { * = tmpBuf{} = [:len()] } else { = rawbyteslice(len()) }copy(, )return}func stringtoslicerune( *[tmpStringBufSize]rune, string) []rune {// two passes. // unlike slicerunetostring, no race because strings are immutable. := 0forrange { ++ }var []runeif != nil && <= len() { * = [tmpStringBufSize]rune{} = [:] } else { = rawruneslice() } = 0for , := range { [] = ++ }return}func slicerunetostring( *tmpBuf, []rune) string {ifraceenabled && len() > 0 {racereadrangepc(unsafe.Pointer(&[0]),uintptr(len())*unsafe.Sizeof([0]),getcallerpc(),abi.FuncPCABIInternal()) }ifmsanenabled && len() > 0 {msanread(unsafe.Pointer(&[0]), uintptr(len())*unsafe.Sizeof([0])) }ifasanenabled && len() > 0 {asanread(unsafe.Pointer(&[0]), uintptr(len())*unsafe.Sizeof([0])) }var [4]byte := 0for , := range { += encoderune([:], ) } , := rawstringtmp(, +3) := 0for , := range {// check for raceif >= {break } += encoderune([:], ) }return [:]}type stringStruct struct { str unsafe.Pointer len int}// Variant with *byte pointer type for DWARF debugging.type stringStructDWARF struct { str *byte len int}func stringStructOf( *string) *stringStruct {return (*stringStruct)(unsafe.Pointer())}func intstring( *[4]byte, int64) ( string) {var []byteif != nil { = [:] = slicebytetostringtmp(&[0], len()) } else { , = rawstring(4) }ifint64(rune()) != { = runeError } := encoderune(, rune())return [:]}// rawstring allocates storage for a new string. The returned// string and byte slice both refer to the same storage.// The storage is not zeroed. Callers should use// b to set the string contents and then drop b.func rawstring( int) ( string, []byte) { := mallocgc(uintptr(), nil, false)returnunsafe.String((*byte)(), ), unsafe.Slice((*byte)(), )}// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.func rawbyteslice( int) ( []byte) { := roundupsize(uintptr(), true) := mallocgc(, nil, false)if != uintptr() {memclrNoHeapPointers(add(, uintptr()), -uintptr()) } *(*slice)(unsafe.Pointer(&)) = slice{, , int()}return}// rawruneslice allocates a new rune slice. The rune slice is not zeroed.func rawruneslice( int) ( []rune) {ifuintptr() > maxAlloc/4 {throw("out of memory") } := roundupsize(uintptr()*4, true) := mallocgc(, nil, false)if != uintptr()*4 {memclrNoHeapPointers(add(, uintptr()*4), -uintptr()*4) } *(*slice)(unsafe.Pointer(&)) = slice{, , int( / 4)}return}// used by cmd/cgofunc gobytes( *byte, int) ( []byte) {if == 0 {returnmake([]byte, 0) }if < 0 || uintptr() > maxAlloc {panic(errorString("gobytes: length out of range")) } := mallocgc(uintptr(), nil, false)memmove(, unsafe.Pointer(), uintptr()) *(*slice)(unsafe.Pointer(&)) = slice{, , }return}// This is exported via linkname to assembly in syscall (for Plan9) and cgo.////go:linkname gostringfunc gostring( *byte) string { := findnull()if == 0 {return"" } , := rawstring()memmove(unsafe.Pointer(&[0]), unsafe.Pointer(), uintptr())return}// internal_syscall_gostring is a version of gostring for internal/syscall/unix.////go:linkname internal_syscall_gostring internal/syscall/unix.gostringfunc internal_syscall_gostring( *byte) string {returngostring()}func gostringn( *byte, int) string {if == 0 {return"" } , := rawstring()memmove(unsafe.Pointer(&[0]), unsafe.Pointer(), uintptr())return}const ( maxUint64 = ^uint64(0) maxInt64 = int64(maxUint64 >> 1))// atoi64 parses an int64 from a string s.// The bool result reports whether s is a number// representable by a value of type int64.func atoi64( string) (int64, bool) {if == "" {return0, false } := falseif [0] == '-' { = true = [1:] } := uint64(0)for := 0; < len(); ++ { := []if < '0' || > '9' {return0, false }if > maxUint64/10 {// overflowreturn0, false } *= 10 := + uint64() - '0'if < {// overflowreturn0, false } = }if ! && > uint64(maxInt64) {return0, false }if && > uint64(maxInt64)+1 {return0, false } := int64()if { = - }return , true}// atoi is like atoi64 but for integers// that fit into an int.func atoi( string) (int, bool) {if , := atoi64(); == int64(int()) {returnint(), }return0, false}// atoi32 is like atoi but for integers// that fit into an int32.func atoi32( string) (int32, bool) {if , := atoi64(); == int64(int32()) {returnint32(), }return0, false}// parseByteCount parses a string that represents a count of bytes.//// s must match the following regular expression://// ^[0-9]+(([KMGT]i)?B)?$//// In other words, an integer byte count with an optional unit// suffix. Acceptable suffixes include one of// - KiB, MiB, GiB, TiB which represent binary IEC/ISO 80000 units, or// - B, which just represents bytes.//// Returns an int64 because that's what its callers want and receive,// but the result is always non-negative.func parseByteCount( string) (int64, bool) {// The empty string is not valid.if == "" {return0, false }// Handle the easy non-suffix case. := [len()-1]if >= '0' && <= '9' { , := atoi64()if ! || < 0 {return0, false }return , }// Failing a trailing digit, this must always end in 'B'. // Also at this point there must be at least one digit before // that B.if != 'B' || len() < 2 {return0, false }// The one before that must always be a digit or 'i'.if := [len()-2]; >= '0' && <= '9' {// Trivial 'B' suffix. , := atoi64([:len()-1])if ! || < 0 {return0, false }return , } elseif != 'i' {return0, false }// Finally, we need at least 4 characters now, for the unit // prefix and at least one digit.iflen() < 4 {return0, false } := 0switch [len()-3] {case'K': = 1case'M': = 2case'G': = 3case'T': = 4default:// Invalid suffix.return0, false } := uint64(1)for := 0; < ; ++ { *= 1024 } , := atoi64([:len()-3])if ! || < 0 {return0, false } := uint64()if > maxUint64/ {// Overflow.return0, false } *= if > uint64(maxInt64) {// Overflow.return0, false }returnint64(), true}//go:nosplitfunc findnull( *byte) int {if == nil {return0 }// Avoid IndexByteString on Plan 9 because it uses SSE instructions // on x86 machines, and those are classified as floating point instructions, // which are illegal in a note handler.ifGOOS == "plan9" { := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer()) := 0for [] != 0 { ++ }return }// pageSize is the unit we scan at a time looking for NULL. // It must be the minimum page size for any architecture Go // runs on. It's okay (just a minor performance loss) if the // actual system page size is larger than this value.const = 4096 := 0 := unsafe.Pointer()// IndexByteString uses wide reads, so we need to be careful // with page boundaries. Call IndexByteString on // [ptr, endOfPage) interval. := int( - uintptr()%)for { := *(*string)(unsafe.Pointer(&stringStruct{, }))// Check one page at a time.if := bytealg.IndexByteString(, 0); != -1 {return + }// Move to next page = unsafe.Pointer(uintptr() + uintptr()) += = }}func findnullw( *uint16) int {if == nil {return0 } := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer()) := 0for [] != 0 { ++ }return}//go:nosplitfunc gostringnocopy( *byte) string { := stringStruct{str: unsafe.Pointer(), len: findnull()} := *(*string)(unsafe.Pointer(&))return}func gostringw( *uint16) string {var [8]byte := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer()) := 0for := 0; [] != 0; ++ { += encoderune([:], rune([])) } , := rawstring( + 4) := 0for := 0; [] != 0; ++ {// check for raceif >= {break } += encoderune([:], rune([])) } [] = 0// for luckreturn [:]}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.