| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package runtime |
| |
| import "unsafe" |
| |
| // The compiler knows that a print of a value of this type |
| // should use printhex instead of printuint (decimal). |
| type hex uint64 |
| |
| func bytes(s string) (ret []byte) { |
| rp := (*slice)(unsafe.Pointer(&ret)) |
| sp := (*_string)(noescape(unsafe.Pointer(&s))) |
| rp.array = sp.str |
| rp.len = uint(sp.len) |
| rp.cap = uint(sp.len) |
| return |
| } |
| |
| // printf is only called from C code. It has no type information for the args, |
| // but C stacks are ignored by the garbage collector anyway, so having |
| // type information would not add anything. |
| //go:nosplit |
| func printf(s *byte) { |
| vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s))) |
| } |
| |
| // sprintf is only called from C code. It has no type information for the args, |
| // but C stacks are ignored by the garbage collector anyway, so having |
| // type information would not add anything. |
| //go:nosplit |
| func snprintf(dst *byte, n int32, s *byte) { |
| buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n] |
| |
| gp := getg() |
| gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C |
| vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s))) |
| buf[len(gp.writebuf)] = '\x00' |
| gp.writebuf = nil |
| } |
| |
| var debuglock mutex |
| |
| // The compiler emits calls to printlock and printunlock around |
| // the multiple calls that implement a single Go print or println |
| // statement. Some of the print helpers (printsp, for example) |
| // call print recursively. There is also the problem of a crash |
| // happening during the print routines and needing to acquire |
| // the print lock to print information about the crash. |
| // For both these reasons, let a thread acquire the printlock 'recursively'. |
| |
| func printlock() { |
| mp := getg().m |
| mp.printlock++ |
| if mp.printlock == 1 { |
| lock(&debuglock) |
| } |
| } |
| |
| func printunlock() { |
| mp := getg().m |
| mp.printlock-- |
| if mp.printlock == 0 { |
| unlock(&debuglock) |
| } |
| } |
| |
| // write to goroutine-local buffer if diverting output, |
| // or else standard error. |
| func gwrite(b []byte) { |
| if len(b) == 0 { |
| return |
| } |
| gp := getg() |
| if gp == nil || gp.writebuf == nil { |
| writeErr(b) |
| return |
| } |
| |
| n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) |
| gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] |
| } |
| |
| func prints(s *byte) { |
| b := (*[1 << 30]byte)(unsafe.Pointer(s)) |
| for i := 0; ; i++ { |
| if b[i] == 0 { |
| gwrite(b[:i]) |
| return |
| } |
| } |
| } |
| |
| func printsp() { |
| print(" ") |
| } |
| |
| func printnl() { |
| print("\n") |
| } |
| |
| // Very simple printf. Only for debugging prints. |
| // Do not add to this without checking with Rob. |
| func vprintf(str string, arg unsafe.Pointer) { |
| printlock() |
| |
| s := bytes(str) |
| start := 0 |
| i := 0 |
| for ; i < len(s); i++ { |
| if s[i] != '%' { |
| continue |
| } |
| if i > start { |
| gwrite(s[start:i]) |
| } |
| if i++; i >= len(s) { |
| break |
| } |
| var siz uintptr |
| switch s[i] { |
| case 't', 'c': |
| siz = 1 |
| case 'd', 'x': // 32-bit |
| arg = roundup(arg, 4) |
| siz = 4 |
| case 'D', 'U', 'X', 'f': // 64-bit |
| arg = roundup(arg, unsafe.Sizeof(uintreg(0))) |
| siz = 8 |
| case 'C': |
| arg = roundup(arg, unsafe.Sizeof(uintreg(0))) |
| siz = 16 |
| case 'p', 's': // pointer-sized |
| arg = roundup(arg, unsafe.Sizeof(uintptr(0))) |
| siz = unsafe.Sizeof(uintptr(0)) |
| case 'S': // pointer-aligned but bigger |
| arg = roundup(arg, unsafe.Sizeof(uintptr(0))) |
| siz = unsafe.Sizeof(string("")) |
| case 'a': // pointer-aligned but bigger |
| arg = roundup(arg, unsafe.Sizeof(uintptr(0))) |
| siz = unsafe.Sizeof([]byte{}) |
| case 'i', 'e': // pointer-aligned but bigger |
| arg = roundup(arg, unsafe.Sizeof(uintptr(0))) |
| siz = unsafe.Sizeof(interface{}(nil)) |
| } |
| switch s[i] { |
| case 'a': |
| printslice(*(*[]byte)(arg)) |
| case 'c': |
| printbyte(*(*byte)(arg)) |
| case 'd': |
| printint(int64(*(*int32)(arg))) |
| case 'D': |
| printint(int64(*(*int64)(arg))) |
| case 'e': |
| printeface(*(*interface{})(arg)) |
| case 'f': |
| printfloat(*(*float64)(arg)) |
| case 'C': |
| printcomplex(*(*complex128)(arg)) |
| case 'i': |
| printiface(*(*fInterface)(arg)) |
| case 'p': |
| printpointer(*(*unsafe.Pointer)(arg)) |
| case 's': |
| prints(*(**byte)(arg)) |
| case 'S': |
| printstring(*(*string)(arg)) |
| case 't': |
| printbool(*(*bool)(arg)) |
| case 'U': |
| printuint(*(*uint64)(arg)) |
| case 'x': |
| printhex(uint64(*(*uint32)(arg))) |
| case 'X': |
| printhex(*(*uint64)(arg)) |
| } |
| arg = add(arg, siz) |
| start = i + 1 |
| } |
| if start < i { |
| gwrite(s[start:i]) |
| } |
| |
| printunlock() |
| } |
| |
| func printpc(p unsafe.Pointer) { |
| print("PC=", hex(uintptr(p))) |
| } |
| |
| func printbool(v bool) { |
| if v { |
| print("true") |
| } else { |
| print("false") |
| } |
| } |
| |
| func printbyte(c byte) { |
| gwrite((*[1]byte)(unsafe.Pointer(&c))[:]) |
| } |
| |
| func printfloat(v float64) { |
| switch { |
| case v != v: |
| print("NaN") |
| return |
| case v+v == v && v > 0: |
| print("+Inf") |
| return |
| case v+v == v && v < 0: |
| print("-Inf") |
| return |
| } |
| |
| const n = 7 // digits printed |
| var buf [n + 7]byte |
| buf[0] = '+' |
| e := 0 // exp |
| if v == 0 { |
| if 1/v < 0 { |
| buf[0] = '-' |
| } |
| } else { |
| if v < 0 { |
| v = -v |
| buf[0] = '-' |
| } |
| |
| // normalize |
| for v >= 10 { |
| e++ |
| v /= 10 |
| } |
| for v < 1 { |
| e-- |
| v *= 10 |
| } |
| |
| // round |
| h := 5.0 |
| for i := 0; i < n; i++ { |
| h /= 10 |
| } |
| v += h |
| if v >= 10 { |
| e++ |
| v /= 10 |
| } |
| } |
| |
| // format +d.dddd+edd |
| for i := 0; i < n; i++ { |
| s := int(v) |
| buf[i+2] = byte(s + '0') |
| v -= float64(s) |
| v *= 10 |
| } |
| buf[1] = buf[2] |
| buf[2] = '.' |
| |
| buf[n+2] = 'e' |
| buf[n+3] = '+' |
| if e < 0 { |
| e = -e |
| buf[n+3] = '-' |
| } |
| |
| buf[n+4] = byte(e/100) + '0' |
| buf[n+5] = byte(e/10)%10 + '0' |
| buf[n+6] = byte(e%10) + '0' |
| gwrite(buf[:]) |
| } |
| |
| func printcomplex(c complex128) { |
| print("(", real(c), imag(c), "i)") |
| } |
| |
| func printuint(v uint64) { |
| var buf [100]byte |
| i := len(buf) |
| for i--; i > 0; i-- { |
| buf[i] = byte(v%10 + '0') |
| if v < 10 { |
| break |
| } |
| v /= 10 |
| } |
| gwrite(buf[i:]) |
| } |
| |
| func printint(v int64) { |
| if v < 0 { |
| print("-") |
| v = -v |
| } |
| printuint(uint64(v)) |
| } |
| |
| func printhex(v uint64) { |
| const dig = "0123456789abcdef" |
| var buf [100]byte |
| i := len(buf) |
| for i--; i > 0; i-- { |
| buf[i] = dig[v%16] |
| if v < 16 { |
| break |
| } |
| v /= 16 |
| } |
| i-- |
| buf[i] = 'x' |
| i-- |
| buf[i] = '0' |
| gwrite(buf[i:]) |
| } |
| |
| func printpointer(p unsafe.Pointer) { |
| printhex(uint64(uintptr(p))) |
| } |
| |
| func printstring(s string) { |
| if uintptr(len(s)) > maxstring { |
| gwrite(bytes("[string too long]")) |
| return |
| } |
| gwrite(bytes(s)) |
| } |
| |
| func printslice(s []byte) { |
| sp := (*slice)(unsafe.Pointer(&s)) |
| print("[", len(s), "/", cap(s), "]") |
| printpointer(unsafe.Pointer(sp.array)) |
| } |
| |
| func printeface(e interface{}) { |
| ep := (*eface)(unsafe.Pointer(&e)) |
| print("(", ep._type, ",", ep.data, ")") |
| } |
| |
| func printiface(i fInterface) { |
| ip := (*iface)(unsafe.Pointer(&i)) |
| print("(", ip.tab, ",", ip.data, ")") |
| } |