// 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 (
	
	
)

// The compiler knows that a print of a value of this type
// should use printhex instead of printuint (decimal).
type hex uint64

// The compiler knows that a print of a value of this type should use
// printquoted instead of printstring.
type quoted string

func bytes( string) ( []byte) {
	 := (*slice)(unsafe.Pointer(&))
	 := stringStructOf(&)
	.array = .str
	.len = .len
	.cap = .len
	return
}

var (
	// printBacklog is a circular buffer of messages written with the builtin
	// print* functions, for use in postmortem analysis of core dumps.
	printBacklog      [512]byte
	printBacklogIndex int
)

// recordForPanic maintains a circular buffer of messages written by the
// runtime leading up to a process crash, allowing the messages to be
// extracted from a core dump.
//
// The text written during a process crash (following "panic" or "fatal
// error") is not saved, since the goroutine stacks will generally be readable
// from the runtime data structures in the core file.
func recordForPanic( []byte) {
	printlock()

	if panicking.Load() == 0 {
		// Not actively crashing: maintain circular buffer of print output.
		for  := 0;  < len(); {
			 := copy(printBacklog[printBacklogIndex:], [:])
			 += 
			printBacklogIndex += 
			printBacklogIndex %= len(printBacklog)
		}
	}

	printunlock()
}

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 (printslice, 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() {
	 := getg().m
	.locks++ // do not reschedule between printlock++ and lock(&debuglock).
	.printlock++
	if .printlock == 1 {
		lock(&debuglock)
	}
	.locks-- // now we know debuglock is held and holding up mp.locks for us.
}

func printunlock() {
	 := getg().m
	.printlock--
	if .printlock == 0 {
		unlock(&debuglock)
	}
}

// write to goroutine-local buffer if diverting output,
// or else standard error.
func gwrite( []byte) {
	if len() == 0 {
		return
	}
	recordForPanic()
	 := getg()
	// Don't use the writebuf if gp.m is dying. We want anything
	// written through gwrite to appear in the terminal rather
	// than be written to in some buffer, if we're in a panicking state.
	// Note that we can't just clear writebuf in the gp.m.dying case
	// because a panic isn't allowed to have any write barriers.
	if  == nil || .writebuf == nil || .m.dying > 0 {
		writeErr()
		return
	}

	 := copy(.writebuf[len(.writebuf):cap(.writebuf)], )
	.writebuf = .writebuf[:len(.writebuf)+]
}

func printsp() {
	printstring(" ")
}

func printnl() {
	printstring("\n")
}

func printbool( bool) {
	if  {
		printstring("true")
	} else {
		printstring("false")
	}
}

func printfloat64( float64) {
	var  [20]byte
	gwrite(strconv.AppendFloat([:0], , 'g', -1, 64))
}

func printfloat32( float32) {
	var  [20]byte
	gwrite(strconv.AppendFloat([:0], float64(), 'g', -1, 32))
}

func printcomplex128( complex128) {
	var  [44]byte
	gwrite(strconv.AppendComplex([:0], , 'g', -1, 128))
}

func printcomplex64( complex64) {
	var  [44]byte
	gwrite(strconv.AppendComplex([:0], complex128(), 'g', -1, 64))
}

func printuint( uint64) {
	// Note: Avoiding strconv.AppendUint so that it's clearer
	// that there are no allocations in this routine.
	// cmd/link/internal/ld.TestAbstractOriginSanity
	// sees the append and doesn't realize it doesn't allocate.
	var  [20]byte
	 := strconv.RuntimeFormatBase10([:], )
	gwrite([:])
}

func printint( int64) {
	// Note: Avoiding strconv.AppendUint so that it's clearer
	// that there are no allocations in this routine.
	// cmd/link/internal/ld.TestAbstractOriginSanity
	// sees the append and doesn't realize it doesn't allocate.
	 :=  < 0
	 := uint64()
	if  {
		 = -
	}
	var  [20]byte
	 := strconv.RuntimeFormatBase10([:], )
	if  {
		--
		[] = '-'
	}
	gwrite([:])
}

var minhexdigits = 0 // protected by printlock

func printhexopts( bool,  int,  uint64) {
	const  = "0123456789abcdef"
	var  [100]byte
	 := len()
	for --;  > 0; -- {
		[] = [%16]
		if  < 16 && len()- >=  {
			break
		}
		 /= 16
	}
	if  {
		--
		[] = 'x'
		--
		[] = '0'
	}
	gwrite([:])
}

func printhex( uint64) {
	printhexopts(true, minhexdigits, )
}

func printquoted( string) {
	printlock()
	gwrite([]byte(`"`))
	for ,  := range  {
		switch  {
		case '\n':
			gwrite([]byte(`\n`))
			continue
		case '\r':
			gwrite([]byte(`\r`))
			continue
		case '\t':
			gwrite([]byte(`\t`))
			print()
			continue
		case '\\', '"':
			gwrite([]byte{byte('\\'), byte()})
			continue
		}
		// For now, only allow basic printable ascii through unescaped
		if  >= ' ' &&  <= '~' {
			gwrite([]byte{byte()})
		} else if  < 127 {
			gwrite(bytes(`\x`))
			printhexopts(false, 2, uint64())
		} else if  < 0x1_0000 {
			gwrite(bytes(`\u`))
			printhexopts(false, 4, uint64())
		} else {
			gwrite(bytes(`\U`))
			printhexopts(false, 8, uint64())
		}
	}
	gwrite([]byte{byte('"')})
	printunlock()
}

func printpointer( unsafe.Pointer) {
	printhex(uint64(uintptr()))
}
func printuintptr( uintptr) {
	printhex(uint64())
}

func printstring( string) {
	gwrite(bytes())
}

func printslice( []byte) {
	 := (*slice)(unsafe.Pointer(&))
	print("[", len(), "/", cap(), "]")
	printpointer(.array)
}

func printeface( eface) {
	print("(", ._type, ",", .data, ")")
}

func printiface( iface) {
	print("(", .tab, ",", .data, ")")
}