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