github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/runtime/print1.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import "unsafe"
     8  
     9  // The compiler knows that a print of a value of this type
    10  // should use printhex instead of printuint (decimal).
    11  type hex uint64
    12  
    13  func bytes(s string) (ret []byte) {
    14  	rp := (*slice)(unsafe.Pointer(&ret))
    15  	sp := (*_string)(noescape(unsafe.Pointer(&s)))
    16  	rp.array = sp.str
    17  	rp.len = uint(sp.len)
    18  	rp.cap = uint(sp.len)
    19  	return
    20  }
    21  
    22  // printf is only called from C code. It has no type information for the args,
    23  // but C stacks are ignored by the garbage collector anyway, so having
    24  // type information would not add anything.
    25  //go:nosplit
    26  func printf(s *byte) {
    27  	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
    28  }
    29  
    30  // sprintf is only called from C code. It has no type information for the args,
    31  // but C stacks are ignored by the garbage collector anyway, so having
    32  // type information would not add anything.
    33  //go:nosplit
    34  func snprintf(dst *byte, n int32, s *byte) {
    35  	buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
    36  
    37  	gp := getg()
    38  	gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C
    39  	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
    40  	buf[len(gp.writebuf)] = '\x00'
    41  	gp.writebuf = nil
    42  }
    43  
    44  var debuglock mutex
    45  
    46  // The compiler emits calls to printlock and printunlock around
    47  // the multiple calls that implement a single Go print or println
    48  // statement. Some of the print helpers (printsp, for example)
    49  // call print recursively. There is also the problem of a crash
    50  // happening during the print routines and needing to acquire
    51  // the print lock to print information about the crash.
    52  // For both these reasons, let a thread acquire the printlock 'recursively'.
    53  
    54  func printlock() {
    55  	mp := getg().m
    56  	mp.printlock++
    57  	if mp.printlock == 1 {
    58  		lock(&debuglock)
    59  	}
    60  }
    61  
    62  func printunlock() {
    63  	mp := getg().m
    64  	mp.printlock--
    65  	if mp.printlock == 0 {
    66  		unlock(&debuglock)
    67  	}
    68  }
    69  
    70  // write to goroutine-local buffer if diverting output,
    71  // or else standard error.
    72  func gwrite(b []byte) {
    73  	if len(b) == 0 {
    74  		return
    75  	}
    76  	gp := getg()
    77  	if gp == nil || gp.writebuf == nil {
    78  		write(2, unsafe.Pointer(&b[0]), int32(len(b)))
    79  		return
    80  	}
    81  
    82  	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
    83  	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
    84  }
    85  
    86  func prints(s *byte) {
    87  	b := (*[1 << 30]byte)(unsafe.Pointer(s))
    88  	for i := 0; ; i++ {
    89  		if b[i] == 0 {
    90  			gwrite(b[:i])
    91  			return
    92  		}
    93  	}
    94  }
    95  
    96  func printsp() {
    97  	print(" ")
    98  }
    99  
   100  func printnl() {
   101  	print("\n")
   102  }
   103  
   104  // Very simple printf.  Only for debugging prints.
   105  // Do not add to this without checking with Rob.
   106  func vprintf(str string, arg unsafe.Pointer) {
   107  	printlock()
   108  
   109  	s := bytes(str)
   110  	start := 0
   111  	i := 0
   112  	for ; i < len(s); i++ {
   113  		if s[i] != '%' {
   114  			continue
   115  		}
   116  		if i > start {
   117  			gwrite(s[start:i])
   118  		}
   119  		if i++; i >= len(s) {
   120  			break
   121  		}
   122  		var siz uintptr
   123  		switch s[i] {
   124  		case 't', 'c':
   125  			siz = 1
   126  		case 'd', 'x': // 32-bit
   127  			arg = roundup(arg, 4)
   128  			siz = 4
   129  		case 'D', 'U', 'X', 'f': // 64-bit
   130  			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
   131  			siz = 8
   132  		case 'C':
   133  			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
   134  			siz = 16
   135  		case 'p', 's': // pointer-sized
   136  			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
   137  			siz = unsafe.Sizeof(uintptr(0))
   138  		case 'S': // pointer-aligned but bigger
   139  			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
   140  			siz = unsafe.Sizeof(string(""))
   141  		case 'a': // pointer-aligned but bigger
   142  			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
   143  			siz = unsafe.Sizeof([]byte{})
   144  		case 'i', 'e': // pointer-aligned but bigger
   145  			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
   146  			siz = unsafe.Sizeof(interface{}(nil))
   147  		}
   148  		switch s[i] {
   149  		case 'a':
   150  			printslice(*(*[]byte)(arg))
   151  		case 'c':
   152  			printbyte(*(*byte)(arg))
   153  		case 'd':
   154  			printint(int64(*(*int32)(arg)))
   155  		case 'D':
   156  			printint(int64(*(*int64)(arg)))
   157  		case 'e':
   158  			printeface(*(*interface{})(arg))
   159  		case 'f':
   160  			printfloat(*(*float64)(arg))
   161  		case 'C':
   162  			printcomplex(*(*complex128)(arg))
   163  		case 'i':
   164  			printiface(*(*fInterface)(arg))
   165  		case 'p':
   166  			printpointer(*(*unsafe.Pointer)(arg))
   167  		case 's':
   168  			prints(*(**byte)(arg))
   169  		case 'S':
   170  			printstring(*(*string)(arg))
   171  		case 't':
   172  			printbool(*(*bool)(arg))
   173  		case 'U':
   174  			printuint(*(*uint64)(arg))
   175  		case 'x':
   176  			printhex(uint64(*(*uint32)(arg)))
   177  		case 'X':
   178  			printhex(*(*uint64)(arg))
   179  		}
   180  		arg = add(arg, siz)
   181  		start = i + 1
   182  	}
   183  	if start < i {
   184  		gwrite(s[start:i])
   185  	}
   186  
   187  	printunlock()
   188  }
   189  
   190  func printpc(p unsafe.Pointer) {
   191  	print("PC=", hex(uintptr(p)))
   192  }
   193  
   194  func printbool(v bool) {
   195  	if v {
   196  		print("true")
   197  	} else {
   198  		print("false")
   199  	}
   200  }
   201  
   202  func printbyte(c byte) {
   203  	gwrite((*[1]byte)(unsafe.Pointer(&c))[:])
   204  }
   205  
   206  func printfloat(v float64) {
   207  	switch {
   208  	case v != v:
   209  		print("NaN")
   210  		return
   211  	case v+v == v && v > 0:
   212  		print("+Inf")
   213  		return
   214  	case v+v == v && v < 0:
   215  		print("-Inf")
   216  		return
   217  	}
   218  
   219  	const n = 7 // digits printed
   220  	var buf [n + 7]byte
   221  	buf[0] = '+'
   222  	e := 0 // exp
   223  	if v == 0 {
   224  		if 1/v < 0 {
   225  			buf[0] = '-'
   226  		}
   227  	} else {
   228  		if v < 0 {
   229  			v = -v
   230  			buf[0] = '-'
   231  		}
   232  
   233  		// normalize
   234  		for v >= 10 {
   235  			e++
   236  			v /= 10
   237  		}
   238  		for v < 1 {
   239  			e--
   240  			v *= 10
   241  		}
   242  
   243  		// round
   244  		h := 5.0
   245  		for i := 0; i < n; i++ {
   246  			h /= 10
   247  		}
   248  		v += h
   249  		if v >= 10 {
   250  			e++
   251  			v /= 10
   252  		}
   253  	}
   254  
   255  	// format +d.dddd+edd
   256  	for i := 0; i < n; i++ {
   257  		s := int(v)
   258  		buf[i+2] = byte(s + '0')
   259  		v -= float64(s)
   260  		v *= 10
   261  	}
   262  	buf[1] = buf[2]
   263  	buf[2] = '.'
   264  
   265  	buf[n+2] = 'e'
   266  	buf[n+3] = '+'
   267  	if e < 0 {
   268  		e = -e
   269  		buf[n+3] = '-'
   270  	}
   271  
   272  	buf[n+4] = byte(e/100) + '0'
   273  	buf[n+5] = byte(e/10)%10 + '0'
   274  	buf[n+6] = byte(e%10) + '0'
   275  	gwrite(buf[:])
   276  }
   277  
   278  func printcomplex(c complex128) {
   279  	print("(", real(c), imag(c), "i)")
   280  }
   281  
   282  func printuint(v uint64) {
   283  	var buf [100]byte
   284  	i := len(buf)
   285  	for i--; i > 0; i-- {
   286  		buf[i] = byte(v%10 + '0')
   287  		if v < 10 {
   288  			break
   289  		}
   290  		v /= 10
   291  	}
   292  	gwrite(buf[i:])
   293  }
   294  
   295  func printint(v int64) {
   296  	if v < 0 {
   297  		print("-")
   298  		v = -v
   299  	}
   300  	printuint(uint64(v))
   301  }
   302  
   303  func printhex(v uint64) {
   304  	const dig = "0123456789abcdef"
   305  	var buf [100]byte
   306  	i := len(buf)
   307  	for i--; i > 0; i-- {
   308  		buf[i] = dig[v%16]
   309  		if v < 16 {
   310  			break
   311  		}
   312  		v /= 16
   313  	}
   314  	i--
   315  	buf[i] = 'x'
   316  	i--
   317  	buf[i] = '0'
   318  	gwrite(buf[i:])
   319  }
   320  
   321  func printpointer(p unsafe.Pointer) {
   322  	printhex(uint64(uintptr(p)))
   323  }
   324  
   325  func printstring(s string) {
   326  	if uintptr(len(s)) > maxstring {
   327  		gwrite(bytes("[string too long]"))
   328  		return
   329  	}
   330  	gwrite(bytes(s))
   331  }
   332  
   333  func printslice(s []byte) {
   334  	sp := (*slice)(unsafe.Pointer(&s))
   335  	print("[", len(s), "/", cap(s), "]")
   336  	printpointer(unsafe.Pointer(sp.array))
   337  }
   338  
   339  func printeface(e interface{}) {
   340  	ep := (*eface)(unsafe.Pointer(&e))
   341  	print("(", ep._type, ",", ep.data, ")")
   342  }
   343  
   344  func printiface(i fInterface) {
   345  	ip := (*iface)(unsafe.Pointer(&i))
   346  	print("(", ip.tab, ",", ip.data, ")")
   347  }