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