From d3b00a8cc463267b24ade4cf57aafdd02440e19c Mon Sep 17 00:00:00 2001
From: Shahar Kohanim <skohanim@gmail.com>
Date: Mon, 29 Feb 2016 11:49:49 +0200
Subject: [PATCH] cmd/link: batch writing of bytes

In best of 10, linking cmd/go shows a ~10% improvement.

tip:              real  0m1.152s user  0m1.005s
this:             real  0m1.065s user  0m0.924s

Change-Id: I303a20b94332feaedc1033c453247a0e4c05c843
Reviewed-on: https://go-review.googlesource.com/19978
Reviewed-by: David Crawshaw <crawshaw@golang.org>
---
 src/cmd/link/internal/ld/data.go | 48 +++++++++++++++++++-------------
 src/cmd/link/internal/ld/lib.go  |  4 +++
 2 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index ca8eabbcca..67af9d5ba8 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -708,7 +708,6 @@ func blk(start *LSym, addr int64, size int64) {
 	}
 
 	eaddr := addr + size
-	var ep []byte
 	var p []byte
 	for ; sym != nil; sym = sym.Next {
 		if sym.Type&obj.SSUB != 0 {
@@ -723,18 +722,16 @@ func blk(start *LSym, addr int64, size int64) {
 			errorexit()
 		}
 
-		for ; addr < sym.Value; addr++ {
-			Cput(0)
+		if addr < sym.Value {
+			strnput("", int(sym.Value-addr))
+			addr = sym.Value
 		}
 		p = sym.P
-		ep = p[len(sym.P):]
-		for -cap(p) < -cap(ep) {
-			Cput(uint8(p[0]))
-			p = p[1:]
-		}
+		Cwrite(p)
 		addr += int64(len(sym.P))
-		for ; addr < sym.Value+sym.Size; addr++ {
-			Cput(0)
+		if addr < sym.Value+sym.Size {
+			strnput("", int(sym.Value+sym.Size-addr))
+			addr = sym.Value + sym.Size
 		}
 		if addr != sym.Value+sym.Size {
 			Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
@@ -746,8 +743,8 @@ func blk(start *LSym, addr int64, size int64) {
 		}
 	}
 
-	for ; addr < eaddr; addr++ {
-		Cput(0)
+	if addr < eaddr {
+		strnput("", int(eaddr-addr))
 	}
 	Cflush()
 }
@@ -899,15 +896,26 @@ func Datblk(addr int64, size int64) {
 	fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr))
 }
 
-func strnput(s string, n int) {
-	for ; n > 0 && s != ""; s = s[1:] {
-		Cput(uint8(s[0]))
-		n--
-	}
+var zeros [512]byte
 
-	for n > 0 {
-		Cput(0)
-		n--
+// strnput writes the first n bytes of s.
+// If n is larger then len(s),
+// it is padded with NUL bytes.
+func strnput(s string, n int) {
+	if len(s) >= n {
+		Cwritestring(s[:n])
+	} else {
+		Cwritestring(s)
+		n -= len(s)
+		for n > 0 {
+			if len(zeros) >= n {
+				Cwrite(zeros[:n])
+				return
+			} else {
+				Cwrite(zeros[:])
+				n -= len(zeros)
+			}
+		}
 	}
 }
 
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 93b2dab304..27fef60f18 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1850,6 +1850,10 @@ func Cseek(p int64) {
 	coutbuf.off = p
 }
 
+func Cwritestring(s string) {
+	coutbuf.WriteString(s)
+}
+
 func Cwrite(p []byte) {
 	coutbuf.Write(p)
 }
-- 
2.30.9