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