diff mbox

Go patch committed: copy print code from Go 1.7 runtime

Message ID CAOyqgcWMZ+PcfKcDK2T1jYxP0pkXzS82jtEOQ1kXTnjd2Uqb=w@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 10, 2016, 11:13 p.m. UTC
This patch copies the code that implements the print and println
predeclared functions from the Go 1.7 runtime.  The compiler is
changed to use the new names, and to call the printlock and
printunlock functions around a sequence of print calls.  The writebuf
field in the g struct changes to a slice.  Bootstrapped and ran Go
testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 240942)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-f3658aea2493c7f1c4a72502f9e7da562c7764c4
+ecf9b645cefc5c3b4e6339adeb452b2d8642cf3e
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 240942)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -7018,6 +7018,26 @@  Builtin_call_expression::do_lower(Gogo*
 	  }
       }
       break;
+
+    case BUILTIN_PRINT:
+    case BUILTIN_PRINTLN:
+      // Force all the arguments into temporary variables, so that we
+      // don't try to evaluate something while holding the print lock.
+      if (this->args() == NULL)
+	break;
+      for (Expression_list::iterator pa = this->args()->begin();
+	   pa != this->args()->end();
+	   ++pa)
+	{
+	  if (!(*pa)->is_variable())
+	    {
+	      Temporary_statement* temp =
+		Statement::make_temporary(NULL, *pa, loc);
+	      inserter->insert(temp);
+	      *pa = Expression::make_temporary_reference(temp, loc);
+	    }
+	}
+      break;
     }
 
   return this;
@@ -8336,7 +8356,9 @@  Builtin_call_expression::do_get_backend(
     case BUILTIN_PRINTLN:
       {
 	const bool is_ln = this->code_ == BUILTIN_PRINTLN;
-        Expression* print_stmts = NULL;
+
+	Expression* print_stmts = Runtime::make_call(Runtime::PRINTLOCK,
+						     location, 0);
 
 	const Expression_list* call_args = this->args();
 	if (call_args != NULL)
@@ -8348,8 +8370,7 @@  Builtin_call_expression::do_get_backend(
 		if (is_ln && p != call_args->begin())
 		  {
                     Expression* print_space =
-                        Runtime::make_call(Runtime::PRINT_SPACE,
-                                           this->location(), 0);
+		      Runtime::make_call(Runtime::PRINTSP, location, 0);
 
                     print_stmts =
                         Expression::make_compound(print_stmts, print_space,
@@ -8360,51 +8381,51 @@  Builtin_call_expression::do_get_backend(
 		Type* type = arg->type();
                 Runtime::Function code;
 		if (type->is_string_type())
-                  code = Runtime::PRINT_STRING;
+                  code = Runtime::PRINTSTRING;
 		else if (type->integer_type() != NULL
 			 && type->integer_type()->is_unsigned())
 		  {
 		    Type* itype = Type::lookup_integer_type("uint64");
 		    arg = Expression::make_cast(itype, arg, location);
-                    code = Runtime::PRINT_UINT64;
+                    code = Runtime::PRINTUINT;
 		  }
 		else if (type->integer_type() != NULL)
 		  {
 		    Type* itype = Type::lookup_integer_type("int64");
 		    arg = Expression::make_cast(itype, arg, location);
-                    code = Runtime::PRINT_INT64;
+                    code = Runtime::PRINTINT;
 		  }
 		else if (type->float_type() != NULL)
 		  {
                     Type* dtype = Type::lookup_float_type("float64");
                     arg = Expression::make_cast(dtype, arg, location);
-                    code = Runtime::PRINT_DOUBLE;
+                    code = Runtime::PRINTFLOAT;
 		  }
 		else if (type->complex_type() != NULL)
 		  {
                     Type* ctype = Type::lookup_complex_type("complex128");
                     arg = Expression::make_cast(ctype, arg, location);
-                    code = Runtime::PRINT_COMPLEX;
+                    code = Runtime::PRINTCOMPLEX;
 		  }
 		else if (type->is_boolean_type())
-                  code = Runtime::PRINT_BOOL;
+                  code = Runtime::PRINTBOOL;
 		else if (type->points_to() != NULL
 			 || type->channel_type() != NULL
 			 || type->map_type() != NULL
 			 || type->function_type() != NULL)
 		  {
                     arg = Expression::make_cast(type, arg, location);
-                    code = Runtime::PRINT_POINTER;
+                    code = Runtime::PRINTPOINTER;
 		  }
 		else if (type->interface_type() != NULL)
 		  {
 		    if (type->interface_type()->is_empty())
-                      code = Runtime::PRINT_EMPTY_INTERFACE;
+                      code = Runtime::PRINTEFACE;
 		    else
-                      code = Runtime::PRINT_INTERFACE;
+                      code = Runtime::PRINTIFACE;
 		  }
 		else if (type->is_slice_type())
-                  code = Runtime::PRINT_SLICE;
+                  code = Runtime::PRINTSLICE;
 		else
 		  {
 		    go_assert(saw_errors());
@@ -8412,30 +8433,22 @@  Builtin_call_expression::do_get_backend(
 		  }
 
                 Expression* call = Runtime::make_call(code, location, 1, arg);
-                if (print_stmts == NULL)
-                  print_stmts = call;
-                else
-                  print_stmts = Expression::make_compound(print_stmts, call,
-                                                          location);
+		print_stmts = Expression::make_compound(print_stmts, call,
+							location);
 	      }
 	  }
 
 	if (is_ln)
 	  {
             Expression* print_nl =
-                Runtime::make_call(Runtime::PRINT_NL, location, 0);
-            if (print_stmts == NULL)
-              print_stmts = print_nl;
-            else
-              print_stmts = Expression::make_compound(print_stmts, print_nl,
-                                                      location);
+                Runtime::make_call(Runtime::PRINTNL, location, 0);
+	    print_stmts = Expression::make_compound(print_stmts, print_nl,
+						    location);
 	  }
 
-        // There aren't any arguments to the print builtin.  The compiler
-        // issues a warning for this so we should avoid getting the backend
-        // representation for this call.  Instead, perform a no-op.
-        if (print_stmts == NULL)
-          return context->backend()->boolean_constant_expression(false);
+	Expression* unlock = Runtime::make_call(Runtime::PRINTUNLOCK,
+						location, 0);
+	print_stmts = Expression::make_compound(print_stmts, unlock, location);
 
         return print_stmts->get_backend(context);
       }
Index: gcc/go/gofrontend/runtime.def
===================================================================
--- gcc/go/gofrontend/runtime.def	(revision 240942)
+++ gcc/go/gofrontend/runtime.def	(working copy)
@@ -299,42 +299,47 @@  DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE,
 	       P2(IFACE, EFACE), R1(INT))
 
 
+// Lock the printer (for print/println).
+DEF_GO_RUNTIME(PRINTLOCK, "runtime.printlock", P0(), R0())
+
+// Unlock the printer (for print/println).
+DEF_GO_RUNTIME(PRINTUNLOCK, "runtime.printunlock", P0(), R0())
+
 // Print a string (for print/println).
-DEF_GO_RUNTIME(PRINT_STRING, "__go_print_string", P1(STRING), R0())
+DEF_GO_RUNTIME(PRINTSTRING, "runtime.printstring", P1(STRING), R0())
 
 // Print a uint64 (for print/println).
-DEF_GO_RUNTIME(PRINT_UINT64, "__go_print_uint64", P1(UINT64), R0())
+DEF_GO_RUNTIME(PRINTUINT, "runtime.printuint", P1(UINT64), R0())
 
 // Print a int64 (for print/println).
-DEF_GO_RUNTIME(PRINT_INT64, "__go_print_int64", P1(INT64), R0())
+DEF_GO_RUNTIME(PRINTINT, "runtime.printint", P1(INT64), R0())
 
 // Print a float64 (for print/println).
-DEF_GO_RUNTIME(PRINT_DOUBLE, "__go_print_double", P1(FLOAT64), R0())
+DEF_GO_RUNTIME(PRINTFLOAT, "runtime.printfloat", P1(FLOAT64), R0())
 
 // Print a complex128 (for print/println).
-DEF_GO_RUNTIME(PRINT_COMPLEX, "__go_print_complex", P1(COMPLEX128), R0())
+DEF_GO_RUNTIME(PRINTCOMPLEX, "runtime.printcomplex", P1(COMPLEX128), R0())
 
 // Print a bool (for print/println).
-DEF_GO_RUNTIME(PRINT_BOOL, "__go_print_bool", P1(BOOL), R0())
+DEF_GO_RUNTIME(PRINTBOOL, "runtime.printbool", P1(BOOL), R0())
 
 // Print a pointer/map/channel/function (for print/println).
-DEF_GO_RUNTIME(PRINT_POINTER, "__go_print_pointer", P1(POINTER), R0())
+DEF_GO_RUNTIME(PRINTPOINTER, "runtime.printpointer", P1(POINTER), R0())
 
 // Print an empty interface (for print/println).
-DEF_GO_RUNTIME(PRINT_EMPTY_INTERFACE, "__go_print_empty_interface",
-	       P1(EFACE), R0())
+DEF_GO_RUNTIME(PRINTEFACE, "runtime.printeface", P1(EFACE), R0())
 
 // Print a non-empty interface (for print/println).
-DEF_GO_RUNTIME(PRINT_INTERFACE, "__go_print_interface", P1(IFACE), R0())
+DEF_GO_RUNTIME(PRINTIFACE, "runtime.printiface", P1(IFACE), R0())
 
 // Print a slice (for print/println).
-DEF_GO_RUNTIME(PRINT_SLICE, "__go_print_slice", P1(SLICE), R0())
+DEF_GO_RUNTIME(PRINTSLICE, "runtime.printslice", P1(SLICE), R0())
 
 // Print a space (for println).
-DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0())
+DEF_GO_RUNTIME(PRINTSP, "runtime.printsp", P0(), R0())
 
 // Print a newline (for println).
-DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0())
+DEF_GO_RUNTIME(PRINTNL, "runtime.printnl", P0(), R0())
 
 
 // Used for field tracking for data analysis.
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 240942)
+++ libgo/Makefile.am	(working copy)
@@ -474,7 +474,6 @@  runtime_files = \
 	runtime/go-new.c \
 	runtime/go-nosys.c \
 	runtime/go-panic.c \
-	runtime/go-print.c \
 	runtime/go-recover.c \
 	runtime/go-reflect-call.c \
 	runtime/go-rune.c \
Index: libgo/go/runtime/print.go
===================================================================
--- libgo/go/runtime/print.go	(revision 240942)
+++ libgo/go/runtime/print.go	(working copy)
@@ -2,12 +2,32 @@ 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build ignore
-
 package runtime
 
 import "unsafe"
 
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname printbool runtime.printbool
+//go:linkname printfloat runtime.printfloat
+//go:linkname printint runtime.printint
+//go:linkname printhex runtime.printhex
+//go:linkname printuint runtime.printuint
+//go:linkname printcomplex runtime.printcomplex
+//go:linkname printstring runtime.printstring
+//go:linkname printpointer runtime.printpointer
+//go:linkname printiface runtime.printiface
+//go:linkname printeface runtime.printeface
+//go:linkname printslice runtime.printslice
+//go:linkname printnl runtime.printnl
+//go:linkname printsp runtime.printsp
+//go:linkname printlock runtime.printlock
+//go:linkname printunlock runtime.printunlock
+// Temporary for C code to call:
+//go:linkname gwrite runtime.gwrite
+//go:linkname printhex runtime.printhex
+
 // The compiler knows that a print of a value of this type
 // should use printhex instead of printuint (decimal).
 type hex uint64
@@ -201,10 +221,6 @@  func printpointer(p unsafe.Pointer) {
 }
 
 func printstring(s string) {
-	if uintptr(len(s)) > maxstring {
-		gwrite(bytes("[string too long]"))
-		return
-	}
 	gwrite(bytes(s))
 }
 
Index: libgo/go/runtime/runtime2.go
===================================================================
--- libgo/go/runtime/runtime2.go	(revision 240942)
+++ libgo/go/runtime/runtime2.go	(working copy)
@@ -347,20 +347,14 @@  type g struct {
 	tracelastp     puintptr // last P emitted an event for this goroutine
 	lockedm        *m
 	sig            uint32
-
-	// Temporary gccgo field.
-	writenbuf int32
-	// Not for gccgo yet: writebuf       []byte
-	// Temporary different type for gccgo.
-	writebuf *byte
-
-	sigcode0 uintptr
-	sigcode1 uintptr
-	sigpc    uintptr
-	gopc     uintptr // pc of go statement that created this goroutine
-	startpc  uintptr // pc of goroutine function
-	racectx  uintptr
-	waiting  *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
+	writebuf       []byte
+	sigcode0       uintptr
+	sigcode1       uintptr
+	sigpc          uintptr
+	gopc           uintptr // pc of go statement that created this goroutine
+	startpc        uintptr // pc of goroutine function
+	racectx        uintptr
+	waiting        *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
 	// Not for gccgo: cgoCtxt        []uintptr // cgo traceback context
 
 	// Per-G GC state
Index: libgo/go/runtime/stubs.go
===================================================================
--- libgo/go/runtime/stubs.go	(revision 240942)
+++ libgo/go/runtime/stubs.go	(working copy)
@@ -445,6 +445,3 @@  func releaseSudog(s *sudog) {
 
 // Temporary hack for gccgo until we port the garbage collector.
 func typeBitsBulkBarrier(typ *_type, p, size uintptr) {}
-
-// Temporary for gccgo until we port print.go.
-type hex uint64
Index: libgo/runtime/mprof.goc
===================================================================
--- libgo/runtime/mprof.goc	(revision 240942)
+++ libgo/runtime/mprof.goc	(working copy)
@@ -419,17 +419,19 @@  func Stack(b Slice, all bool) (n int) {
 		n = 0;
 	else{
 		G* g = runtime_g();
-		g->writebuf = (byte*)b.__values;
-		g->writenbuf = b.__count;
+		g->writebuf.__values = b.__values;
+		g->writebuf.__count = 0;
+		g->writebuf.__capacity = b.__count;
 		USED(pc);
 		runtime_goroutineheader(g);
 		runtime_traceback();
 		runtime_printcreatedby(g);
 		if(all)
 			runtime_tracebackothers(g);
-		n = b.__count - g->writenbuf;
-		g->writebuf = nil;
-		g->writenbuf = 0;
+		n = g->writebuf.__count;
+		g->writebuf.__values = nil;
+		g->writebuf.__count = 0;
+		g->writebuf.__capacity = 0;
 	}
 	
 	if(all) {
Index: libgo/runtime/panic.c
===================================================================
--- libgo/runtime/panic.c	(revision 240942)
+++ libgo/runtime/panic.c	(working copy)
@@ -72,9 +72,11 @@  __go_rundefer(void)
 void
 runtime_startpanic(void)
 {
+	G *g;
 	M *m;
 
-	m = runtime_m();
+	g = runtime_g();
+	m = g->m;
 	if(runtime_mheap.cachealloc.size == 0) { // very early
 		runtime_printf("runtime: panic before malloc heap initialized\n");
 		m->mallocing = 1; // tell rest of panic not to try to malloc
@@ -83,8 +85,9 @@  runtime_startpanic(void)
 	switch(m->dying) {
 	case 0:
 		m->dying = 1;
-		if(runtime_g() != nil)
-			runtime_g()->writebuf = nil;
+		g->writebuf.__values = nil;
+		g->writebuf.__count = 0;
+		g->writebuf.__capacity = 0;
 		runtime_xadd(&runtime_panicking, 1);
 		runtime_lock(&paniclk);
 		if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
Index: libgo/runtime/print.c
===================================================================
--- libgo/runtime/print.c	(revision 240942)
+++ libgo/runtime/print.c	(working copy)
@@ -9,58 +9,60 @@ 
 #include "array.h"
 #include "go-type.h"
 
-//static Lock debuglock;
+extern void runtime_printlock(void)
+  __asm__(GOSYM_PREFIX "runtime.printlock");
+extern void runtime_printunlock(void)
+  __asm__(GOSYM_PREFIX "runtime.printunlock");
+extern void gwrite(Slice)
+  __asm__(GOSYM_PREFIX "runtime.gwrite");
+extern void runtime_printint(int64)
+  __asm__(GOSYM_PREFIX "runtime.printint");
+extern void runtime_printuint(uint64)
+  __asm__(GOSYM_PREFIX "runtime.printuint");
+extern void runtime_printhex(uint64)
+  __asm__(GOSYM_PREFIX "runtime.printhex");
+extern void runtime_printfloat(float64)
+  __asm__(GOSYM_PREFIX "runtime.printfloat");
+extern void runtime_printcomplex(complex double)
+  __asm__(GOSYM_PREFIX "runtime.printcomplex");
+extern void runtime_printbool(_Bool)
+  __asm__(GOSYM_PREFIX "runtime.printbool");
+extern void runtime_printstring(String)
+  __asm__(GOSYM_PREFIX "runtime.printstring");
+extern void runtime_printpointer(void *)
+  __asm__(GOSYM_PREFIX "runtime.printpointer");
+extern void runtime_printslice(Slice)
+  __asm__(GOSYM_PREFIX "runtime.printslice");
+extern void runtime_printeface(Eface)
+  __asm__(GOSYM_PREFIX "runtime.printeface");
+extern void runtime_printiface(Iface)
+  __asm__(GOSYM_PREFIX "runtime.printiface");
 
 // Clang requires this function to not be inlined (see below).
 static void go_vprintf(const char*, va_list)
 __attribute__((noinline));
 
-// write to goroutine-local buffer if diverting output,
-// or else standard error.
 static void
-gwrite(const void *v, intgo n)
+runtime_prints(const char *s)
 {
-	G* g = runtime_g();
-
-	if(g == nil || g->writebuf == nil) {
-		// Avoid -D_FORTIFY_SOURCE problems.
-		int rv __attribute__((unused));
-
-		rv = runtime_write(2, v, n);
-		return;
-	}
-
-	if(g->writenbuf == 0)
-		return;
+	Slice sl;
 
-	if(n > g->writenbuf)
-		n = g->writenbuf;
-	runtime_memmove(g->writebuf, v, n);
-	g->writebuf += n;
-	g->writenbuf -= n;
+	// Use memcpy to avoid const-cast warning.
+	memcpy(&sl.__values, &s, sizeof(char*));
+	sl.__count = runtime_findnull((const byte*)s);
+	sl.__capacity = sl.__count;
+	gwrite(sl);
 }
 
-void
-runtime_dump(byte *p, int32 n)
+static void
+runtime_printbyte(int8 c)
 {
-	int32 i;
+	Slice sl;
 
-	for(i=0; i<n; i++) {
-		runtime_printpointer((byte*)(uintptr)(p[i]>>4));
-		runtime_printpointer((byte*)(uintptr)(p[i]&0xf));
-		if((i&15) == 15)
-			runtime_prints("\n");
-		else
-			runtime_prints(" ");
-	}
-	if(n & 15)
-		runtime_prints("\n");
-}
-
-void
-runtime_prints(const char *s)
-{
-	gwrite(s, runtime_findnull((const byte*)s));
+	sl.__values = &c;
+	sl.__count = 1;
+	sl.__capacity = 1;
+	gwrite(sl);
 }
 
 #if defined (__clang__) && (defined (__i386__) || defined (__x86_64__))
@@ -104,15 +106,17 @@  runtime_snprintf(byte *buf, int32 n, con
 	va_list va;
 	int32 m;
 
-	g->writebuf = buf;
-	g->writenbuf = n-1;
+	g->writebuf.__values = buf;
+	g->writebuf.__count = 0;
+	g->writebuf.__capacity = n-1;
 	va_start(va, s);
 	go_vprintf(s, va);
 	va_end(va);
-	*g->writebuf = '\0';
-	m = g->writebuf - buf;
-	g->writenbuf = 0;
-	g->writebuf = nil;
+	m = g->writebuf.__count;
+	((byte*)g->writebuf.__values)[m] = '\0';
+	g->writebuf.__values = nil;
+	g->writebuf.__count = 0;
+	g->writebuf.__capacity = 0;
 	return m;
 }
 
@@ -122,15 +126,21 @@  static void
 go_vprintf(const char *s, va_list va)
 {
 	const char *p, *lp;
+	Slice sl;
 
-	//runtime_lock(&debuglock);
+	runtime_printlock();
 
 	lp = p = s;
 	for(; *p; p++) {
 		if(*p != '%')
 			continue;
-		if(p > lp)
-			gwrite(lp, p-lp);
+		if(p > lp) {
+			// Use memcpy to avoid const-cast warning.
+			memcpy(&sl.__values, &lp, sizeof(char*));
+			sl.__count = p - lp;
+			sl.__capacity = p - lp;
+			gwrite(sl);
+		}
 		p++;
 		switch(*p) {
 		case 'a':
@@ -181,192 +191,13 @@  go_vprintf(const char *s, va_list va)
 		}
 		lp = p+1;
 	}
-	if(p > lp)
-		gwrite(lp, p-lp);
-
-	//runtime_unlock(&debuglock);
-}
-
-void
-runtime_printpc(void *p __attribute__ ((unused)))
-{
-	runtime_prints("PC=");
-	runtime_printhex((uint64)(uintptr)runtime_getcallerpc(p));
-}
-
-void
-runtime_printbool(_Bool v)
-{
-	if(v) {
-		gwrite("true", 4);
-		return;
-	}
-	gwrite("false", 5);
-}
-
-void
-runtime_printbyte(int8 c)
-{
-	gwrite(&c, 1);
-}
-
-void
-runtime_printfloat(double v)
-{
-	byte buf[20];
-	int32 e, s, i, n;
-	float64 h;
-
-	if(ISNAN(v)) {
-		gwrite("NaN", 3);
-		return;
-	}
-	if(isinf(v)) {
-		if(signbit(v)) {
-			gwrite("-Inf", 4);
-		} else {
-			gwrite("+Inf", 4);
-		}
-		return;
-	}
-
-	n = 7;	// digits printed
-	e = 0;	// exp
-	s = 0;	// sign
-	if(v == 0) {
-		if(isinf(1/v) && 1/v < 0)
-			s = 1;
-	} else {
-		// sign
-		if(v < 0) {
-			v = -v;
-			s = 1;
-		}
-
-		// normalize
-		while(v >= 10) {
-			e++;
-			v /= 10;
-		}
-		while(v < 1) {
-			e--;
-			v *= 10;
-		}
-
-		// round
-		h = 5;
-		for(i=0; i<n; i++)
-			h /= 10;
-
-		v += h;
-		if(v >= 10) {
-			e++;
-			v /= 10;
-		}
-	}
-
-	// format +d.dddd+edd
-	buf[0] = '+';
-	if(s)
-		buf[0] = '-';
-	for(i=0; i<n; i++) {
-		s = v;
-		buf[i+2] = s+'0';
-		v -= 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] = (e/100) + '0';
-	buf[n+5] = (e/10)%10 + '0';
-	buf[n+6] = (e%10) + '0';
-	gwrite(buf, n+7);
-}
-
-void
-runtime_printcomplex(complex double v)
-{
-	gwrite("(", 1);
-	runtime_printfloat(creal(v));
-	runtime_printfloat(cimag(v));
-	gwrite("i)", 2);
-}
-
-void
-runtime_printuint(uint64 v)
-{
-	byte buf[100];
-	int32 i;
-
-	for(i=nelem(buf)-1; i>0; i--) {
-		buf[i] = v%10 + '0';
-		if(v < 10)
-			break;
-		v = v/10;
-	}
-	gwrite(buf+i, nelem(buf)-i);
-}
-
-void
-runtime_printint(int64 v)
-{
-	if(v < 0) {
-		gwrite("-", 1);
-		v = -v;
+	if(p > lp) {
+		// Use memcpy to avoid const-cast warning.
+		memcpy(&sl.__values, &lp, sizeof(char*));
+		sl.__count = p - lp;
+		sl.__capacity = p - lp;
+		gwrite(sl);
 	}
-	runtime_printuint(v);
-}
-
-void
-runtime_printhex(uint64 v)
-{
-	static const char *dig = "0123456789abcdef";
-	byte buf[100];
-	int32 i;
-
-	i=nelem(buf);
-	for(; v>0; v/=16)
-		buf[--i] = dig[v%16];
-	if(i == nelem(buf))
-		buf[--i] = '0';
-	buf[--i] = 'x';
-	buf[--i] = '0';
-	gwrite(buf+i, nelem(buf)-i);
-}
-
-void
-runtime_printpointer(void *p)
-{
-	runtime_printhex((uintptr)p);
-}
 
-void
-runtime_printstring(String v)
-{
-	// if(v.len > runtime_maxstring) {
-	//	gwrite("[string too long]", 17);
-	//	return;
-	// }
-	if(v.len > 0)
-		gwrite(v.str, v.len);
-}
-
-void
-__go_print_space(void)
-{
-	gwrite(" ", 1);
-}
-
-void
-__go_print_nl(void)
-{
-	gwrite("\n", 1);
+	runtime_printunlock();
 }
Index: libgo/runtime/proc.c
===================================================================
--- libgo/runtime/proc.c	(revision 240942)
+++ libgo/runtime/proc.c	(working copy)
@@ -2037,8 +2037,9 @@  goexit0(G *gp)
 	gp->paniconfault = 0;
 	gp->_defer = nil; // should be true already but just in case.
 	gp->_panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
-	gp->writenbuf = 0;
-	gp->writebuf = nil;
+	gp->writebuf.__values = nil;
+	gp->writebuf.__count = 0;
+	gp->writebuf.__capacity = 0;
 	gp->waitreason = runtime_gostringnocopy(nil);
 	gp->param = nil;
 	m->curg = nil;
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 240942)
+++ libgo/runtime/runtime.h	(working copy)
@@ -309,7 +309,6 @@  extern	bool	runtime_isarchive;
 #define runtime_strstr(s1, s2) __builtin_strstr((s1), (s2))
 intgo	runtime_findnull(const byte*);
 intgo	runtime_findnullw(const uint16*);
-void	runtime_dump(byte*, int32);
 
 void	runtime_gogo(G*);
 struct __go_func_type;
@@ -324,7 +323,6 @@  void	runtime_goenvs_unix(void)
 void	runtime_throw(const char*) __attribute__ ((noreturn));
 void	runtime_panicstring(const char*) __attribute__ ((noreturn));
 bool	runtime_canpanic(G*);
-void	runtime_prints(const char*);
 void	runtime_printf(const char*, ...);
 int32	runtime_snprintf(byte*, int32, const char*, ...);
 #define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
@@ -534,35 +532,8 @@  void __wrap_rtems_task_variable_add(void
 #endif
 
 /*
- * Names generated by gccgo.
- */
-#define runtime_printbool	__go_print_bool
-#define runtime_printfloat	__go_print_double
-#define runtime_printint	__go_print_int64
-#define runtime_printiface	__go_print_interface
-#define runtime_printeface	__go_print_empty_interface
-#define runtime_printstring	__go_print_string
-#define runtime_printpointer	__go_print_pointer
-#define runtime_printuint	__go_print_uint64
-#define runtime_printslice	__go_print_slice
-#define runtime_printcomplex	__go_print_complex
-
-/*
  * runtime go-called
  */
-void	runtime_printbool(_Bool);
-void	runtime_printbyte(int8);
-void	runtime_printfloat(double);
-void	runtime_printint(int64);
-void	runtime_printiface(Iface);
-void	runtime_printeface(Eface);
-void	runtime_printstring(String);
-void	runtime_printpc(void*);
-void	runtime_printpointer(void*);
-void	runtime_printuint(uint64);
-void	runtime_printhex(uint64);
-void	runtime_printslice(Slice);
-void	runtime_printcomplex(complex double);
 void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool,
 		  void **, void **)
   __asm__ (GOSYM_PREFIX "reflect.call");