Source file
src/runtime/string.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/bytealg"
10 "internal/goarch"
11 "internal/runtime/math"
12 "internal/runtime/strconv"
13 "internal/runtime/sys"
14 "unsafe"
15 )
16
17
18
19 const tmpStringBufSize = 32
20
21 type tmpBuf [tmpStringBufSize]byte
22
23
24
25
26
27
28 func concatstrings(buf *tmpBuf, a []string) string {
29 idx := 0
30 l := 0
31 count := 0
32 for i, x := range a {
33 n := len(x)
34 if n == 0 {
35 continue
36 }
37 if l+n < l {
38 throw("string concatenation too long")
39 }
40 l += n
41 count++
42 idx = i
43 }
44 if count == 0 {
45 return ""
46 }
47
48
49
50
51 if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
52 return a[idx]
53 }
54 s, b := rawstringtmp(buf, l)
55 for _, x := range a {
56 n := copy(b, x)
57 b = b[n:]
58 }
59 return s
60 }
61
62
63
64
65 func concatstring2(buf *tmpBuf, a0, a1 string) string {
66 return concatstrings(buf, []string{a0, a1})
67 }
68
69 func concatstring3(buf *tmpBuf, a0, a1, a2 string) string {
70 return concatstrings(buf, []string{a0, a1, a2})
71 }
72
73 func concatstring4(buf *tmpBuf, a0, a1, a2, a3 string) string {
74 return concatstrings(buf, []string{a0, a1, a2, a3})
75 }
76
77 func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string {
78 return concatstrings(buf, []string{a0, a1, a2, a3, a4})
79 }
80
81
82
83
84 func concatbytes(buf *tmpBuf, a []string) []byte {
85 l := 0
86 for _, x := range a {
87 n := len(x)
88 if l+n < l {
89 throw("string concatenation too long")
90 }
91 l += n
92 }
93 if l == 0 {
94
95 return []byte{}
96 }
97
98 var b []byte
99 if buf != nil && l <= len(buf) {
100 *buf = tmpBuf{}
101 b = buf[:l]
102 } else {
103 b = rawbyteslice(l)
104 }
105 offset := 0
106 for _, x := range a {
107 copy(b[offset:], x)
108 offset += len(x)
109 }
110
111 return b
112 }
113
114
115
116
117 func concatbyte2(buf *tmpBuf, a0, a1 string) []byte {
118 return concatbytes(buf, []string{a0, a1})
119 }
120
121 func concatbyte3(buf *tmpBuf, a0, a1, a2 string) []byte {
122 return concatbytes(buf, []string{a0, a1, a2})
123 }
124
125 func concatbyte4(buf *tmpBuf, a0, a1, a2, a3 string) []byte {
126 return concatbytes(buf, []string{a0, a1, a2, a3})
127 }
128
129 func concatbyte5(buf *tmpBuf, a0, a1, a2, a3, a4 string) []byte {
130 return concatbytes(buf, []string{a0, a1, a2, a3, a4})
131 }
132
133
134
135
136
137
138
139 func slicebytetostring(buf *tmpBuf, ptr *byte, n int) string {
140 if n == 0 {
141
142
143
144 return ""
145 }
146 if raceenabled {
147 racereadrangepc(unsafe.Pointer(ptr),
148 uintptr(n),
149 sys.GetCallerPC(),
150 abi.FuncPCABIInternal(slicebytetostring))
151 }
152 if msanenabled {
153 msanread(unsafe.Pointer(ptr), uintptr(n))
154 }
155 if asanenabled {
156 asanread(unsafe.Pointer(ptr), uintptr(n))
157 }
158 if n == 1 {
159 p := unsafe.Pointer(&staticuint64s[*ptr])
160 if goarch.BigEndian {
161 p = add(p, 7)
162 }
163 return unsafe.String((*byte)(p), 1)
164 }
165
166 var p unsafe.Pointer
167 if buf != nil && n <= len(buf) {
168 p = unsafe.Pointer(buf)
169 } else {
170 p = mallocgc(uintptr(n), nil, false)
171 }
172 memmove(p, unsafe.Pointer(ptr), uintptr(n))
173 return unsafe.String((*byte)(p), n)
174 }
175
176
177
178 func stringDataOnStack(s string) bool {
179 ptr := uintptr(unsafe.Pointer(unsafe.StringData(s)))
180 stk := getg().stack
181 return stk.lo <= ptr && ptr < stk.hi
182 }
183
184 func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
185 if buf != nil && l <= len(buf) {
186 b = buf[:l]
187 s = slicebytetostringtmp(&b[0], len(b))
188 } else {
189 s, b = rawstring(l)
190 }
191 return
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 func slicebytetostringtmp(ptr *byte, n int) string {
209 if raceenabled && n > 0 {
210 racereadrangepc(unsafe.Pointer(ptr),
211 uintptr(n),
212 sys.GetCallerPC(),
213 abi.FuncPCABIInternal(slicebytetostringtmp))
214 }
215 if msanenabled && n > 0 {
216 msanread(unsafe.Pointer(ptr), uintptr(n))
217 }
218 if asanenabled && n > 0 {
219 asanread(unsafe.Pointer(ptr), uintptr(n))
220 }
221 return unsafe.String(ptr, n)
222 }
223
224 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
225 var b []byte
226 if buf != nil && len(s) <= len(buf) {
227 *buf = tmpBuf{}
228 b = buf[:len(s)]
229 } else {
230 b = rawbyteslice(len(s))
231 }
232 copy(b, s)
233 return b
234 }
235
236 func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
237
238
239 n := 0
240 for range s {
241 n++
242 }
243
244 var a []rune
245 if buf != nil && n <= len(buf) {
246 *buf = [tmpStringBufSize]rune{}
247 a = buf[:n]
248 } else {
249 a = rawruneslice(n)
250 }
251
252 n = 0
253 for _, r := range s {
254 a[n] = r
255 n++
256 }
257 return a
258 }
259
260 func slicerunetostring(buf *tmpBuf, a []rune) string {
261 if raceenabled && len(a) > 0 {
262 racereadrangepc(unsafe.Pointer(&a[0]),
263 uintptr(len(a))*unsafe.Sizeof(a[0]),
264 sys.GetCallerPC(),
265 abi.FuncPCABIInternal(slicerunetostring))
266 }
267 if msanenabled && len(a) > 0 {
268 msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
269 }
270 if asanenabled && len(a) > 0 {
271 asanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
272 }
273 var dum [4]byte
274 size1 := 0
275 for _, r := range a {
276 size1 += encoderune(dum[:], r)
277 }
278 s, b := rawstringtmp(buf, size1+3)
279 size2 := 0
280 for _, r := range a {
281
282 if size2 >= size1 {
283 break
284 }
285 size2 += encoderune(b[size2:], r)
286 }
287 return s[:size2]
288 }
289
290 type stringStruct struct {
291 str unsafe.Pointer
292 len int
293 }
294
295
296 type stringStructDWARF struct {
297 str *byte
298 len int
299 }
300
301 func stringStructOf(sp *string) *stringStruct {
302 return (*stringStruct)(unsafe.Pointer(sp))
303 }
304
305 func intstring(buf *[4]byte, v int64) (s string) {
306 var b []byte
307 if buf != nil {
308 b = buf[:]
309 s = slicebytetostringtmp(&b[0], len(b))
310 } else {
311 s, b = rawstring(4)
312 }
313 if int64(rune(v)) != v {
314 v = runeError
315 }
316 n := encoderune(b, rune(v))
317 return s[:n]
318 }
319
320
321
322
323
324 func rawstring(size int) (s string, b []byte) {
325 p := mallocgc(uintptr(size), nil, false)
326 return unsafe.String((*byte)(p), size), unsafe.Slice((*byte)(p), size)
327 }
328
329
330 func rawbyteslice(size int) (b []byte) {
331 cap := roundupsize(uintptr(size), true)
332 p := mallocgc(cap, nil, false)
333 if cap != uintptr(size) {
334 memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
335 }
336
337 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
338 return
339 }
340
341
342 func rawruneslice(size int) (b []rune) {
343 if uintptr(size) > maxAlloc/4 {
344 throw("out of memory")
345 }
346 mem := roundupsize(uintptr(size)*4, true)
347 p := mallocgc(mem, nil, false)
348 if mem != uintptr(size)*4 {
349 memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
350 }
351
352 *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
353 return
354 }
355
356
357 func gobytes(p *byte, n int) (b []byte) {
358 if n == 0 {
359 return make([]byte, 0)
360 }
361
362 if n < 0 || uintptr(n) > maxAlloc {
363 panic(errorString("gobytes: length out of range"))
364 }
365
366 bp := mallocgc(uintptr(n), nil, false)
367 memmove(bp, unsafe.Pointer(p), uintptr(n))
368
369 *(*slice)(unsafe.Pointer(&b)) = slice{bp, n, n}
370 return
371 }
372
373
374
375
376 func gostring(p *byte) string {
377 l := findnull(p)
378 if l == 0 {
379 return ""
380 }
381 s, b := rawstring(l)
382 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
383 return s
384 }
385
386
387
388
389 func internal_syscall_gostring(p *byte) string {
390 return gostring(p)
391 }
392
393 func gostringn(p *byte, l int) string {
394 if l == 0 {
395 return ""
396 }
397 s, b := rawstring(l)
398 memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))
399 return s
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 func parseByteCount(s string) (int64, bool) {
416
417 if s == "" {
418 return 0, false
419 }
420
421 last := s[len(s)-1]
422 if last >= '0' && last <= '9' {
423 n, ok := strconv.Atoi64(s)
424 if !ok || n < 0 {
425 return 0, false
426 }
427 return n, ok
428 }
429
430
431
432 if last != 'B' || len(s) < 2 {
433 return 0, false
434 }
435
436 if c := s[len(s)-2]; c >= '0' && c <= '9' {
437
438 n, ok := strconv.Atoi64(s[:len(s)-1])
439 if !ok || n < 0 {
440 return 0, false
441 }
442 return n, ok
443 } else if c != 'i' {
444 return 0, false
445 }
446
447
448 if len(s) < 4 {
449 return 0, false
450 }
451 power := 0
452 switch s[len(s)-3] {
453 case 'K':
454 power = 1
455 case 'M':
456 power = 2
457 case 'G':
458 power = 3
459 case 'T':
460 power = 4
461 default:
462
463 return 0, false
464 }
465 m := uint64(1)
466 for i := 0; i < power; i++ {
467 m *= 1024
468 }
469 n, ok := strconv.Atoi64(s[:len(s)-3])
470 if !ok || n < 0 {
471 return 0, false
472 }
473 un := uint64(n)
474 if un > math.MaxUint64/m {
475
476 return 0, false
477 }
478 un *= m
479 if un > uint64(math.MaxInt64) {
480
481 return 0, false
482 }
483 return int64(un), true
484 }
485
486
487 func findnull(s *byte) int {
488 if s == nil {
489 return 0
490 }
491
492
493
494
495 if GOOS == "plan9" {
496 p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
497 l := 0
498 for p[l] != 0 {
499 l++
500 }
501 return l
502 }
503
504
505
506
507
508 const pageSize = 4096
509
510 offset := 0
511 ptr := unsafe.Pointer(s)
512
513
514
515 safeLen := int(pageSize - uintptr(ptr)%pageSize)
516
517 for {
518 t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
519
520 if i := bytealg.IndexByteString(t, 0); i != -1 {
521 return offset + i
522 }
523
524 ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
525 offset += safeLen
526 safeLen = pageSize
527 }
528 }
529
530 func findnullw(s *uint16) int {
531 if s == nil {
532 return 0
533 }
534 p := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(s))
535 l := 0
536 for p[l] != 0 {
537 l++
538 }
539 return l
540 }
541
542
543 func gostringnocopy(str *byte) string {
544 ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
545 s := *(*string)(unsafe.Pointer(&ss))
546 return s
547 }
548
549 func gostringw(strw *uint16) string {
550 var buf [8]byte
551 str := (*[maxAlloc/2/2 - 1]uint16)(unsafe.Pointer(strw))
552 n1 := 0
553 for i := 0; str[i] != 0; i++ {
554 n1 += encoderune(buf[:], rune(str[i]))
555 }
556 s, b := rawstring(n1 + 4)
557 n2 := 0
558 for i := 0; str[i] != 0; i++ {
559
560 if n2 >= n1 {
561 break
562 }
563 n2 += encoderune(b[n2:], rune(str[i]))
564 }
565 b[n2] = 0
566 return s[:n2]
567 }
568
View as plain text