2014-08-28 21:26:40 -06:00
|
|
|
// 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"
|
|
|
|
|
cmd/gc: allow runtime to define a hex integer type for printing
As part of the translation of the runtime, we need to rewrite
C printf calls to Go print calls. Consider this C printf:
runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
g->sig, g->sigcode0, g->sigcode1, g->sigpc);
Today the only way to write that in Go is:
print("[signal ")
printhex(uint64(g->sig))
print(" code=")
printhex(uint64(g->sigcode0))
print(" addr=")
printhex(uint64(g->sigcode1))
print(" pc=")
printhex(uint64(g->sigpc))
print("]\n")
(That's nearly exactly what runtime code looked like in C before
I added runtime·printf.)
This CL recognizes the unexported type runtime.hex as an integer
that should be printed in hexadecimal instead of decimal.
It's a little kludgy, but it's restricted to package runtime.
Other packages can define type hex with no effect at all.
Now we can translate that original printf as the more compact:
print("[signal ", hex(g->sig), " code=", hex(g->sigcode0),
" addr=", hex(g->sigcode1), " pc=", hex(g->sigpc), "]\n")
LGTM=r, iant
R=r, iant
CC=golang-codereviews
https://golang.org/cl/133220043
2014-08-29 11:22:17 -06:00
|
|
|
// The compiler knows that a print of a value of this type
|
|
|
|
// should use printhex instead of printuint (decimal).
|
|
|
|
type hex uint64
|
|
|
|
|
2014-08-28 21:26:40 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
cmd/gc: avoid use of goprintf
goprintf is a printf-like print for Go.
It is used in the code generated by 'defer print(...)' and 'go print(...)'.
Normally print(1, 2, 3) turns into
printint(1)
printint(2)
printint(3)
but defer and go need a single function call to give the runtime;
they give the runtime something like goprintf("%d%d%d", 1, 2, 3).
Variadic functions like goprintf cannot be described in the new
type information world, so we have to replace it.
Replace with a custom function, so that defer print(1, 2, 3) turns
into
defer func(a1, a2, a3 int) {
print(a1, a2, a3)
}(1, 2, 3)
(and then the print becomes three different printints as usual).
Fixes #8614.
LGTM=austin
R=austin
CC=golang-codereviews, r
https://golang.org/cl/159700043
2014-10-28 19:52:53 -06:00
|
|
|
// 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.
|
2014-08-28 21:26:40 -06:00
|
|
|
//go:nosplit
|
|
|
|
func printf(s *byte) {
|
2014-08-29 00:26:50 -06:00
|
|
|
vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
|
2014-08-28 21:26:40 -06:00
|
|
|
}
|
|
|
|
|
cmd/gc: avoid use of goprintf
goprintf is a printf-like print for Go.
It is used in the code generated by 'defer print(...)' and 'go print(...)'.
Normally print(1, 2, 3) turns into
printint(1)
printint(2)
printint(3)
but defer and go need a single function call to give the runtime;
they give the runtime something like goprintf("%d%d%d", 1, 2, 3).
Variadic functions like goprintf cannot be described in the new
type information world, so we have to replace it.
Replace with a custom function, so that defer print(1, 2, 3) turns
into
defer func(a1, a2, a3 int) {
print(a1, a2, a3)
}(1, 2, 3)
(and then the print becomes three different printints as usual).
Fixes #8614.
LGTM=austin
R=austin
CC=golang-codereviews, r
https://golang.org/cl/159700043
2014-10-28 19:52:53 -06:00
|
|
|
// 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.
|
2014-08-28 21:26:40 -06:00
|
|
|
//go:nosplit
|
|
|
|
func snprintf(dst *byte, n int32, s *byte) {
|
2014-08-29 08:29:00 -06:00
|
|
|
buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
|
2014-08-28 21:26:40 -06:00
|
|
|
|
|
|
|
gp := getg()
|
|
|
|
gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C
|
2014-09-02 16:56:50 -06:00
|
|
|
vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
|
2014-08-28 21:26:40 -06:00
|
|
|
buf[len(gp.writebuf)] = '\x00'
|
|
|
|
gp.writebuf = nil
|
|
|
|
}
|
|
|
|
|
2014-11-05 12:42:54 -07:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2014-08-28 21:26:40 -06:00
|
|
|
|
|
|
|
// 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 {
|
|
|
|
write(2, unsafe.Pointer(&b[0]), int32(len(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) {
|
2014-11-05 12:42:54 -07:00
|
|
|
printlock()
|
2014-08-28 21:26:40 -06:00
|
|
|
|
|
|
|
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])
|
|
|
|
}
|
|
|
|
|
2014-11-05 12:42:54 -07:00
|
|
|
printunlock()
|
2014-08-28 21:26:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func printpc(p unsafe.Pointer) {
|
cmd/gc: allow runtime to define a hex integer type for printing
As part of the translation of the runtime, we need to rewrite
C printf calls to Go print calls. Consider this C printf:
runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
g->sig, g->sigcode0, g->sigcode1, g->sigpc);
Today the only way to write that in Go is:
print("[signal ")
printhex(uint64(g->sig))
print(" code=")
printhex(uint64(g->sigcode0))
print(" addr=")
printhex(uint64(g->sigcode1))
print(" pc=")
printhex(uint64(g->sigpc))
print("]\n")
(That's nearly exactly what runtime code looked like in C before
I added runtime·printf.)
This CL recognizes the unexported type runtime.hex as an integer
that should be printed in hexadecimal instead of decimal.
It's a little kludgy, but it's restricted to package runtime.
Other packages can define type hex with no effect at all.
Now we can translate that original printf as the more compact:
print("[signal ", hex(g->sig), " code=", hex(g->sigcode0),
" addr=", hex(g->sigcode1), " pc=", hex(g->sigpc), "]\n")
LGTM=r, iant
R=r, iant
CC=golang-codereviews
https://golang.org/cl/133220043
2014-08-29 11:22:17 -06:00
|
|
|
print("PC=", hex(uintptr(p)))
|
2014-08-28 21:26:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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, ")")
|
|
|
|
}
|