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