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