diff --git a/api/next.txt b/api/next.txt index cebbe877b6..b8e09df5c2 100644 --- a/api/next.txt +++ b/api/next.txt @@ -1,6 +1,7 @@ pkg archive/zip, method (*Writer) SetOffset(int64) pkg bufio, method (*Reader) Discard(int) (int, error) pkg bufio, method (ReadWriter) Discard(int) (int, error) +pkg bytes, func LastIndexByte([]uint8, uint8) int pkg bytes, method (*Buffer) Cap() int pkg bytes, method (*Reader) Size() int64 pkg crypto, type Decrypter interface { Decrypt, Public } @@ -18,16 +19,56 @@ pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196 pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200 pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 +pkg crypto/tls, method (*Config) SetSessionTicketKeys([][32]uint8) +pkg crypto/tls, type Certificate struct, SignedCertificateTimestamps [][]uint8 +pkg crypto/tls, type ConnectionState struct, OCSPResponse []uint8 +pkg crypto/tls, type ConnectionState struct, SignedCertificateTimestamps [][]uint8 +pkg crypto/x509, method (*CertificateRequest) CheckSignature() error +pkg crypto/x509, type Certificate struct, UnhandledCriticalExtensions []asn1.ObjectIdentifier pkg crypto/x509/pkix, type Name struct, ExtraNames []AttributeTypeAndValue pkg database/sql, method (*DB) Stats() DBStats pkg database/sql, type DBStats struct pkg database/sql, type DBStats struct, OpenConnections int +pkg debug/dwarf, const ClassAddress = 1 +pkg debug/dwarf, const ClassAddress Class +pkg debug/dwarf, const ClassBlock = 2 +pkg debug/dwarf, const ClassBlock Class +pkg debug/dwarf, const ClassConstant = 3 +pkg debug/dwarf, const ClassConstant Class +pkg debug/dwarf, const ClassExprLoc = 4 +pkg debug/dwarf, const ClassExprLoc Class +pkg debug/dwarf, const ClassFlag = 5 +pkg debug/dwarf, const ClassFlag Class +pkg debug/dwarf, const ClassLinePtr = 6 +pkg debug/dwarf, const ClassLinePtr Class +pkg debug/dwarf, const ClassLocListPtr = 7 +pkg debug/dwarf, const ClassLocListPtr Class +pkg debug/dwarf, const ClassMacPtr = 8 +pkg debug/dwarf, const ClassMacPtr Class +pkg debug/dwarf, const ClassRangeListPtr = 9 +pkg debug/dwarf, const ClassRangeListPtr Class +pkg debug/dwarf, const ClassReference = 10 +pkg debug/dwarf, const ClassReference Class +pkg debug/dwarf, const ClassReferenceAlt = 13 +pkg debug/dwarf, const ClassReferenceAlt Class +pkg debug/dwarf, const ClassReferenceSig = 11 +pkg debug/dwarf, const ClassReferenceSig Class +pkg debug/dwarf, const ClassString = 12 +pkg debug/dwarf, const ClassString Class +pkg debug/dwarf, const ClassStringAlt = 14 +pkg debug/dwarf, const ClassStringAlt Class pkg debug/dwarf, method (*Data) LineReader(*Entry) (*LineReader, error) +pkg debug/dwarf, method (*Entry) AttrField(Attr) *Field pkg debug/dwarf, method (*LineReader) Next(*LineEntry) error pkg debug/dwarf, method (*LineReader) Reset() pkg debug/dwarf, method (*LineReader) Seek(LineReaderPos) pkg debug/dwarf, method (*LineReader) SeekPC(uint64, *LineEntry) error pkg debug/dwarf, method (*LineReader) Tell() LineReaderPos +pkg debug/dwarf, method (*Reader) AddressSize() int +pkg debug/dwarf, method (Class) GoString() string +pkg debug/dwarf, method (Class) String() string +pkg debug/dwarf, type Class int +pkg debug/dwarf, type Field struct, Class Class pkg debug/dwarf, type LineEntry struct pkg debug/dwarf, type LineEntry struct, Address uint64 pkg debug/dwarf, type LineEntry struct, BasicBlock bool @@ -227,48 +268,52 @@ pkg encoding/base64, var RawURLEncoding *Encoding pkg encoding/json, type UnmarshalTypeError struct, Offset int64 pkg flag, func UnquoteUsage(*Flag) (string, string) pkg go/ast, type EmptyStmt struct, Implicit bool -pkg go/exact, const Bool = 1 -pkg go/exact, const Bool Kind -pkg go/exact, const Complex = 5 -pkg go/exact, const Complex Kind -pkg go/exact, const Float = 4 -pkg go/exact, const Float Kind -pkg go/exact, const Int = 3 -pkg go/exact, const Int Kind -pkg go/exact, const String = 2 -pkg go/exact, const String Kind -pkg go/exact, const Unknown = 0 -pkg go/exact, const Unknown Kind -pkg go/exact, func BinaryOp(Value, token.Token, Value) Value -pkg go/exact, func BitLen(Value) int -pkg go/exact, func BoolVal(Value) bool -pkg go/exact, func Bytes(Value) []uint8 -pkg go/exact, func Compare(Value, token.Token, Value) bool -pkg go/exact, func Denom(Value) Value -pkg go/exact, func Float32Val(Value) (float32, bool) -pkg go/exact, func Float64Val(Value) (float64, bool) -pkg go/exact, func Imag(Value) Value -pkg go/exact, func Int64Val(Value) (int64, bool) -pkg go/exact, func MakeBool(bool) Value -pkg go/exact, func MakeFloat64(float64) Value -pkg go/exact, func MakeFromBytes([]uint8) Value -pkg go/exact, func MakeFromLiteral(string, token.Token) Value -pkg go/exact, func MakeImag(Value) Value -pkg go/exact, func MakeInt64(int64) Value -pkg go/exact, func MakeString(string) Value -pkg go/exact, func MakeUint64(uint64) Value -pkg go/exact, func MakeUnknown() Value -pkg go/exact, func Num(Value) Value -pkg go/exact, func Real(Value) Value -pkg go/exact, func Shift(Value, token.Token, uint) Value -pkg go/exact, func Sign(Value) int -pkg go/exact, func StringVal(Value) string -pkg go/exact, func Uint64Val(Value) (uint64, bool) -pkg go/exact, func UnaryOp(token.Token, Value, int) Value -pkg go/exact, type Kind int -pkg go/exact, type Value interface, Kind() Kind -pkg go/exact, type Value interface, String() string -pkg go/exact, type Value interface, unexported methods +pkg go/build, type Package struct, PkgTargetRoot string +pkg go/constant, const Bool = 1 +pkg go/constant, const Bool Kind +pkg go/constant, const Complex = 5 +pkg go/constant, const Complex Kind +pkg go/constant, const Float = 4 +pkg go/constant, const Float Kind +pkg go/constant, const Int = 3 +pkg go/constant, const Int Kind +pkg go/constant, const String = 2 +pkg go/constant, const String Kind +pkg go/constant, const Unknown = 0 +pkg go/constant, const Unknown Kind +pkg go/constant, func BinaryOp(Value, token.Token, Value) Value +pkg go/constant, func BitLen(Value) int +pkg go/constant, func BoolVal(Value) bool +pkg go/constant, func Bytes(Value) []uint8 +pkg go/constant, func Compare(Value, token.Token, Value) bool +pkg go/constant, func Denom(Value) Value +pkg go/constant, func Float32Val(Value) (float32, bool) +pkg go/constant, func Float64Val(Value) (float64, bool) +pkg go/constant, func Imag(Value) Value +pkg go/constant, func Int64Val(Value) (int64, bool) +pkg go/constant, func MakeBool(bool) Value +pkg go/constant, func MakeFloat64(float64) Value +pkg go/constant, func MakeFromBytes([]uint8) Value +pkg go/constant, func MakeFromLiteral(string, token.Token, uint) Value +pkg go/constant, func MakeImag(Value) Value +pkg go/constant, func MakeInt64(int64) Value +pkg go/constant, func MakeString(string) Value +pkg go/constant, func MakeUint64(uint64) Value +pkg go/constant, func MakeUnknown() Value +pkg go/constant, func Num(Value) Value +pkg go/constant, func Real(Value) Value +pkg go/constant, func Shift(Value, token.Token, uint) Value +pkg go/constant, func Sign(Value) int +pkg go/constant, func StringVal(Value) string +pkg go/constant, func Uint64Val(Value) (uint64, bool) +pkg go/constant, func UnaryOp(token.Token, Value, uint) Value +pkg go/constant, type Kind int +pkg go/constant, type Value interface, Kind() Kind +pkg go/constant, type Value interface, String() string +pkg go/constant, type Value interface, unexported methods +pkg go/importer, func Default() types.Importer +pkg go/importer, func For(string, Lookup) types.Importer +pkg go/importer, type Lookup func(string) (io.ReadCloser, error) pkg go/types, const Bool = 1 pkg go/types, const Bool BasicKind pkg go/types, const Byte = 8 @@ -376,6 +421,7 @@ pkg go/types, func New(string) Type pkg go/types, func NewArray(Type, int64) *Array pkg go/types, func NewChan(ChanDir, Type) *Chan pkg go/types, func NewChecker(*Config, *token.FileSet, *Package, *Info) *Checker +pkg go/types, func NewConst(token.Pos, *Package, string, Type, constant.Value) *Const pkg go/types, func NewConst(token.Pos, *Package, string, Type, exact.Value) *Const pkg go/types, func NewField(token.Pos, *Package, string, Type, bool) *Var pkg go/types, func NewFunc(token.Pos, *Package, string, *Signature) *Func @@ -432,6 +478,7 @@ pkg go/types, method (*Const) Pkg() *Package pkg go/types, method (*Const) Pos() token.Pos pkg go/types, method (*Const) String() string pkg go/types, method (*Const) Type() Type +pkg go/types, method (*Const) Val() constant.Value pkg go/types, method (*Const) Val() exact.Value pkg go/types, method (*Func) Exported() bool pkg go/types, method (*Func) FullName() string @@ -590,6 +637,7 @@ pkg go/types, type Config struct, Error func(error) pkg go/types, type Config struct, FakeImportC bool pkg go/types, type Config struct, IgnoreFuncBodies bool pkg go/types, type Config struct, Import Importer +pkg go/types, type Config struct, Importer Importer pkg go/types, type Config struct, Packages map[string]*Package pkg go/types, type Config struct, Sizes Sizes pkg go/types, type Const struct @@ -600,6 +648,8 @@ pkg go/types, type Error struct, Pos token.Pos pkg go/types, type Error struct, Soft bool pkg go/types, type Func struct pkg go/types, type Importer func(map[string]*Package, string) (*Package, error) +pkg go/types, type Importer interface { Import } +pkg go/types, type Importer interface, Import(string) (*Package, error) pkg go/types, type Info struct pkg go/types, type Info struct, Defs map[*ast.Ident]Object pkg go/types, type Info struct, Implicits map[ast.Node]Object @@ -649,6 +699,7 @@ pkg go/types, type Type interface, String() string pkg go/types, type Type interface, Underlying() Type pkg go/types, type TypeAndValue struct pkg go/types, type TypeAndValue struct, Type Type +pkg go/types, type TypeAndValue struct, Value constant.Value pkg go/types, type TypeAndValue struct, Value exact.Value pkg go/types, type TypeName struct pkg go/types, type Var struct @@ -690,6 +741,18 @@ pkg image/color, type CMYK struct, K uint8 pkg image/color, type CMYK struct, M uint8 pkg image/color, type CMYK struct, Y uint8 pkg image/color, var CMYKModel Model +pkg image/gif, const DisposalBackground = 2 +pkg image/gif, const DisposalBackground ideal-int +pkg image/gif, const DisposalNone = 1 +pkg image/gif, const DisposalNone ideal-int +pkg image/gif, const DisposalPrevious = 3 +pkg image/gif, const DisposalPrevious ideal-int +pkg image/gif, type GIF struct, BackgroundIndex uint8 +pkg image/gif, type GIF struct, Config image.Config +pkg image/gif, type GIF struct, Disposal []uint8 +pkg io, func CopyBuffer(Writer, Reader, []uint8) (int64, error) +pkg log, const LUTC = 32 +pkg log, const LUTC ideal-int pkg log, func Output(int, string) error pkg log, method (*Logger) SetOutput(io.Writer) pkg math/big, const Above = 1 @@ -716,6 +779,7 @@ pkg math/big, const ToPositiveInf = 5 pkg math/big, const ToPositiveInf RoundingMode pkg math/big, const ToZero = 2 pkg math/big, const ToZero RoundingMode +pkg math/big, func Jacobi(*Int, *Int) int pkg math/big, func NewFloat(float64) *Float pkg math/big, func ParseFloat(string, int, uint, RoundingMode) (*Float, int, error) pkg math/big, func ScanFloat(io.ByteScanner, int, uint, RoundingMode) (*Float, int, error) @@ -758,6 +822,7 @@ pkg math/big, method (*Float) Signbit() bool pkg math/big, method (*Float) String() string pkg math/big, method (*Float) Sub(*Float, *Float) *Float pkg math/big, method (*Float) Uint64() (uint64, Accuracy) +pkg math/big, method (*Int) ModSqrt(*Int, *Int) *Int pkg math/big, method (Accuracy) String() string pkg math/big, method (ErrNaN) Error() string pkg math/big, method (RoundingMode) String() string @@ -765,25 +830,48 @@ pkg math/big, type Accuracy int8 pkg math/big, type ErrNaN struct pkg math/big, type Float struct pkg math/big, type RoundingMode uint8 +pkg mime, const BEncoding = 98 +pkg mime, const BEncoding WordEncoder +pkg mime, const QEncoding = 113 +pkg mime, const QEncoding WordEncoder pkg mime, func ExtensionsByType(string) ([]string, error) +pkg mime, method (*WordDecoder) Decode(string) (string, error) +pkg mime, method (*WordDecoder) DecodeHeader(string) (string, error) +pkg mime, method (WordEncoder) Encode(string, string) string +pkg mime, type WordDecoder struct +pkg mime, type WordDecoder struct, CharsetReader func(string, io.Reader) (io.Reader, error) +pkg mime, type WordEncoder uint8 +pkg mime/quotedprintable, func NewReader(io.Reader) *Reader pkg mime/quotedprintable, func NewReader(io.Reader) io.Reader pkg mime/quotedprintable, func NewWriter(io.Writer) *Writer +pkg mime/quotedprintable, method (*Reader) Read([]uint8) (int, error) pkg mime/quotedprintable, method (*Writer) Close() error pkg mime/quotedprintable, method (*Writer) Write([]uint8) (int, error) +pkg mime/quotedprintable, type Reader struct pkg mime/quotedprintable, type Writer struct pkg mime/quotedprintable, type Writer struct, Binary bool +pkg net, func SocketConn(*os.File, SocketAddr) (Conn, error) +pkg net, func SocketPacketConn(*os.File, SocketAddr) (PacketConn, error) +pkg net, type OpError struct, Source Addr +pkg net, type SocketAddr interface { Addr, Raw } +pkg net, type SocketAddr interface, Addr([]uint8) Addr +pkg net, type SocketAddr interface, Raw(Addr) []uint8 pkg net/http/fcgi, var ErrConnClosed error pkg net/http/fcgi, var ErrRequestAborted error pkg net/http/pprof, func Trace(http.ResponseWriter, *http.Request) pkg net/smtp, method (*Client) TLSConnectionState() (tls.ConnectionState, bool) +pkg os, func LookupEnv(string) (string, bool) pkg os/signal, func Ignore(...os.Signal) pkg os/signal, func Reset(...os.Signal) +pkg reflect, func ArrayOf(int, Type) Type +pkg reflect, func FuncOf([]Type, []Type, bool) Type pkg runtime, func ReadTrace() []uint8 pkg runtime, func StartTrace() error pkg runtime, func StopTrace() pkg runtime/pprof, func StartTrace(io.Writer) error pkg runtime/pprof, func StopTrace() pkg strings, func Compare(string, string) int +pkg strings, func LastIndexByte(string, uint8) int pkg strings, method (*Reader) Size() int64 pkg syscall (darwin-386), type SysProcAttr struct, Ctty int pkg syscall (darwin-386), type SysProcAttr struct, Foreground bool diff --git a/doc/effective_go.html b/doc/effective_go.html index d6be37994b..8a827d0433 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -1382,7 +1382,7 @@ limit of how much data to read. Here is the signature of the os:

-func (file *File) Read(buf []byte) (n int, err error)
+func (f *File) Read(buf []byte) (n int, err error)
 

The method returns the number of bytes read and an error value, if diff --git a/doc/go1.5.txt b/doc/go1.5.txt index b0602f9b77..f2ceb1d56b 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -1,25 +1,29 @@ Overall: -toolchain in Go -new GC +- toolchain in Go +- new GC +- go tool asm, go tool compile, go tool link +- default output files changed: now file.o and a.out Language: -permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591) +- permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591) Build: -Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993) +- Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993) New Ports: -darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127) -darwin/arm64 -linux/arm64 (cgo is supported, but only with external linking) -openbsd/arm (no cgo or external linking) -The port to Snow Leopard (OS X 10.6) is no longer actively maintained. - -Runtime: -goroutine scheduling order changed; never guaranteed by language, but can break tests that implicitly assume a specific execution order +- darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127) +- darwin/arm64 +- linux/arm64 (cgo is supported, but only with external linking) +- openbsd/arm (no cgo or external linking) Removed Ports: -dragonfly/386 (https://golang.org/cl/7543) +- dragonfly/386 (https://golang.org/cl/7543) +- The port to Snow Leopard (OS X 10.6) is no longer actively maintained. + +Runtime: +- goroutine scheduling order changed; never guaranteed by language, + but can break tests that implicitly assume a specific execution + order API additions and behavior changes: @@ -53,9 +57,12 @@ mime: add ExtensionByType (https://golang.org/cl/7444) mime/quotedprintable: new package (https://golang.org/cl/5940 + others) net: add Source field to OpError (https://go-review.googlesource.com/9231) net: fix inconsistent errors (https://golang.org/cl/9236) +net: add SocketConn, SocketPacketConn (https://golang.org/cl/9275) +net: use Go's DNS resolver when system configuration permits (https://golang.org/cl/8945) net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157) net/http: ignore the Unix epoch time in ServeContent (https://golang.org/cl/7915) net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933) +net/mail: adds AddressParser type (https://golang.org/cl/10392) net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151) os: add LookupEnv (https://golang.org/cl/9791) os/signal: add Ignore and Reset (https://golang.org/cl/3580) @@ -63,6 +70,7 @@ reflect: add ArrayOf (https://golang.org/cl/4111) reflect: add FuncOf (https://golang.org/cl/1996) runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020) runtime, syscall: use get_random_bytes syscall for NaCl (Go 1.5 now requires NaCl SDK pepper-39 or above) (https://golang.org/cl/1755) +runtime/pprof: memory profiles include overall memory statistics by default (https://golang.org/cl/9491) strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828) syscall: Add Foreground and Pgid to SysProcAttr (https://golang.org/cl/5130) syscall: add missing Syscall9 for darwin/amd64 (https://golang.org/cl/6555) @@ -106,6 +114,8 @@ cmd/gc: allocate backing storage for non-escaping interfaces on stack (https://g encoding/xml: avoid an allocation for tags without attributes (https://golang.org/cl/4160) image: many optimizations runtime: add ARM runtime.cmpstring and bytes.Compare (https://golang.org/cl/8010) +runtime: do not scan maps when k/v do not contain pointers (https://golang.org/cl/3288) +runtime: reduce thrashing of gs between ps (https://golang.org/cl/9872) sort: number of Sort performance optimizations (https://golang.org/cl/2100, https://golang.org/cl/2614, ...) strconv: optimize decimal to string conversion (https://golang.org/cl/2105) strconv: optimize float to string conversion (https://golang.org/cl/5600) diff --git a/doc/go_spec.html b/doc/go_spec.html index d02697bd0a..b5f18f3a02 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,24 +1,9 @@ - - -

Introduction

@@ -2605,7 +2590,7 @@ one may write:

 t.z          // t.z
 t.y          // t.T1.y
-t.x          // (*t.TO).x
+t.x          // (*t.T0).x
 
 p.z          // (*p).z
 p.y          // (*p).T1.y
@@ -3305,7 +3290,7 @@ Operators combine operands into expressions.
 

-Expression = UnaryExpr | Expression binary_op UnaryExpr .
+Expression = UnaryExpr | Expression binary_op Expression .
 UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
 
 binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
diff --git a/misc/android/cleaner.go b/misc/android/cleaner.go
new file mode 100644
index 0000000000..dafb162697
--- /dev/null
+++ b/misc/android/cleaner.go
@@ -0,0 +1,39 @@
+// Copyright 2015 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.
+
+// Cleaner removes anything from /data/local/tmp/goroot not on a builtin list.
+// Used by androidtest.bash.
+package main
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+func main() {
+	const goroot = "/data/local/tmp/goroot"
+	expect := make(map[string]bool)
+	for _, f := range strings.Split(files, "\n") {
+		expect[filepath.Join(goroot, f)] = true
+	}
+
+	err := filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error {
+		if expect[path] {
+			return nil
+		}
+		log.Printf("removing %s", path)
+		if err := os.RemoveAll(path); err != nil {
+			return err
+		}
+		if info.IsDir() {
+			return filepath.SkipDir
+		}
+		return nil
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 6e1d1065f6..3cc2af5919 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -6,7 +6,8 @@ package cgotest
 
 import "testing"
 
-func TestSetgid(t *testing.T)  { testSetgid(t) }
-func Test6997(t *testing.T)    { test6997(t) }
-func TestBuildID(t *testing.T) { testBuildID(t) }
-func Test9400(t *testing.T)    { test9400(t) }
+func TestSetgid(t *testing.T)      { testSetgid(t) }
+func Test6997(t *testing.T)        { test6997(t) }
+func TestBuildID(t *testing.T)     { testBuildID(t) }
+func Test9400(t *testing.T)        { test9400(t) }
+func TestSigProcMask(t *testing.T) { testSigProcMask(t) }
diff --git a/misc/cgo/test/sigprocmask_linux.c b/misc/cgo/test/sigprocmask_linux.c
new file mode 100644
index 0000000000..518c533fa4
--- /dev/null
+++ b/misc/cgo/test/sigprocmask_linux.c
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+extern void IntoGoAndBack();
+
+int CheckBlocked() {
+	sigset_t mask;
+	sigprocmask(SIG_BLOCK, NULL, &mask);
+	return sigismember(&mask, SIGIO);
+}
+
+static void* sigthreadfunc(void* unused) {
+	sigset_t mask;
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGIO);
+	sigprocmask(SIG_BLOCK, &mask, NULL);
+	IntoGoAndBack();
+	return NULL;
+}
+
+int RunSigThread() {
+	pthread_t thread;
+	int r;
+
+	r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
+	if (r != 0)
+		return r;
+	return pthread_join(thread, NULL);
+}
diff --git a/misc/cgo/test/sigprocmask_linux.go b/misc/cgo/test/sigprocmask_linux.go
new file mode 100644
index 0000000000..7d343e92c4
--- /dev/null
+++ b/misc/cgo/test/sigprocmask_linux.go
@@ -0,0 +1,38 @@
+// Copyright 2015 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 cgotest
+
+/*
+#cgo CFLAGS: -pthread
+#cgo LDFLAGS: -pthread
+extern int RunSigThread();
+extern int CheckBlocked();
+*/
+import "C"
+import (
+	"os"
+	"os/signal"
+	"syscall"
+	"testing"
+)
+
+var blocked bool
+
+//export IntoGoAndBack
+func IntoGoAndBack() {
+	// Verify that SIGIO stays blocked on the C thread
+	// even when unblocked for signal.Notify().
+	signal.Notify(make(chan os.Signal), syscall.SIGIO)
+	blocked = C.CheckBlocked() != 0
+}
+
+func testSigProcMask(t *testing.T) {
+	if r := C.RunSigThread(); r != 0 {
+		t.Error("pthread_create/pthread_join failed")
+	}
+	if !blocked {
+		t.Error("Go runtime unblocked SIGIO")
+	}
+}
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
index 9862a37993..492d25e134 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -15,6 +15,14 @@ if [ ! -f src/libgo/libgo.go ]; then
 fi
 
 goos=$(go env GOOS)
+goarch=$(go env GOARCH)
+
+# Directory where cgo headers and outputs will be installed.
+# The installation directory format varies depending on the platform.
+installdir=pkg/${goos}_${goarch}_testcshared_shared
+if [ "${goos}/${goarch}" == "android/arm" ]; then
+	installdir=pkg/${goos}_${goarch}_testcshared
+fi
 
 # Temporary directory on the android device.
 androidpath=/data/local/tmp/testcshared-$$
@@ -22,9 +30,9 @@ androidpath=/data/local/tmp/testcshared-$$
 function cleanup() {
 	rm -rf libgo.so libgo2.so libgo.h testp testp2 testp3 pkg
 
-	rm -rf $(go env GOROOT)/pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared
+	rm -rf $(go env GOROOT)/${installdir}
 
-	if [ "$(go env GOOS)" == "android" ]; then
+	if [ "$goos" == "android" ]; then
 		adb shell rm -rf $androidpath
 	fi
 }
@@ -38,11 +46,8 @@ function run() {
 	case "$goos" in
 	"android")
 		local args=$@
-		for ((i=0; i < ${#args}; i++)); do
-			args[$i]=${args[$i]//.\//${androidpath}\/}
-			args[$i]=${args[$i]//=./=${androidpath}}
-		done
-		output=$(adb shell ${args} | tr -d '\r')
+		output=$(adb shell "cd ${androidpath}; $@")
+		output=$(echo $output|tr -d '\r')
 		case $output in
 			*PASS) echo "PASS";; 
 			*) echo "$output";;
@@ -73,8 +78,9 @@ binpush libgo.so
 
 # test0: exported symbols in shared lib are accessible.
 # TODO(iant): using _shared here shouldn't really be necessary.
-$(go env CC) $(go env GOGCCFLAGS) -I pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared -o testp main0.c libgo.so
+$(go env CC) $(go env GOGCCFLAGS) -I ${installdir} -o testp main0.c libgo.so
 binpush testp
+
 output=$(run LD_LIBRARY_PATH=. ./testp)
 if [ "$output" != "PASS" ]; then
 	echo "FAIL test0 got ${output}"
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
new file mode 100644
index 0000000000..f7a99afce4
--- /dev/null
+++ b/misc/cgo/testshared/shared_test.go
@@ -0,0 +1,584 @@
+// Copyright 2015 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 shared_test
+
+import (
+	"bufio"
+	"bytes"
+	"debug/elf"
+	"encoding/binary"
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+	"time"
+)
+
+var gopathInstallDir, gorootInstallDir, suffix string
+
+// This is the smallest set of packages we can link into a shared
+// library (runtime/cgo is built implicitly).
+var minpkgs = []string{"runtime", "sync/atomic"}
+var soname = "libruntime,sync-atomic.so"
+
+// run runs a command and calls t.Errorf if it fails.
+func run(t *testing.T, msg string, args ...string) {
+	c := exec.Command(args[0], args[1:]...)
+	if output, err := c.CombinedOutput(); err != nil {
+		t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
+	}
+}
+
+// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
+// t.Errorf if the command fails.
+func goCmd(t *testing.T, args ...string) {
+	newargs := []string{args[0], "-installsuffix=" + suffix}
+	if testing.Verbose() {
+		newargs = append(newargs, "-v")
+	}
+	newargs = append(newargs, args[1:]...)
+	c := exec.Command("go", newargs...)
+	var output []byte
+	var err error
+	if testing.Verbose() {
+		fmt.Printf("+ go %s\n", strings.Join(newargs, " "))
+		c.Stdout = os.Stdout
+		c.Stderr = os.Stderr
+		err = c.Run()
+	} else {
+		output, err = c.CombinedOutput()
+	}
+	if err != nil {
+		if t != nil {
+			t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
+		} else {
+			log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
+		}
+	}
+}
+
+// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
+func testMain(m *testing.M) (int, error) {
+	// Because go install -buildmode=shared $standard_library_package always
+	// installs into $GOROOT, here are some gymnastics to come up with a unique
+	// installsuffix to use in this test that we can clean up afterwards.
+	myContext := build.Default
+	runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
+	if err != nil {
+		return 0, fmt.Errorf("import failed: %v", err)
+	}
+	for i := 0; i < 10000; i++ {
+		try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63())
+		err = os.Mkdir(try, 0700)
+		if os.IsExist(err) {
+			continue
+		}
+		if err == nil {
+			gorootInstallDir = try
+		}
+		break
+	}
+	if err != nil {
+		return 0, fmt.Errorf("can't create temporary directory: %v", err)
+	}
+	if gorootInstallDir == "" {
+		return 0, errors.New("could not create temporary directory after 10000 tries")
+	}
+	defer os.RemoveAll(gorootInstallDir)
+
+	// Some tests need to edit the source in GOPATH, so copy this directory to a
+	// temporary directory and chdir to that.
+	scratchDir, err := ioutil.TempDir("", "testshared")
+	if err != nil {
+		return 0, fmt.Errorf("TempDir failed: %v", err)
+	}
+	defer os.RemoveAll(scratchDir)
+	err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+		scratchPath := filepath.Join(scratchDir, path)
+		if info.IsDir() {
+			if path == "." {
+				return nil
+			}
+			return os.Mkdir(scratchPath, info.Mode())
+		} else {
+			fromBytes, err := ioutil.ReadFile(path)
+			if err != nil {
+				return err
+			}
+			return ioutil.WriteFile(scratchPath, fromBytes, info.Mode())
+		}
+	})
+	if err != nil {
+		return 0, fmt.Errorf("walk failed: %v", err)
+	}
+	os.Setenv("GOPATH", scratchDir)
+	myContext.GOPATH = scratchDir
+	os.Chdir(scratchDir)
+
+	// All tests depend on runtime being built into a shared library. Because
+	// that takes a few seconds, do it here and have all tests use the version
+	// built here.
+	suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2]
+	goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
+
+	myContext.InstallSuffix = suffix + "_dynlink"
+	depP, err := myContext.Import("dep", ".", build.ImportComment)
+	if err != nil {
+		return 0, fmt.Errorf("import failed: %v", err)
+	}
+	gopathInstallDir = depP.PkgTargetRoot
+	return m.Run(), nil
+}
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	exitCode, err := testMain(m)
+	if err != nil {
+		log.Fatal(err)
+	}
+	os.Exit(exitCode)
+}
+
+// The shared library was built at the expected location.
+func TestSOBuilt(t *testing.T) {
+	_, err := os.Stat(filepath.Join(gorootInstallDir, soname))
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+// The install command should have created a "shlibname" file for the
+// listed packages (and runtime/cgo) indicating the name of the shared
+// library containing it.
+func TestShlibnameFiles(t *testing.T) {
+	pkgs := append([]string{}, minpkgs...)
+	pkgs = append(pkgs, "runtime/cgo")
+	for _, pkg := range pkgs {
+		shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname")
+		contentsb, err := ioutil.ReadFile(shlibnamefile)
+		if err != nil {
+			t.Errorf("error reading shlibnamefile for %s: %v", pkg, err)
+			continue
+		}
+		contents := strings.TrimSpace(string(contentsb))
+		if contents != soname {
+			t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents)
+		}
+	}
+}
+
+// Is a given offset into the file contained in a loaded segment?
+func isOffsetLoaded(f *elf.File, offset uint64) bool {
+	for _, prog := range f.Progs {
+		if prog.Type == elf.PT_LOAD {
+			if prog.Off <= offset && offset < prog.Off+prog.Filesz {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func rnd(v int32, r int32) int32 {
+	if r <= 0 {
+		return v
+	}
+	v += r - 1
+	c := v % r
+	if c < 0 {
+		c += r
+	}
+	v -= c
+	return v
+}
+
+func readwithpad(r io.Reader, sz int32) ([]byte, error) {
+	data := make([]byte, rnd(sz, 4))
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+type note struct {
+	name    string
+	tag     int32
+	desc    string
+	section *elf.Section
+}
+
+// Read all notes from f. As ELF section names are not supposed to be special, one
+// looks for a particular note by scanning all SHT_NOTE sections looking for a note
+// with a particular "name" and "tag".
+func readNotes(f *elf.File) ([]*note, error) {
+	var notes []*note
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, tag int32
+			err := binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &tag)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed:", err)
+			}
+			name, err := readwithpad(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed:", err)
+			}
+			desc, err := readwithpad(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed:", err)
+			}
+			notes = append(notes, ¬e{name: string(name), tag: tag, desc: string(desc), section: sect})
+		}
+	}
+	return notes, nil
+}
+
+func dynStrings(path string, flag elf.DynTag) []string {
+	f, err := elf.Open(path)
+	defer f.Close()
+	if err != nil {
+		log.Fatal("elf.Open failed: ", err)
+	}
+	dynstrings, err := f.DynString(flag)
+	if err != nil {
+		log.Fatal("dynstring failed: ", err)
+	}
+	return dynstrings
+}
+
+func AssertIsLinkedTo(t *testing.T, path, lib string) {
+	for _, dynstring := range dynStrings(path, elf.DT_NEEDED) {
+		if dynstring == lib {
+			return
+		}
+	}
+	t.Errorf("%s is not linked to %s", path, lib)
+}
+
+func AssertHasRPath(t *testing.T, path, dir string) {
+	for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} {
+		for _, dynstring := range dynStrings(path, tag) {
+			for _, rpath := range strings.Split(dynstring, ":") {
+				if filepath.Clean(rpath) == filepath.Clean(dir) {
+					return
+				}
+			}
+		}
+	}
+	t.Errorf("%s does not have rpath %s", path, dir)
+}
+
+// Build a trivial program that links against the shared runtime and check it runs.
+func TestTrivialExecutable(t *testing.T) {
+	goCmd(t, "install", "-linkshared", "trivial")
+	run(t, "trivial executable", "./bin/trivial")
+	AssertIsLinkedTo(t, "./bin/trivial", soname)
+	AssertHasRPath(t, "./bin/trivial", gorootInstallDir)
+}
+
+// Build a GOPATH package into a shared library that links against the goroot runtime
+// and an executable that links against both.
+func TestGOPathShlib(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdep.so"), soname)
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertIsLinkedTo(t, "./bin/exe", soname)
+	AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+	AssertHasRPath(t, "./bin/exe", gorootInstallDir)
+	AssertHasRPath(t, "./bin/exe", gopathInstallDir)
+	// And check it runs.
+	run(t, "executable linked to GOPATH library", "./bin/exe")
+}
+
+// The shared library contains a note listing the packages it contains in a section
+// that is not mapped into memory.
+func testPkgListNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != 0 {
+		t.Errorf("package list section has flags %v", note.section.Flags)
+	}
+	if isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("package list section contained in PT_LOAD segment")
+	}
+	if note.desc != "dep\n" {
+		t.Errorf("incorrect package list %q", note.desc)
+	}
+}
+
+// The shared library contains a note containing the ABI hash that is mapped into
+// memory and there is a local symbol called go.link.abihashbytes that points 16
+// bytes into it.
+func testABIHashNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != elf.SHF_ALLOC {
+		t.Errorf("abi hash section has flags %v", note.section.Flags)
+	}
+	if !isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("abihash section not contained in PT_LOAD segment")
+	}
+	var hashbytes elf.Symbol
+	symbols, err := f.Symbols()
+	if err != nil {
+		t.Errorf("error reading symbols %v", err)
+		return
+	}
+	for _, sym := range symbols {
+		if sym.Name == "go.link.abihashbytes" {
+			hashbytes = sym
+		}
+	}
+	if hashbytes.Name == "" {
+		t.Errorf("no symbol called go.link.abihashbytes")
+		return
+	}
+	if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
+		t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
+	}
+	if f.Sections[hashbytes.Section] != note.section {
+		t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name)
+	}
+	if hashbytes.Value-note.section.Addr != 16 {
+		t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr)
+	}
+}
+
+// A Go shared library contains a note indicating which other Go shared libraries it
+// was linked against in an unmapped section.
+func testDepsNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != 0 {
+		t.Errorf("package list section has flags %v", note.section.Flags)
+	}
+	if isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("package list section contained in PT_LOAD segment")
+	}
+	// libdep.so just links against the lib containing the runtime.
+	if note.desc != soname {
+		t.Errorf("incorrect dependency list %q", note.desc)
+	}
+}
+
+// The shared library contains notes with defined contents; see above.
+func TestNotes(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	f, err := elf.Open(filepath.Join(gopathInstallDir, "libdep.so"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	notes, err := readNotes(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+	pkgListNoteFound := false
+	abiHashNoteFound := false
+	depsNoteFound := false
+	for _, note := range notes {
+		if note.name != "GO\x00\x00" {
+			continue
+		}
+		switch note.tag {
+		case 1: // ELF_NOTE_GOPKGLIST_TAG
+			if pkgListNoteFound {
+				t.Error("multiple package list notes")
+			}
+			testPkgListNote(t, f, note)
+			pkgListNoteFound = true
+		case 2: // ELF_NOTE_GOABIHASH_TAG
+			if abiHashNoteFound {
+				t.Error("multiple abi hash notes")
+			}
+			testABIHashNote(t, f, note)
+			abiHashNoteFound = true
+		case 3: // ELF_NOTE_GODEPS_TAG
+			if depsNoteFound {
+				t.Error("multiple abi hash notes")
+			}
+			testDepsNote(t, f, note)
+			depsNoteFound = true
+		}
+	}
+	if !pkgListNoteFound {
+		t.Error("package list note not found")
+	}
+	if !abiHashNoteFound {
+		t.Error("abi hash note not found")
+	}
+	if !depsNoteFound {
+		t.Error("deps note not found")
+	}
+}
+
+// Build a GOPATH package (dep) into a shared library that links against the goroot
+// runtime, another package (dep2) that links against the first, and and an
+// executable that links against dep2.
+func TestTwoGOPathShlibs(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
+	goCmd(t, "install", "-linkshared", "exe2")
+	run(t, "executable linked to GOPATH library", "./bin/exe2")
+}
+
+// Testing rebuilding of shared libraries when they are stale is a bit more
+// complicated that it seems like it should be. First, we make everything "old": but
+// only a few seconds old, or it might be older than 6g (or the runtime source) and
+// everything will get rebuilt. Then define a timestamp slightly newer than this
+// time, which is what we set the mtime to of a file to cause it to be seen as new,
+// and finally another slightly even newer one that we can compare files against to
+// see if they have been rebuilt.
+var oldTime = time.Now().Add(-9 * time.Second)
+var nearlyNew = time.Now().Add(-6 * time.Second)
+var stampTime = time.Now().Add(-3 * time.Second)
+
+// resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the
+// test-specific parts of GOROOT) appear old.
+func resetFileStamps() {
+	chtime := func(path string, info os.FileInfo, err error) error {
+		return os.Chtimes(path, oldTime, oldTime)
+	}
+	reset := func(path string) {
+		if err := filepath.Walk(path, chtime); err != nil {
+			log.Fatalf("resetFileStamps failed: %v", err)
+		}
+
+	}
+	reset("bin")
+	reset("pkg")
+	reset("src")
+	reset(gorootInstallDir)
+}
+
+// touch makes path newer than the "old" time stamp used by resetFileStamps.
+func touch(path string) {
+	if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
+		log.Fatalf("os.Chtimes failed: %v", err)
+	}
+}
+
+// isNew returns if the path is newer than the time stamp used by touch.
+func isNew(path string) bool {
+	fi, err := os.Stat(path)
+	if err != nil {
+		log.Fatalf("os.Stat failed: %v", err)
+	}
+	return fi.ModTime().After(stampTime)
+}
+
+// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by
+// isNew)
+func AssertRebuilt(t *testing.T, msg, path string) {
+	if !isNew(path) {
+		t.Errorf("%s was not rebuilt (%s)", msg, path)
+	}
+}
+
+// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew)
+func AssertNotRebuilt(t *testing.T, msg, path string) {
+	if isNew(path) {
+		t.Errorf("%s was rebuilt (%s)", msg, path)
+	}
+}
+
+func TestRebuilding(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-linkshared", "exe")
+
+	// If the source is newer than both the .a file and the .so, both are rebuilt.
+	resetFileStamps()
+	touch("src/dep/dep.go")
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "dep.a"))
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdep.so"))
+
+	// If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
+	resetFileStamps()
+	touch(filepath.Join(gopathInstallDir, "dep.a"))
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "dep.a"))
+	AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdep.so"))
+}
+
+func appendFile(path, content string) {
+	f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660)
+	if err != nil {
+		log.Fatalf("os.OpenFile failed: %v", err)
+	}
+	defer func() {
+		err := f.Close()
+		if err != nil {
+			log.Fatalf("f.Close failed: %v", err)
+		}
+	}()
+	_, err = f.WriteString(content)
+	if err != nil {
+		log.Fatalf("f.WriteString failed: %v", err)
+	}
+}
+
+func TestABIChecking(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-linkshared", "exe")
+
+	// If we make an ABI-breaking change to dep and rebuild libp.so but not exe,
+	// exe will abort with a complaint on startup.
+	// This assumes adding an exported function breaks ABI, which is not true in
+	// some senses but suffices for the narrow definition of ABI compatiblity the
+	// toolchain uses today.
+	appendFile("src/dep/dep.go", "func ABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	c := exec.Command("./bin/exe")
+	output, err := c.CombinedOutput()
+	if err == nil {
+		t.Fatal("executing exe did not fail after ABI break")
+	}
+	scanner := bufio.NewScanner(bytes.NewReader(output))
+	foundMsg := false
+	const wantLine = "abi mismatch detected between the executable and libdep.so"
+	for scanner.Scan() {
+		if scanner.Text() == wantLine {
+			foundMsg = true
+			break
+		}
+	}
+	if err = scanner.Err(); err != nil {
+		t.Errorf("scanner encountered error: %v", err)
+	}
+	if !foundMsg {
+		t.Fatalf("exe failed, but without line %q; got output:\n%s", wantLine, output)
+	}
+
+	// Rebuilding exe makes it work again.
+	goCmd(t, "install", "-linkshared", "exe")
+	run(t, "rebuilt exe", "./bin/exe")
+
+	// If we make a change which does not break ABI (such as adding an unexported
+	// function) and rebuild libdep.so, exe still works.
+	appendFile("src/dep/dep.go", "func noABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	run(t, "after non-ABI breaking change", "./bin/exe")
+}
diff --git a/misc/cgo/testshared/src/dep/dep.go b/misc/cgo/testshared/src/dep/dep.go
index fb112cdb82..d3bed3f8ff 100644
--- a/misc/cgo/testshared/src/dep/dep.go
+++ b/misc/cgo/testshared/src/dep/dep.go
@@ -2,6 +2,12 @@ package dep
 
 var V int = 1
 
+var HasMask []string = []string{"hi"}
+
+type HasProg struct {
+	array [1024]*byte
+}
+
 func F() int {
 	return V
 }
diff --git a/misc/cgo/testshared/src/dep2/dep2.go b/misc/cgo/testshared/src/dep2/dep2.go
new file mode 100644
index 0000000000..bac1086a4a
--- /dev/null
+++ b/misc/cgo/testshared/src/dep2/dep2.go
@@ -0,0 +1,11 @@
+package dep2
+
+import "dep"
+
+var W int = 1
+
+var hasProg dep.HasProg
+
+func G() int {
+	return dep.F() + 1
+}
diff --git a/misc/cgo/testshared/src/exe2/exe2.go b/misc/cgo/testshared/src/exe2/exe2.go
new file mode 100644
index 0000000000..acdb4ddcc5
--- /dev/null
+++ b/misc/cgo/testshared/src/exe2/exe2.go
@@ -0,0 +1,7 @@
+package main
+
+import "dep2"
+
+func main() {
+	dep2.W = dep2.G() + 1
+}
diff --git a/misc/cgo/testshared/test.bash b/misc/cgo/testshared/test.bash
deleted file mode 100755
index 21004adaf8..0000000000
--- a/misc/cgo/testshared/test.bash
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2015 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.
-
-# Test that -buildmode=shared can produce a shared library and that
-# -linkshared can link against it to produce a working executable.
-
-set -eu
-
-export GOPATH="$(pwd)"
-
-die () {
-    echo $@
-    exit 1
-}
-
-# Because go install -buildmode=shared $standard_library_package always
-# installs into $GOROOT, here are some gymnastics to come up with a
-# unique installsuffix to use in this test that we can clean up
-# afterwards.
-rootdir="$(dirname $(go list -f '{{.Target}}' runtime))"
-template="${rootdir}_XXXXXXXX_dynlink"
-std_install_dir=$(mktemp -d "$template")
-
-cleanup () {
-    rm -rf $std_install_dir ./bin/ ./pkg/
-}
-trap cleanup EXIT
-
-mysuffix=$(echo $std_install_dir | sed -e 's/.*_\([^_]*\)_dynlink/\1/')
-
-# This is the smallest set of packages we can link into a shared
-# library (runtime/cgo is built implicitly). Check they are built into
-# a library with the expected name.
-minpkgs="runtime sync/atomic"
-soname=libruntime,sync-atomic.so
-
-go install -installsuffix="$mysuffix" -buildmode=shared $minpkgs || die "install -buildmode=shared failed"
-
-if [ ! -f "$std_install_dir/$soname" ]; then
-    echo "$std_install_dir/$soname not found!"
-    exit 1
-fi
-
-# The install command should have created a "shlibname" file for the
-# listed packages (and runtime/cgo) indicating the name of the shared
-# library containing it.
-for pkg in $minpkgs runtime/cgo; do
-    if [ ! -f "$std_install_dir/$pkg.shlibname" ]; then
-        die "no shlibname file for $pkg"
-    fi
-    if [ "$(cat "$std_install_dir/$pkg.shlibname")" != "$soname" ]; then
-        die "shlibname file for $pkg has wrong contents"
-    fi
-done
-
-# Build a trivial program that links against the shared library we
-# just made and check it runs.
-go install -installsuffix="$mysuffix" -linkshared trivial || die "build -linkshared failed"
-./bin/trivial || die "./bin/trivial failed"
-
-# And check that it is actually dynamically linked against the library
-# we hope it is linked against.
-
-ensure_ldd () {
-    a="$(ldd $1)" || die "ldd $1 failed: $a"
-    { echo "$a" | grep -q "$2"; } || die "$1 does not appear to be linked against $2"
-}
-
-ensure_ldd ./bin/trivial $std_install_dir/$soname
-
-# Build a GOPATH package into a shared library that links against the above one.
-rootdir="$(dirname $(go list -installsuffix="$mysuffix" -linkshared -f '{{.Target}}' dep))"
-go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep
-ensure_ldd $rootdir/libdep.so $std_install_dir/$soname
-
-
-# And exe that links against both
-go install -installsuffix="$mysuffix" -linkshared exe
-ensure_ldd ./bin/exe $rootdir/libdep.so
-ensure_ldd ./bin/exe $std_install_dir/$soname
-
-# Now, test rebuilding of shared libraries when they are stale.
-
-will_check_rebuilt () {
-    for f in $@; do cp $f $f.bak; done
-}
-
-assert_rebuilt () {
-    find $1 -newer $1.bak | grep -q . || die "$1 was not rebuilt"
-}
-
-assert_not_rebuilt () {
-    find $1 -newer $1.bak | grep  . && die "$1 was rebuilt" || true
-}
-
-# If the source is newer than both the .a file and the .so, both are rebuilt.
-touch src/dep/dep.go
-will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a
-go install -installsuffix="$mysuffix" -linkshared exe
-assert_rebuilt $rootdir/dep.a
-assert_rebuilt $rootdir/libdep.so
-
-# If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
-touch $rootdir/dep.a
-will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a
-go install  -installsuffix="$mysuffix" -linkshared exe
-assert_not_rebuilt $rootdir/dep.a
-assert_rebuilt $rootdir/libdep.so
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index 1c013c1784..8e53726ea5 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -35,7 +35,7 @@ go	src=..
 				gofmt_test.go
 				testdata
 					+
-			link
+			newlink
 				testdata
 					+
 		archive
diff --git a/misc/trace/README.md b/misc/trace/README.md
index b9364de78c..775fdb8c10 100644
--- a/misc/trace/README.md
+++ b/misc/trace/README.md
@@ -1,6 +1,37 @@
-This directory contains helper file for trace viewer (go tool trace).
+This directory contains helper file for trace viewer (`go tool trace`).
 
-trace_viewer_lean.html was generated following instructions in:
-https://github.com/google/trace-viewer/wiki/Embedding
-on revision 895aa74558d19d91906fb720df6458244ef160c6 using:
+`trace_viewer_lean.html` was generated by following
+[instructions](https://github.com/google/trace-viewer/wiki/Embedding)
+on revision `895aa74558d19d91906fb720df6458244ef160c6` using:
+```
 trace-viewer$ ./vulcanize_trace_viewer --config=lean
+```
+
+The license for trace-viewer is as follows:
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/androidtest.bash b/src/androidtest.bash
index aad1f7ec8d..39e73c350b 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -24,10 +24,11 @@ if [ "$GOOS" != "android" ]; then
 fi
 
 export CGO_ENABLED=1
+unset GOBIN
 
-# Run the build for the host bootstrap, so we can build go_android_exec.
+# Do the build first, so we can build go_android_exec and cleaner.
 # Also lets us fail early before the (slow) adb push if the build is broken.
-./make.bash
+. ./make.bash --no-banner
 export GOROOT=$(dirname $(pwd))
 export PATH=$GOROOT/bin:$PATH
 GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
@@ -50,9 +51,21 @@ cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
 cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
 cp -a "${GOROOT}/pkg/android_$GOARCH" "${FAKE_GOROOT}/pkg/"
 echo '# Syncing test files to android device'
+adb shell mkdir -p /data/local/tmp/goroot
 time adb sync data &> /dev/null
-echo ''
-rm -rf "$ANDROID_PRODUCT_OUT"
 
-# Run standard build and tests.
-./all.bash --no-clean
+export CLEANER=/tmp/androidcleaner-$$
+cp ../misc/android/cleaner.go $CLEANER.go
+echo 'var files = `' >> $CLEANER.go
+(cd $ANDROID_PRODUCT_OUT/data/local/tmp/goroot; find . >> $CLEANER.go)
+echo '`' >> $CLEANER.go
+go build -o $CLEANER $CLEANER.go
+adb push $CLEANER /data/local/tmp/cleaner
+rm $CLEANER $CLEANER.go
+adb shell /data/local/tmp/cleaner
+
+rm -rf "$ANDROID_PRODUCT_OUT"
+echo ''
+
+# Run standard tests.
+bash run.bash --no-rebuild
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index abd8f148a7..cd23fb57d6 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -463,6 +463,10 @@ func (tr *Reader) readHeader() *Header {
 	hdr.Uid = int(tr.octal(s.next(8)))
 	hdr.Gid = int(tr.octal(s.next(8)))
 	hdr.Size = tr.octal(s.next(12))
+	if hdr.Size < 0 {
+		tr.err = ErrHeader
+		return nil
+	}
 	hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
 	s.next(8) // chksum
 	hdr.Typeflag = s.next(1)[0]
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index 9601ffe459..ab1e8445a4 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -741,3 +741,19 @@ func TestUninitializedRead(t *testing.T) {
 	}
 
 }
+
+// Negative header size should not cause panic.
+// Issues 10959 and 10960.
+func TestNegativeHdrSize(t *testing.T) {
+	f, err := os.Open("testdata/neg-size.tar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	r := NewReader(f)
+	_, err = r.Next()
+	if err != ErrHeader {
+		t.Error("want ErrHeader, got", err)
+	}
+	io.Copy(ioutil.Discard, r)
+}
diff --git a/src/archive/tar/testdata/neg-size.tar b/src/archive/tar/testdata/neg-size.tar
new file mode 100644
index 0000000000..5deea3d05c
Binary files /dev/null and b/src/archive/tar/testdata/neg-size.tar differ
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 8136b840d4..f68ab09723 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"hash"
 	"hash/crc32"
 	"io"
@@ -77,6 +78,9 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
 	if err != nil {
 		return err
 	}
+	if end.directoryRecords > uint64(size)/fileHeaderLen {
+		return fmt.Errorf("archive/zip: TOC declares impossible %d files in %d byte zip", end.directoryRecords, size)
+	}
 	z.r = r
 	z.File = make([]*File, 0, end.directoryRecords)
 	z.Comment = end.comment
@@ -146,16 +150,22 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
 	if f.hasDataDescriptor() {
 		desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
 	}
-	rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
+	rc = &checksumReader{
+		rc:   rc,
+		hash: crc32.NewIEEE(),
+		f:    f,
+		desr: desr,
+	}
 	return
 }
 
 type checksumReader struct {
-	rc   io.ReadCloser
-	hash hash.Hash32
-	f    *File
-	desr io.Reader // if non-nil, where to read the data descriptor
-	err  error     // sticky error
+	rc    io.ReadCloser
+	hash  hash.Hash32
+	nread uint64 // number of bytes read so far
+	f     *File
+	desr  io.Reader // if non-nil, where to read the data descriptor
+	err   error     // sticky error
 }
 
 func (r *checksumReader) Read(b []byte) (n int, err error) {
@@ -164,10 +174,14 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
 	}
 	n, err = r.rc.Read(b)
 	r.hash.Write(b[:n])
+	r.nread += uint64(n)
 	if err == nil {
 		return
 	}
 	if err == io.EOF {
+		if r.nread != r.f.UncompressedSize64 {
+			return 0, io.ErrUnexpectedEOF
+		}
 		if r.desr != nil {
 			if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
 				err = err1
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 29d0652dcc..4806b89458 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -531,3 +531,54 @@ func TestIssue8186(t *testing.T) {
 		}
 	}
 }
+
+// Verify we return ErrUnexpectedEOF when length is short.
+func TestIssue10957(t *testing.T) {
+	data := []byte("PK\x03\x040000000PK\x01\x0200000" +
+		"0000000000000000000\x00" +
+		"\x00\x00\x00\x00\x00000000000000PK\x01" +
+		"\x020000000000000000000" +
+		"00000\v\x00\x00\x00\x00\x00000000000" +
+		"00000000000000PK\x01\x0200" +
+		"00000000000000000000" +
+		"00\v\x00\x00\x00\x00\x00000000000000" +
+		"00000000000PK\x01\x020000<" +
+		"0\x00\x0000000000000000\v\x00\v" +
+		"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
+		"00000000PK\x01\x0200000000" +
+		"0000000000000000\v\x00\x00\x00" +
+		"\x00\x0000PK\x05\x06000000\x05\x000000" +
+		"\v\x00\x00\x00\x00\x00")
+	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for i, f := range z.File {
+		r, err := f.Open()
+		if err != nil {
+			continue
+		}
+		if f.UncompressedSize64 < 1e6 {
+			n, err := io.Copy(ioutil.Discard, r)
+			if i == 3 && err != io.ErrUnexpectedEOF {
+				t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
+			}
+			if err == nil && uint64(n) != f.UncompressedSize64 {
+				t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64)
+			}
+		}
+		r.Close()
+	}
+}
+
+// Verify the number of files is sane.
+func TestIssue10956(t *testing.T) {
+	data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" +
+		"0000PK\x05\x06000000000000" +
+		"0000\v\x00000\x00\x00\x00\x00\x00\x00\x000")
+	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	const want = "TOC declares impossible 3472328296227680304 files in 57 byte"
+	if err == nil && !strings.Contains(err.Error(), want) {
+		t.Errorf("error = %v; want %q", err, want)
+	}
+}
diff --git a/src/buildall.bash b/src/buildall.bash
index a07529e733..ba23d31a50 100755
--- a/src/buildall.bash
+++ b/src/buildall.bash
@@ -36,7 +36,7 @@ fi
 targets="$((ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
 $(ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
 
-./make.bash
+./make.bash || exit 1
 GOROOT="$(cd .. && pwd)"
 
 failed=false
diff --git a/src/cmd/6l/z.go b/src/cmd/6l/z.go
deleted file mode 100644
index 06ab7d0f9a..0000000000
--- a/src/cmd/6l/z.go
+++ /dev/null
@@ -1 +0,0 @@
-package main
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 725c6352cb..d5d2772ef3 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -493,7 +493,10 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			if arch.IsARM64STLXR(op) {
 				prog.From = a[0]
 				prog.To = a[1]
-				prog.To2 = a[2]
+				if a[2].Type != obj.TYPE_REG {
+					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
+				}
+				prog.RegTo2 = a[2].Reg
 				break
 			}
 			prog.From = a[0]
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index c74f26974a..bf5cb1eef3 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -51,7 +51,7 @@ func Usage() {
 	os.Exit(2)
 }
 
-func Parse(theChar int) {
+func Parse() {
 	flag.Usage = Usage
 	flag.Parse()
 	if flag.NArg() != 1 {
@@ -64,6 +64,6 @@ func Parse(theChar int) {
 		if strings.HasSuffix(input, ".s") {
 			input = input[:len(input)-2]
 		}
-		*OutputFile = fmt.Sprintf("%s.%c", input, theChar)
+		*OutputFile = fmt.Sprintf("%s.o", input)
 	}
 }
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index 730042b149..7e495b8edf 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -13,7 +13,6 @@ import (
 	"text/scanner"
 
 	"cmd/asm/internal/flags"
-	"cmd/internal/obj"
 )
 
 // Input is the main input: a stack of readers and some macro definitions.
@@ -436,7 +435,7 @@ func (in *Input) line() {
 	if tok != '\n' {
 		in.Error("unexpected token at end of #line: ", tok)
 	}
-	obj.Linklinehist(linkCtxt, histLine, file, line)
+	linkCtxt.LineHist.Update(histLine, file, line)
 	in.Stack.SetPos(line, file)
 }
 
diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go
index 28a4b85253..6a4d95491f 100644
--- a/src/cmd/asm/internal/lex/tokenizer.go
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -10,8 +10,6 @@ import (
 	"strings"
 	"text/scanner"
 	"unicode"
-
-	"cmd/internal/obj"
 )
 
 // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
@@ -40,7 +38,7 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
 	s.Position.Filename = name
 	s.IsIdentRune = isIdentRune
 	if file != nil {
-		obj.Linklinehist(linkCtxt, histLine, name, 0)
+		linkCtxt.LineHist.Push(histLine, name)
 	}
 	return &Tokenizer{
 		s:        &s,
@@ -149,6 +147,6 @@ func (t *Tokenizer) Close() {
 	if t.file != nil {
 		t.file.Close()
 		// It's an open file, so pop the line history.
-		obj.Linklinehist(linkCtxt, histLine, "", 0)
+		linkCtxt.LineHist.Pop(histLine)
 	}
 }
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 32bdee6624..db0e28e2e5 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -29,7 +29,7 @@ func main() {
 		log.Fatalf("asm: unrecognized architecture %s", GOARCH)
 	}
 
-	flags.Parse(architecture.Thechar)
+	flags.Parse()
 
 	// Create object file, write header.
 	fd, err := os.Create(*flags.OutputFile)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 30f828c4e9..87f21ed822 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -846,6 +846,8 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 			fmt.Fprint(fgo2, "}\n")
 		}
 	}
+
+	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
 }
 
 // Write out the C header allowing C code to call exported gccgo functions.
@@ -1009,6 +1011,8 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		fmt.Fprint(fgo2, ")\n")
 		fmt.Fprint(fgo2, "}\n")
 	}
+
+	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
 }
 
 // writeExportHeader writes out the start of the _cgo_export.h file.
@@ -1374,6 +1378,17 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
 #endif
 
 /* End of boilerplate cgo prologue.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+`
+
+// gccExportHeaderEpilog goes at the end of the generated header file.
+const gccExportHeaderEpilog = `
+#ifdef __cplusplus
+}
+#endif
 `
 
 // gccgoExportFileProlog is written to the _cgo_export.c file when
diff --git a/src/cmd/6g/cgen.go b/src/cmd/compile/internal/amd64/cgen.go
similarity index 98%
rename from src/cmd/6g/cgen.go
rename to src/cmd/compile/internal/amd64/cgen.go
index 23e2d1b57f..71f8f88322 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/compile/internal/amd64/cgen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
diff --git a/src/cmd/6g/galign.go b/src/cmd/compile/internal/amd64/galign.go
similarity index 97%
rename from src/cmd/6g/galign.go
rename to src/cmd/compile/internal/amd64/galign.go
index 0ca87537ff..79bf94a075 100644
--- a/src/cmd/6g/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -65,7 +65,7 @@ func betypeinit() {
 	}
 }
 
-func main() {
+func Main() {
 	if obj.Getgoos() == "nacl" {
 		resvd = append(resvd, x86.REG_BP, x86.REG_R15)
 	} else if obj.Framepointer_enabled != 0 {
@@ -101,6 +101,7 @@ func main() {
 	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
 	gc.Thearch.Ginsboolval = ginsboolval
+	gc.Thearch.Ginscmp = ginscmp
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
diff --git a/src/cmd/6g/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
similarity index 97%
rename from src/cmd/6g/ggen.go
rename to src/cmd/compile/internal/amd64/ggen.go
index 6e5e6bc4ca..6425633818 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) {
 	// iterate through declarations - they are sorted in decreasing xoffset order.
 	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if !n.Needzero {
+		if !n.Name.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -190,9 +190,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
diff --git a/src/cmd/6g/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
similarity index 95%
rename from src/cmd/6g/gsubr.go
rename to src/cmd/compile/internal/amd64/gsubr.go
index 53d0f038d9..a8e4170bee 100644
--- a/src/cmd/6g/gsubr.go
+++ b/src/cmd/compile/internal/amd64/gsubr.go
@@ -28,10 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
@@ -99,33 +100,67 @@ func ginscon(as int, c int64, n2 *gc.Node) {
 	gins(as, &n1, n2)
 }
 
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+	// General case.
+	var r1, r2, g1, g2 gc.Node
+	if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+		r1 = *n1
+	} else {
+		gc.Regalloc(&r1, t, n1)
+		gc.Regalloc(&g1, n1.Type, &r1)
+		gc.Cgen(n1, &g1)
+		gmove(&g1, &r1)
+	}
+	if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) {
+		r2 = *n2
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+	}
+	gins(optoas(gc.OCMP, t), &r1, &r2)
+	if r1.Op == gc.OREGISTER {
+		gc.Regfree(&g1)
+		gc.Regfree(&r1)
+	}
+	if r2.Op == gc.OREGISTER {
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
 func ginsboolval(a int, n *gc.Node) {
 	gins(jmptoset(a), nil, n)
 }
 
-/*
- * set up nodes representing 2^63
- */
-var bigi gc.Node
-
-var bigf gc.Node
-
-var bignodes_did int
+// set up nodes representing 2^63
+var (
+	bigi         gc.Node
+	bigf         gc.Node
+	bignodes_did bool
+)
 
 func bignodes() {
-	if bignodes_did != 0 {
+	if bignodes_did {
 		return
 	}
-	bignodes_did = 1
+	bignodes_did = true
 
-	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1)
-	gc.Mpshiftfix(bigi.Val.U.Xval, 63)
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
 
-	bigf = bigi
-	bigf.Type = gc.Types[gc.TFLOAT64]
-	bigf.Val.Ctype = gc.CTFLT
-	bigf.Val.U.Fval = new(gc.Mpflt)
-	gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval)
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+
+	bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
 }
 
 /*
@@ -156,7 +191,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	// convert constant to desired type
 	if f.Op == gc.OLITERAL {
 		var con gc.Node
-		gc.Convconst(&con, t.Type, &f.Val)
+		f.Convconst(&con, t.Type)
 		f = &con
 		ft = tt // so big switch will choose a simple mov
 
@@ -170,10 +205,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 			// 64-bit immediates are really 32-bit sign-extended
 			// unless moving into a register.
 			if gc.Isint[tt] {
-				if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 {
-					goto hard
-				}
-				if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 {
+				if i := con.Int(); int64(int32(i)) != i {
 					goto hard
 				}
 			}
@@ -1237,7 +1269,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 		if !gc.Isconst(n, gc.CTINT) {
 			break
 		}
-		v := gc.Mpgetfix(n.Val.U.Xval)
+		v := n.Int()
 		if v >= 32000 || v <= -32000 {
 			break
 		}
diff --git a/src/cmd/6g/peep.go b/src/cmd/compile/internal/amd64/peep.go
similarity index 99%
rename from src/cmd/6g/peep.go
rename to src/cmd/compile/internal/amd64/peep.go
index cd07199ed1..19db68e944 100644
--- a/src/cmd/6g/peep.go
+++ b/src/cmd/compile/internal/amd64/peep.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
diff --git a/src/cmd/6g/prog.go b/src/cmd/compile/internal/amd64/prog.go
similarity index 99%
rename from src/cmd/6g/prog.go
rename to src/cmd/compile/internal/amd64/prog.go
index 5f604742c3..00918c8691 100644
--- a/src/cmd/6g/prog.go
+++ b/src/cmd/compile/internal/amd64/prog.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
diff --git a/src/cmd/6g/reg.go b/src/cmd/compile/internal/amd64/reg.go
similarity index 98%
rename from src/cmd/6g/reg.go
rename to src/cmd/compile/internal/amd64/reg.go
index cab07b5b4e..7d4f40641d 100644
--- a/src/cmd/6g/reg.go
+++ b/src/cmd/compile/internal/amd64/reg.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
diff --git a/src/cmd/5g/cgen.go b/src/cmd/compile/internal/arm/cgen.go
similarity index 90%
rename from src/cmd/5g/cgen.go
rename to src/cmd/compile/internal/arm/cgen.go
index 2e922391cb..8ea6c5f3f2 100644
--- a/src/cmd/5g/cgen.go
+++ b/src/cmd/compile/internal/arm/cgen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
@@ -53,28 +53,6 @@ func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
 	return cgenindex(n, res, bounded)
 }
 
-func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) {
-	var n1 gc.Node
-
-	gc.Regalloc(&n1, t, nil)
-	gc.Cgen(n, &n1)
-	a := optoas(gc.OCMP, t)
-	if a != arm.ACMP {
-		var n2 gc.Node
-		gc.Nodconst(&n2, t, 0)
-		var n3 gc.Node
-		gc.Regalloc(&n3, t, nil)
-		gmove(&n2, &n3)
-		gins(a, &n1, &n3)
-		gc.Regfree(&n3)
-	} else {
-		gins(arm.ATST, &n1, nil)
-	}
-	a = optoas(o, t)
-	gc.Patch(gc.Gbranch(a, t, likely), to)
-	gc.Regfree(&n1)
-}
-
 func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// determine alignment.
 	// want to avoid unaligned access, so have to use
diff --git a/src/cmd/5g/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go
similarity index 99%
rename from src/cmd/5g/cgen64.go
rename to src/cmd/compile/internal/arm/cgen64.go
index 699e555f71..6c88b76e20 100644
--- a/src/cmd/5g/cgen64.go
+++ b/src/cmd/compile/internal/arm/cgen64.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
@@ -237,7 +237,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	//	shld hi:lo, c
 	//	shld lo:t, c
 	case gc.OLROT:
-		v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+		v := uint64(r.Int())
 
 		var bl gc.Node
 		gc.Regalloc(&bl, lo1.Type, nil)
@@ -291,7 +291,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 		var p4 *obj.Prog
 		var p5 *obj.Prog
 		if r.Op == gc.OLITERAL {
-			v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+			v := uint64(r.Int())
 			if v >= 64 {
 				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
 				// here and below (verify it optimizes to EOR)
@@ -452,7 +452,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 		var creg gc.Node
 		var p3 *obj.Prog
 		if r.Op == gc.OLITERAL {
-			v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+			v := uint64(r.Int())
 			if v >= 64 {
 				if bh.Type.Etype == gc.TINT32 {
 					//	MOVW	bh->31, al
diff --git a/src/cmd/5g/galign.go b/src/cmd/compile/internal/arm/galign.go
similarity index 96%
rename from src/cmd/5g/galign.go
rename to src/cmd/compile/internal/arm/galign.go
index 3c8ba519eb..60a39d3fe4 100644
--- a/src/cmd/5g/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
@@ -37,7 +37,7 @@ func betypeinit() {
 	gc.Widthreg = 4
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -65,6 +65,7 @@ func main() {
 	gc.Thearch.Expandchecks = expandchecks
 	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
diff --git a/src/cmd/5g/ggen.go b/src/cmd/compile/internal/arm/ggen.go
similarity index 93%
rename from src/cmd/5g/ggen.go
rename to src/cmd/compile/internal/arm/ggen.go
index 0cf0d9299c..6633351032 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
@@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) {
 	r0 := uint32(0)
 	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if !n.Needzero {
+		if !n.Name.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -183,7 +183,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	w := int(nl.Type.Width * 8)
 
 	if op == gc.OLROT {
-		v := int(gc.Mpgetfix(nr.Val.U.Xval))
+		v := nr.Int()
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		if w == 32 {
@@ -210,7 +210,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gc.Cgen(nl, &n1)
-		sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
+		sc := uint64(nr.Int())
 		if sc == 0 {
 		} else // nothing to do
 		if sc >= uint64(nl.Type.Width*8) {
@@ -479,6 +479,32 @@ func ginscon(as int, c int64, n *gc.Node) {
 	gc.Regfree(&n2)
 }
 
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL {
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 {
+		gins(arm.ACMP, &r1, n2)
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		gins(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
 // addr += index*width if possible.
 func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
 	switch width {
diff --git a/src/cmd/5g/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go
similarity index 98%
rename from src/cmd/5g/gsubr.go
rename to src/cmd/compile/internal/arm/gsubr.go
index 57d511e6f6..5263f15ac2 100644
--- a/src/cmd/5g/gsubr.go
+++ b/src/cmd/compile/internal/arm/gsubr.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 	"fmt"
@@ -53,7 +53,7 @@ func ncon(i uint32) *gc.Node {
 	if ncon_n.Type == nil {
 		gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
 	}
-	gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i))
+	ncon_n.SetInt(int64(i))
 	return &ncon_n
 }
 
@@ -89,7 +89,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 		case gc.ONAME:
 			if n.Class == gc.PPARAMREF {
 				var n1 gc.Node
-				gc.Cgen(n.Heapaddr, &n1)
+				gc.Cgen(n.Name.Heapaddr, &n1)
 				sclean[nsclean-1] = n1
 				n = &n1
 			}
@@ -111,8 +111,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 
 	case gc.OLITERAL:
 		var n1 gc.Node
-		gc.Convconst(&n1, n.Type, &n.Val)
-		i := gc.Mpgetfix(n1.Val.U.Xval)
+		n.Convconst(&n1, n.Type)
+		i := n1.Int()
 		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
 		i >>= 32
 		if n.Type.Etype == gc.TINT64 {
@@ -160,12 +160,12 @@ func gmove(f *gc.Node, t *gc.Node) {
 		var con gc.Node
 		switch tt {
 		default:
-			gc.Convconst(&con, t.Type, &f.Val)
+			f.Convconst(&con, t.Type)
 
 		case gc.TINT16,
 			gc.TINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TINT32])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(arm.AMOVW, &con, &r1)
@@ -176,7 +176,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 		case gc.TUINT16,
 			gc.TUINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TUINT32])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(arm.AMOVW, &con, &r1)
@@ -1118,7 +1118,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 		if !gc.Isconst(n, gc.CTINT) {
 			break
 		}
-		v := gc.Mpgetfix(n.Val.U.Xval)
+		v := n.Int()
 		if v >= 32000 || v <= -32000 {
 			break
 		}
diff --git a/src/cmd/5g/peep.go b/src/cmd/compile/internal/arm/peep.go
similarity index 99%
rename from src/cmd/5g/peep.go
rename to src/cmd/compile/internal/arm/peep.go
index b76719d74e..66eba417c0 100644
--- a/src/cmd/5g/peep.go
+++ b/src/cmd/compile/internal/arm/peep.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 	"fmt"
diff --git a/src/cmd/5g/prog.go b/src/cmd/compile/internal/arm/prog.go
similarity index 99%
rename from src/cmd/5g/prog.go
rename to src/cmd/compile/internal/arm/prog.go
index c472cdf042..cdf9d29192 100644
--- a/src/cmd/5g/prog.go
+++ b/src/cmd/compile/internal/arm/prog.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
diff --git a/src/cmd/5g/reg.go b/src/cmd/compile/internal/arm/reg.go
similarity index 98%
rename from src/cmd/5g/reg.go
rename to src/cmd/compile/internal/arm/reg.go
index 2afdf12416..b72ccc9815 100644
--- a/src/cmd/5g/reg.go
+++ b/src/cmd/compile/internal/arm/reg.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 import "cmd/internal/obj/arm"
-import "cmd/internal/gc"
+import "cmd/compile/internal/gc"
 
 const (
 	NREGVAR = 32
diff --git a/src/cmd/7g/cgen.go b/src/cmd/compile/internal/arm64/cgen.go
similarity index 98%
rename from src/cmd/7g/cgen.go
rename to src/cmd/compile/internal/arm64/cgen.go
index 6f268b4185..30326d73e2 100644
--- a/src/cmd/7g/cgen.go
+++ b/src/cmd/compile/internal/arm64/cgen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 )
diff --git a/src/cmd/7g/galign.go b/src/cmd/compile/internal/arm64/galign.go
similarity index 96%
rename from src/cmd/7g/galign.go
rename to src/cmd/compile/internal/arm64/galign.go
index 34b4ab6142..38def8f5a4 100644
--- a/src/cmd/7g/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 )
@@ -37,7 +37,7 @@ func betypeinit() {
 	gc.Widthreg = 8
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -65,6 +65,7 @@ func main() {
 	gc.Thearch.Expandchecks = expandchecks
 	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
diff --git a/src/cmd/7g/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
similarity index 97%
rename from src/cmd/7g/ggen.go
rename to src/cmd/compile/internal/arm64/ggen.go
index b824a3a18c..851ca4e30f 100644
--- a/src/cmd/7g/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 	"fmt"
@@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) {
 	// iterate through declarations - they are sorted in decreasing xoffset order.
 	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if !n.Needzero {
+		if !n.Name.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -147,9 +147,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
diff --git a/src/cmd/7g/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go
similarity index 95%
rename from src/cmd/7g/gsubr.go
rename to src/cmd/compile/internal/arm64/gsubr.go
index a34a4306ae..0a14654d83 100644
--- a/src/cmd/7g/gsubr.go
+++ b/src/cmd/compile/internal/arm64/gsubr.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 	"fmt"
@@ -102,6 +102,34 @@ func ginscon2(as int, n2 *gc.Node, c int64) {
 	gc.Regfree(&ntmp)
 }
 
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int())
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		gcmp(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
 /*
  * generate move:
  *	t = f
@@ -133,13 +161,13 @@ func gmove(f *gc.Node, t *gc.Node) {
 		var con gc.Node
 		switch tt {
 		default:
-			gc.Convconst(&con, t.Type, &f.Val)
+			f.Convconst(&con, t.Type)
 
 		case gc.TINT32,
 			gc.TINT16,
 			gc.TINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TINT64])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(arm64.AMOVD, &con, &r1)
@@ -151,7 +179,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 			gc.TUINT16,
 			gc.TUINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TUINT64])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(arm64.AMOVD, &con, &r1)
@@ -440,14 +468,13 @@ hard:
 }
 
 func intLiteral(n *gc.Node) (x int64, ok bool) {
-	if n == nil || n.Op != gc.OLITERAL {
+	switch {
+	case n == nil:
 		return
-	}
-	switch n.Val.Ctype {
-	case gc.CTINT, gc.CTRUNE:
-		return gc.Mpgetfix(n.Val.U.Xval), true
-	case gc.CTBOOL:
-		return int64(obj.Bool2int(n.Val.U.Bval)), true
+	case gc.Isconst(n, gc.CTINT):
+		return n.Int(), true
+	case gc.Isconst(n, gc.CTBOOL):
+		return int64(obj.Bool2int(n.Bool())), true
 	}
 	return
 }
diff --git a/src/cmd/7g/peep.go b/src/cmd/compile/internal/arm64/peep.go
similarity index 99%
rename from src/cmd/7g/peep.go
rename to src/cmd/compile/internal/arm64/peep.go
index 49bc69b132..3dbccb70b2 100644
--- a/src/cmd/7g/peep.go
+++ b/src/cmd/compile/internal/arm64/peep.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 	"fmt"
@@ -422,9 +422,9 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		// 7g never generates a from3
 		fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(&p.From3))
 	}
-	if p.To2.Type != obj.TYPE_NONE {
+	if p.RegTo2 != obj.REG_NONE {
 		// 7g never generates a to2
-		fmt.Printf("copyu: to2 (%v) not implemented\n", gc.Ctxt.Dconv(&p.To2))
+		fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2)))
 	}
 
 	switch p.As {
diff --git a/src/cmd/7g/prog.go b/src/cmd/compile/internal/arm64/prog.go
similarity index 99%
rename from src/cmd/7g/prog.go
rename to src/cmd/compile/internal/arm64/prog.go
index 023f302e14..1106e788a5 100644
--- a/src/cmd/7g/prog.go
+++ b/src/cmd/compile/internal/arm64/prog.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm64"
 )
diff --git a/src/cmd/7g/reg.go b/src/cmd/compile/internal/arm64/reg.go
similarity index 98%
rename from src/cmd/7g/reg.go
rename to src/cmd/compile/internal/arm64/reg.go
index 0e5ac73499..7bc756b7bf 100644
--- a/src/cmd/7g/reg.go
+++ b/src/cmd/compile/internal/arm64/reg.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj/arm64"
 )
 
diff --git a/src/cmd/internal/gc/big/accuracy_string.go b/src/cmd/compile/internal/big/accuracy_string.go
similarity index 100%
rename from src/cmd/internal/gc/big/accuracy_string.go
rename to src/cmd/compile/internal/big/accuracy_string.go
diff --git a/src/cmd/internal/gc/big/arith.go b/src/cmd/compile/internal/big/arith.go
similarity index 99%
rename from src/cmd/internal/gc/big/arith.go
rename to src/cmd/compile/internal/big/arith.go
index 328c85c4f7..1ff6349d9d 100644
--- a/src/cmd/internal/gc/big/arith.go
+++ b/src/cmd/compile/internal/big/arith.go
@@ -196,7 +196,6 @@ func subVV_g(z, x, y []Word) (c Word) {
 	return
 }
 
-// Argument y must be either 0 or 1.
 // The resulting carry c is either 0 or 1.
 func addVW_g(z, x []Word, y Word) (c Word) {
 	if use_addWW_g {
diff --git a/src/cmd/internal/gc/big/arith_decl.go b/src/cmd/compile/internal/big/arith_decl.go
similarity index 100%
rename from src/cmd/internal/gc/big/arith_decl.go
rename to src/cmd/compile/internal/big/arith_decl.go
diff --git a/src/cmd/internal/gc/big/arith_test.go b/src/cmd/compile/internal/big/arith_test.go
similarity index 99%
rename from src/cmd/internal/gc/big/arith_test.go
rename to src/cmd/compile/internal/big/arith_test.go
index cd92dd7173..f46a494f17 100644
--- a/src/cmd/internal/gc/big/arith_test.go
+++ b/src/cmd/compile/internal/big/arith_test.go
@@ -155,6 +155,7 @@ var sumVW = []argVW{
 	{nat{1}, nat{1}, 0, 0},
 	{nat{0}, nat{_M}, 1, 1},
 	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+	{nat{585}, nat{314}, 271, 0},
 }
 
 var prodVW = []argVW{
diff --git a/src/cmd/internal/gc/big/bits_test.go b/src/cmd/compile/internal/big/bits_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/bits_test.go
rename to src/cmd/compile/internal/big/bits_test.go
diff --git a/src/cmd/internal/gc/big/calibrate_test.go b/src/cmd/compile/internal/big/calibrate_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/calibrate_test.go
rename to src/cmd/compile/internal/big/calibrate_test.go
diff --git a/src/cmd/internal/gc/big/decimal.go b/src/cmd/compile/internal/big/decimal.go
similarity index 100%
rename from src/cmd/internal/gc/big/decimal.go
rename to src/cmd/compile/internal/big/decimal.go
diff --git a/src/cmd/internal/gc/big/decimal_test.go b/src/cmd/compile/internal/big/decimal_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/decimal_test.go
rename to src/cmd/compile/internal/big/decimal_test.go
diff --git a/src/cmd/internal/gc/big/example_test.go b/src/cmd/compile/internal/big/example_test.go
similarity index 97%
rename from src/cmd/internal/gc/big/example_test.go
rename to src/cmd/compile/internal/big/example_test.go
index 078be47f95..cb91bc23bd 100644
--- a/src/cmd/internal/gc/big/example_test.go
+++ b/src/cmd/compile/internal/big/example_test.go
@@ -5,9 +5,9 @@
 package big_test
 
 import (
+	"cmd/compile/internal/big"
 	"fmt"
 	"log"
-	"math/big"
 )
 
 func ExampleRat_SetString() {
diff --git a/src/cmd/internal/gc/big/float.go b/src/cmd/compile/internal/big/float.go
similarity index 93%
rename from src/cmd/internal/gc/big/float.go
rename to src/cmd/compile/internal/big/float.go
index ed55e8e513..dcb72c5754 100644
--- a/src/cmd/internal/gc/big/float.go
+++ b/src/cmd/compile/internal/big/float.go
@@ -65,12 +65,16 @@ type Float struct {
 	exp  int32
 }
 
-// Float operations that would lead to a NaN under IEEE-754 rules cause
-// a run-time panic of ErrNaN type.
+// An ErrNaN panic is raised by a Float operation that would lead to
+// a NaN under IEEE-754 rules. An ErrNaN implements the error interface.
 type ErrNaN struct {
 	msg string
 }
 
+func (err ErrNaN) Error() string {
+	return err.msg
+}
+
 // NewFloat allocates and returns a new Float set to x,
 // with precision 53 and rounding mode ToNearestEven.
 // NewFloat panics with ErrNaN if x is a NaN.
@@ -849,9 +853,6 @@ func (x *Float) Int64() (int64, Accuracy) {
 	panic("unreachable")
 }
 
-// TODO(gri) Float32 and Float64 are very similar internally but for the
-// floatxx parameters and some conversions. Should factor out shared code.
-
 // Float32 returns the float32 value nearest to x. If x is too small to be
 // represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result
 // is (0, Below) or (-0, Above), respectively, depending on the sign of x.
@@ -876,64 +877,70 @@ func (x *Float) Float32() (float32, Accuracy) {
 			emax  = bias              //   127  largest unbiased exponent (normal)
 		)
 
-		// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
-		// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
-		// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
-		// corresponding Float exponent.
-		// (see also implementation of math.Ldexp for similar code)
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
 
-		if x.exp < dmin+1 {
-			// underflow
-			if x.neg {
-				var z float32
-				return -z, Above
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
 			}
-			return 0.0, Below
 		}
-		// x.exp >= dmin+1
 
+		// round
 		var r Float
-		r.prec = mbits + 1 // +1 for implicit msb
-		if x.exp < emin+1 {
-			// denormal number - round to fewer bits
-			r.prec = uint32(x.exp - dmin)
-		}
+		r.prec = uint32(p)
 		r.Set(x)
+		e = r.exp - 1
 
 		// Rounding may have caused r to overflow to ±Inf
 		// (rounding never causes underflows to 0).
 		if r.form == inf {
-			r.exp = emax + 2 // cause overflow below
+			e = emax + 1 // cause overflow below
 		}
 
-		if r.exp > emax+1 {
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
 			// overflow
 			if x.neg {
 				return float32(math.Inf(-1)), Below
 			}
 			return float32(math.Inf(+1)), Above
 		}
-		// dmin+1 <= r.exp <= emax+1
 
-		var s uint32
-		if r.neg {
-			s = 1 << (fbits - 1)
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint32
+		if x.neg {
+			sign = 1 << (fbits - 1)
 		}
 
-		m := high32(r.mant) >> ebits & (1<> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = high32(r.mant) >> ebits & (1<= dmin+1
 
+		// round
 		var r Float
-		r.prec = mbits + 1 // +1 for implicit msb
-		if x.exp < emin+1 {
-			// denormal number - round to fewer bits
-			r.prec = uint32(x.exp - dmin)
-		}
+		r.prec = uint32(p)
 		r.Set(x)
+		e = r.exp - 1
 
 		// Rounding may have caused r to overflow to ±Inf
 		// (rounding never causes underflows to 0).
 		if r.form == inf {
-			r.exp = emax + 2 // cause overflow below
+			e = emax + 1 // cause overflow below
 		}
 
-		if r.exp > emax+1 {
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
 			// overflow
 			if x.neg {
 				return math.Inf(-1), Below
 			}
 			return math.Inf(+1), Above
 		}
-		// dmin+1 <= r.exp <= emax+1
 
-		var s uint64
-		if r.neg {
-			s = 1 << (fbits - 1)
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint64
+		if x.neg {
+			sign = 1 << (fbits - 1)
 		}
 
-		m := high64(r.mant) >> ebits & (1<> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = high64(r.mant) >> ebits & (1< 0
+
+		// handle factors of 2 in 'a'
+		s := a.abs.trailingZeroBits()
+		if s&1 != 0 {
+			bmod8 := b.abs[0] & 7
+			if bmod8 == 3 || bmod8 == 5 {
+				j = -j
+			}
+		}
+		c.Rsh(&a, s) // a = 2^s*c
+
+		// swap numerator and denominator
+		if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
+			j = -j
+		}
+		a.Set(&b)
+		b.Set(&c)
+	}
+}
+
+// ModSqrt sets z to a square root of x mod p if such a square root exists, and
+// returns z. The modulus p must be an odd prime. If x is not a square mod p,
+// ModSqrt leaves z unchanged and returns nil. This function panics if p is
+// not an odd integer.
+func (z *Int) ModSqrt(x, p *Int) *Int {
+	switch Jacobi(x, p) {
+	case -1:
+		return nil // x is not a square mod p
+	case 0:
+		return z.SetInt64(0) // sqrt(0) mod p = 0
+	case 1:
+		break
+	}
+	if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
+		x = new(Int).Mod(x, p)
+	}
+
+	// Break p-1 into s*2^e such that s is odd.
+	var s Int
+	s.Sub(p, intOne)
+	e := s.abs.trailingZeroBits()
+	s.Rsh(&s, e)
+
+	// find some non-square n
+	var n Int
+	n.SetInt64(2)
+	for Jacobi(&n, p) != -1 {
+		n.Add(&n, intOne)
+	}
+
+	// Core of the Tonelli-Shanks algorithm. Follows the description in
+	// section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
+	// Brown:
+	// https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
+	var y, b, g, t Int
+	y.Add(&s, intOne)
+	y.Rsh(&y, 1)
+	y.Exp(x, &y, p)  // y = x^((s+1)/2)
+	b.Exp(x, &s, p)  // b = x^s
+	g.Exp(&n, &s, p) // g = n^s
+	r := e
+	for {
+		// find the least m such that ord_p(b) = 2^m
+		var m uint
+		t.Set(&b)
+		for t.Cmp(intOne) != 0 {
+			t.Mul(&t, &t).Mod(&t, p)
+			m++
+		}
+
+		if m == 0 {
+			return z.Set(&y)
+		}
+
+		t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
+		// t = g^(2^(r-m-1)) mod p
+		g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
+		y.Mul(&y, &t).Mod(&y, p)
+		b.Mul(&b, &g).Mod(&b, p)
+		r = m
+	}
+}
+
 // Lsh sets z = x << n and returns z.
 func (z *Int) Lsh(x *Int, n uint) *Int {
 	z.abs = z.abs.shl(x.abs, n)
diff --git a/src/cmd/internal/gc/big/int_test.go b/src/cmd/compile/internal/big/int_test.go
similarity index 90%
rename from src/cmd/internal/gc/big/int_test.go
rename to src/cmd/compile/internal/big/int_test.go
index a972a7249b..c19e88addb 100644
--- a/src/cmd/internal/gc/big/int_test.go
+++ b/src/cmd/compile/internal/big/int_test.go
@@ -525,6 +525,7 @@ var expTests = []struct {
 	{"1234", "-1", "1", "0"},
 
 	// misc
+	{"5", "1", "3", "2"},
 	{"5", "-7", "", "1"},
 	{"-5", "-7", "", "1"},
 	{"5", "0", "", "1"},
@@ -703,6 +704,13 @@ var primes = []string{
 	"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
 	"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
 	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+	// ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+	"3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
+	"57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
+	"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
+	"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
+	"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
 }
 
 var composites = []string{
@@ -1248,6 +1256,136 @@ func TestModInverse(t *testing.T) {
 	}
 }
 
+// testModSqrt is a helper for TestModSqrt,
+// which checks that ModSqrt can compute a square-root of elt^2.
+func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
+	var sqChk, sqrtChk, sqrtsq Int
+	sq.Mul(elt, elt)
+	sq.Mod(sq, mod)
+	z := sqrt.ModSqrt(sq, mod)
+	if z != sqrt {
+		t.Errorf("ModSqrt returned wrong value %s", z)
+	}
+
+	// test ModSqrt arguments outside the range [0,mod)
+	sqChk.Add(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+	sqChk.Sub(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+
+	// make sure we actually got a square root
+	if sqrt.Cmp(elt) == 0 {
+		return true // we found the "desired" square root
+	}
+	sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
+	sqrtsq.Mod(&sqrtsq, mod)
+	return sq.Cmp(&sqrtsq) == 0
+}
+
+func TestModSqrt(t *testing.T) {
+	var elt, mod, modx4, sq, sqrt Int
+	r := rand.New(rand.NewSource(9))
+	for i, s := range primes[1:] { // skip 2, use only odd primes
+		mod.SetString(s, 10)
+		modx4.Lsh(&mod, 2)
+
+		// test a few random elements per prime
+		for x := 1; x < 5; x++ {
+			elt.Rand(r, &modx4)
+			elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
+			}
+		}
+	}
+
+	// exhaustive test for small values
+	for n := 3; n < 100; n++ {
+		mod.SetInt64(int64(n))
+		if !mod.ProbablyPrime(10) {
+			continue
+		}
+		isSquare := make([]bool, n)
+
+		// test all the squares
+		for x := 1; x < n; x++ {
+			elt.SetInt64(int64(x))
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
+			}
+			isSquare[sq.Uint64()] = true
+		}
+
+		// test all non-squares
+		for x := 1; x < n; x++ {
+			sq.SetInt64(int64(x))
+			z := sqrt.ModSqrt(&sq, &mod)
+			if !isSquare[x] && z != nil {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
+			}
+		}
+	}
+}
+
+func TestJacobi(t *testing.T) {
+	testCases := []struct {
+		x, y   int64
+		result int
+	}{
+		{0, 1, 1},
+		{0, -1, 1},
+		{1, 1, 1},
+		{1, -1, 1},
+		{0, 5, 0},
+		{1, 5, 1},
+		{2, 5, -1},
+		{-2, 5, -1},
+		{2, -5, -1},
+		{-2, -5, 1},
+		{3, 5, -1},
+		{5, 5, 0},
+		{-5, 5, 0},
+		{6, 5, 1},
+		{6, -5, 1},
+		{-6, 5, 1},
+		{-6, -5, -1},
+	}
+
+	var x, y Int
+
+	for i, test := range testCases {
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		expected := test.result
+		actual := Jacobi(&x, &y)
+		if actual != expected {
+			t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
+		}
+	}
+}
+
+func TestJacobiPanic(t *testing.T) {
+	const failureMsg = "test failure"
+	defer func() {
+		msg := recover()
+		if msg == nil || msg == failureMsg {
+			panic(msg)
+		}
+		t.Log(msg)
+	}()
+	x := NewInt(1)
+	y := NewInt(2)
+	// Jacobi should panic when the second argument is even.
+	Jacobi(x, y)
+	panic(failureMsg)
+}
+
 var encodingTests = []string{
 	"-539345864568634858364538753846587364875430589374589",
 	"-678645873",
diff --git a/src/cmd/internal/gc/big/intconv.go b/src/cmd/compile/internal/big/intconv.go
similarity index 100%
rename from src/cmd/internal/gc/big/intconv.go
rename to src/cmd/compile/internal/big/intconv.go
diff --git a/src/cmd/internal/gc/big/intconv_test.go b/src/cmd/compile/internal/big/intconv_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/intconv_test.go
rename to src/cmd/compile/internal/big/intconv_test.go
diff --git a/src/cmd/internal/gc/big/nat.go b/src/cmd/compile/internal/big/nat.go
similarity index 89%
rename from src/cmd/internal/gc/big/nat.go
rename to src/cmd/compile/internal/big/nat.go
index 2a279d186c..c3eef76fa1 100644
--- a/src/cmd/internal/gc/big/nat.go
+++ b/src/cmd/compile/internal/big/nat.go
@@ -216,6 +216,34 @@ func basicMul(z, x, y nat) {
 	}
 }
 
+// montgomery computes x*y*2^(-n*_W) mod m,
+// assuming k = -1/m mod 2^_W.
+// z is used for storing the result which is returned;
+// z must not alias x, y or m.
+func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
+	var c1, c2 Word
+	z = z.make(n)
+	z.clear()
+	for i := 0; i < n; i++ {
+		d := y[i]
+		c1 += addMulVVW(z, x, d)
+		t := z[0] * k
+		c2 = addMulVVW(z, m, t)
+
+		copy(z, z[1:])
+		z[n-1] = c1 + c2
+		if z[n-1] < c1 {
+			c1 = 1
+		} else {
+			c1 = 0
+		}
+	}
+	if c1 != 0 {
+		subVV(z, z, m)
+	}
+	return z
+}
+
 // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
 // Factored out for readability - do not use outside karatsuba.
 func karatsubaAdd(z, x nat, n int) {
@@ -888,6 +916,13 @@ func (z nat) expNN(x, y, m nat) nat {
 	}
 	// y > 0
 
+	// x**1 mod m == x mod m
+	if len(y) == 1 && y[0] == 1 && len(m) != 0 {
+		_, z = z.div(z, x, m)
+		return z
+	}
+	// y > 1
+
 	if len(m) != 0 {
 		// We likely end up being as long as the modulus.
 		z = z.make(len(m))
@@ -898,8 +933,11 @@ func (z nat) expNN(x, y, m nat) nat {
 	// 4-bit, windowed exponentiation. This involves precomputing 14 values
 	// (x^2...x^15) but then reduces the number of multiply-reduces by a
 	// third. Even for a 32-bit exponent, this reduces the number of
-	// operations.
+	// operations. Uses Montgomery method for odd moduli.
 	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+		if m[0]&1 == 1 {
+			return z.expNNMontgomery(x, y, m)
+		}
 		return z.expNNWindowed(x, y, m)
 	}
 
@@ -1022,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 	return z.norm()
 }
 
+// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
+// Uses Montgomery representation.
+func (z nat) expNNMontgomery(x, y, m nat) nat {
+	var zz, one, rr, RR nat
+
+	numWords := len(m)
+
+	// We want the lengths of x and m to be equal.
+	if len(x) > numWords {
+		_, rr = rr.div(rr, x, m)
+	} else if len(x) < numWords {
+		rr = rr.make(numWords)
+		rr.clear()
+		for i := range x {
+			rr[i] = x[i]
+		}
+	} else {
+		rr = x
+	}
+	x = rr
+
+	// Ideally the precomputations would be performed outside, and reused
+	// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+	// Iteration for Multiplicative Inverses Modulo Prime Powers".
+	k0 := 2 - m[0]
+	t := m[0] - 1
+	for i := 1; i < _W; i <<= 1 {
+		t *= t
+		k0 *= (t + 1)
+	}
+	k0 = -k0
+
+	// RR = 2ˆ(2*_W*len(m)) mod m
+	RR = RR.setWord(1)
+	zz = zz.shl(RR, uint(2*numWords*_W))
+	_, RR = RR.div(RR, zz, m)
+	if len(RR) < numWords {
+		zz = zz.make(numWords)
+		copy(zz, RR)
+		RR = zz
+	}
+	// one = 1, with equal length to that of m
+	one = one.make(numWords)
+	one.clear()
+	one[0] = 1
+
+	const n = 4
+	// powers[i] contains x^i
+	var powers [1 << n]nat
+	powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
+	powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
+	for i := 2; i < 1<= 0; i-- {
+		yi := y[i]
+		for j := 0; j < _W; j += n {
+			if i != len(y)-1 || j != 0 {
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+			}
+			zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
+			z, zz = zz, z
+			yi <<= n
+		}
+	}
+	// convert to regular number
+	zz = zz.montgomery(z, one, m, k0, numWords)
+	return zz.norm()
+}
+
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
 // If it returns true, n is prime with probability 1 - 1/4^reps.
 // If it returns false, n is not prime.
diff --git a/src/cmd/internal/gc/big/nat_test.go b/src/cmd/compile/internal/big/nat_test.go
similarity index 83%
rename from src/cmd/internal/gc/big/nat_test.go
rename to src/cmd/compile/internal/big/nat_test.go
index b25a89f731..a15a2bcac0 100644
--- a/src/cmd/internal/gc/big/nat_test.go
+++ b/src/cmd/compile/internal/big/nat_test.go
@@ -332,6 +332,67 @@ func TestTrailingZeroBits(t *testing.T) {
 	}
 }
 
+var montgomeryTests = []struct {
+	x, y, m      string
+	k0           uint64
+	out32, out64 string
+}{
+	{
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
+		0x0000000000000000,
+		"0xffffffffffffffffffffffffffffffffffffffffff",
+		"0xffffffffffffffffffffffffffffffffff",
+	},
+	{
+		"0x0000000080000000",
+		"0x00000000ffffffff",
+		"0x0000000010000001",
+		0xff0000000fffffff,
+		"0x0000000088000000",
+		"0x0000000007800001",
+	},
+	{
+		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
+		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
+	},
+	{
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
+		"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
+	},
+}
+
+func TestMontgomery(t *testing.T) {
+	for i, test := range montgomeryTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		m := natFromString(test.m)
+
+		var out nat
+		if _W == 32 {
+			out = natFromString(test.out32)
+		} else {
+			out = natFromString(test.out64)
+		}
+
+		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
+		z := nat(nil).montgomery(x, y, m, k0, len(m))
+		z = z.norm()
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
 var expNNTests = []struct {
 	x, y, m string
 	out     string
diff --git a/src/cmd/internal/gc/big/natconv.go b/src/cmd/compile/internal/big/natconv.go
similarity index 100%
rename from src/cmd/internal/gc/big/natconv.go
rename to src/cmd/compile/internal/big/natconv.go
diff --git a/src/cmd/internal/gc/big/natconv_test.go b/src/cmd/compile/internal/big/natconv_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/natconv_test.go
rename to src/cmd/compile/internal/big/natconv_test.go
diff --git a/src/cmd/internal/gc/big/rat.go b/src/cmd/compile/internal/big/rat.go
similarity index 100%
rename from src/cmd/internal/gc/big/rat.go
rename to src/cmd/compile/internal/big/rat.go
diff --git a/src/cmd/internal/gc/big/rat_test.go b/src/cmd/compile/internal/big/rat_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/rat_test.go
rename to src/cmd/compile/internal/big/rat_test.go
diff --git a/src/cmd/internal/gc/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go
similarity index 100%
rename from src/cmd/internal/gc/big/ratconv.go
rename to src/cmd/compile/internal/big/ratconv.go
diff --git a/src/cmd/internal/gc/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/ratconv_test.go
rename to src/cmd/compile/internal/big/ratconv_test.go
diff --git a/src/cmd/internal/gc/big/roundingmode_string.go b/src/cmd/compile/internal/big/roundingmode_string.go
similarity index 100%
rename from src/cmd/internal/gc/big/roundingmode_string.go
rename to src/cmd/compile/internal/big/roundingmode_string.go
diff --git a/src/cmd/internal/gc/big/vendor.bash b/src/cmd/compile/internal/big/vendor.bash
similarity index 66%
rename from src/cmd/internal/gc/big/vendor.bash
rename to src/cmd/compile/internal/big/vendor.bash
index 84aa750462..1b191ccb8f 100755
--- a/src/cmd/internal/gc/big/vendor.bash
+++ b/src/cmd/compile/internal/big/vendor.bash
@@ -15,9 +15,15 @@ rm *.go
 cp $BIGDIR/*.go .
 
 # Use pure Go arith ops w/o build tag.
-sed 's/^\/\/ \+build math_big_pure_go$//' arith_decl_pure.go > arith_decl.go
+sed 's|^// \+build math_big_pure_go$||' arith_decl_pure.go > arith_decl.go
 rm arith_decl_pure.go
 
+# Import vendored math/big in external tests (e.g., floatexample_test.go).
+for f in *_test.go; do
+	sed 's|"math/big"|"cmd/compile/internal/big"|' $f > foo.go
+	mv foo.go $f
+done
+
 # gofmt to clean up after sed
 gofmt -w .
 
diff --git a/src/cmd/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
similarity index 99%
rename from src/cmd/internal/gc/align.go
rename to src/cmd/compile/internal/gc/align.go
index 789e59bfd0..892595a214 100644
--- a/src/cmd/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -71,8 +71,8 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 			// in typecheck.c.  usually addrescapes runs after
 			// widstruct, in which case we could drop this,
 			// but function closure functions are the exception.
-			if f.Nname.Stackparam != nil {
-				f.Nname.Stackparam.Xoffset = o
+			if f.Nname.Param.Stackparam != nil {
+				f.Nname.Param.Stackparam.Xoffset = o
 				f.Nname.Xoffset = 0
 			} else {
 				f.Nname.Xoffset = o
diff --git a/src/cmd/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
similarity index 100%
rename from src/cmd/internal/gc/builtin.go
rename to src/cmd/compile/internal/gc/builtin.go
diff --git a/src/cmd/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
similarity index 100%
rename from src/cmd/internal/gc/builtin/runtime.go
rename to src/cmd/compile/internal/gc/builtin/runtime.go
diff --git a/src/cmd/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go
similarity index 100%
rename from src/cmd/internal/gc/builtin/unsafe.go
rename to src/cmd/compile/internal/gc/builtin/unsafe.go
diff --git a/src/cmd/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
similarity index 100%
rename from src/cmd/internal/gc/bv.go
rename to src/cmd/compile/internal/gc/bv.go
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
similarity index 73%
rename from src/cmd/internal/gc/cgen.go
rename to src/cmd/compile/internal/gc/cgen.go
index 501cdcb1c8..ca58b1c6a3 100644
--- a/src/cmd/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -43,14 +43,7 @@ func cgen_wb(n, res *Node, wb bool) {
 
 	switch n.Op {
 	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
-		if res.Op != ONAME || !res.Addable || wb {
-			var n1 Node
-			Tempname(&n1, n.Type)
-			Cgen_slice(n, &n1)
-			cgen_wb(&n1, res, wb)
-		} else {
-			Cgen_slice(n, res)
-		}
+		cgen_slice(n, res, wb)
 		return
 
 	case OEFACE:
@@ -67,6 +60,10 @@ func cgen_wb(n, res *Node, wb bool) {
 	case ODOTTYPE:
 		cgen_dottype(n, res, nil, wb)
 		return
+
+	case OAPPEND:
+		cgen_append(n, res)
+		return
 	}
 
 	if n.Ullman >= UINF {
@@ -545,7 +542,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			var n1 Node
 			Regalloc(&n1, Types[Tptr], res)
 			p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
-			Datastring(nl.Val.U.Sval, &p1.From)
+			Datastring(nl.Val.U.(string), &p1.From)
 			p1.From.Type = obj.TYPE_ADDR
 			Thearch.Gmove(&n1, res)
 			Regfree(&n1)
@@ -569,8 +566,7 @@ func cgen_wb(n, res *Node, wb bool) {
 
 			var n2 Node
 			Nodconst(&n2, Types[Tptr], 0)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
-			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
+			p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
 
 			n2 = n1
 			n2.Op = OINDREG
@@ -610,8 +606,7 @@ func cgen_wb(n, res *Node, wb bool) {
 
 			var n2 Node
 			Nodconst(&n2, Types[Tptr], 0)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
-			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
+			p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
 
 			n2 = n1
 			n2.Op = OINDREG
@@ -790,6 +785,9 @@ abop: // asymmetric binary
 var sys_wbptr *Node
 
 func cgen_wbptr(n, res *Node) {
+	if Curfn != nil && Curfn.Func.Nowritebarrier {
+		Yyerror("write barrier prohibited")
+	}
 	if Debug_wb > 0 {
 		Warn("write barrier")
 	}
@@ -804,19 +802,7 @@ func cgen_wbptr(n, res *Node) {
 	}
 
 	wbEnabled := syslook("writeBarrierEnabled", 0)
-	switch Ctxt.Arch.Thechar {
-	default:
-		Fatal("cgen_wbptr: unknown architecture")
-	case '5', '7', '9':
-		var tmp Node
-		Regalloc(&tmp, Types[TUINT8], nil)
-		Thearch.Gmove(wbEnabled, &tmp)
-		Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT8]), &tmp, Nodintconst(0))
-		Regfree(&tmp)
-	case '6', '8':
-		Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT8]), wbEnabled, Nodintconst(0))
-	}
-	pbr := Gbranch(Thearch.Optoas(ONE, Types[TUINT8]), nil, -1)
+	pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
 	Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
 	pjmp := Gbranch(obj.AJMP, nil, 0)
 	Patch(pbr, Pc)
@@ -845,6 +831,9 @@ func cgen_wbptr(n, res *Node) {
 }
 
 func cgen_wbfat(n, res *Node) {
+	if Curfn != nil && Curfn.Func.Nowritebarrier {
+		Yyerror("write barrier prohibited")
+	}
 	if Debug_wb > 0 {
 		Warn("write barrier")
 	}
@@ -1047,7 +1036,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 				if Isconst(nl, CTSTR) {
 					Fatal("constant string constant index")
 				}
-				v := uint64(Mpgetfix(nr.Val.U.Xval))
+				v := uint64(Mpgetfix(nr.Val.U.(*Mpint)))
 				var n2 Node
 				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 					if Debug['B'] == 0 && !n.Bounded {
@@ -1055,14 +1044,9 @@ func Agenr(n *Node, a *Node, res *Node) {
 						n1.Op = OINDREG
 						n1.Type = Types[Tptr]
 						n1.Xoffset = int64(Array_nel)
-						var n4 Node
-						Regalloc(&n4, n1.Type, nil)
-						Thearch.Gmove(&n1, &n4)
 						Nodconst(&n2, Types[TUINT32], int64(v))
-						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2)
-						Regfree(&n4)
-						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
-						Ginscall(Panicindex, 0)
+						p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1)
+						Ginscall(Panicindex, -1)
 						Patch(p1, Pc)
 					}
 
@@ -1088,7 +1072,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 			if Debug['B'] == 0 && !n.Bounded {
 				// check bounds
 				if Isconst(nl, CTSTR) {
-					Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval)))
+					Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.(string))))
 				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 					n1 = n3
 					n1.Op = OINDREG
@@ -1099,23 +1083,21 @@ func Agenr(n *Node, a *Node, res *Node) {
 				} else {
 					Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
 				}
-
-				Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4)
+				p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1)
 				if n4.Op == OREGISTER {
 					Regfree(&n4)
 				}
-				p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1)
 				if p2 != nil {
 					Patch(p2, Pc)
 				}
-				Ginscall(Panicindex, 0)
+				Ginscall(Panicindex, -1)
 				Patch(p1, Pc)
 			}
 
 			if Isconst(nl, CTSTR) {
 				Regalloc(&n3, Types[Tptr], res)
 				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
-				Datastring(nl.Val.U.Sval, &p1.From)
+				Datastring(nl.Val.U.(string), &p1.From)
 				p1.From.Type = obj.TYPE_ADDR
 			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 				n1 = n3
@@ -1206,15 +1188,14 @@ func Agenr(n *Node, a *Node, res *Node) {
 				if Isconst(nl, CTSTR) {
 					Fatal("constant string constant index") // front end should handle
 				}
-				v := uint64(Mpgetfix(nr.Val.U.Xval))
+				v := uint64(Mpgetfix(nr.Val.U.(*Mpint)))
 				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 					if Debug['B'] == 0 && !n.Bounded {
 						nlen := n3
 						nlen.Type = Types[TUINT32]
 						nlen.Xoffset += int64(Array_nel)
 						Nodconst(&n2, Types[TUINT32], int64(v))
-						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2)
-						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
+						p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +1)
 						Ginscall(Panicindex, -1)
 						Patch(p1, Pc)
 					}
@@ -1252,7 +1233,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 
 				var nlen Node
 				if Isconst(nl, CTSTR) {
-					Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
+					Nodconst(&nlen, t, int64(len(nl.Val.U.(string))))
 				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 					nlen = n3
 					nlen.Type = t
@@ -1261,8 +1242,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 					Nodconst(&nlen, t, nl.Type.Bound)
 				}
 
-				Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
-				p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
+				p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
 				if p2 != nil {
 					Patch(p2, Pc)
 				}
@@ -1273,7 +1253,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 			if Isconst(nl, CTSTR) {
 				Regalloc(&n3, Types[Tptr], res)
 				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
-				Datastring(nl.Val.U.Sval, &p1.From)
+				Datastring(nl.Val.U.(string), &p1.From)
 				p1.From.Type = obj.TYPE_ADDR
 				Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
 				goto indexdone1
@@ -1398,28 +1378,10 @@ func Agenr(n *Node, a *Node, res *Node) {
 			if Isconst(nl, CTSTR) {
 				Fatal("constant string constant index") // front end should handle
 			}
-			v := uint64(Mpgetfix(nr.Val.U.Xval))
+			v := uint64(Mpgetfix(nr.Val.U.(*Mpint)))
 			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
 				if Debug['B'] == 0 && !n.Bounded {
-					if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') {
-						var tmp2 Node
-						Regalloc(&tmp2, Types[Simtype[TUINT]], nil)
-						Thearch.Gmove(&nlen, &tmp2)
-						Regfree(&nlen) // in case it is OINDREG
-						nlen = tmp2
-					}
-					var n2 Node
-					Nodconst(&n2, Types[Simtype[TUINT]], int64(v))
-					if Smallintconst(nr) {
-						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2)
-					} else {
-						Regalloc(&tmp, Types[Simtype[TUINT]], nil)
-						Thearch.Gmove(&n2, &tmp)
-						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp)
-						Regfree(&tmp)
-					}
-
-					p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1)
+					p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1)
 					Ginscall(Panicindex, -1)
 					Patch(p1, Pc)
 				}
@@ -1454,28 +1416,14 @@ func Agenr(n *Node, a *Node, res *Node) {
 				t = Types[TUINT64]
 			}
 			if Isconst(nl, CTSTR) {
-				Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
+				Nodconst(&nlen, t, int64(len(nl.Val.U.(string))))
 			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
-				if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
-					var n5 Node
-					Regalloc(&n5, t, nil)
-					Thearch.Gmove(&nlen, &n5)
-					Regfree(&nlen)
-					nlen = n5
-				}
+				// nlen already initialized
 			} else {
 				Nodconst(&nlen, t, nl.Type.Bound)
-				if !Smallintconst(&nlen) {
-					var n5 Node
-					Regalloc(&n5, t, nil)
-					Thearch.Gmove(&nlen, &n5)
-					nlen = n5
-					freelen = 1
-				}
 			}
 
-			Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
-			p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
+			p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
 			Ginscall(Panicindex, -1)
 			Patch(p1, Pc)
 		}
@@ -1483,7 +1431,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 		if Isconst(nl, CTSTR) {
 			Regalloc(&n3, Types[Tptr], res)
 			p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
-			Datastring(nl.Val.U.Sval, &p1.From)
+			Datastring(nl.Val.U.(string), &p1.From)
 			p1.From.Type = obj.TYPE_ADDR
 			Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
 			goto indexdone
@@ -1637,7 +1585,7 @@ func Agen(n *Node, res *Node) {
 			Fatal("agen: bad ONAME class %#x", n.Class)
 		}
 
-		Cgen(n.Heapaddr, res)
+		Cgen(n.Name.Heapaddr, res)
 		if n.Xoffset != 0 {
 			addOffset(res, n.Xoffset)
 		}
@@ -1770,7 +1718,7 @@ func Igen(n *Node, a *Node, res *Node) {
 				// Compute &a[i] as &a + i*width.
 				a.Type = n.Type
 
-				a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
+				a.Xoffset += Mpgetfix(n.Right.Val.U.(*Mpint)) * n.Type.Width
 				Fixlargeoffset(a)
 				return
 			}
@@ -1920,11 +1868,11 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 			Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
 		}
 		if genval {
-			Cgen(Nodbool(wantTrue == n.Val.U.Bval), res)
+			Cgen(Nodbool(wantTrue == n.Val.U.(bool)), res)
 			return
 		}
 		// If n == wantTrue, jump; otherwise do nothing.
-		if wantTrue == n.Val.U.Bval {
+		if wantTrue == n.Val.U.(bool) {
 			Patch(Gbranch(obj.AJMP, nil, likely), to)
 		}
 		return
@@ -2214,14 +2162,27 @@ func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) {
 	}
 }
 
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
+// stkof returns n's offset from SP if n is on the stack
+// (either a local variable or the return value from a function call
+// or the arguments to a function call).
+// If n is not on the stack, stkof returns -1000.
+// If n is on the stack but in an unknown location
+// (due to array index arithmetic), stkof returns +1000.
+//
+// NOTE(rsc): It is possible that the ODOT and OINDEX cases
+// are not relevant here, since it shouldn't be possible for them
+// to be involved in an overlapping copy. Only function results
+// from one call and the arguments to the next can overlap in
+// any non-trivial way. If they can be dropped, then this function
+// becomes much simpler and also more trustworthy.
+// The fact that it works at all today is probably due to the fact
+// that ODOT and OINDEX are irrelevant.
 func stkof(n *Node) int64 {
 	switch n.Op {
 	case OINDREG:
+		if n.Reg != int16(Thearch.REGSP) {
+			return -1000 // not on stack
+		}
 		return n.Xoffset
 
 	case ODOT:
@@ -2230,7 +2191,7 @@ func stkof(n *Node) int64 {
 			break
 		}
 		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
+		if off == -1000 || off == +1000 {
 			return off
 		}
 		return off + n.Xoffset
@@ -2241,13 +2202,13 @@ func stkof(n *Node) int64 {
 			break
 		}
 		off := stkof(n.Left)
-		if off == -1000 || off == 1000 {
+		if off == -1000 || off == +1000 {
 			return off
 		}
 		if Isconst(n.Right, CTINT) {
-			return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval)
+			return off + t.Type.Width*Mpgetfix(n.Right.Val.U.(*Mpint))
 		}
-		return 1000
+		return +1000 // on stack but not sure exactly where
 
 	case OCALLMETH, OCALLINTER, OCALLFUNC:
 		t := n.Left.Type
@@ -2268,7 +2229,7 @@ func stkof(n *Node) int64 {
 
 	// botch - probably failing to recognize address
 	// arithmetic on the above. eg INDEX and DOT
-	return -1000
+	return -1000 // not on stack
 }
 
 /*
@@ -2446,8 +2407,7 @@ func Ginscall(f *Node, proc int) {
 
 		if proc == 2 {
 			Nodreg(®, Types[TINT32], Thearch.REGRETURN)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), ®, Nodintconst(0))
-			p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1)
+			p := Thearch.Ginscmp(OEQ, Types[TINT32], ®, Nodintconst(0), +1)
 			cgen_ret(nil)
 			Patch(p, Pc)
 		}
@@ -2576,7 +2536,7 @@ func cgen_call(n *Node, proc int) {
 	}
 
 	// call direct
-	n.Left.Method = true
+	n.Left.Name.Method = true
 
 	Ginscall(n.Left, proc)
 }
@@ -2701,7 +2661,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) {
 	case TUINT64:
 		var m Magic
 		m.W = w
-		m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
+		m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint)))
 		Umagic(&m)
 		if m.Bad != 0 {
 			break
@@ -2739,7 +2699,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) {
 	case TINT64:
 		var m Magic
 		m.W = w
-		m.Sd = Mpgetfix(nr.Val.U.Xval)
+		m.Sd = Mpgetfix(nr.Val.U.(*Mpint))
 		Smagic(&m)
 		if m.Bad != 0 {
 			break
@@ -2843,3 +2803,762 @@ func Fixlargeoffset(n *Node) {
 		n.Xoffset = 0
 	}
 }
+
+func cgen_append(n, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("cgen_append-n", n)
+		Dump("cgen_append-res", res)
+	}
+	if res.Op != ONAME && !samesafeexpr(res, n.List.N) {
+		Dump("cgen_append-n", n)
+		Dump("cgen_append-res", res)
+		Fatal("append not lowered")
+	}
+	for l := n.List; l != nil; l = l.Next {
+		if l.N.Ullman >= UINF {
+			Fatal("append with function call arguments")
+		}
+	}
+
+	// res = append(src, x, y, z)
+	//
+	// If res and src are the same, we can avoid writing to base and cap
+	// unless we grow the underlying array.
+	needFullUpdate := !samesafeexpr(res, n.List.N)
+
+	// Copy src triple into base, len, cap.
+	base := temp(Types[Tptr])
+	len := temp(Types[TUINT])
+	cap := temp(Types[TUINT])
+
+	var src Node
+	Igen(n.List.N, &src, nil)
+	src.Type = Types[Tptr]
+	Thearch.Gmove(&src, base)
+	src.Type = Types[TUINT]
+	src.Xoffset += int64(Widthptr)
+	Thearch.Gmove(&src, len)
+	src.Xoffset += int64(Widthptr)
+	Thearch.Gmove(&src, cap)
+
+	// if len+argc <= cap goto L1
+	var rlen Node
+	Regalloc(&rlen, Types[TUINT], nil)
+	Thearch.Gmove(len, &rlen)
+	Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &rlen)
+	p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1)
+	// Note: rlen and src are Regrealloc'ed below at the target of the
+	// branch we just emitted; do not reuse these Go variables for
+	// other purposes. They need to still describe the same things
+	// below that they describe right here.
+	Regfree(&src)
+
+	// base, len, cap = growslice(type, base, len, cap, newlen)
+	var arg Node
+	arg.Op = OINDREG
+	arg.Reg = int16(Thearch.REGSP)
+	arg.Addable = true
+	arg.Xoffset = 0
+	if HasLinkRegister() {
+		arg.Xoffset = int64(Ctxt.Arch.Ptrsize)
+	}
+	arg.Type = Ptrto(Types[TUINT8])
+	Cgen(typename(res.Type), &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[Tptr]
+	Cgen(base, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(len, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(cap, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&rlen, &arg)
+	arg.Xoffset += int64(Widthptr)
+	Regfree(&rlen)
+
+	fn := syslook("growslice", 1)
+	substArgTypes(fn, res.Type.Type, res.Type.Type)
+	Ginscall(fn, 0)
+
+	if Widthptr == 4 && Widthreg == 8 {
+		arg.Xoffset += 4
+	}
+
+	arg.Type = Types[Tptr]
+	Cgen(&arg, base)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&arg, len)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&arg, cap)
+
+	// Update res with base, len+argc, cap.
+	if needFullUpdate {
+		if Debug_append > 0 {
+			Warn("append: full update")
+		}
+		Patch(p, Pc)
+	}
+	if res.Op == ONAME {
+		Gvardef(res)
+	}
+	var dst, r1 Node
+	Igen(res, &dst, nil)
+	dst.Type = Types[TUINT]
+	dst.Xoffset += int64(Widthptr)
+	Regalloc(&r1, Types[TUINT], nil)
+	Thearch.Gmove(len, &r1)
+	Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &r1)
+	Thearch.Gmove(&r1, &dst)
+	Regfree(&r1)
+	dst.Xoffset += int64(Widthptr)
+	Thearch.Gmove(cap, &dst)
+	dst.Type = Types[Tptr]
+	dst.Xoffset -= 2 * int64(Widthptr)
+	cgen_wb(base, &dst, needwritebarrier(&dst, base))
+	Regfree(&dst)
+
+	if !needFullUpdate {
+		if Debug_append > 0 {
+			Warn("append: len-only update")
+		}
+		// goto L2;
+		// L1:
+		//	update len only
+		// L2:
+		q := Gbranch(obj.AJMP, nil, 0)
+		Patch(p, Pc)
+		// At the goto above, src refers to cap and rlen holds the new len
+		if src.Op == OREGISTER || src.Op == OINDREG {
+			Regrealloc(&src)
+		}
+		Regrealloc(&rlen)
+		src.Xoffset -= int64(Widthptr)
+		Thearch.Gmove(&rlen, &src)
+		Regfree(&src)
+		Regfree(&rlen)
+		Patch(q, Pc)
+	}
+
+	// Copy data into place.
+	// Could do write barrier check around entire copy instead of each element.
+	// Could avoid reloading registers on each iteration if we know the cgen_wb
+	// is not going to use a write barrier.
+	i := 0
+	var r2 Node
+	for l := n.List.Next; l != nil; l = l.Next {
+		Regalloc(&r1, Types[Tptr], nil)
+		Thearch.Gmove(base, &r1)
+		Regalloc(&r2, Types[TUINT], nil)
+		Thearch.Gmove(len, &r2)
+		if i > 0 {
+			Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
+		}
+		w := res.Type.Type.Width
+		if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) {
+			// r1 updated by back end
+		} else if w == 1 {
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
+		} else {
+			Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), int64(w), &r2)
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
+		}
+		Regfree(&r2)
+
+		r1.Op = OINDREG
+		r1.Type = res.Type.Type
+		cgen_wb(l.N, &r1, needwritebarrier(&r1, l.N))
+		Regfree(&r1)
+		i++
+	}
+}
+
+// Generate res = n, where n is x[i:j] or x[i:j:k].
+// If wb is true, need write barrier updating res's base pointer.
+// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values.
+func cgen_slice(n, res *Node, wb bool) {
+	if Debug['g'] != 0 {
+		Dump("cgen_slice-n", n)
+		Dump("cgen_slice-res", res)
+	}
+
+	needFullUpdate := !samesafeexpr(n.Left, res)
+
+	// orderexpr has made sure that x is safe (but possibly expensive)
+	// and i, j, k are cheap. On a system with registers (anything but 386)
+	// we can evaluate x first and then know we have enough registers
+	// for i, j, k as well.
+	var x, xbase, xlen, xcap, i, j, k Node
+	if n.Op != OSLICEARR && n.Op != OSLICE3ARR {
+		Igen(n.Left, &x, nil)
+	}
+
+	indexRegType := Types[TUINT]
+	if Widthreg > Widthptr { // amd64p32
+		indexRegType = Types[TUINT64]
+	}
+
+	// On most systems, we use registers.
+	// The 386 has basically no registers, so substitute functions
+	// that can work with temporaries instead.
+	regalloc := Regalloc
+	ginscon := Thearch.Ginscon
+	gins := Thearch.Gins
+	if Thearch.Thechar == '8' {
+		regalloc = func(n *Node, t *Type, reuse *Node) {
+			Tempname(n, t)
+		}
+		ginscon = func(as int, c int64, n *Node) {
+			var n1 Node
+			Regalloc(&n1, n.Type, n)
+			Thearch.Gmove(n, &n1)
+			Thearch.Ginscon(as, c, &n1)
+			Thearch.Gmove(&n1, n)
+			Regfree(&n1)
+		}
+		gins = func(as int, f, t *Node) *obj.Prog {
+			var n1 Node
+			Regalloc(&n1, t.Type, t)
+			Thearch.Gmove(t, &n1)
+			Thearch.Gins(as, f, &n1)
+			Thearch.Gmove(&n1, t)
+			Regfree(&n1)
+			return nil
+		}
+	}
+
+	panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks
+
+	loadlen := func() {
+		if xlen.Op != 0 {
+			return
+		}
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+			Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound)
+			return
+		}
+		if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
+			Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.(string))))
+			return
+		}
+		regalloc(&xlen, indexRegType, nil)
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&x, &xlen)
+		x.Xoffset -= int64(Widthptr)
+	}
+
+	loadcap := func() {
+		if xcap.Op != 0 {
+			return
+		}
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR {
+			loadlen()
+			xcap = xlen
+			if xcap.Op == OREGISTER {
+				Regrealloc(&xcap)
+			}
+			return
+		}
+		regalloc(&xcap, indexRegType, nil)
+		x.Xoffset += 2 * int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&x, &xcap)
+		x.Xoffset -= 2 * int64(Widthptr)
+	}
+
+	var x1, x2, x3 *Node // unevaluated index arguments
+	x1 = n.Right.Left
+	switch n.Op {
+	default:
+		x2 = n.Right.Right
+	case OSLICE3, OSLICE3ARR:
+		x2 = n.Right.Right.Left
+		x3 = n.Right.Right.Right
+	}
+
+	// load computes src into targ, but if src refers to the len or cap of n.Left,
+	// load copies those from xlen, xcap, loading xlen if needed.
+	// If targ.Op == OREGISTER on return, it must be Regfreed,
+	// but it should not be modified without first checking whether it is
+	// xlen or xcap's register.
+	load := func(src, targ *Node) {
+		if src == nil {
+			return
+		}
+		switch src.Op {
+		case OLITERAL:
+			*targ = *src
+			return
+		case OLEN:
+			// NOTE(rsc): This doesn't actually trigger, because order.go
+			// has pulled all the len and cap calls into separate assignments
+			// to temporaries. There are tests in test/sliceopt.go that could
+			// be enabled if this is fixed.
+			if samesafeexpr(n.Left, src.Left) {
+				if Debug_slice > 0 {
+					Warn("slice: reuse len")
+				}
+				loadlen()
+				*targ = xlen
+				if targ.Op == OREGISTER {
+					Regrealloc(targ)
+				}
+				return
+			}
+		case OCAP:
+			// NOTE(rsc): This doesn't actually trigger; see note in case OLEN above.
+			if samesafeexpr(n.Left, src.Left) {
+				if Debug_slice > 0 {
+					Warn("slice: reuse cap")
+				}
+				loadcap()
+				*targ = xcap
+				if targ.Op == OREGISTER {
+					Regrealloc(targ)
+				}
+				return
+			}
+		}
+		if i.Op != 0 && samesafeexpr(x1, src) {
+			if Debug_slice > 0 {
+				Warn("slice: reuse 1st index")
+			}
+			*targ = i
+			if targ.Op == OREGISTER {
+				Regrealloc(targ)
+			}
+			return
+		}
+		if j.Op != 0 && samesafeexpr(x2, src) {
+			if Debug_slice > 0 {
+				Warn("slice: reuse 2nd index")
+			}
+			*targ = j
+			if targ.Op == OREGISTER {
+				Regrealloc(targ)
+			}
+			return
+		}
+		if Thearch.Cgenindex != nil {
+			regalloc(targ, indexRegType, nil)
+			p := Thearch.Cgenindex(src, targ, false)
+			if p != nil {
+				panics = append(panics, p)
+			}
+		} else if Thearch.Igenindex != nil {
+			p := Thearch.Igenindex(src, targ, false)
+			if p != nil {
+				panics = append(panics, p)
+			}
+		} else {
+			regalloc(targ, indexRegType, nil)
+			var tmp Node
+			Cgenr(src, &tmp, targ)
+			Thearch.Gmove(&tmp, targ)
+			Regfree(&tmp)
+		}
+	}
+
+	load(x1, &i)
+	load(x2, &j)
+	load(x3, &k)
+
+	// i defaults to 0.
+	if i.Op == 0 {
+		Nodconst(&i, indexRegType, 0)
+	}
+
+	// j defaults to len(x)
+	if j.Op == 0 {
+		loadlen()
+		j = xlen
+		if j.Op == OREGISTER {
+			Regrealloc(&j)
+		}
+	}
+
+	// k defaults to cap(x)
+	// Only need to load it if we're recalculating cap or doing a full update.
+	if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) {
+		loadcap()
+		k = xcap
+		if k.Op == OREGISTER {
+			Regrealloc(&k)
+		}
+	}
+
+	// Check constant indexes for negative values, and against constant length if known.
+	// The func obvious below checks for out-of-order constant indexes.
+	var bound int64 = -1
+	if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+		bound = n.Left.Type.Type.Bound
+	} else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
+		bound = int64(len(n.Left.Val.U.(string)))
+	}
+	if Isconst(&i, CTINT) {
+		if mpcmpfixc(i.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+	if Isconst(&j, CTINT) {
+		if mpcmpfixc(j.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+	if Isconst(&k, CTINT) {
+		if mpcmpfixc(k.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+
+	// same reports whether n1 and n2 are the same register or constant.
+	same := func(n1, n2 *Node) bool {
+		return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg ||
+			n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset ||
+			n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) == 0
+	}
+
+	// obvious reports whether n1 <= n2 is obviously true,
+	// and it calls Yyerror if n1 <= n2 is obviously false.
+	obvious := func(n1, n2 *Node) bool {
+		if Debug['B'] != 0 { // -B disables bounds checks
+			return true
+		}
+		if same(n1, n2) {
+			return true // n1 == n2
+		}
+		if iszero(n1) {
+			return true // using unsigned compare, so 0 <= n2 always true
+		}
+		if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) {
+			return true // len(x) <= cap(x) always true
+		}
+		if Isconst(n1, CTINT) && Isconst(n2, CTINT) {
+			if Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) <= 0 {
+				return true // n1, n2 constants such that n1 <= n2
+			}
+			Yyerror("slice index out of bounds")
+			return true
+		}
+		return false
+	}
+
+	compare := func(n1, n2 *Node) {
+		// n1 might be a 64-bit constant, even on 32-bit architectures,
+		// but it will be represented in 32 bits.
+		if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) {
+			if mpcmpfixc(n1.Val.U.(*Mpint), 1<<31) >= 0 {
+				Fatal("missed slice out of bounds check")
+			}
+			var tmp Node
+			Nodconst(&tmp, indexRegType, Mpgetfix(n1.Val.U.(*Mpint)))
+			n1 = &tmp
+		}
+		p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1)
+		panics = append(panics, p)
+	}
+
+	loadcap()
+	max := &xcap
+	if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) {
+		if obvious(&k, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 3rd index")
+			}
+		} else {
+			compare(&k, max)
+		}
+		max = &k
+	}
+	if j.Op != 0 {
+		if obvious(&j, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 2nd index")
+			}
+		} else {
+			compare(&j, max)
+		}
+		max = &j
+	}
+	if i.Op != 0 {
+		if obvious(&i, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 1st index")
+			}
+		} else {
+			compare(&i, max)
+		}
+		max = &i
+	}
+	if k.Op != 0 && i.Op != 0 {
+		obvious(&i, &k) // emit compile-time error for x[3:n:2]
+	}
+
+	if len(panics) > 0 {
+		p := Gbranch(obj.AJMP, nil, 0)
+		for _, q := range panics {
+			Patch(q, Pc)
+		}
+		Ginscall(panicslice, -1)
+		Patch(p, Pc)
+	}
+
+	// Checks are done.
+	// Compute new len as j-i, cap as k-i.
+	// If i and j are same register, len is constant 0.
+	// If i and k are same register, cap is constant 0.
+	// If j and k are same register, len and cap are same.
+
+	// Done with xlen and xcap.
+	// Now safe to modify j and k even if they alias xlen, xcap.
+	if xlen.Op == OREGISTER {
+		Regfree(&xlen)
+	}
+	if xcap.Op == OREGISTER {
+		Regfree(&xcap)
+	}
+
+	// are j and k the same value?
+	sameJK := same(&j, &k)
+
+	if i.Op != 0 {
+		// j -= i
+		if same(&i, &j) {
+			if Debug_slice > 0 {
+				Warn("slice: result len == 0")
+			}
+			if j.Op == OREGISTER {
+				Regfree(&j)
+			}
+			Nodconst(&j, indexRegType, 0)
+		} else {
+			switch j.Op {
+			case OLITERAL:
+				if Isconst(&i, CTINT) {
+					Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint)))
+					if Debug_slice > 0 {
+						Warn("slice: result len == %d", Mpgetfix(j.Val.U.(*Mpint)))
+					}
+					break
+				}
+				fallthrough
+			case ONAME:
+				if !istemp(&j) {
+					var r Node
+					regalloc(&r, indexRegType, nil)
+					Thearch.Gmove(&j, &r)
+					j = r
+				}
+				fallthrough
+			case OREGISTER:
+				if i.Op == OLITERAL {
+					v := Mpgetfix(i.Val.U.(*Mpint))
+					if v != 0 {
+						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j)
+					}
+				} else {
+					gins(Thearch.Optoas(OSUB, indexRegType), &i, &j)
+				}
+			}
+		}
+
+		// k -= i if k different from j and cap is needed.j
+		// (The modifications to j above cannot affect i: if j and i were aliased,
+		// we replace j with a constant 0 instead of doing a subtraction,
+		// leaving i unmodified.)
+		if k.Op == 0 {
+			if Debug_slice > 0 && n.Op != OSLICESTR {
+				Warn("slice: result cap not computed")
+			}
+			// no need
+		} else if same(&i, &k) {
+			if k.Op == OREGISTER {
+				Regfree(&k)
+			}
+			Nodconst(&k, indexRegType, 0)
+			if Debug_slice > 0 {
+				Warn("slice: result cap == 0")
+			}
+		} else if sameJK {
+			if Debug_slice > 0 {
+				Warn("slice: result cap == result len")
+			}
+			// k and j were the same value; make k-i the same as j-i.
+			if k.Op == OREGISTER {
+				Regfree(&k)
+			}
+			k = j
+			if k.Op == OREGISTER {
+				Regrealloc(&k)
+			}
+		} else {
+			switch k.Op {
+			case OLITERAL:
+				if Isconst(&i, CTINT) {
+					Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint)))
+					if Debug_slice > 0 {
+						Warn("slice: result cap == %d", Mpgetfix(k.Val.U.(*Mpint)))
+					}
+					break
+				}
+				fallthrough
+			case ONAME:
+				if !istemp(&k) {
+					var r Node
+					regalloc(&r, indexRegType, nil)
+					Thearch.Gmove(&k, &r)
+					k = r
+				}
+				fallthrough
+			case OREGISTER:
+				if same(&i, &k) {
+					Regfree(&k)
+					Nodconst(&k, indexRegType, 0)
+					if Debug_slice > 0 {
+						Warn("slice: result cap == 0")
+					}
+				} else if i.Op == OLITERAL {
+					v := Mpgetfix(i.Val.U.(*Mpint))
+					if v != 0 {
+						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k)
+					}
+				} else {
+					gins(Thearch.Optoas(OSUB, indexRegType), &i, &k)
+				}
+			}
+		}
+	}
+
+	adjustBase := true
+	if i.Op == 0 || iszero(&i) {
+		if Debug_slice > 0 {
+			Warn("slice: skip base adjustment for 1st index 0")
+		}
+		adjustBase = false
+	} else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) {
+		if Debug_slice > 0 {
+			if n.Op == OSLICESTR {
+				Warn("slice: skip base adjustment for string len == 0")
+			} else {
+				Warn("slice: skip base adjustment for cap == 0")
+			}
+		}
+		adjustBase = false
+	}
+
+	if !adjustBase && !needFullUpdate {
+		if Debug_slice > 0 {
+			if k.Op != 0 {
+				Warn("slice: len/cap-only update")
+			} else {
+				Warn("slice: len-only update")
+			}
+		}
+		if i.Op == OREGISTER {
+			Regfree(&i)
+		}
+		// Write len (and cap if needed) back to x.
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&j, &x)
+		x.Xoffset -= int64(Widthptr)
+		if k.Op != 0 {
+			x.Xoffset += 2 * int64(Widthptr)
+			x.Type = Types[TUINT]
+			Thearch.Gmove(&k, &x)
+			x.Xoffset -= 2 * int64(Widthptr)
+		}
+		Regfree(&x)
+	} else {
+		// Compute new base. May smash i.
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+			Cgenr(n.Left, &xbase, nil)
+			Cgen_checknil(&xbase)
+		} else {
+			regalloc(&xbase, Ptrto(res.Type.Type), nil)
+			x.Type = xbase.Type
+			Thearch.Gmove(&x, &xbase)
+			Regfree(&x)
+		}
+		if i.Op != 0 && adjustBase {
+			// Branch around the base adjustment if the resulting cap will be 0.
+			var p *obj.Prog
+			size := &k
+			if k.Op == 0 {
+				size = &j
+			}
+			if Isconst(size, CTINT) {
+				// zero was checked above, must be non-zero.
+			} else {
+				var tmp Node
+				Nodconst(&tmp, indexRegType, 0)
+				p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1)
+			}
+			var w int64
+			if n.Op == OSLICESTR {
+				w = 1 // res is string, elem size is 1 (byte)
+			} else {
+				w = res.Type.Type.Width // res is []T, elem size is T.width
+			}
+			if Isconst(&i, CTINT) {
+				ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.(*Mpint))*w, &xbase)
+			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) {
+				// done by back end
+			} else if w == 1 {
+				gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
+			} else {
+				if i.Op == ONAME && !istemp(&i) {
+					var tmp Node
+					Tempname(&tmp, i.Type)
+					Thearch.Gmove(&i, &tmp)
+					i = tmp
+				}
+				ginscon(Thearch.Optoas(OMUL, i.Type), w, &i)
+				gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
+			}
+			if p != nil {
+				Patch(p, Pc)
+			}
+		}
+		if i.Op == OREGISTER {
+			Regfree(&i)
+		}
+
+		// Write len, cap, base to result.
+		if res.Op == ONAME {
+			Gvardef(res)
+		}
+		Igen(res, &x, nil)
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&j, &x)
+		x.Xoffset -= int64(Widthptr)
+		if k.Op != 0 {
+			x.Xoffset += 2 * int64(Widthptr)
+			Thearch.Gmove(&k, &x)
+			x.Xoffset -= 2 * int64(Widthptr)
+		}
+		x.Type = xbase.Type
+		cgen_wb(&xbase, &x, wb)
+		Regfree(&xbase)
+		Regfree(&x)
+	}
+
+	if j.Op == OREGISTER {
+		Regfree(&j)
+	}
+	if k.Op == OREGISTER {
+		Regfree(&k)
+	}
+}
diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
similarity index 91%
rename from src/cmd/internal/gc/closure.go
rename to src/cmd/compile/internal/gc/closure.go
index 8d5fd5a600..64cd97206c 100644
--- a/src/cmd/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -17,7 +17,7 @@ func closurehdr(ntype *Node) {
 	var a *Node
 
 	n := Nod(OCLOSURE, nil, nil)
-	n.Ntype = ntype
+	n.Param.Ntype = ntype
 	n.Funcdepth = Funcdepth
 	n.Func.Outerfunc = Curfn
 
@@ -72,8 +72,8 @@ func closurebody(body *NodeList) *Node {
 	var v *Node
 	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		v = l.N
-		v.Closure.Closure = v.Outer
-		v.Outerexpr = oldname(v.Sym)
+		v.Param.Closure.Param.Closure = v.Param.Outer
+		v.Param.Outerexpr = oldname(v.Sym)
 	}
 
 	return func_
@@ -83,16 +83,16 @@ func typecheckclosure(func_ *Node, top int) {
 	var n *Node
 
 	for l := func_.Func.Cvars; l != nil; l = l.Next {
-		n = l.N.Closure
-		if !n.Captured {
-			n.Captured = true
-			if n.Decldepth == 0 {
+		n = l.N.Param.Closure
+		if !n.Name.Captured {
+			n.Name.Captured = true
+			if n.Name.Decldepth == 0 {
 				Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
 			}
 
 			// Ignore assignments to the variable in straightline code
 			// preceding the first capturing by a closure.
-			if n.Decldepth == decldepth {
+			if n.Name.Decldepth == decldepth {
 				n.Assigned = false
 			}
 		}
@@ -100,14 +100,14 @@ func typecheckclosure(func_ *Node, top int) {
 
 	for l := func_.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
-			l.N.Decldepth = 1
+			l.N.Name.Decldepth = 1
 		}
 	}
 
 	oldfn := Curfn
-	typecheck(&func_.Ntype, Etype)
-	func_.Type = func_.Ntype.Type
-	func_.Top = top
+	typecheck(&func_.Param.Ntype, Etype)
+	func_.Type = func_.Param.Ntype.Type
+	func_.Param.Top = top
 
 	// Type check the body now, but only if we're inside a function.
 	// At top level (in a variable initialization: curfn==nil) we're not
@@ -193,7 +193,7 @@ func makeclosure(func_ *Node) *Node {
 
 	xfunc.Nname = newfuncname(closurename(func_))
 	xfunc.Nname.Sym.Flags |= SymExported // disable export
-	xfunc.Nname.Ntype = xtype
+	xfunc.Nname.Param.Ntype = xtype
 	xfunc.Nname.Defn = xfunc
 	declare(xfunc.Nname, PFUNC)
 	xfunc.Nname.Funcdepth = func_.Funcdepth
@@ -207,8 +207,8 @@ func makeclosure(func_ *Node) *Node {
 	}
 	typecheck(&xfunc, Etop)
 
-	xfunc.Closure = func_
-	func_.Closure = xfunc
+	xfunc.Param.Closure = func_
+	func_.Param.Closure = xfunc
 
 	func_.Nbody = nil
 	func_.List = nil
@@ -229,7 +229,7 @@ func capturevars(xfunc *Node) {
 	lno := int(lineno)
 	lineno = xfunc.Lineno
 
-	func_ := xfunc.Closure
+	func_ := xfunc.Param.Closure
 	func_.Func.Enter = nil
 	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		v = l.N
@@ -249,14 +249,14 @@ func capturevars(xfunc *Node) {
 		// so that the outer frame also grabs them and knows they escape.
 		dowidth(v.Type)
 
-		outer = v.Outerexpr
-		v.Outerexpr = nil
+		outer = v.Param.Outerexpr
+		v.Param.Outerexpr = nil
 
 		// out parameters will be assigned to implicitly upon return.
-		if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 {
-			v.Byval = true
+		if outer.Class != PPARAMOUT && !v.Param.Closure.Addrtaken && !v.Param.Closure.Assigned && v.Type.Width <= 128 {
+			v.Name.Byval = true
 		} else {
-			v.Closure.Addrtaken = true
+			v.Param.Closure.Addrtaken = true
 			outer = Nod(OADDR, outer, nil)
 		}
 
@@ -266,10 +266,10 @@ func capturevars(xfunc *Node) {
 				name = v.Curfn.Nname.Sym
 			}
 			how := "ref"
-			if v.Byval {
+			if v.Name.Byval {
 				how = "value"
 			}
-			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
+			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Param.Closure.Addrtaken, v.Param.Closure.Assigned, int32(v.Type.Width))
 		}
 
 		typecheck(&outer, Erv)
@@ -284,9 +284,9 @@ func capturevars(xfunc *Node) {
 func transformclosure(xfunc *Node) {
 	lno := int(lineno)
 	lineno = xfunc.Lineno
-	func_ := xfunc.Closure
+	func_ := xfunc.Param.Closure
 
-	if func_.Top&Ecall != 0 {
+	if func_.Param.Top&Ecall != 0 {
 		// If the closure is directly called, we transform it to a plain function call
 		// with variables passed as args. This avoids allocation of a closure object.
 		// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
@@ -321,7 +321,7 @@ func transformclosure(xfunc *Node) {
 			}
 			fld = typ(TFIELD)
 			fld.Funarg = 1
-			if v.Byval {
+			if v.Name.Byval {
 				// If v is captured by value, we merely downgrade it to PPARAM.
 				v.Class = PPARAM
 
@@ -335,7 +335,7 @@ func transformclosure(xfunc *Node) {
 				addr = newname(Lookupf("&%s", v.Sym.Name))
 				addr.Type = Ptrto(v.Type)
 				addr.Class = PPARAM
-				v.Heapaddr = addr
+				v.Name.Heapaddr = addr
 				fld.Nname = addr
 			}
 
@@ -375,14 +375,14 @@ func transformclosure(xfunc *Node) {
 			cv = Nod(OCLOSUREVAR, nil, nil)
 
 			cv.Type = v.Type
-			if !v.Byval {
+			if !v.Name.Byval {
 				cv.Type = Ptrto(v.Type)
 			}
 			offset = Rnd(offset, int64(cv.Type.Align))
 			cv.Xoffset = offset
 			offset += cv.Type.Width
 
-			if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
+			if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
 				//  If it is a small variable captured by value, downgrade it to PAUTO.
 				// This optimization is currently enabled only for amd64, see:
 				// https://github.com/golang/go/issues/9865
@@ -395,13 +395,13 @@ func transformclosure(xfunc *Node) {
 				// Declare variable holding addresses taken from closure
 				// and initialize in entry prologue.
 				addr = newname(Lookupf("&%s", v.Sym.Name))
-				addr.Ntype = Nod(OIND, typenod(v.Type), nil)
+				addr.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
 				addr.Class = PAUTO
 				addr.Used = true
 				addr.Curfn = xfunc
 				xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
-				v.Heapaddr = addr
-				if v.Byval {
+				v.Name.Heapaddr = addr
+				if v.Name.Byval {
 					cv = Nod(OADDR, cv, nil)
 				}
 				body = list(body, Nod(OAS, addr, cv))
@@ -420,7 +420,7 @@ func transformclosure(xfunc *Node) {
 func walkclosure(func_ *Node, init **NodeList) *Node {
 	// If no closure vars, don't bother wrapping.
 	if func_.Func.Cvars == nil {
-		return func_.Closure.Nname
+		return func_.Param.Closure.Nname
 	}
 
 	// Create closure in the form of a composite literal.
@@ -448,7 +448,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 			continue
 		}
 		typ1 = typenod(v.Type)
-		if !v.Byval {
+		if !v.Name.Byval {
 			typ1 = Nod(OIND, typ1, nil)
 		}
 		typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
@@ -457,7 +457,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
 	clos.Esc = func_.Esc
 	clos.Right.Implicit = true
-	clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter)
+	clos.List = concat(list1(Nod(OCFUNC, func_.Param.Closure.Nname, nil)), func_.Func.Enter)
 
 	// Force type conversion from *struct to the func type.
 	clos = Nod(OCONVNOP, clos, nil)
@@ -583,7 +583,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
 	xfunc.Func.Dupok = true
 	xfunc.Nname = newfuncname(sym)
 	xfunc.Nname.Sym.Flags |= SymExported // disable export
-	xfunc.Nname.Ntype = xtype
+	xfunc.Nname.Param.Ntype = xtype
 	xfunc.Nname.Defn = xfunc
 	declare(xfunc.Nname, PFUNC)
 
@@ -606,10 +606,10 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
 	xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
 	var body *NodeList
 	if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
-		ptr.Ntype = typenod(rcvrtype)
+		ptr.Param.Ntype = typenod(rcvrtype)
 		body = list(body, Nod(OAS, ptr, cv))
 	} else {
-		ptr.Ntype = typenod(Ptrto(rcvrtype))
+		ptr.Param.Ntype = typenod(Ptrto(rcvrtype))
 		body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
 	}
 
diff --git a/src/cmd/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
similarity index 78%
rename from src/cmd/internal/gc/const.go
rename to src/cmd/compile/internal/gc/const.go
index ad2915812e..b3605ab206 100644
--- a/src/cmd/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -5,10 +5,47 @@
 package gc
 
 import (
+	"cmd/compile/internal/big"
 	"cmd/internal/obj"
 	"strings"
 )
 
+// Int returns n as an int.
+// n must be an integer constant.
+func (n *Node) Int() int64 {
+	if !Isconst(n, CTINT) {
+		Fatal("Int(%v)", n)
+	}
+	return Mpgetfix(n.Val.U.(*Mpint))
+}
+
+// SetInt sets n's value to i.
+// n must be an integer constant.
+func (n *Node) SetInt(i int64) {
+	if !Isconst(n, CTINT) {
+		Fatal("SetInt(%v)", n)
+	}
+	Mpmovecfix(n.Val.U.(*Mpint), i)
+}
+
+// SetBigInt sets n's value to x.
+// n must be an integer constant.
+func (n *Node) SetBigInt(x *big.Int) {
+	if !Isconst(n, CTINT) {
+		Fatal("SetBigInt(%v)", n)
+	}
+	n.Val.U.(*Mpint).Val.Set(x)
+}
+
+// Bool returns n as an bool.
+// n must be an boolean constant.
+func (n *Node) Bool() bool {
+	if !Isconst(n, CTBOOL) {
+		Fatal("Int(%v)", n)
+	}
+	return n.Val.U.(bool)
+}
+
 /*
  * truncate float literal fv to 32-bit or 64-bit precision
  * according to type; return truncated value.
@@ -20,7 +57,7 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
 
 	var v Val
 	v.Ctype = CTFLT
-	v.U.Fval = oldv
+	v.U = oldv
 	overflow(v, t)
 
 	fv := newMpflt()
@@ -190,8 +227,8 @@ func convlit1(np **Node, t *Type, explicit bool) {
 		// if it is an unsafe.Pointer
 		case TUINTPTR:
 			if n.Type.Etype == TUNSAFEPTR {
-				n.Val.U.Xval = new(Mpint)
-				Mpmovecfix(n.Val.U.Xval, 0)
+				n.Val.U = new(Mpint)
+				Mpmovecfix(n.Val.U.(*Mpint), 0)
 				n.Val.Ctype = CTINT
 			} else {
 				goto bad
@@ -204,6 +241,9 @@ func convlit1(np **Node, t *Type, explicit bool) {
 		}
 
 	case CTINT, CTRUNE, CTFLT, CTCPLX:
+		if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
+			goto bad
+		}
 		ct := int(n.Val.Ctype)
 		if Isint[et] {
 			switch ct {
@@ -229,7 +269,7 @@ func convlit1(np **Node, t *Type, explicit bool) {
 
 				// flowthrough
 			case CTFLT:
-				n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t)
+				n.Val.U = truncfltlit(n.Val.U.(*Mpflt), t)
 			}
 		} else if Iscomplex[et] {
 			switch ct {
@@ -264,27 +304,25 @@ bad:
 		defaultlit(&n, nil)
 		*np = n
 	}
-
-	return
 }
 
 func copyval(v Val) Val {
 	switch v.Ctype {
 	case CTINT, CTRUNE:
 		i := new(Mpint)
-		mpmovefixfix(i, v.U.Xval)
-		v.U.Xval = i
+		mpmovefixfix(i, v.U.(*Mpint))
+		v.U = i
 
 	case CTFLT:
 		f := newMpflt()
-		mpmovefltflt(f, v.U.Fval)
-		v.U.Fval = f
+		mpmovefltflt(f, v.U.(*Mpflt))
+		v.U = f
 
 	case CTCPLX:
 		c := new(Mpcplx)
-		mpmovefltflt(&c.Real, &v.U.Cval.Real)
-		mpmovefltflt(&c.Imag, &v.U.Cval.Imag)
-		v.U.Cval = c
+		mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real)
+		mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag)
+		v.U = c
 	}
 
 	return v
@@ -294,17 +332,17 @@ func tocplx(v Val) Val {
 	switch v.Ctype {
 	case CTINT, CTRUNE:
 		c := new(Mpcplx)
-		Mpmovefixflt(&c.Real, v.U.Xval)
+		Mpmovefixflt(&c.Real, v.U.(*Mpint))
 		Mpmovecflt(&c.Imag, 0.0)
 		v.Ctype = CTCPLX
-		v.U.Cval = c
+		v.U = c
 
 	case CTFLT:
 		c := new(Mpcplx)
-		mpmovefltflt(&c.Real, v.U.Fval)
+		mpmovefltflt(&c.Real, v.U.(*Mpflt))
 		Mpmovecflt(&c.Imag, 0.0)
 		v.Ctype = CTCPLX
-		v.U.Cval = c
+		v.U = c
 	}
 
 	return v
@@ -314,18 +352,18 @@ func toflt(v Val) Val {
 	switch v.Ctype {
 	case CTINT, CTRUNE:
 		f := newMpflt()
-		Mpmovefixflt(f, v.U.Xval)
+		Mpmovefixflt(f, v.U.(*Mpint))
 		v.Ctype = CTFLT
-		v.U.Fval = f
+		v.U = f
 
 	case CTCPLX:
 		f := newMpflt()
-		mpmovefltflt(f, &v.U.Cval.Real)
-		if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
-			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
+		mpmovefltflt(f, &v.U.(*Mpcplx).Real)
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
+			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
 		}
 		v.Ctype = CTFLT
-		v.U.Fval = f
+		v.U = f
 	}
 
 	return v
@@ -338,22 +376,22 @@ func toint(v Val) Val {
 
 	case CTFLT:
 		i := new(Mpint)
-		if mpmovefltfix(i, v.U.Fval) < 0 {
-			Yyerror("constant %v truncated to integer", Fconv(v.U.Fval, obj.FmtSharp))
+		if mpmovefltfix(i, v.U.(*Mpflt)) < 0 {
+			Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp))
 		}
 		v.Ctype = CTINT
-		v.U.Xval = i
+		v.U = i
 
 	case CTCPLX:
 		i := new(Mpint)
-		if mpmovefltfix(i, &v.U.Cval.Real) < 0 {
-			Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
+		if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 {
+			Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
 		}
-		if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
-			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
+			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
 		}
 		v.Ctype = CTINT
-		v.U.Xval = i
+		v.U = i
 	}
 
 	return v
@@ -365,7 +403,7 @@ func doesoverflow(v Val, t *Type) bool {
 		if !Isint[t.Etype] {
 			Fatal("overflow: %v integer constant", t)
 		}
-		if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 {
 			return true
 		}
 
@@ -373,7 +411,7 @@ func doesoverflow(v Val, t *Type) bool {
 		if !Isfloat[t.Etype] {
 			Fatal("overflow: %v floating-point constant", t)
 		}
-		if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 {
 			return true
 		}
 
@@ -381,7 +419,7 @@ func doesoverflow(v Val, t *Type) bool {
 		if !Iscomplex[t.Etype] {
 			Fatal("overflow: %v complex constant", t)
 		}
-		if mpcmpfltflt(&v.U.Cval.Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.Cval.Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Imag, maxfltval[t.Etype]) >= 0 {
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 {
 			return true
 		}
 	}
@@ -396,32 +434,37 @@ func overflow(v Val, t *Type) {
 		return
 	}
 
+	// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
+	if t.Etype == TUNSAFEPTR {
+		return
+	}
+
 	if !doesoverflow(v, t) {
 		return
 	}
 
 	switch v.Ctype {
 	case CTINT, CTRUNE:
-		Yyerror("constant %v overflows %v", v.U.Xval, t)
+		Yyerror("constant %v overflows %v", v.U.(*Mpint), t)
 
 	case CTFLT:
-		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
+		Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
 
 	case CTCPLX:
-		Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
+		Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
 	}
 }
 
 func tostr(v Val) Val {
 	switch v.Ctype {
 	case CTINT, CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 {
 			Yyerror("overflow in int -> string")
 		}
-		r := uint(Mpgetfix(v.U.Xval))
+		r := uint(Mpgetfix(v.U.(*Mpint)))
 		v = Val{}
 		v.Ctype = CTSTR
-		v.U.Sval = string(r)
+		v.U = string(r)
 
 	case CTFLT:
 		Yyerror("no float -> string")
@@ -430,7 +473,7 @@ func tostr(v Val) Val {
 	case CTNIL:
 		v = Val{}
 		v.Ctype = CTSTR
-		v.U.Sval = ""
+		v.U = ""
 	}
 
 	return v
@@ -519,7 +562,7 @@ func evconst(n *Node) {
 				l2 = l1
 				for l2 != nil && Isconst(l2.N, CTSTR) {
 					nr = l2.N
-					strs = append(strs, nr.Val.U.Sval)
+					strs = append(strs, nr.Val.U.(string))
 					l2 = l2.Next
 				}
 
@@ -527,7 +570,7 @@ func evconst(n *Node) {
 				*nl = *l1.N
 				nl.Orig = nl
 				nl.Val.Ctype = CTSTR
-				nl.Val.U.Sval = strings.Join(strs, "")
+				nl.Val.U = strings.Join(strs, "")
 				l1.N = nl
 				l1.Next = l2
 			}
@@ -607,7 +650,7 @@ func evconst(n *Node) {
 
 		case OMINUS<<16 | CTINT,
 			OMINUS<<16 | CTRUNE:
-			mpnegfix(v.U.Xval)
+			mpnegfix(v.U.(*Mpint))
 
 		case OCOM<<16 | CTINT,
 			OCOM<<16 | CTRUNE:
@@ -634,23 +677,23 @@ func evconst(n *Node) {
 				mpmovefixfix(&b, Maxintval[et])
 			}
 
-			mpxorfixfix(v.U.Xval, &b)
+			mpxorfixfix(v.U.(*Mpint), &b)
 
 		case OPLUS<<16 | CTFLT:
 			break
 
 		case OMINUS<<16 | CTFLT:
-			mpnegflt(v.U.Fval)
+			mpnegflt(v.U.(*Mpflt))
 
 		case OPLUS<<16 | CTCPLX:
 			break
 
 		case OMINUS<<16 | CTCPLX:
-			mpnegflt(&v.U.Cval.Real)
-			mpnegflt(&v.U.Cval.Imag)
+			mpnegflt(&v.U.(*Mpcplx).Real)
+			mpnegflt(&v.U.(*Mpcplx).Imag)
 
 		case ONOT<<16 | CTBOOL:
-			if !v.U.Bval {
+			if !v.U.(bool) {
 				goto settrue
 			}
 			goto setfalse
@@ -754,77 +797,77 @@ func evconst(n *Node) {
 
 	case OADD<<16 | CTINT,
 		OADD<<16 | CTRUNE:
-		mpaddfixfix(v.U.Xval, rv.U.Xval, 0)
+		mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0)
 
 	case OSUB<<16 | CTINT,
 		OSUB<<16 | CTRUNE:
-		mpsubfixfix(v.U.Xval, rv.U.Xval)
+		mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OMUL<<16 | CTINT,
 		OMUL<<16 | CTRUNE:
-		mpmulfixfix(v.U.Xval, rv.U.Xval)
+		mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case ODIV<<16 | CTINT,
 		ODIV<<16 | CTRUNE:
-		if mpcmpfixc(rv.U.Xval, 0) == 0 {
+		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
 			Yyerror("division by zero")
-			Mpmovecfix(v.U.Xval, 1)
+			mpsetovf(v.U.(*Mpint))
 			break
 		}
 
-		mpdivfixfix(v.U.Xval, rv.U.Xval)
+		mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OMOD<<16 | CTINT,
 		OMOD<<16 | CTRUNE:
-		if mpcmpfixc(rv.U.Xval, 0) == 0 {
+		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
 			Yyerror("division by zero")
-			Mpmovecfix(v.U.Xval, 1)
+			mpsetovf(v.U.(*Mpint))
 			break
 		}
 
-		mpmodfixfix(v.U.Xval, rv.U.Xval)
+		mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OLSH<<16 | CTINT,
 		OLSH<<16 | CTRUNE:
-		mplshfixfix(v.U.Xval, rv.U.Xval)
+		mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case ORSH<<16 | CTINT,
 		ORSH<<16 | CTRUNE:
-		mprshfixfix(v.U.Xval, rv.U.Xval)
+		mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OOR<<16 | CTINT,
 		OOR<<16 | CTRUNE:
-		mporfixfix(v.U.Xval, rv.U.Xval)
+		mporfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OAND<<16 | CTINT,
 		OAND<<16 | CTRUNE:
-		mpandfixfix(v.U.Xval, rv.U.Xval)
+		mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OANDNOT<<16 | CTINT,
 		OANDNOT<<16 | CTRUNE:
-		mpandnotfixfix(v.U.Xval, rv.U.Xval)
+		mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OXOR<<16 | CTINT,
 		OXOR<<16 | CTRUNE:
-		mpxorfixfix(v.U.Xval, rv.U.Xval)
+		mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint))
 
 	case OADD<<16 | CTFLT:
-		mpaddfltflt(v.U.Fval, rv.U.Fval)
+		mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
 
 	case OSUB<<16 | CTFLT:
-		mpsubfltflt(v.U.Fval, rv.U.Fval)
+		mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
 
 	case OMUL<<16 | CTFLT:
-		mpmulfltflt(v.U.Fval, rv.U.Fval)
+		mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
 
 	case ODIV<<16 | CTFLT:
-		if mpcmpfltc(rv.U.Fval, 0) == 0 {
+		if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 {
 			Yyerror("division by zero")
-			Mpmovecflt(v.U.Fval, 1.0)
+			Mpmovecflt(v.U.(*Mpflt), 1.0)
 			break
 		}
 
-		mpdivfltflt(v.U.Fval, rv.U.Fval)
+		mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
 
 		// The default case above would print 'ideal % ideal',
 	// which is not quite an ideal error.
@@ -837,25 +880,25 @@ func evconst(n *Node) {
 		return
 
 	case OADD<<16 | CTCPLX:
-		mpaddfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
-		mpaddfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
+		mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
+		mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
 
 	case OSUB<<16 | CTCPLX:
-		mpsubfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
-		mpsubfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
+		mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
+		mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
 
 	case OMUL<<16 | CTCPLX:
-		cmplxmpy(v.U.Cval, rv.U.Cval)
+		cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
 
 	case ODIV<<16 | CTCPLX:
-		if mpcmpfltc(&rv.U.Cval.Real, 0) == 0 && mpcmpfltc(&rv.U.Cval.Imag, 0) == 0 {
+		if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 {
 			Yyerror("complex division by zero")
-			Mpmovecflt(&rv.U.Cval.Real, 1.0)
-			Mpmovecflt(&rv.U.Cval.Imag, 0.0)
+			Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0)
+			Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0)
 			break
 		}
 
-		cmplxdiv(v.U.Cval, rv.U.Cval)
+		cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
 
 	case OEQ<<16 | CTNIL:
 		goto settrue
@@ -865,90 +908,90 @@ func evconst(n *Node) {
 
 	case OEQ<<16 | CTINT,
 		OEQ<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) == 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE<<16 | CTINT,
 		ONE<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) != 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLT<<16 | CTINT,
 		OLT<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) < 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLE<<16 | CTINT,
 		OLE<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) <= 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGE<<16 | CTINT,
 		OGE<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) >= 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGT<<16 | CTINT,
 		OGT<<16 | CTRUNE:
-		if Mpcmpfixfix(v.U.Xval, rv.U.Xval) > 0 {
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OEQ<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) == 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) != 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLT<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) < 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLE<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) <= 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGE<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) >= 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGT<<16 | CTFLT:
-		if mpcmpfltflt(v.U.Fval, rv.U.Fval) > 0 {
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OEQ<<16 | CTCPLX:
-		if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) == 0 && mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) == 0 {
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE<<16 | CTCPLX:
-		if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) != 0 || mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) != 0 {
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 {
 			goto settrue
 		}
 		goto setfalse
@@ -990,25 +1033,25 @@ func evconst(n *Node) {
 		goto setfalse
 
 	case OOROR<<16 | CTBOOL:
-		if v.U.Bval || rv.U.Bval {
+		if v.U.(bool) || rv.U.(bool) {
 			goto settrue
 		}
 		goto setfalse
 
 	case OANDAND<<16 | CTBOOL:
-		if v.U.Bval && rv.U.Bval {
+		if v.U.(bool) && rv.U.(bool) {
 			goto settrue
 		}
 		goto setfalse
 
 	case OEQ<<16 | CTBOOL:
-		if v.U.Bval == rv.U.Bval {
+		if v.U.(bool) == rv.U.(bool) {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE<<16 | CTBOOL:
-		if v.U.Bval != rv.U.Bval {
+		if v.U.(bool) != rv.U.(bool) {
 			goto settrue
 		}
 		goto setfalse
@@ -1033,7 +1076,7 @@ ret:
 
 	// truncate precision for non-ideal float.
 	if v.Ctype == CTFLT && n.Type.Etype != TIDEAL {
-		n.Val.U.Fval = truncfltlit(v.U.Fval, n.Type)
+		n.Val.U = truncfltlit(v.U.(*Mpflt), n.Type)
 	}
 	return
 
@@ -1088,15 +1131,15 @@ func nodcplxlit(r Val, i Val) *Node {
 	c := new(Mpcplx)
 	n := Nod(OLITERAL, nil, nil)
 	n.Type = Types[TIDEAL]
-	n.Val.U.Cval = c
+	n.Val.U = c
 	n.Val.Ctype = CTCPLX
 
 	if r.Ctype != CTFLT || i.Ctype != CTFLT {
 		Fatal("nodcplxlit ctype %d/%d", r.Ctype, i.Ctype)
 	}
 
-	mpmovefltflt(&c.Real, r.U.Fval)
-	mpmovefltflt(&c.Imag, i.U.Fval)
+	mpmovefltflt(&c.Real, r.U.(*Mpflt))
+	mpmovefltflt(&c.Imag, i.U.(*Mpflt))
 	return n
 }
 
@@ -1311,7 +1354,7 @@ func defaultlit2(lp **Node, rp **Node, force int) {
 }
 
 func cmpslit(l, r *Node) int {
-	return stringsCompare(l.Val.U.Sval, r.Val.U.Sval)
+	return stringsCompare(l.Val.U.(string), r.Val.U.(string))
 }
 
 func Smallintconst(n *Node) bool {
@@ -1328,7 +1371,7 @@ func Smallintconst(n *Node) bool {
 			return true
 
 		case TIDEAL, TINT64, TUINT64, TPTR64:
-			if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
+			if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 {
 				break
 			}
 			return true
@@ -1351,10 +1394,10 @@ func nonnegconst(n *Node) int {
 			TINT64,
 			TUINT64,
 			TIDEAL:
-			if Mpcmpfixfix(n.Val.U.Xval, Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
+			if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 {
 				break
 			}
-			return int(Mpgetfix(n.Val.U.Xval))
+			return int(Mpgetfix(n.Val.U.(*Mpint)))
 		}
 	}
 
@@ -1392,39 +1435,37 @@ func iconv(x int64, et int) int64 {
 	return x
 }
 
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-func Convconst(con *Node, t *Type, val *Val) {
+// Convconst converts constant node n to type t and
+// places the result in con.
+func (n *Node) Convconst(con *Node, t *Type) {
 	tt := Simsimtype(t)
 
 	// copy the constant for conversion
 	Nodconst(con, Types[TINT8], 0)
 
 	con.Type = t
-	con.Val = *val
+	con.Val = n.Val
 
 	if Isint[tt] {
 		con.Val.Ctype = CTINT
-		con.Val.U.Xval = new(Mpint)
+		con.Val.U = new(Mpint)
 		var i int64
-		switch val.Ctype {
+		switch n.Val.Ctype {
 		default:
-			Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong))
+			Fatal("convconst ctype=%d %v", n.Val.Ctype, Tconv(t, obj.FmtLong))
 
 		case CTINT, CTRUNE:
-			i = Mpgetfix(val.U.Xval)
+			i = Mpgetfix(n.Val.U.(*Mpint))
 
 		case CTBOOL:
-			i = int64(obj.Bool2int(val.U.Bval))
+			i = int64(obj.Bool2int(n.Val.U.(bool)))
 
 		case CTNIL:
 			i = 0
 		}
 
 		i = iconv(i, tt)
-		Mpmovecfix(con.Val.U.Xval, i)
+		Mpmovecfix(con.Val.U.(*Mpint), i)
 		return
 	}
 
@@ -1434,7 +1475,7 @@ func Convconst(con *Node, t *Type, val *Val) {
 			Fatal("convconst ctype=%d %v", con.Val.Ctype, t)
 		}
 		if tt == TFLOAT32 {
-			con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t)
+			con.Val.U = truncfltlit(con.Val.U.(*Mpflt), t)
 		}
 		return
 	}
@@ -1442,10 +1483,9 @@ func Convconst(con *Node, t *Type, val *Val) {
 	if Iscomplex[tt] {
 		con.Val = tocplx(con.Val)
 		if tt == TCOMPLEX64 {
-			con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32])
-			con.Val.U.Cval.Imag = *truncfltlit(&con.Val.U.Cval.Imag, Types[TFLOAT32])
+			con.Val.U.(*Mpcplx).Real = *truncfltlit(&con.Val.U.(*Mpcplx).Real, Types[TFLOAT32])
+			con.Val.U.(*Mpcplx).Imag = *truncfltlit(&con.Val.U.(*Mpcplx).Imag, Types[TFLOAT32])
 		}
-
 		return
 	}
 
diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go
similarity index 98%
rename from src/cmd/internal/gc/cplx.go
rename to src/cmd/compile/internal/gc/cplx.go
index cf48c922d7..56a4892636 100644
--- a/src/cmd/internal/gc/cplx.go
+++ b/src/cmd/compile/internal/gc/cplx.go
@@ -89,8 +89,8 @@ func subnode(nr *Node, ni *Node, nc *Node) {
 	t := Types[tc]
 
 	if nc.Op == OLITERAL {
-		nodfconst(nr, t, &nc.Val.U.Cval.Real)
-		nodfconst(ni, t, &nc.Val.U.Cval.Imag)
+		nodfconst(nr, t, &nc.Val.U.(*Mpcplx).Real)
+		nodfconst(ni, t, &nc.Val.U.(*Mpcplx).Imag)
 		return
 	}
 
@@ -226,7 +226,7 @@ func nodfconst(n *Node, t *Type, fval *Mpflt) {
 	n.Op = OLITERAL
 	n.Addable = true
 	ullmancalc(n)
-	n.Val.U.Fval = fval
+	n.Val.U = fval
 	n.Val.Ctype = CTFLT
 	n.Type = t
 
diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
similarity index 97%
rename from src/cmd/internal/gc/dcl.go
rename to src/cmd/compile/internal/gc/dcl.go
index 08d2469094..4a9cb295c8 100644
--- a/src/cmd/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -183,7 +183,7 @@ func declare(n *Node, ctxt uint8) {
 	}
 
 	if ctxt == PEXTERN && s.Name == "init" {
-		Yyerror("cannot declare init - must be func", s)
+		Yyerror("cannot declare init - must be func")
 	}
 
 	gen := 0
@@ -260,7 +260,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
 			v = vl.N
 			v.Op = ONAME
 			declare(v, dclcontext)
-			v.Ntype = t
+			v.Param.Ntype = t
 			v.Defn = as2
 			if Funcdepth > 0 {
 				init = list(init, Nod(ODCL, v, nil))
@@ -288,7 +288,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
 		v = vl.N
 		v.Op = ONAME
 		declare(v, dclcontext)
-		v.Ntype = t
+		v.Param.Ntype = t
 
 		if e != nil || Funcdepth > 0 || isblank(v) {
 			if Funcdepth > 0 {
@@ -313,18 +313,19 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
  * new_name_list [[type] = expr_list]
  */
 func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
+	lno := int32(0) // default is to leave line number alone in listtreecopy
 	if cl == nil {
 		if t != nil {
 			Yyerror("const declaration cannot have type without expression")
 		}
 		cl = lastconst
 		t = lasttype
+		lno = vl.N.Lineno
 	} else {
 		lastconst = cl
 		lasttype = t
 	}
-
-	cl = listtreecopy(cl)
+	cl = listtreecopy(cl, lno)
 
 	var v *Node
 	var c *Node
@@ -342,7 +343,7 @@ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
 		v.Op = OLITERAL
 		declare(v, dclcontext)
 
-		v.Ntype = t
+		v.Param.Ntype = t
 		v.Defn = c
 
 		vv = list(vv, Nod(ODCLCONST, v, nil))
@@ -430,7 +431,7 @@ func oldname(s *Sym) *Node {
 		// are parsing x := 5 inside the closure, until we get to
 		// the := it looks like a reference to the outer x so we'll
 		// make x a closure variable unnecessarily.
-		if n.Closure == nil || n.Closure.Funcdepth != Funcdepth {
+		if n.Param.Closure == nil || n.Param.Closure.Funcdepth != Funcdepth {
 			// create new closure var.
 			c := Nod(ONAME, nil, nil)
 
@@ -441,15 +442,15 @@ func oldname(s *Sym) *Node {
 			c.Addable = false
 			c.Ullman = 2
 			c.Funcdepth = Funcdepth
-			c.Outer = n.Closure
-			n.Closure = c
-			c.Closure = n
+			c.Param.Outer = n.Param.Closure
+			n.Param.Closure = c
+			c.Param.Closure = n
 			c.Xoffset = 0
 			Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
 		}
 
 		// return ref to closure var, not original
-		return n.Closure
+		return n.Param.Closure
 	}
 
 	return n
@@ -554,7 +555,7 @@ func ifacedcl(n *Node) {
 	dclcontext = PPARAM
 	markdcl()
 	Funcdepth++
-	n.Outer = Curfn
+	n.Param.Outer = Curfn
 	Curfn = n
 	funcargs(n.Right)
 
@@ -583,13 +584,13 @@ func funchdr(n *Node) {
 	markdcl()
 	Funcdepth++
 
-	n.Outer = Curfn
+	n.Param.Outer = Curfn
 	Curfn = n
 
 	if n.Nname != nil {
-		funcargs(n.Nname.Ntype)
-	} else if n.Ntype != nil {
-		funcargs(n.Ntype)
+		funcargs(n.Nname.Param.Ntype)
+	} else if n.Param.Ntype != nil {
+		funcargs(n.Param.Ntype)
 	} else {
 		funcargs2(n.Type)
 	}
@@ -615,7 +616,7 @@ func funcargs(nt *Node) {
 		}
 		if n.Left != nil {
 			n.Left.Op = ONAME
-			n.Left.Ntype = n.Right
+			n.Left.Param.Ntype = n.Right
 			declare(n.Left, PPARAM)
 			if dclcontext == PAUTO {
 				vargen++
@@ -632,7 +633,7 @@ func funcargs(nt *Node) {
 		}
 		if n.Left != nil {
 			n.Left.Op = ONAME
-			n.Left.Ntype = n.Right
+			n.Left.Param.Ntype = n.Right
 			declare(n.Left, PPARAM)
 			if dclcontext == PAUTO {
 				vargen++
@@ -679,7 +680,7 @@ func funcargs(nt *Node) {
 			n.Left = nn
 		}
 
-		n.Left.Ntype = n.Right
+		n.Left.Param.Ntype = n.Right
 		declare(n.Left, PPARAMOUT)
 		if dclcontext == PAUTO {
 			i++
@@ -747,8 +748,8 @@ func funcbody(n *Node) {
 	}
 	popdcl()
 	Funcdepth--
-	Curfn = n.Outer
-	n.Outer = nil
+	Curfn = n.Param.Outer
+	n.Param.Outer = nil
 	if Funcdepth == 0 {
 		dclcontext = PEXTERN
 	}
@@ -770,7 +771,7 @@ func typedcl0(s *Sym) *Node {
  * return the ODCLTYPE node to use.
  */
 func typedcl1(n *Node, t *Node, local bool) *Node {
-	n.Ntype = t
+	n.Param.Ntype = t
 	n.Local = local
 	return Nod(ODCLTYPE, n, nil)
 }
@@ -830,7 +831,7 @@ func structfield(n *Node) *Type {
 	switch n.Val.Ctype {
 	case CTSTR:
 		f.Note = new(string)
-		*f.Note = n.Val.U.Sval
+		*f.Note = n.Val.U.(string)
 
 	default:
 		Yyerror("field annotation must be string")
diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
similarity index 93%
rename from src/cmd/internal/gc/esc.go
rename to src/cmd/compile/internal/gc/esc.go
index c816feaa7f..2c134933c4 100644
--- a/src/cmd/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -154,7 +154,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
 	}
 
 	if n.Op == OCLOSURE {
-		m := v.visit(n.Closure)
+		m := v.visit(n.Param.Closure)
 		if m < min {
 			min = m
 		}
@@ -379,7 +379,7 @@ type EscState struct {
 	theSink Node
 
 	dsts      *NodeList // all dst nodes
-	loopdepth int       // for detecting nested loop scopes
+	loopdepth int32     // for detecting nested loop scopes
 	pdepth    int       // for debug printing in recursions.
 	dstcount  int       // diagnostic
 	edgecount int       // diagnostic
@@ -387,6 +387,19 @@ type EscState struct {
 	recursive bool      // recursive function or group of mutually recursive functions.
 }
 
+// funcSym returns n.Nname.Sym if no nils are encountered along the way.
+func funcSym(n *Node) *Sym {
+	if n == nil || n.Nname == nil {
+		return nil
+	}
+	return n.Nname.Sym
+}
+
+// curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
+func curfnSym(n *Node) *Sym {
+	return funcSym(n.Curfn)
+}
+
 func escAnalyze(all *NodeList, recursive bool) {
 	var es EscState
 	e := &es
@@ -428,13 +441,7 @@ func escAnalyze(all *NodeList, recursive bool) {
 	if Debug['m'] != 0 {
 		for l := e.noesc; l != nil; l = l.Next {
 			if l.N.Esc == EscNone {
-				var tmp *Sym
-				if l.N.Curfn != nil && l.N.Curfn.Nname != nil {
-					tmp = l.N.Curfn.Nname.Sym
-				} else {
-					tmp = nil
-				}
-				Warnl(int(l.N.Lineno), "%v %v does not escape", tmp, Nconv(l.N, obj.FmtShort))
+				Warnl(int(l.N.Lineno), "%v %v does not escape", curfnSym(l.N), Nconv(l.N, obj.FmtShort))
 			}
 		}
 	}
@@ -579,6 +586,19 @@ func esc(e *EscState, n *Node, up *Node) {
 		}
 	}
 
+	// Big stuff escapes unconditionally
+	// "Big" conditions that were scattered around in walk have been gathered here
+	if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
+		n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
+		n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
+		if Debug['m'] > 1 {
+			Warnl(int(n.Lineno), "%v is too large for stack", n)
+		}
+		n.Esc = EscHeap
+		addrescapes(n)
+		escassign(e, &e.theSink, n)
+	}
+
 	esc(e, n.Left, n)
 	esc(e, n.Right, n)
 	esc(e, n.Ntest, n)
@@ -593,13 +613,7 @@ func esc(e *EscState, n *Node, up *Node) {
 	}
 
 	if Debug['m'] > 1 {
-		var tmp *Sym
-		if Curfn != nil && Curfn.Nname != nil {
-			tmp = Curfn.Nname.Sym
-		} else {
-			tmp = nil
-		}
-		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, tmp, n)
+		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
 	}
 
 	switch n.Op {
@@ -629,8 +643,12 @@ func esc(e *EscState, n *Node, up *Node) {
 
 		// Everything but fixed array is a dereference.
 	case ORANGE:
-		if Isfixedarray(n.Type) && n.List != nil && n.List.Next != nil {
-			escassign(e, n.List.Next.N, n.Right)
+		if n.List != nil && n.List.Next != nil {
+			if Isfixedarray(n.Type) {
+				escassign(e, n.List.Next.N, n.Right)
+			} else {
+				escassign(e, n.List.Next.N, addDereference(n.Right))
+			}
 		}
 
 	case OSWITCH:
@@ -670,13 +688,7 @@ func esc(e *EscState, n *Node, up *Node) {
 			// b escapes as well. If we ignore such OSLICEARR, we will conclude
 			// that b does not escape when b contents do.
 			if Debug['m'] != 0 {
-				var tmp *Sym
-				if n.Curfn != nil && n.Curfn.Nname != nil {
-					tmp = n.Curfn.Nname.Sym
-				} else {
-					tmp = nil
-				}
-				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", tmp, Nconv(n.Left, obj.FmtShort))
+				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", curfnSym(n), Nconv(n.Left, obj.FmtShort))
 			}
 
 			break
@@ -763,7 +775,15 @@ func esc(e *EscState, n *Node, up *Node) {
 			for ll := n.List.Next; ll != nil; ll = ll.Next {
 				escassign(e, &e.theSink, ll.N) // lose track of assign to dereference
 			}
+		} else {
+			// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
+			slice2 := n.List.Next.N
+			escassign(e, &e.theSink, addDereference(slice2)) // lose track of assign of dereference
+			if Debug['m'] > 2 {
+				Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", curfnSym(n), Nconv(n, obj.FmtShort))
+			}
 		}
+		escassign(e, &e.theSink, addDereference(n.List.N)) // The original elements are now leaked, too
 
 	case OCONV, OCONVNOP:
 		escassign(e, n, n.Left)
@@ -776,19 +796,15 @@ func esc(e *EscState, n *Node, up *Node) {
 
 	case OARRAYLIT:
 		if Isslice(n.Type) {
-			n.Esc = EscNone // until proven otherwise
+			// Slice itself is not leaked until proven otherwise
+			n.Esc = EscNone
 			e.noesc = list(e.noesc, n)
 			n.Escloopdepth = e.loopdepth
+		}
 
-			// Values make it to memory, lose track.
-			for ll := n.List; ll != nil; ll = ll.Next {
-				escassign(e, &e.theSink, ll.N.Right)
-			}
-		} else {
-			// Link values to array.
-			for ll := n.List; ll != nil; ll = ll.Next {
-				escassign(e, n, ll.N.Right)
-			}
+		// Link values to array/slice
+		for ll := n.List; ll != nil; ll = ll.Next {
+			escassign(e, n, ll.N.Right)
 		}
 
 		// Link values to struct.
@@ -833,8 +849,8 @@ func esc(e *EscState, n *Node, up *Node) {
 			if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs
 				continue
 			}
-			a = v.Closure
-			if !v.Byval {
+			a = v.Param.Closure
+			if !v.Name.Byval {
 				a = Nod(OADDR, a, nil)
 				a.Lineno = v.Lineno
 				a.Escloopdepth = e.loopdepth
@@ -909,14 +925,8 @@ func escassign(e *EscState, dst *Node, src *Node) {
 	}
 
 	if Debug['m'] > 1 {
-		var tmp *Sym
-		if Curfn != nil && Curfn.Nname != nil {
-			tmp = Curfn.Nname.Sym
-		} else {
-			tmp = nil
-		}
 		fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
-			Ctxt.Line(int(lineno)), e.loopdepth, tmp,
+			Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn),
 			Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0),
 			Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0))
 	}
@@ -1038,12 +1048,15 @@ func escassign(e *EscState, dst *Node, src *Node) {
 
 	case OAPPEND:
 		// Append returns first argument.
+		// Subsequent arguments are already leaked because they are operands to append.
 		escassign(e, dst, src.List.N)
 
 	case OINDEX:
 		// Index of array preserves input value.
 		if Isfixedarray(src.Left.Type) {
 			escassign(e, dst, src.Left)
+		} else {
+			escflows(e, dst, src)
 		}
 
 		// Might be pointer arithmetic, in which case
@@ -1269,6 +1282,24 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
 	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
 }
 
+func initEscretval(e *EscState, n *Node, fntype *Type) {
+	i := 0
+	n.Escretval = nil // Suspect this is not nil for indirect calls.
+	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
+		src := Nod(ONAME, nil, nil)
+		buf := fmt.Sprintf(".out%d", i)
+		i++
+		src.Sym = Lookup(buf)
+		src.Type = t.Type
+		src.Class = PAUTO
+		src.Curfn = Curfn
+		src.Escloopdepth = e.loopdepth
+		src.Used = true
+		src.Lineno = n.Lineno
+		n.Escretval = list(n.Escretval, src)
+	}
+}
+
 // This is a bit messier than fortunate, pulled out of esc's big
 // switch for clarity.	We either have the paramnodes, which may be
 // connected to other things through flows or we have the parameter type
@@ -1277,7 +1308,7 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
 // this-package
 func esccall(e *EscState, n *Node, up *Node) {
 	var fntype *Type
-
+	var indirect bool
 	var fn *Node
 	switch n.Op {
 	default:
@@ -1286,6 +1317,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 	case OCALLFUNC:
 		fn = n.Left
 		fntype = fn.Type
+		indirect = fn.Op != ONAME || fn.Class != PFUNC
 
 	case OCALLMETH:
 		fn = n.Left.Right.Sym.Def
@@ -1297,6 +1329,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 
 	case OCALLINTER:
 		fntype = n.Left.Type
+		indirect = true
 	}
 
 	ll := n.List
@@ -1307,8 +1340,30 @@ func esccall(e *EscState, n *Node, up *Node) {
 		}
 	}
 
+	if indirect {
+		// We know nothing!
+		// Leak all the parameters
+		for ; ll != nil; ll = ll.Next {
+			escassign(e, &e.theSink, ll.N)
+			if Debug['m'] > 2 {
+				fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+			}
+		}
+		// Set up bogus outputs
+		initEscretval(e, n, fntype)
+		// If there is a receiver, it also leaks to heap.
+		if n.Op != OCALLFUNC {
+			t := getthisx(fntype).Type
+			src := n.Left.Left
+			if haspointers(t.Type) {
+				escassign(e, &e.theSink, src)
+			}
+		}
+		return
+	}
+
 	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
-		fn.Defn != nil && fn.Defn.Nbody != nil && fn.Ntype != nil && fn.Defn.Esc < EscFuncTagged {
+		fn.Defn != nil && fn.Defn.Nbody != nil && fn.Param.Ntype != nil && fn.Defn.Esc < EscFuncTagged {
 		if Debug['m'] > 2 {
 			fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
 		}
@@ -1320,17 +1375,17 @@ func esccall(e *EscState, n *Node, up *Node) {
 		}
 
 		// set up out list on this call node
-		for lr := fn.Ntype.Rlist; lr != nil; lr = lr.Next {
+		for lr := fn.Param.Ntype.Rlist; lr != nil; lr = lr.Next {
 			n.Escretval = list(n.Escretval, lr.N.Left) // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
 		}
 
 		// Receiver.
 		if n.Op != OCALLFUNC {
-			escassign(e, fn.Ntype.Left.Left, n.Left.Left)
+			escassign(e, fn.Param.Ntype.Left.Left, n.Left.Left)
 		}
 
 		var src *Node
-		for lr := fn.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
+		for lr := fn.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
 			src = ll.N
 			if lr.N.Isddd && !n.Isddd {
 				// Introduce ODDDARG node to represent ... allocation.
@@ -1376,23 +1431,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 	}
 
 	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
-	i := 0
-
-	var src *Node
-	var buf string
-	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
-		src = Nod(ONAME, nil, nil)
-		buf = fmt.Sprintf(".out%d", i)
-		i++
-		src.Sym = Lookup(buf)
-		src.Type = t.Type
-		src.Class = PAUTO
-		src.Curfn = Curfn
-		src.Escloopdepth = e.loopdepth
-		src.Used = true
-		src.Lineno = n.Lineno
-		n.Escretval = list(n.Escretval, src)
-	}
+	initEscretval(e, n, fntype)
 
 	//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
 
@@ -1405,9 +1444,8 @@ func esccall(e *EscState, n *Node, up *Node) {
 		}
 	}
 
-	var a *Node
 	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
-		src = ll.N
+		src := ll.N
 		if t.Isddd && !n.Isddd {
 			// Introduce ODDDARG node to represent ... allocation.
 			src = Nod(ODDDARG, nil, nil)
@@ -1425,7 +1463,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 
 		if haspointers(t.Type) {
 			if escassignfromtag(e, t.Note, n.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
-				a = src
+				a := src
 				for a.Op == OCONVNOP {
 					a = a.Left
 				}
@@ -1510,13 +1548,7 @@ func escflood(e *EscState, dst *Node) {
 	}
 
 	if Debug['m'] > 1 {
-		var tmp *Sym
-		if dst.Curfn != nil && dst.Curfn.Nname != nil {
-			tmp = dst.Curfn.Nname.Sym
-		} else {
-			tmp = nil
-		}
-		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), tmp, dst.Escloopdepth)
+		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), curfnSym(dst), dst.Escloopdepth)
 	}
 
 	for l := dst.Escflowsrc; l != nil; l = l.Next {
@@ -1548,14 +1580,8 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
 	src.Esclevel = level
 
 	if Debug['m'] > 1 {
-		var tmp *Sym
-		if src.Curfn != nil && src.Curfn.Nname != nil {
-			tmp = src.Curfn.Nname.Sym
-		} else {
-			tmp = nil
-		}
 		fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n",
-			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), tmp, src.Escloopdepth)
+			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), curfnSym(src), src.Escloopdepth)
 	}
 
 	e.pdepth++
@@ -1627,7 +1653,7 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
 			if leaks && Debug['m'] != 0 {
 				Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
 			}
-			escwalk(e, level, dst, src.Closure)
+			escwalk(e, level, dst, src.Param.Closure)
 		}
 
 	case OPTRLIT, OADDR:
@@ -1657,6 +1683,10 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
 		if Isfixedarray(src.Type) {
 			break
 		}
+		for ll := src.List; ll != nil; ll = ll.Next {
+			escwalk(e, level.dec(), dst, ll.N.Right)
+		}
+
 		fallthrough
 
 	case ODDDARG,
diff --git a/src/cmd/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
similarity index 99%
rename from src/cmd/internal/gc/export.go
rename to src/cmd/compile/internal/gc/export.go
index 1efc8150c5..5117490ac8 100644
--- a/src/cmd/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -64,7 +64,7 @@ func autoexport(n *Node, ctxt uint8) {
 	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
 		return
 	}
-	if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method
+	if n.Param != nil && n.Param.Ntype != nil && n.Param.Ntype.Op == OTFUNC && n.Param.Ntype.Left != nil { // method
 		return
 	}
 
diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
similarity index 96%
rename from src/cmd/internal/gc/fmt.go
rename to src/cmd/compile/internal/gc/fmt.go
index 1a991a0a65..4b93363c73 100644
--- a/src/cmd/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -302,12 +302,12 @@ func Vconv(v *Val, flag int) string {
 	switch v.Ctype {
 	case CTINT:
 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
-			return Bconv(v.U.Xval, obj.FmtSharp)
+			return Bconv(v.U.(*Mpint), obj.FmtSharp)
 		}
-		return Bconv(v.U.Xval, 0)
+		return Bconv(v.U.(*Mpint), 0)
 
 	case CTRUNE:
-		x := Mpgetfix(v.U.Xval)
+		x := Mpgetfix(v.U.(*Mpint))
 		if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
 			return fmt.Sprintf("'%c'", int(x))
 		}
@@ -317,34 +317,34 @@ func Vconv(v *Val, flag int) string {
 		if 0 <= x && x <= utf8.MaxRune {
 			return fmt.Sprintf("'\\U%08x'", uint64(x))
 		}
-		return fmt.Sprintf("('\\x00' + %v)", v.U.Xval)
+		return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
 
 	case CTFLT:
 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
-			return Fconv(v.U.Fval, 0)
+			return Fconv(v.U.(*Mpflt), 0)
 		}
-		return Fconv(v.U.Fval, obj.FmtSharp)
+		return Fconv(v.U.(*Mpflt), obj.FmtSharp)
 
 	case CTCPLX:
 		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
-			return fmt.Sprintf("(%v+%vi)", &v.U.Cval.Real, &v.U.Cval.Imag)
+			return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
 		}
-		if mpcmpfltc(&v.U.Cval.Real, 0) == 0 {
-			return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp))
+		if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 {
+			return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
 		}
-		if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 {
-			return Fconv(&v.U.Cval.Real, obj.FmtSharp)
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 {
+			return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp)
 		}
-		if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 {
-			return fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 {
+			return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
 		}
-		return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
+		return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
 
 	case CTSTR:
-		return strconv.Quote(v.U.Sval)
+		return strconv.Quote(v.U.(string))
 
 	case CTBOOL:
-		if v.U.Bval {
+		if v.U.(bool) {
 			return "true"
 		}
 		return "false"
@@ -1127,7 +1127,7 @@ func exprfmt(n *Node, prec int) string {
 		// Special case: name used as local variable in export.
 	// _ becomes ~b%d internally; print as _ for export
 	case ONAME:
-		if fmtmode == FExp && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+		if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
 			return "_"
 		}
 		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Vargen > 0 {
@@ -1199,7 +1199,7 @@ func exprfmt(n *Node, prec int) string {
 		if n.Nbody != nil {
 			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
 		}
-		return fmt.Sprintf("%v { %v }", n.Type, n.Closure.Nbody)
+		return fmt.Sprintf("%v { %v }", n.Type, n.Param.Closure.Nbody)
 
 	case OCOMPLIT:
 		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
@@ -1521,9 +1521,9 @@ func nodedump(n *Node, flag int) string {
 		} else {
 			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
 		}
-		if recur && n.Type == nil && n.Ntype != nil {
+		if recur && n.Type == nil && n.Param.Ntype != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype)
 		}
 
 	case OASOP:
@@ -1531,9 +1531,9 @@ func nodedump(n *Node, flag int) string {
 
 	case OTYPE:
 		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type)
-		if recur && n.Type == nil && n.Ntype != nil {
+		if recur && n.Type == nil && n.Param.Ntype != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype)
 		}
 	}
 
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
similarity index 86%
rename from src/cmd/internal/gc/gen.go
rename to src/cmd/compile/internal/gc/gen.go
index e6af897033..c0dd9964ea 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -57,14 +57,14 @@ func addrescapes(n *Node) {
 
 		// expression to refer to stack copy
 		case PPARAM, PPARAMOUT:
-			n.Stackparam = Nod(OPARAM, n, nil)
+			n.Param.Stackparam = Nod(OPARAM, n, nil)
 
-			n.Stackparam.Type = n.Type
-			n.Stackparam.Addable = true
+			n.Param.Stackparam.Type = n.Type
+			n.Param.Stackparam.Addable = true
 			if n.Xoffset == BADWIDTH {
 				Fatal("addrescapes before param assignment")
 			}
-			n.Stackparam.Xoffset = n.Xoffset
+			n.Param.Stackparam.Xoffset = n.Xoffset
 			fallthrough
 
 		case PAUTO:
@@ -78,10 +78,10 @@ func addrescapes(n *Node) {
 			oldfn := Curfn
 
 			Curfn = n.Curfn
-			n.Heapaddr = temp(Ptrto(n.Type))
+			n.Name.Heapaddr = temp(Ptrto(n.Type))
 			buf := fmt.Sprintf("&%v", n.Sym)
-			n.Heapaddr.Sym = Lookup(buf)
-			n.Heapaddr.Orig.Sym = n.Heapaddr.Sym
+			n.Name.Heapaddr.Sym = Lookup(buf)
+			n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym
 			n.Esc = EscHeap
 			if Debug['m'] != 0 {
 				fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
@@ -262,7 +262,7 @@ func cgen_dcl(n *Node) {
 	if n.Alloc == nil {
 		n.Alloc = callnew(n.Type)
 	}
-	Cgen_as(n.Heapaddr, n.Alloc)
+	Cgen_as(n.Name.Heapaddr, n.Alloc)
 }
 
 /*
@@ -333,21 +333,22 @@ func Clearslim(n *Node) {
 
 	switch Simtype[n.Type.Etype] {
 	case TCOMPLEX64, TCOMPLEX128:
-		z.Val.U.Cval = new(Mpcplx)
-		Mpmovecflt(&z.Val.U.Cval.Real, 0.0)
-		Mpmovecflt(&z.Val.U.Cval.Imag, 0.0)
+		z.Val.U = new(Mpcplx)
+		Mpmovecflt(&z.Val.U.(*Mpcplx).Real, 0.0)
+		Mpmovecflt(&z.Val.U.(*Mpcplx).Imag, 0.0)
 
 	case TFLOAT32, TFLOAT64:
 		var zero Mpflt
 		Mpmovecflt(&zero, 0.0)
 		z.Val.Ctype = CTFLT
-		z.Val.U.Fval = &zero
+		z.Val.U = &zero
 
 	case TPTR32, TPTR64, TCHAN, TMAP:
 		z.Val.Ctype = CTNIL
 
 	case TBOOL:
 		z.Val.Ctype = CTBOOL
+		z.Val.U = false
 
 	case TINT8,
 		TINT16,
@@ -358,8 +359,8 @@ func Clearslim(n *Node) {
 		TUINT32,
 		TUINT64:
 		z.Val.Ctype = CTINT
-		z.Val.U.Xval = new(Mpint)
-		Mpmovecfix(z.Val.U.Xval, 0)
+		z.Val.U = new(Mpint)
+		Mpmovecfix(z.Val.U.(*Mpint), 0)
 
 	default:
 		Fatal("clearslim called on type %v", n.Type)
@@ -428,8 +429,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
 	Cgen(&iface, &r1)
 	if !isnilinter(n.Left.Type) {
 		// Holding itab, want concrete type in second word.
-		Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
-		p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
+		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
 		r2 = r1
 		r2.Op = OINDREG
 		r2.Xoffset = int64(Widthptr)
@@ -438,8 +438,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
 	}
 	Regalloc(&r2, byteptr, nil)
 	Cgen(typename(n.Type), &r2)
-	Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
-	p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
+	p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
 	Regfree(&r2) // not needed for success path; reclaimed on one failure path
 	iface.Xoffset += int64(Widthptr)
 	Cgen(&iface, &r1)
@@ -521,8 +520,7 @@ func Cgen_As2dottype(n, res, resok *Node) {
 	Cgen(&iface, &r1)
 	if !isnilinter(n.Left.Type) {
 		// Holding itab, want concrete type in second word.
-		Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
-		p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
+		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
 		r2 = r1
 		r2.Op = OINDREG
 		r2.Xoffset = int64(Widthptr)
@@ -531,8 +529,7 @@ func Cgen_As2dottype(n, res, resok *Node) {
 	}
 	Regalloc(&r2, byteptr, nil)
 	Cgen(typename(n.Type), &r2)
-	Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
-	p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
+	p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
 	iface.Type = n.Type
 	iface.Xoffset += int64(Widthptr)
 	Cgen(&iface, &r1)
@@ -555,122 +552,6 @@ func Cgen_As2dottype(n, res, resok *Node) {
 	Patch(q, Pc)
 }
 
-/*
- * generate:
- *	res = s[lo, hi];
- * n->left is s
- * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
- * caller (cgen) guarantees res is an addable ONAME.
- *
- * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
- */
-func Cgen_slice(n *Node, res *Node) {
-	cap := n.List.N
-	len := n.List.Next.N
-	var offs *Node
-	if n.List.Next.Next != nil {
-		offs = n.List.Next.Next.N
-	}
-
-	// evaluate base pointer first, because it is the only
-	// possibly complex expression. once that is evaluated
-	// and stored, updating the len and cap can be done
-	// without making any calls, so without doing anything that
-	// might cause preemption or garbage collection.
-	// this makes the whole slice update atomic as far as the
-	// garbage collector can see.
-	base := temp(Types[TUINTPTR])
-
-	tmplen := temp(Types[TINT])
-	var tmpcap *Node
-	if n.Op != OSLICESTR {
-		tmpcap = temp(Types[TINT])
-	} else {
-		tmpcap = tmplen
-	}
-
-	var src Node
-	if isnil(n.Left) {
-		Tempname(&src, n.Left.Type)
-		Cgen(n.Left, &src)
-	} else {
-		src = *n.Left
-	}
-	if n.Op == OSLICE || n.Op == OSLICE3 || n.Op == OSLICESTR {
-		src.Xoffset += int64(Array_array)
-	}
-
-	if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
-		if !Isptr[n.Left.Type.Etype] {
-			Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign))
-		}
-		Cgen(&src, base)
-		Cgen_checknil(base)
-	} else {
-		src.Type = Types[Tptr]
-		Cgen(&src, base)
-	}
-
-	// committed to the update
-	Gvardef(res)
-
-	// compute len and cap.
-	// len = n-i, cap = m-i, and offs = i*width.
-	// computing offs last lets the multiply overwrite i.
-	Cgen((*Node)(len), tmplen)
-
-	if n.Op != OSLICESTR {
-		Cgen(cap, tmpcap)
-	}
-
-	// if new cap != 0 { base += add }
-	// This avoids advancing base past the end of the underlying array/string,
-	// so that it cannot point at the next object in memory.
-	// If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
-	// In essence we are replacing x[i:j:k] where i == j == k
-	// or x[i:j] where i == j == cap(x) with x[0:0:0].
-	if offs != nil {
-		p1 := gjmp(nil)
-		p2 := gjmp(nil)
-		Patch(p1, Pc)
-
-		var con Node
-		Nodconst(&con, tmpcap.Type, 0)
-		cmp := Nod(OEQ, tmpcap, &con)
-		typecheck(&cmp, Erv)
-		Bgen(cmp, true, -1, p2)
-
-		add := Nod(OADD, base, offs)
-		typecheck(&add, Erv)
-		Cgen(add, base)
-
-		Patch(p2, Pc)
-	}
-
-	// dst.array = src.array  [ + lo *width ]
-	dst := *res
-
-	dst.Xoffset += int64(Array_array)
-	dst.Type = Types[Tptr]
-	Cgen(base, &dst)
-
-	// dst.len = hi [ - lo ]
-	dst = *res
-
-	dst.Xoffset += int64(Array_nel)
-	dst.Type = Types[Simtype[TUINT]]
-	Cgen(tmplen, &dst)
-
-	if n.Op != OSLICESTR {
-		// dst.cap = cap [ - lo ]
-		dst = *res
-
-		dst.Xoffset += int64(Array_cap)
-		dst.Type = Types[Simtype[TUINT]]
-		Cgen(tmpcap, &dst)
-	}
-}
-
 /*
  * gather series of offsets
  * >=0 is direct addressed field
@@ -1085,7 +966,7 @@ func cgen_callmeth(n *Node, proc int) {
 	l := n.Left
 
 	if l.Op != ODOTMETH {
-		Fatal("cgen_callmeth: not dotmethod: %v")
+		Fatal("cgen_callmeth: not dotmethod: %v", l)
 	}
 
 	n2 := *n
@@ -1241,7 +1122,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
 		nodl.Type = Ptrto(Types[TUINT8])
 		Regalloc(&nodr, Types[Tptr], nil)
 		p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
-		Datastring(nr.Val.U.Sval, &p.From)
+		Datastring(nr.Val.U.(string), &p.From)
 		p.From.Type = obj.TYPE_ADDR
 		Thearch.Gmove(&nodr, &nodl)
 		Regfree(&nodr)
@@ -1249,7 +1130,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
 		// length
 		nodl.Type = Types[Simtype[TUINT]]
 		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
-		Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
+		Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.(string))))
 		Thearch.Gmove(&nodr, &nodl)
 		return true
 	}
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
similarity index 93%
rename from src/cmd/internal/gc/go.go
rename to src/cmd/compile/internal/gc/go.go
index 71bce0bf2c..dc33f62ba4 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -6,7 +6,7 @@ package gc
 
 import (
 	"bytes"
-	"cmd/internal/gc/big"
+	"cmd/compile/internal/big"
 	"cmd/internal/obj"
 )
 
@@ -83,13 +83,13 @@ type Mpcplx struct {
 
 type Val struct {
 	Ctype int16
-	U     struct {
-		Bval bool    // bool value CTBOOL
-		Xval *Mpint  // int CTINT, rune CTRUNE
-		Fval *Mpflt  // float CTFLT
-		Cval *Mpcplx // float CTCPLX
-		Sval string  // string CTSTR
-	}
+	// U contains one of:
+	// bool     bool when Ctype == CTBOOL
+	// *Mpint   int when Ctype == CTINT, rune when Ctype == CTRUNE
+	// *Mpflt   float when Ctype == CTFLT
+	// *Mpcplx  pair of floats when Ctype == CTCPLX
+	// string   string when Ctype == CTSTR
+	U interface{}
 }
 
 type Pkg struct {
@@ -448,7 +448,7 @@ var nsavederrors int
 
 var nsyntaxerrors int
 
-var decldepth int
+var decldepth int32
 
 var safemode int
 
@@ -778,13 +778,27 @@ type Arch struct {
 	Expandchecks func(*obj.Prog)
 	Getg         func(*Node)
 	Gins         func(int, *Node, *Node) *obj.Prog
+
+	// Ginscmp generates code comparing n1 to n2 and jumping away if op is satisfied.
+	// The returned prog should be Patch'ed with the jump target.
+	// If op is not satisfied, code falls through to the next emitted instruction.
+	// Likely is the branch prediction hint: +1 for likely, -1 for unlikely, 0 for no opinion.
+	//
+	// Ginscmp must be able to handle all kinds of arguments for n1 and n2,
+	// not just simple registers, although it can assume that there are no
+	// function calls needed during the evaluation, and on 32-bit systems
+	// the values are guaranteed not to be 64-bit values, so no in-memory
+	// temporaries are necessary.
+	Ginscmp func(op int, t *Type, n1, n2 *Node, likely int) *obj.Prog
+
 	// Ginsboolval inserts instructions to convert the result
 	// of a just-completed comparison to a boolean value.
 	// The first argument is the conditional jump instruction
 	// corresponding to the desired value.
 	// The second argument is the destination.
 	// If not present, Ginsboolval will be emulated with jumps.
-	Ginsboolval  func(int, *Node)
+	Ginsboolval func(int, *Node)
+
 	Ginscon      func(int, int64, *Node)
 	Ginsnop      func()
 	Gmove        func(*Node, *Node)
diff --git a/src/cmd/internal/gc/go.y b/src/cmd/compile/internal/gc/go.y
similarity index 92%
rename from src/cmd/internal/gc/go.y
rename to src/cmd/compile/internal/gc/go.y
index f1904b0085..ae2e7613ab 100644
--- a/src/cmd/internal/gc/go.y
+++ b/src/cmd/compile/internal/gc/go.y
@@ -21,6 +21,7 @@
 package gc
 
 import (
+	"fmt"
 	"strings"
 )
 %}
@@ -116,7 +117,68 @@ import (
 %left		')'
 %left		PreferToRightParen
 
-// TODO(rsc): Add %error-verbose
+%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',':
+	"unexpected comma during import block"
+
+%error loadsys package LIMPORT LNAME ';':
+	"missing import path; require quoted string"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';':
+	"missing { after if clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';':
+	"missing { after switch clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';':
+	"missing { after for clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY:
+	"missing { after for clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' ';' '{':
+	"unexpected semicolon or newline before {"
+
+%error loadsys package imports LTYPE LNAME ';':
+	"unexpected semicolon or newline in type declaration"
+
+%error loadsys package imports LCHAN '}':
+	"unexpected } in channel type"
+
+%error loadsys package imports LCHAN ')':
+	"unexpected ) in channel type"
+
+%error loadsys package imports LCHAN ',':
+	"unexpected comma in channel type"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE:
+	"unexpected semicolon or newline before else"
+
+%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME:
+	"name list not allowed in interface type"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME:
+	"var declaration not allowed in for initializer"
+
+%error loadsys package imports LVAR LNAME '[' ']' LNAME '{':
+	"unexpected { at end of statement"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{':
+	"unexpected { at end of statement"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';':
+	"argument to go/defer must be function call"
+
+%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';':
+	"need trailing comma before newline in composite literal"
+
+%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';':
+	"need trailing comma before newline in composite literal"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME:
+	"nested func not allowed"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';':
+	"else must be followed by if or statement block"
 
 %%
 file:
@@ -1130,13 +1192,13 @@ hidden_importsym:
 	{
 		var p *Pkg
 
-		if $2.U.Sval == "" {
+		if $2.U.(string) == "" {
 			p = importpkg;
 		} else {
-			if isbadimport($2.U.Sval) {
+			if isbadimport($2.U.(string)) {
 				errorexit();
 			}
-			p = mkpkg($2.U.Sval);
+			p = mkpkg($2.U.(string));
 		}
 		$$ = Pkglookup($4.Name, p);
 	}
@@ -1144,13 +1206,13 @@ hidden_importsym:
 	{
 		var p *Pkg
 
-		if $2.U.Sval == "" {
+		if $2.U.(string) == "" {
 			p = importpkg;
 		} else {
-			if isbadimport($2.U.Sval) {
+			if isbadimport($2.U.(string)) {
 				errorexit();
 			}
-			p = mkpkg($2.U.Sval);
+			p = mkpkg($2.U.(string));
 		}
 		$$ = Pkglookup("?", p);
 	}
@@ -1360,7 +1422,7 @@ fndcl:
 		$$ = Nod(ODCLFUNC, nil, nil);
 		$$.Nname = newfuncname($1);
 		$$.Nname.Defn = $$;
-		$$.Nname.Ntype = t;		// TODO: check if nname already has an ntype
+		$$.Nname.Param.Ntype = t;		// TODO: check if nname already has an ntype
 		declare($$.Nname, PFUNC);
 
 		funchdr($$);
@@ -1395,7 +1457,7 @@ fndcl:
 		$$.Func.Shortname = newfuncname($4);
 		$$.Nname = methodname1($$.Func.Shortname, rcvr.Right);
 		$$.Nname.Defn = $$;
-		$$.Nname.Ntype = t;
+		$$.Nname.Param.Ntype = t;
 		$$.Nname.Nointerface = nointerface;
 		declare($$.Nname, PFUNC);
 
@@ -1944,7 +2006,7 @@ oliteral:
 hidden_import:
 	LIMPORT LNAME LLITERAL ';'
 	{
-		importimport($2, $3.U.Sval);
+		importimport($2, $3.U.(string));
 	}
 |	LVAR hidden_pkg_importsym hidden_type ';'
 	{
@@ -1975,9 +2037,9 @@ hidden_import:
 		importlist = list(importlist, $2);
 
 		if Debug['E'] > 0 {
-			print("import [%q] func %lN \n", importpkg.Path, $2);
+			fmt.Printf("import [%q] func %v \n", importpkg.Path, $2)
 			if Debug['m'] > 2 && $2.Func.Inl != nil {
-				print("inl body:%+H\n", $2.Func.Inl);
+				fmt.Printf("inl body:%v\n", $2.Func.Inl)
 			}
 		}
 	}
@@ -2171,14 +2233,14 @@ hidden_literal:
 		$$ = nodlit($2);
 		switch($$.Val.Ctype){
 		case CTINT, CTRUNE:
-			mpnegfix($$.Val.U.Xval);
+			mpnegfix($$.Val.U.(*Mpint));
 			break;
 		case CTFLT:
-			mpnegflt($$.Val.U.Fval);
+			mpnegflt($$.Val.U.(*Mpflt));
 			break;
 		case CTCPLX:
-			mpnegflt(&$$.Val.U.Cval.Real);
-			mpnegflt(&$$.Val.U.Cval.Imag);
+			mpnegflt(&$$.Val.U.(*Mpcplx).Real);
+			mpnegflt(&$$.Val.U.(*Mpcplx).Imag);
 			break;
 		default:
 			Yyerror("bad negated constant");
@@ -2198,11 +2260,11 @@ hidden_constant:
 	{
 		if $2.Val.Ctype == CTRUNE && $4.Val.Ctype == CTINT {
 			$$ = $2;
-			mpaddfixfix($2.Val.U.Xval, $4.Val.U.Xval, 0);
+			mpaddfixfix($2.Val.U.(*Mpint), $4.Val.U.(*Mpint), 0);
 			break;
 		}
-		$4.Val.U.Cval.Real = $4.Val.U.Cval.Imag;
-		Mpmovecflt(&$4.Val.U.Cval.Imag, 0.0);
+		$4.Val.U.(*Mpcplx).Real = $4.Val.U.(*Mpcplx).Imag;
+		Mpmovecflt(&$4.Val.U.(*Mpcplx).Imag, 0.0);
 		$$ = nodcplxlit($2.Val, $4.Val);
 	}
 
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
similarity index 98%
rename from src/cmd/internal/gc/gsubr.go
rename to src/cmd/compile/internal/gc/gsubr.go
index 53b3f6c41d..5ec4587e74 100644
--- a/src/cmd/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -90,6 +90,10 @@ func Gbranch(as int, t *Type, likely int) *obj.Prog {
 		p.From.Offset = int64(obj.Bool2int(likely > 0))
 	}
 
+	if Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
 	return p
 }
 
@@ -210,7 +214,7 @@ func ggloblnod(nam *Node) {
 	p.To.Sym = nil
 	p.To.Type = obj.TYPE_CONST
 	p.To.Offset = nam.Type.Width
-	if nam.Readonly {
+	if nam.Name.Readonly {
 		p.From3.Offset = obj.RODATA
 	}
 	if nam.Type != nil && !haspointers(nam.Type) {
@@ -365,7 +369,7 @@ func Naddr(a *obj.Addr, n *Node) {
 		if s == nil {
 			s = Lookup(".noname")
 		}
-		if n.Method {
+		if n.Name.Method {
 			if n.Type != nil {
 				if n.Type.Sym != nil {
 					if n.Type.Sym.Pkg != nil {
@@ -408,20 +412,20 @@ func Naddr(a *obj.Addr, n *Node) {
 
 		case CTFLT:
 			a.Type = obj.TYPE_FCONST
-			a.Val = mpgetflt(n.Val.U.Fval)
+			a.Val = mpgetflt(n.Val.U.(*Mpflt))
 
 		case CTINT, CTRUNE:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
-			a.Offset = Mpgetfix(n.Val.U.Xval)
+			a.Offset = Mpgetfix(n.Val.U.(*Mpint))
 
 		case CTSTR:
-			datagostring(n.Val.U.Sval, a)
+			datagostring(n.Val.U.(string), a)
 
 		case CTBOOL:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
-			a.Offset = int64(obj.Bool2int(n.Val.U.Bval))
+			a.Offset = int64(obj.Bool2int(n.Val.U.(bool)))
 
 		case CTNIL:
 			a.Sym = nil
@@ -621,20 +625,20 @@ func gclean() {
 	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
 		n := reg[r-Thearch.REGMIN]
 		if n != 0 {
-			Yyerror("reg %v left allocated", obj.Rconv(r))
 			if Debug['v'] != 0 {
 				Regdump()
 			}
+			Yyerror("reg %v left allocated", obj.Rconv(r))
 		}
 	}
 
 	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
 		n := reg[r-Thearch.REGMIN]
 		if n != 0 {
-			Yyerror("reg %v left allocated", obj.Rconv(r))
 			if Debug['v'] != 0 {
 				Regdump()
 			}
+			Yyerror("reg %v left allocated", obj.Rconv(r))
 		}
 	}
 }
diff --git a/src/cmd/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
similarity index 98%
rename from src/cmd/internal/gc/init.go
rename to src/cmd/compile/internal/gc/init.go
index b5d1e505a5..92bfeecdef 100644
--- a/src/cmd/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -116,7 +116,7 @@ func fninit(n *NodeList) {
 	initsym := Lookup("init")
 	fn.Nname = newname(initsym)
 	fn.Nname.Defn = fn
-	fn.Nname.Ntype = Nod(OTFUNC, nil, nil)
+	fn.Nname.Param.Ntype = Nod(OTFUNC, nil, nil)
 	declare(fn.Nname, PFUNC)
 	funchdr(fn)
 
diff --git a/src/cmd/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
similarity index 98%
rename from src/cmd/internal/gc/inl.go
rename to src/cmd/compile/internal/gc/inl.go
index dd2087dec3..22a5d3d9fe 100644
--- a/src/cmd/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -511,10 +511,10 @@ func mkinlcall(np **Node, fn *Node, isddd bool) {
 
 func tinlvar(t *Type) *Node {
 	if t.Nname != nil && !isblank(t.Nname) {
-		if t.Nname.Inlvar == nil {
+		if t.Nname.Name.Inlvar == nil {
 			Fatal("missing inlvar for %v\n", t.Nname)
 		}
-		return t.Nname.Inlvar
+		return t.Nname.Name.Inlvar
 	}
 
 	typecheck(&nblank, Erv|Easgn)
@@ -577,13 +577,13 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 			continue
 		}
 		if ll.N.Op == ONAME {
-			ll.N.Inlvar = inlvar(ll.N)
+			ll.N.Name.Inlvar = inlvar(ll.N)
 
 			// Typecheck because inlvar is not necessarily a function parameter.
-			typecheck(&ll.N.Inlvar, Erv)
+			typecheck(&ll.N.Name.Inlvar, Erv)
 
 			if ll.N.Class&^PHEAP != PAUTO {
-				ninit = list(ninit, Nod(ODCL, ll.N.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
+				ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
 			}
 		}
 	}
@@ -594,7 +594,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 		if t != nil && t.Nname != nil && !isblank(t.Nname) {
 			m = inlvar(t.Nname)
 			typecheck(&m, Erv)
-			t.Nname.Inlvar = m
+			t.Nname.Name.Inlvar = m
 		} else {
 			// anonymous return values, synthesize names for use in assignment that replaces return
 			m = retvar(t, i)
@@ -611,7 +611,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 		// method call with a receiver.
 		t := getthisx(fn.Type).Type
 
-		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil {
+		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
 			Fatal("missing inlvar for %v\n", t.Nname)
 		}
 		if n.Left.Left == nil {
@@ -680,7 +680,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 		// append receiver inlvar to LHS.
 		t := getthisx(fn.Type).Type
 
-		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil {
+		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
 			Fatal("missing inlvar for %v\n", t.Nname)
 		}
 		if t == nil {
@@ -907,11 +907,11 @@ func inlsubst(n *Node) *Node {
 
 	switch n.Op {
 	case ONAME:
-		if n.Inlvar != nil { // These will be set during inlnode
+		if n.Name.Inlvar != nil { // These will be set during inlnode
 			if Debug['m'] > 2 {
-				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, obj.FmtSign), Nconv(n.Inlvar, obj.FmtSign))
+				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign))
 			}
-			return n.Inlvar
+			return n.Name.Inlvar
 		}
 
 		if Debug['m'] > 2 {
diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
similarity index 95%
rename from src/cmd/internal/gc/lex.go
rename to src/cmd/compile/internal/gc/lex.go
index 4bbda957a5..cf41c40964 100644
--- a/src/cmd/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:generate go tool yacc go.y
-//go:generate go run yaccerrors.go
 //go:generate go run mkbuiltin.go runtime unsafe
 
 package gc
@@ -35,7 +34,11 @@ var goarch string
 
 var goroot string
 
-var Debug_wb int
+var (
+	Debug_wb     int
+	Debug_append int
+	Debug_slice  int
+)
 
 // Debug arguments.
 // These can be specified with the -d flag, as in "-d nil"
@@ -45,9 +48,12 @@ var debugtab = []struct {
 	name string
 	val  *int
 }{
-	{"nil", &Debug_checknil},          // print information about nil checks
-	{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
+	{"append", &Debug_append},         // print information about append compilation
 	{"disablenil", &Disable_checknil}, // disable nil checks
+	{"gcprog", &Debug_gcprog},         // print dump of GC programs
+	{"nil", &Debug_checknil},          // print information about nil checks
+	{"slice", &Debug_slice},           // print information about slice compilation
+	{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
 	{"wb", &Debug_wb},                 // print information about write barriers
 }
 
@@ -308,7 +314,7 @@ func Main() {
 	lexlineno = 1
 
 	for _, infile = range flag.Args() {
-		linehist(infile, 0, 0)
+		linehistpush(infile)
 
 		curio.infile = infile
 		var err error
@@ -339,7 +345,7 @@ func Main() {
 			errorexit()
 		}
 
-		linehist("", 0, 0)
+		linehistpop()
 		if curio.bin != nil {
 			obj.Bterm(curio.bin)
 		}
@@ -394,7 +400,7 @@ func Main() {
 	// This needs to run before escape analysis,
 	// because variables captured by value do not escape.
 	for l := xtop; l != nil; l = l.Next {
-		if l.N.Op == ODCLFUNC && l.N.Closure != nil {
+		if l.N.Op == ODCLFUNC && l.N.Param.Closure != nil {
 			Curfn = l.N
 			capturevars(l.N)
 		}
@@ -440,17 +446,15 @@ func Main() {
 	// which stores the addresses of stack variables into the closure.
 	// If the closure does not escape, it needs to be on the stack
 	// or else the stack copier will not update it.
+	// Large values are also moved off stack in escape analysis;
+	// because large values may contain pointers, it must happen early.
 	escapes(xtop)
 
-	// Escape analysis moved escaped values off stack.
-	// Move large values off stack too.
-	movelarge(xtop)
-
 	// Phase 7: Transform closure bodies to properly reference captured variables.
 	// This needs to happen before walk, because closures must be transformed
 	// before walk reaches a call of a closure.
 	for l := xtop; l != nil; l = l.Next {
-		if l.N.Op == ODCLFUNC && l.N.Closure != nil {
+		if l.N.Op == ODCLFUNC && l.N.Param.Closure != nil {
 			Curfn = l.N
 			transformclosure(l.N)
 		}
@@ -577,7 +581,7 @@ func findpkg(name string) (file string, ok bool) {
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
-		file = fmt.Sprintf("%s.%c", name, Thearch.Thechar)
+		file = fmt.Sprintf("%s.o", name)
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
@@ -599,7 +603,7 @@ func findpkg(name string) (file string, ok bool) {
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
-		file = fmt.Sprintf("%s/%s.%c", p.dir, name, Thearch.Thechar)
+		file = fmt.Sprintf("%s/%s.o", p.dir, name)
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
@@ -620,7 +624,7 @@ func findpkg(name string) (file string, ok bool) {
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
-		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.%c", goroot, goos, goarch, suffixsep, suffix, name, Thearch.Thechar)
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
 		if obj.Access(file, 0) >= 0 {
 			return file, true
 		}
@@ -631,7 +635,7 @@ func findpkg(name string) (file string, ok bool) {
 
 func fakeimport() {
 	importpkg = mkpkg("fake")
-	cannedimports("fake.6", "$$\n")
+	cannedimports("fake.o", "$$\n")
 }
 
 func importfile(f *Val, line int) {
@@ -641,13 +645,13 @@ func importfile(f *Val, line int) {
 		return
 	}
 
-	if len(f.U.Sval) == 0 {
+	if len(f.U.(string)) == 0 {
 		Yyerror("import path is empty")
 		fakeimport()
 		return
 	}
 
-	if isbadimport(f.U.Sval) {
+	if isbadimport(f.U.(string)) {
 		fakeimport()
 		return
 	}
@@ -656,29 +660,29 @@ func importfile(f *Val, line int) {
 	// but we reserve the import path "main" to identify
 	// the main package, just as we reserve the import
 	// path "math" to identify the standard math package.
-	if f.U.Sval == "main" {
+	if f.U.(string) == "main" {
 		Yyerror("cannot import \"main\"")
 		errorexit()
 	}
 
-	if myimportpath != "" && f.U.Sval == myimportpath {
-		Yyerror("import %q while compiling that package (import cycle)", f.U.Sval)
+	if myimportpath != "" && f.U.(string) == myimportpath {
+		Yyerror("import %q while compiling that package (import cycle)", f.U.(string))
 		errorexit()
 	}
 
-	if f.U.Sval == "unsafe" {
+	if f.U.(string) == "unsafe" {
 		if safemode != 0 {
 			Yyerror("cannot import package unsafe")
 			errorexit()
 		}
 
-		importpkg = mkpkg(f.U.Sval)
-		cannedimports("unsafe.6", unsafeimport)
+		importpkg = mkpkg(f.U.(string))
+		cannedimports("unsafe.o", unsafeimport)
 		imported_unsafe = 1
 		return
 	}
 
-	path_ := f.U.Sval
+	path_ := f.U.(string)
 	if islocalname(path_) {
 		if path_[0] == '/' {
 			Yyerror("import path cannot be absolute path")
@@ -704,7 +708,7 @@ func importfile(f *Val, line int) {
 
 	file, found := findpkg(path_)
 	if !found {
-		Yyerror("can't find import: %q", f.U.Sval)
+		Yyerror("can't find import: %q", f.U.(string))
 		errorexit()
 	}
 
@@ -729,7 +733,7 @@ func importfile(f *Val, line int) {
 	var imp *obj.Biobuf
 	imp, err = obj.Bopenr(file)
 	if err != nil {
-		Yyerror("can't open import: %q: %v", f.U.Sval, err)
+		Yyerror("can't open import: %q: %v", f.U.(string), err)
 		errorexit()
 	}
 
@@ -758,7 +762,7 @@ func importfile(f *Val, line int) {
 
 	// assume files move (get installed)
 	// so don't record the full path.
-	linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib
+	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
 
 	/*
 	 * position the input right
@@ -792,7 +796,7 @@ func importfile(f *Val, line int) {
 		return
 	}
 
-	Yyerror("no import in %q", f.U.Sval)
+	Yyerror("no import in %q", f.U.(string))
 	unimportfile()
 }
 
@@ -1060,8 +1064,8 @@ l0:
 			ungetc(int(v))
 		}
 
-		yylval.val.U.Xval = new(Mpint)
-		Mpmovecfix(yylval.val.U.Xval, v)
+		yylval.val.U = new(Mpint)
+		Mpmovecfix(yylval.val.U.(*Mpint), v)
 		yylval.val.Ctype = CTRUNE
 		if Debug['x'] != 0 {
 			fmt.Printf("lex: codepoint literal\n")
@@ -1399,11 +1403,11 @@ ncu:
 	ungetc(c)
 
 	str = lexbuf.String()
-	yylval.val.U.Xval = new(Mpint)
-	mpatofix(yylval.val.U.Xval, str)
-	if yylval.val.U.Xval.Ovf {
+	yylval.val.U = new(Mpint)
+	mpatofix(yylval.val.U.(*Mpint), str)
+	if yylval.val.U.(*Mpint).Ovf {
 		Yyerror("overflow in constant")
-		Mpmovecfix(yylval.val.U.Xval, 0)
+		Mpmovecfix(yylval.val.U.(*Mpint), 0)
 	}
 
 	yylval.val.Ctype = CTINT
@@ -1430,6 +1434,11 @@ casedot:
 	}
 
 caseep:
+	if importpkg == nil && (c == 'p' || c == 'P') {
+		// p is allowed in .a/.o imports,
+		// but not in .go sources.  See #9036.
+		Yyerror("malformed floating point constant")
+	}
 	cp.WriteByte(byte(c))
 	c = getc()
 	if c == '+' || c == '-' {
@@ -1438,7 +1447,7 @@ caseep:
 	}
 
 	if !yy_isdigit(c) {
-		Yyerror("malformed fp constant exponent")
+		Yyerror("malformed floating point constant exponent")
 	}
 	for yy_isdigit(c) {
 		cp.WriteByte(byte(c))
@@ -1455,12 +1464,12 @@ casei:
 	cp = nil
 
 	str = lexbuf.String()
-	yylval.val.U.Cval = new(Mpcplx)
-	Mpmovecflt(&yylval.val.U.Cval.Real, 0.0)
-	mpatoflt(&yylval.val.U.Cval.Imag, str)
-	if yylval.val.U.Cval.Imag.Val.IsInf() {
+	yylval.val.U = new(Mpcplx)
+	Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0)
+	mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str)
+	if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() {
 		Yyerror("overflow in imaginary constant")
-		Mpmovecflt(&yylval.val.U.Cval.Real, 0.0)
+		Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0)
 	}
 
 	yylval.val.Ctype = CTCPLX
@@ -1475,11 +1484,11 @@ caseout:
 	ungetc(c)
 
 	str = lexbuf.String()
-	yylval.val.U.Fval = newMpflt()
-	mpatoflt(yylval.val.U.Fval, str)
-	if yylval.val.U.Fval.Val.IsInf() {
+	yylval.val.U = newMpflt()
+	mpatoflt(yylval.val.U.(*Mpflt), str)
+	if yylval.val.U.(*Mpflt).Val.IsInf() {
 		Yyerror("overflow in float constant")
-		Mpmovecflt(yylval.val.U.Fval, 0.0)
+		Mpmovecflt(yylval.val.U.(*Mpflt), 0.0)
 	}
 
 	yylval.val.Ctype = CTFLT
@@ -1490,7 +1499,7 @@ caseout:
 	return LLITERAL
 
 strlit:
-	yylval.val.U.Sval = internString(cp.Bytes())
+	yylval.val.U = internString(cp.Bytes())
 	yylval.val.Ctype = CTSTR
 	if Debug['x'] != 0 {
 		fmt.Printf("lex: string literal\n")
@@ -1649,7 +1658,7 @@ func getlinepragma() int {
 	}
 
 	name = text[:linep-1]
-	linehist(name, int32(n), 0)
+	linehistupdate(name, n)
 	return c
 
 out:
@@ -2590,6 +2599,6 @@ func mkpackage(pkgname string) {
 		if i := strings.LastIndex(p, "."); i >= 0 {
 			p = p[:i]
 		}
-		outfile = fmt.Sprintf("%s.%c", p, Thearch.Thechar)
+		outfile = fmt.Sprintf("%s.o", p)
 	}
 }
diff --git a/src/cmd/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
similarity index 83%
rename from src/cmd/internal/gc/mkbuiltin.go
rename to src/cmd/compile/internal/gc/mkbuiltin.go
index b2362a6f01..f4569b48c2 100644
--- a/src/cmd/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -13,21 +13,14 @@ package main
 import (
 	"bufio"
 	"fmt"
-	"go/build"
 	"io"
 	"log"
 	"os"
 	"os/exec"
-	"runtime"
 	"strings"
 )
 
 func main() {
-	gochar, err := build.ArchChar(runtime.GOARCH)
-	if err != nil {
-		log.Fatal(err)
-	}
-
 	f, err := os.Create("builtin.go")
 	if err != nil {
 		log.Fatal(err)
@@ -40,7 +33,7 @@ func main() {
 	fmt.Fprintln(w, "package gc")
 
 	for _, name := range os.Args[1:] {
-		mkbuiltin(w, gochar, name)
+		mkbuiltin(w, name)
 	}
 
 	if err := w.Flush(); err != nil {
@@ -49,11 +42,11 @@ func main() {
 }
 
 // Compile .go file, import data from .6 file, and write Go string version.
-func mkbuiltin(w io.Writer, gochar string, name string) {
-	if err := exec.Command("go", "tool", gochar+"g", "-A", "builtin/"+name+".go").Run(); err != nil {
+func mkbuiltin(w io.Writer, name string) {
+	if err := exec.Command("go", "tool", "compile", "-A", "builtin/"+name+".go").Run(); err != nil {
 		log.Fatal(err)
 	}
-	obj := fmt.Sprintf("%s.%s", name, gochar)
+	obj := "name.o"
 	defer os.Remove(obj)
 
 	r, err := os.Open(obj)
@@ -77,7 +70,7 @@ Begin:
 	fmt.Fprintf(w, "\nconst %simport = \"\" +\n", name)
 
 	// sys.go claims to be in package PACKAGE to avoid
-	// conflicts during "6g sys.go".  Rename PACKAGE to $2.
+	// conflicts during "go tool compile sys.go".  Rename PACKAGE to $2.
 	replacer := strings.NewReplacer("PACKAGE", name)
 
 	// Process imports, stopping at $$ that closes them.
diff --git a/src/cmd/internal/gc/mparith2.go b/src/cmd/compile/internal/gc/mparith2.go
similarity index 98%
rename from src/cmd/internal/gc/mparith2.go
rename to src/cmd/compile/internal/gc/mparith2.go
index de96e97809..2c7e5176ac 100644
--- a/src/cmd/internal/gc/mparith2.go
+++ b/src/cmd/compile/internal/gc/mparith2.go
@@ -5,7 +5,7 @@
 package gc
 
 import (
-	"cmd/internal/gc/big"
+	"cmd/compile/internal/big"
 	"cmd/internal/obj"
 	"fmt"
 )
@@ -13,7 +13,7 @@ import (
 /// implements fix arithmetic
 
 func mpsetovf(a *Mpint) {
-	a.Val.SetUint64(0)
+	a.Val.SetUint64(1) // avoid spurious div-zero errors
 	a.Ovf = true
 }
 
diff --git a/src/cmd/internal/gc/mparith3.go b/src/cmd/compile/internal/gc/mparith3.go
similarity index 84%
rename from src/cmd/internal/gc/mparith3.go
rename to src/cmd/compile/internal/gc/mparith3.go
index 2700b64a89..0e0b626475 100644
--- a/src/cmd/internal/gc/mparith3.go
+++ b/src/cmd/compile/internal/gc/mparith3.go
@@ -5,7 +5,7 @@
 package gc
 
 import (
-	"cmd/internal/gc/big"
+	"cmd/compile/internal/big"
 	"cmd/internal/obj"
 	"fmt"
 	"math"
@@ -105,24 +105,8 @@ func mpcmpfltc(b *Mpflt, c float64) int {
 	return mpcmpfltflt(b, &a)
 }
 
-func mpgetfltN(a *Mpflt, prec int, bias int) float64 {
-	var x float64
-	switch prec {
-	case 53:
-		x, _ = a.Val.Float64()
-	case 24:
-		// We should be using a.Val.Float32() here but that seems incorrect
-		// for certain denormal values (all.bash fails). The current code
-		// appears to work for all existing test cases, though there ought
-		// to be issues with denormal numbers that are incorrectly rounded.
-		// TODO(gri) replace with a.Val.Float32() once correctly working
-		// See also: https://github.com/golang/go/issues/10321
-		var t Mpflt
-		t.Val.SetPrec(24).Set(&a.Val)
-		x, _ = t.Val.Float64()
-	default:
-		panic("unreachable")
-	}
+func mpgetflt(a *Mpflt) float64 {
+	x, _ := a.Val.Float64()
 
 	// check for overflow
 	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
@@ -132,12 +116,16 @@ func mpgetfltN(a *Mpflt, prec int, bias int) float64 {
 	return x
 }
 
-func mpgetflt(a *Mpflt) float64 {
-	return mpgetfltN(a, 53, -1023)
-}
-
 func mpgetflt32(a *Mpflt) float64 {
-	return mpgetfltN(a, 24, -127)
+	x32, _ := a.Val.Float32()
+	x := float64(x32)
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+		Yyerror("mpgetflt32 ovf")
+	}
+
+	return x
 }
 
 func Mpmovecflt(a *Mpflt, c float64) {
diff --git a/src/cmd/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
similarity index 98%
rename from src/cmd/internal/gc/obj.go
rename to src/cmd/compile/internal/gc/obj.go
index 05c5b1a811..9bb334ca34 100644
--- a/src/cmd/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -102,8 +102,7 @@ func dumpobj() {
 			obj.Bputc(bout, 0)
 		}
 		obj.Bseek(bout, startobj-ArhdrSize, 0)
-		name := fmt.Sprintf("_go_.%c", Thearch.Thechar)
-		formathdr(arhdr[:], name, size)
+		formathdr(arhdr[:], "_go_.o", size)
 		bout.Write(arhdr[:])
 	}
 
@@ -382,11 +381,11 @@ func gdata(nam *Node, nr *Node, wid int) {
 	if nr.Op == OLITERAL {
 		switch nr.Val.Ctype {
 		case CTCPLX:
-			gdatacomplex(nam, nr.Val.U.Cval)
+			gdatacomplex(nam, nr.Val.U.(*Mpcplx))
 			return
 
 		case CTSTR:
-			gdatastring(nam, nr.Val.U.Sval)
+			gdatastring(nam, nr.Val.U.(string))
 			return
 		}
 	}
diff --git a/src/cmd/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
similarity index 100%
rename from src/cmd/internal/gc/opnames.go
rename to src/cmd/compile/internal/gc/opnames.go
diff --git a/src/cmd/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
similarity index 89%
rename from src/cmd/internal/gc/order.go
rename to src/cmd/compile/internal/gc/order.go
index f08f5f20fe..ee0ec52e7b 100644
--- a/src/cmd/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -104,9 +104,23 @@ func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node {
 // If not, ordercheapexpr allocates a new tmp, emits tmp = n,
 // and then returns tmp.
 func ordercheapexpr(n *Node, order *Order) *Node {
+	if n == nil {
+		return nil
+	}
 	switch n.Op {
 	case ONAME, OLITERAL:
 		return n
+	case OLEN, OCAP:
+		l := ordercheapexpr(n.Left, order)
+		if l == n.Left {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Orig = a
+		a.Left = l
+		typecheck(&a, Erv)
+		return a
 	}
 
 	return ordercopyexpr(n, n.Type, order, 0)
@@ -124,7 +138,7 @@ func ordersafeexpr(n *Node, order *Order) *Node {
 	case ONAME, OLITERAL:
 		return n
 
-	case ODOT:
+	case ODOT, OLEN, OCAP:
 		l := ordersafeexpr(n.Left, order)
 		if l == n.Left {
 			return n
@@ -264,7 +278,7 @@ func orderblock(l **NodeList) {
 func orderexprinplace(np **Node, outer *Order) {
 	n := *np
 	var order Order
-	orderexpr(&n, &order)
+	orderexpr(&n, &order, nil)
 	addinit(&n, order.out)
 
 	// insert new temporaries from order
@@ -358,8 +372,8 @@ func ordercallargs(l **NodeList, order *Order) {
 // Ordercall orders the call expression n.
 // n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
 func ordercall(n *Node, order *Order) {
-	orderexpr(&n.Left, order)
-	orderexpr(&n.Right, order) // ODDDARG temp
+	orderexpr(&n.Left, order, nil)
+	orderexpr(&n.Right, order, nil) // ODDDARG temp
 	ordercallargs(&n.List, order)
 }
 
@@ -447,8 +461,14 @@ func orderstmt(n *Node, order *Order) {
 	case OVARKILL:
 		order.out = list(order.out, n)
 
-	case OAS,
-		OAS2,
+	case OAS:
+		t := marktemp(order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, n.Left)
+		ordermapassign(n, order)
+		cleantemp(t, order)
+
+	case OAS2,
 		OCLOSE,
 		OCOPY,
 		OPRINT,
@@ -456,38 +476,36 @@ func orderstmt(n *Node, order *Order) {
 		ORECOVER,
 		ORECV:
 		t := marktemp(order)
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 		switch n.Op {
-		case OAS, OAS2, OAS2DOTTYPE:
+		case OAS2, OAS2DOTTYPE:
 			ordermapassign(n, order)
-
 		default:
 			order.out = list(order.out, n)
 		}
-
 		cleantemp(t, order)
 
-		// Special: rewrite l op= r into l = l op r.
-	// This simplies quite a few operations;
-	// most important is that it lets us separate
-	// out map read from map write when l is
-	// a map index expression.
 	case OASOP:
+		// Special: rewrite l op= r into l = l op r.
+		// This simplies quite a few operations;
+		// most important is that it lets us separate
+		// out map read from map write when l is
+		// a map index expression.
 		t := marktemp(order)
 
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 		n.Left = ordersafeexpr(n.Left, order)
-		tmp1 := treecopy(n.Left)
+		tmp1 := treecopy(n.Left, 0)
 		if tmp1.Op == OINDEXMAP {
 			tmp1.Etype = 0 // now an rvalue not an lvalue
 		}
 		tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
 		n.Right = Nod(int(n.Etype), tmp1, n.Right)
 		typecheck(&n.Right, Erv)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Right, order, nil)
 		n.Etype = 0
 		n.Op = OAS
 		ordermapassign(n, order)
@@ -500,8 +518,8 @@ func orderstmt(n *Node, order *Order) {
 
 		orderexprlist(n.List, order)
 		r := n.Rlist.N
-		orderexpr(&r.Left, order)
-		orderexpr(&r.Right, order)
+		orderexpr(&r.Left, order, nil)
+		orderexpr(&r.Right, order, nil)
 
 		// See case OINDEXMAP below.
 		if r.Right.Op == OARRAYBYTESTR {
@@ -527,7 +545,7 @@ func orderstmt(n *Node, order *Order) {
 		t := marktemp(order)
 
 		orderexprlist(n.List, order)
-		orderexpr(&n.Rlist.N.Left, order) // i in i.(T)
+		orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T)
 		if isblank(n.List.N) {
 			order.out = list(order.out, n)
 		} else {
@@ -548,7 +566,7 @@ func orderstmt(n *Node, order *Order) {
 		t := marktemp(order)
 
 		orderexprlist(n.List, order)
-		orderexpr(&n.Rlist.N.Left, order) // arg to recv
+		orderexpr(&n.Rlist.N.Left, order, nil) // arg to recv
 		ch := n.Rlist.N.Left.Type
 		tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type))
 		var tmp2 *Node
@@ -617,8 +635,8 @@ func orderstmt(n *Node, order *Order) {
 
 	case ODELETE:
 		t := marktemp(order)
-		orderexpr(&n.List.N, order)
-		orderexpr(&n.List.Next.N, order)
+		orderexpr(&n.List.N, order, nil)
+		orderexpr(&n.List.Next.N, order, nil)
 		orderaddrtemp(&n.List.Next.N, order) // map key
 		order.out = list(order.out, n)
 		cleantemp(t, order)
@@ -659,7 +677,7 @@ func orderstmt(n *Node, order *Order) {
 	case OPANIC:
 		t := marktemp(order)
 
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 		if !Isinter(n.Left.Type) {
 			orderaddrtemp(&n.Left, order)
 		}
@@ -677,7 +695,7 @@ func orderstmt(n *Node, order *Order) {
 	case ORANGE:
 		t := marktemp(order)
 
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Right, order, nil)
 		switch n.Type.Etype {
 		default:
 			Fatal("orderstmt range %v", n.Type)
@@ -793,7 +811,7 @@ func orderstmt(n *Node, order *Order) {
 					// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
 					// r->left == N means 'case <-c'.
 					// c is always evaluated; x and ok are only evaluated when assigned.
-					orderexpr(&r.Right.Left, order)
+					orderexpr(&r.Right.Left, order, nil)
 
 					if r.Right.Left.Op != ONAME {
 						r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0)
@@ -853,12 +871,12 @@ func orderstmt(n *Node, order *Order) {
 
 					// case c <- x
 					// r->left is c, r->right is x, both are always evaluated.
-					orderexpr(&r.Left, order)
+					orderexpr(&r.Left, order, nil)
 
 					if !istemp(r.Left) {
 						r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
 					}
-					orderexpr(&r.Right, order)
+					orderexpr(&r.Right, order, nil)
 					if !istemp(r.Right) {
 						r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
 					}
@@ -884,8 +902,8 @@ func orderstmt(n *Node, order *Order) {
 	case OSEND:
 		t := marktemp(order)
 
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 		orderaddrtemp(&n.Right, order)
 		order.out = list(order.out, n)
 		cleantemp(t, order)
@@ -900,7 +918,7 @@ func orderstmt(n *Node, order *Order) {
 	case OSWITCH:
 		t := marktemp(order)
 
-		orderexpr(&n.Ntest, order)
+		orderexpr(&n.Ntest, order, nil)
 		for l := n.List; l != nil; l = l.Next {
 			if l.N.Op != OXCASE {
 				Fatal("order switch case %v", Oconv(int(l.N.Op), 0))
@@ -919,7 +937,7 @@ func orderstmt(n *Node, order *Order) {
 // Orderexprlist orders the expression list l into order.
 func orderexprlist(l *NodeList, order *Order) {
 	for ; l != nil; l = l.Next {
-		orderexpr(&l.N, order)
+		orderexpr(&l.N, order, nil)
 	}
 }
 
@@ -933,7 +951,10 @@ func orderexprlistinplace(l *NodeList, order *Order) {
 
 // Orderexpr orders a single expression, appending side
 // effects to order->out as needed.
-func orderexpr(np **Node, order *Order) {
+// If this is part of an assignment lhs = *np, lhs is given.
+// Otherwise lhs == nil. (When lhs != nil it may be possible
+// to avoid copying the result of the expression to a temporary.)
+func orderexpr(np **Node, order *Order, lhs *Node) {
 	n := *np
 	if n == nil {
 		return
@@ -944,8 +965,8 @@ func orderexpr(np **Node, order *Order) {
 
 	switch n.Op {
 	default:
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 
@@ -974,7 +995,7 @@ func orderexpr(np **Node, order *Order) {
 		haslit := false
 		for l := n.List; l != nil; l = l.Next {
 			hasbyte = hasbyte || l.N.Op == OARRAYBYTESTR
-			haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.Sval) != 0
+			haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.(string)) != 0
 		}
 
 		if haslit && hasbyte {
@@ -986,8 +1007,8 @@ func orderexpr(np **Node, order *Order) {
 		}
 
 	case OCMPSTR:
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 
 		// Mark string(byteSlice) arguments to reuse byteSlice backing
 		// buffer during conversion. String comparison does not
@@ -1001,9 +1022,9 @@ func orderexpr(np **Node, order *Order) {
 
 		// key must be addressable
 	case OINDEXMAP:
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Right, order, nil)
 
 		// For x = m[string(k)] where k is []byte, the allocation of
 		// backing bytes for the string can be avoided by reusing
@@ -1029,7 +1050,7 @@ func orderexpr(np **Node, order *Order) {
 		// concrete type (not interface) argument must be addressable
 	// temporary to pass to runtime.
 	case OCONVIFACE:
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 
 		if !Isinter(n.Left.Type) {
 			orderaddrtemp(&n.Left, order)
@@ -1037,7 +1058,7 @@ func orderexpr(np **Node, order *Order) {
 
 	case OANDAND, OOROR:
 		mark := marktemp(order)
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 
 		// Clean temporaries from first branch at beginning of second.
 		// Leave them on the stack so that they can be killed in the outer
@@ -1048,8 +1069,7 @@ func orderexpr(np **Node, order *Order) {
 		n.Right.Ninit = concat(l, n.Right.Ninit)
 		orderexprinplace(&n.Right, order)
 
-	case OAPPEND,
-		OCALLFUNC,
+	case OCALLFUNC,
 		OCALLINTER,
 		OCALLMETH,
 		OCAP,
@@ -1064,7 +1084,37 @@ func orderexpr(np **Node, order *Order) {
 		OREAL,
 		ORECOVER:
 		ordercall(n, order)
-		n = ordercopyexpr(n, n.Type, order, 0)
+		if lhs == nil || lhs.Op != ONAME || flag_race != 0 {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OAPPEND:
+		ordercallargs(&n.List, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OSLICE, OSLICEARR, OSLICESTR:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right.Left, order, nil)
+		n.Right.Left = ordercheapexpr(n.Right.Left, order)
+		orderexpr(&n.Right.Right, order, nil)
+		n.Right.Right = ordercheapexpr(n.Right.Right, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OSLICE3, OSLICE3ARR:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right.Left, order, nil)
+		n.Right.Left = ordercheapexpr(n.Right.Left, order)
+		orderexpr(&n.Right.Right.Left, order, nil)
+		n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order)
+		orderexpr(&n.Right.Right.Right, order, nil)
+		n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
 
 	case OCLOSURE:
 		if n.Noescape && n.Func.Cvars != nil {
@@ -1072,8 +1122,8 @@ func orderexpr(np **Node, order *Order) {
 		}
 
 	case OARRAYLIT, OCALLPART:
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 		if n.Noescape {
@@ -1090,7 +1140,7 @@ func orderexpr(np **Node, order *Order) {
 		}
 
 	case ODOTTYPE, ODOTTYPE2:
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 		// TODO(rsc): The Isfat is for consistency with componentgen and walkexpr.
 		// It needs to be removed in all three places.
 		// That would allow inlining x.(struct{*int}) the same as x.(*int).
@@ -1099,18 +1149,17 @@ func orderexpr(np **Node, order *Order) {
 		}
 
 	case ORECV:
-		orderexpr(&n.Left, order)
+		orderexpr(&n.Left, order, nil)
 		n = ordercopyexpr(n, n.Type, order, 1)
 
 	case OEQ, ONE:
-		orderexpr(&n.Left, order)
-		orderexpr(&n.Right, order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
 		t := n.Left.Type
 		if t.Etype == TSTRUCT || Isfixedarray(t) {
 			// for complex comparisons, we need both args to be
 			// addressable so we can pass them to the runtime.
 			orderaddrtemp(&n.Left, order)
-
 			orderaddrtemp(&n.Right, order)
 		}
 	}
diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
similarity index 96%
rename from src/cmd/internal/gc/pgen.go
rename to src/cmd/compile/internal/gc/pgen.go
index 2c225c8778..c170060896 100644
--- a/src/cmd/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -5,8 +5,8 @@
 package gc
 
 import (
+	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
-	"cmd/internal/ssa"
 	"crypto/md5"
 	"fmt"
 	"strings"
@@ -201,8 +201,8 @@ func cmpstackvar(a *Node, b *Node) int {
 		return bp - ap
 	}
 
-	ap = obj.Bool2int(a.Needzero)
-	bp = obj.Bool2int(b.Needzero)
+	ap = obj.Bool2int(a.Name.Needzero)
+	bp = obj.Bool2int(b.Name.Needzero)
 	if ap != bp {
 		return bp - ap
 	}
@@ -302,25 +302,6 @@ func allocauto(ptxt *obj.Prog) {
 	}
 }
 
-func movelarge(l *NodeList) {
-	for ; l != nil; l = l.Next {
-		if l.N.Op == ODCLFUNC {
-			movelargefn(l.N)
-		}
-	}
-}
-
-func movelargefn(fn *Node) {
-	var n *Node
-
-	for l := fn.Func.Dcl; l != nil; l = l.Next {
-		n = l.N
-		if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize {
-			addrescapes(n)
-		}
-	}
-}
-
 func Cgen_checknil(n *Node) {
 	if Disable_checknil != 0 {
 		return
diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
similarity index 99%
rename from src/cmd/internal/gc/plive.go
rename to src/cmd/compile/internal/gc/plive.go
index 040a77814e..b4d0699d1f 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -944,7 +944,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
 		*xoffset += t.Width
 
 	case TARRAY:
-		// The value of t->bound is -1 for slices types and >0 for
+		// The value of t->bound is -1 for slices types and >=0 for
 		// for fixed array types.  All other values are invalid.
 		if t.Bound < -1 {
 			Fatal("onebitwalktype1: invalid bound, %v", t)
@@ -1281,8 +1281,8 @@ func livenessepilogue(lv *Liveness) {
 						}
 						bvset(all, pos) // silence future warnings in this block
 						n = lv.vars[pos]
-						if !n.Needzero {
-							n.Needzero = true
+						if !n.Name.Needzero {
+							n.Name.Needzero = true
 							if debuglive >= 1 {
 								Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Nname, Nconv(n, obj.FmtLong))
 							}
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
similarity index 100%
rename from src/cmd/internal/gc/popt.go
rename to src/cmd/compile/internal/gc/popt.go
diff --git a/src/cmd/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
similarity index 94%
rename from src/cmd/internal/gc/racewalk.go
rename to src/cmd/compile/internal/gc/racewalk.go
index e7f35006dc..05a902e8c1 100644
--- a/src/cmd/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -186,31 +186,6 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) {
 	// as we do not instrument runtime code.
 	// typedslicecopy is instrumented in runtime.
 	case OCALLFUNC:
-		if n.Left.Sym != nil && n.Left.Sym.Pkg == Runtimepkg && (strings.HasPrefix(n.Left.Sym.Name, "writebarrier") || n.Left.Sym.Name == "typedmemmove") {
-			// Find the dst argument.
-			// The list can be reordered, so it's not necessary just the first or the second element.
-			var l *NodeList
-			for l = n.List; l != nil; l = l.Next {
-				if n.Left.Sym.Name == "typedmemmove" {
-					if l.N.Left.Xoffset == int64(Widthptr) {
-						break
-					}
-				} else {
-					if l.N.Left.Xoffset == 0 {
-						break
-					}
-				}
-			}
-
-			if l == nil {
-				Fatal("racewalk: writebarrier no arg")
-			}
-			if l.N.Right.Op != OADDR {
-				Fatal("racewalk: writebarrier bad arg")
-			}
-			callinstr(&l.N.Right.Left, init, 1, 0)
-		}
-
 		racewalknode(&n.Left, init, 0, 0)
 		goto ret
 
@@ -324,9 +299,8 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) {
 		}
 		goto ret
 
-		// Seems to only lead to double instrumentation.
-	//racewalknode(&n->left, init, 0, 0);
 	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
+		racewalknode(&n.Left, init, 0, 0)
 		goto ret
 
 	case OADDR:
@@ -509,7 +483,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 			*np = n
 		}
 
-		n = treecopy(n)
+		n = treecopy(n, 0)
 		makeaddable(n)
 		var f *Node
 		if t.Etype == TSTRUCT || Isfixedarray(t) {
diff --git a/src/cmd/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
similarity index 100%
rename from src/cmd/internal/gc/range.go
rename to src/cmd/compile/internal/gc/range.go
diff --git a/src/cmd/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
similarity index 81%
rename from src/cmd/internal/gc/reflect.go
rename to src/cmd/compile/internal/gc/reflect.go
index 9979fe85fd..6c0962f258 100644
--- a/src/cmd/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -5,8 +5,10 @@
 package gc
 
 import (
+	"cmd/internal/gcprog"
 	"cmd/internal/obj"
 	"fmt"
+	"os"
 )
 
 /*
@@ -687,7 +689,7 @@ func haspointers(t *Type) bool {
 
 // typeptrdata returns the length in bytes of the prefix of t
 // containing pointer data. Anything after this offset is scalar data.
-func typeptrdata(t *Type) uint64 {
+func typeptrdata(t *Type) int64 {
 	if !haspointers(t) {
 		return 0
 	}
@@ -699,24 +701,24 @@ func typeptrdata(t *Type) uint64 {
 		TFUNC,
 		TCHAN,
 		TMAP:
-		return uint64(Widthptr)
+		return int64(Widthptr)
 
 	case TSTRING:
 		// struct { byte *str; intgo len; }
-		return uint64(Widthptr)
+		return int64(Widthptr)
 
 	case TINTER:
 		// struct { Itab *tab;	void *data; } or
 		// struct { Type *type; void *data; }
-		return 2 * uint64(Widthptr)
+		return 2 * int64(Widthptr)
 
 	case TARRAY:
 		if Isslice(t) {
 			// struct { byte *array; uintgo len; uintgo cap; }
-			return uint64(Widthptr)
+			return int64(Widthptr)
 		}
 		// haspointers already eliminated t.Bound == 0.
-		return uint64(t.Bound-1)*uint64(t.Type.Width) + typeptrdata(t.Type)
+		return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type)
 
 	case TSTRUCT:
 		// Find the last field that has pointers.
@@ -726,7 +728,7 @@ func typeptrdata(t *Type) uint64 {
 				lastPtrField = t1
 			}
 		}
-		return uint64(lastPtrField.Width) + typeptrdata(lastPtrField.Type)
+		return lastPtrField.Width + typeptrdata(lastPtrField.Type)
 
 	default:
 		Fatal("typeptrdata: unexpected type, %v", t)
@@ -771,6 +773,8 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	// The linker magically takes the max of all the sizes.
 	zero := Pkglookup("zerovalue", Runtimepkg)
 
+	gcsym, useGCProg, ptrdata := dgcsym(t)
+
 	// We use size 0 here so we get the pointer to the zero value,
 	// but don't allocate space for the zero value unless we need it.
 	// TODO: how do we get this symbol into bss?  We really want
@@ -787,14 +791,14 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	//		fieldAlign    uint8
 	//		kind          uint8
 	//		alg           unsafe.Pointer
-	//		gc            unsafe.Pointer
+	//		gcdata        unsafe.Pointer
 	//		string        *string
 	//		*extraType
 	//		ptrToThis     *Type
 	//		zero          unsafe.Pointer
 	//	}
 	ot = duintptr(s, ot, uint64(t.Width))
-	ot = duintptr(s, ot, typeptrdata(t))
+	ot = duintptr(s, ot, uint64(ptrdata))
 
 	ot = duint32(s, ot, typehash(t))
 	ot = duint8(s, ot, 0) // unused
@@ -811,8 +815,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	ot = duint8(s, ot, t.Align) // align
 	ot = duint8(s, ot, t.Align) // fieldAlign
 
-	gcprog := usegcprog(t)
-
 	i = kinds[t.Etype]
 	if t.Etype == TARRAY && t.Bound < 0 {
 		i = obj.KindSlice
@@ -823,7 +825,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	if isdirectiface(t) {
 		i |= obj.KindDirectIface
 	}
-	if gcprog {
+	if useGCProg {
 		i |= obj.KindGCProg
 	}
 	ot = duint8(s, ot, uint8(i)) // kind
@@ -832,48 +834,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	} else {
 		ot = dsymptr(s, ot, algsym, 0)
 	}
-
-	// gc
-	if gcprog {
-		var gcprog1 *Sym
-		var gcprog0 *Sym
-		gengcprog(t, &gcprog0, &gcprog1)
-		if gcprog0 != nil {
-			ot = dsymptr(s, ot, gcprog0, 0)
-		} else {
-			ot = duintptr(s, ot, 0)
-		}
-		ot = dsymptr(s, ot, gcprog1, 0)
-	} else {
-		var gcmask [16]uint8
-		gengcmask(t, gcmask[:])
-		x1 := uint64(0)
-		for i := 0; i < 8; i++ {
-			x1 = x1<<8 | uint64(gcmask[i])
-		}
-		var p string
-		if Widthptr == 4 {
-			p = fmt.Sprintf("gcbits.0x%016x", x1)
-		} else {
-			x2 := uint64(0)
-			for i := 0; i < 8; i++ {
-				x2 = x2<<8 | uint64(gcmask[i+8])
-			}
-			p = fmt.Sprintf("gcbits.0x%016x%016x", x1, x2)
-		}
-
-		sbits := Pkglookup(p, Runtimepkg)
-		if sbits.Flags&SymUniq == 0 {
-			sbits.Flags |= SymUniq
-			for i := 0; i < 2*Widthptr; i++ {
-				duint8(sbits, i, gcmask[i])
-			}
-			ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL)
-		}
-
-		ot = dsymptr(s, ot, sbits, 0)
-		ot = duintptr(s, ot, 0)
-	}
+	ot = dsymptr(s, ot, gcsym, 0)
 
 	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
 
@@ -1419,269 +1380,193 @@ func dalgsym(t *Type) *Sym {
 	return s
 }
 
-func usegcprog(t *Type) bool {
-	if !haspointers(t) {
-		return false
-	}
-	if t.Width == BADWIDTH {
-		dowidth(t)
+// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
+// which holds 1-bit entries describing where pointers are in a given type.
+// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes
+// depending on the system. Above this length, the GC information is
+// recorded as a GC program, which can express repetition compactly.
+// In either form, the information is used by the runtime to initialize the
+// heap bitmap, and for large types (like 128 or more words), they are
+// roughly the same speed. GC programs are never much larger and often
+// more compact. (If large arrays are involved, they can be arbitrarily more
+// compact.)
+//
+// The cutoff must be large enough that any allocation large enough to
+// use a GC program is large enough that it does not share heap bitmap
+// bytes with any other objects, allowing the GC program execution to
+// assume an aligned start and not use atomic operations. In the current
+// runtime, this means all malloc size classes larger than the cutoff must
+// be multiples of four words. On 32-bit systems that's 16 bytes, and
+// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
+// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
+// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated
+// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
+// must be >= 4.
+//
+// We use 16 because the GC programs do have some constant overhead
+// to get started, and processing 128 pointers seems to be enough to
+// amortize that overhead well.
+const maxPtrmaskBytes = 16
+
+// dgcsym emits and returns a data symbol containing GC information for type t,
+// along with a boolean reporting whether the UseGCProg bit should be set in
+// the type kind, and the ptrdata field to record in the reflect type information.
+func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) {
+	ptrdata = typeptrdata(t)
+	if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
+		sym = dgcptrmask(t)
+		return
 	}
 
-	// Calculate size of the unrolled GC mask.
-	nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr)
-
-	size := nptr
-	if size%2 != 0 {
-		size *= 2 // repeated
-	}
-	size = size * obj.GcBits / 8 // 4 bits per word
-
-	// Decide whether to use unrolled GC mask or GC program.
-	// We could use a more elaborate condition, but this seems to work well in practice.
-	// For small objects GC program can't give significant reduction.
-	// While large objects usually contain arrays; and even if it don't
-	// the program uses 2-bits per word while mask uses 4-bits per word,
-	// so the program is still smaller.
-	return size > int64(2*Widthptr)
+	useGCProg = true
+	sym, ptrdata = dgcprog(t)
+	return
 }
 
-// Generates sparse GC bitmask (4 bits per word).
-func gengcmask(t *Type, gcmask []byte) {
-	for i := int64(0); i < 16; i++ {
-		gcmask[i] = 0
+// dgcptrmask emits and returns the symbol containing a pointer mask for type t.
+func dgcptrmask(t *Type) *Sym {
+	ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
+	fillptrmask(t, ptrmask)
+	p := fmt.Sprintf("gcbits.%x", ptrmask)
+
+	sym := Pkglookup(p, Runtimepkg)
+	if sym.Flags&SymUniq == 0 {
+		sym.Flags |= SymUniq
+		for i, x := range ptrmask {
+			duint8(sym, i, x)
+		}
+		ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
+	}
+	return sym
+}
+
+// fillptrmask fills in ptrmask with 1s corresponding to the
+// word offsets in t that hold pointers.
+// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
+func fillptrmask(t *Type, ptrmask []byte) {
+	for i := range ptrmask {
+		ptrmask[i] = 0
 	}
 	if !haspointers(t) {
 		return
 	}
 
-	// Generate compact mask as stacks use.
+	vec := bvalloc(8 * int32(len(ptrmask)))
 	xoffset := int64(0)
-
-	vec := bvalloc(2 * int32(Widthptr) * 8)
 	onebitwalktype1(t, &xoffset, vec)
 
-	// Unfold the mask for the GC bitmap format:
-	// 4 bits per word, 2 high bits encode pointer info.
-	pos := gcmask
-
-	nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr)
-	half := false
-
-	// If number of words is odd, repeat the mask.
-	// This makes simpler handling of arrays in runtime.
-	var i int64
-	var bits uint8
-	for j := int64(0); j <= (nptr % 2); j++ {
-		for i = 0; i < nptr; i++ {
-			// convert 0=scalar / 1=pointer to GC bit encoding
-			if bvget(vec, int32(i)) == 0 {
-				bits = obj.BitsScalar
-			} else {
-				bits = obj.BitsPointer
-			}
-			bits <<= 2
-			if half {
-				bits <<= 4
-			}
-			pos[0] |= byte(bits)
-			half = !half
-			if !half {
-				pos = pos[1:]
-			}
+	nptr := typeptrdata(t) / int64(Widthptr)
+	for i := int64(0); i < nptr; i++ {
+		if bvget(vec, int32(i)) == 1 {
+			ptrmask[i/8] |= 1 << (uint(i) % 8)
 		}
 	}
 }
 
-// Helper object for generation of GC programs.
-type ProgGen struct {
-	s        *Sym
-	datasize int32
-	data     [256 / obj.PointersPerByte]uint8
-	ot       int64
+// dgcprog emits and returns the symbol containing a GC program for type t
+// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
+// In practice, the size is typeptrdata(t) except for non-trivial arrays.
+// For non-trivial arrays, the program describes the full t.Width size.
+func dgcprog(t *Type) (*Sym, int64) {
+	dowidth(t)
+	if t.Width == BADWIDTH {
+		Fatal("dgcprog: %v badwidth", t)
+	}
+	sym := typesymprefix(".gcprog", t)
+	var p GCProg
+	p.init(sym)
+	p.emit(t, 0)
+	offset := p.w.BitIndex() * int64(Widthptr)
+	p.end()
+	if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
+		Fatal("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
+	}
+	return sym, offset
 }
 
-func proggeninit(g *ProgGen, s *Sym) {
-	g.s = s
-	g.datasize = 0
-	g.ot = 0
-	g.data = [256 / obj.PointersPerByte]uint8{}
+type GCProg struct {
+	sym    *Sym
+	symoff int
+	w      gcprog.Writer
 }
 
-func proggenemit(g *ProgGen, v uint8) {
-	g.ot = int64(duint8(g.s, int(g.ot), v))
+var Debug_gcprog int // set by -d gcprog
+
+func (p *GCProg) init(sym *Sym) {
+	p.sym = sym
+	p.symoff = 4 // first 4 bytes hold program length
+	p.w.Init(p.writeByte)
+	if Debug_gcprog > 0 {
+		fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym)
+		p.w.Debug(os.Stderr)
+	}
 }
 
-// Emits insData block from g->data.
-func proggendataflush(g *ProgGen) {
-	if g.datasize == 0 {
+func (p *GCProg) writeByte(x byte) {
+	p.symoff = duint8(p.sym, p.symoff, x)
+}
+
+func (p *GCProg) end() {
+	p.w.End()
+	duint32(p.sym, 0, uint32(p.symoff-4))
+	ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
+	if Debug_gcprog > 0 {
+		fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym)
+	}
+}
+
+func (p *GCProg) emit(t *Type, offset int64) {
+	dowidth(t)
+	if !haspointers(t) {
 		return
 	}
-	proggenemit(g, obj.InsData)
-	proggenemit(g, uint8(g.datasize))
-	s := (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte
-	for i := int32(0); i < s; i++ {
-		proggenemit(g, g.data[i])
+	if t.Width == int64(Widthptr) {
+		p.w.Ptr(offset / int64(Widthptr))
+		return
 	}
-	g.datasize = 0
-	g.data = [256 / obj.PointersPerByte]uint8{}
-}
-
-func proggendata(g *ProgGen, d uint8) {
-	g.data[g.datasize/obj.PointersPerByte] |= d << uint((g.datasize%obj.PointersPerByte)*obj.BitsPerPointer)
-	g.datasize++
-	if g.datasize == 255 {
-		proggendataflush(g)
-	}
-}
-
-// Skip v bytes due to alignment, etc.
-func proggenskip(g *ProgGen, off int64, v int64) {
-	for i := off; i < off+v; i++ {
-		if (i % int64(Widthptr)) == 0 {
-			proggendata(g, obj.BitsScalar)
-		}
-	}
-}
-
-// Emit insArray instruction.
-func proggenarray(g *ProgGen, len int64) {
-	proggendataflush(g)
-	proggenemit(g, obj.InsArray)
-	for i := int32(0); i < int32(Widthptr); i, len = i+1, len>>8 {
-		proggenemit(g, uint8(len))
-	}
-}
-
-func proggenarrayend(g *ProgGen) {
-	proggendataflush(g)
-	proggenemit(g, obj.InsArrayEnd)
-}
-
-func proggenfini(g *ProgGen) int64 {
-	proggendataflush(g)
-	proggenemit(g, obj.InsEnd)
-	return g.ot
-}
-
-// Generates GC program for large types.
-func gengcprog(t *Type, pgc0 **Sym, pgc1 **Sym) {
-	nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr)
-	size := nptr
-	if size%2 != 0 {
-		size *= 2 // repeated twice
-	}
-	size = size * obj.PointersPerByte / 8 // 4 bits per word
-	size++                                // unroll flag in the beginning, used by runtime (see runtime.markallocated)
-
-	// emity space in BSS for unrolled program
-	*pgc0 = nil
-
-	// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
-	if size <= obj.MaxGCMask {
-		gc0 := typesymprefix(".gc", t)
-		ggloblsym(gc0, int32(size), obj.DUPOK|obj.NOPTR)
-		*pgc0 = gc0
-	}
-
-	// program in RODATA
-	gc1 := typesymprefix(".gcprog", t)
-
-	var g ProgGen
-	proggeninit(&g, gc1)
-	xoffset := int64(0)
-	gengcprog1(&g, t, &xoffset)
-	ot := proggenfini(&g)
-	ggloblsym(gc1, int32(ot), obj.DUPOK|obj.RODATA)
-	*pgc1 = gc1
-}
-
-// Recursively walks type t and writes GC program into g.
-func gengcprog1(g *ProgGen, t *Type, xoffset *int64) {
 	switch t.Etype {
-	case TINT8,
-		TUINT8,
-		TINT16,
-		TUINT16,
-		TINT32,
-		TUINT32,
-		TINT64,
-		TUINT64,
-		TINT,
-		TUINT,
-		TUINTPTR,
-		TBOOL,
-		TFLOAT32,
-		TFLOAT64,
-		TCOMPLEX64,
-		TCOMPLEX128:
-		proggenskip(g, *xoffset, t.Width)
-		*xoffset += t.Width
-
-	case TPTR32,
-		TPTR64,
-		TUNSAFEPTR,
-		TFUNC,
-		TCHAN,
-		TMAP:
-		proggendata(g, obj.BitsPointer)
-		*xoffset += t.Width
+	default:
+		Fatal("GCProg.emit: unexpected type %v", t)
 
 	case TSTRING:
-		proggendata(g, obj.BitsPointer)
-		proggendata(g, obj.BitsScalar)
-		*xoffset += t.Width
+		p.w.Ptr(offset / int64(Widthptr))
 
-		// Assuming IfacePointerOnly=1.
 	case TINTER:
-		proggendata(g, obj.BitsPointer)
-
-		proggendata(g, obj.BitsPointer)
-		*xoffset += t.Width
+		p.w.Ptr(offset / int64(Widthptr))
+		p.w.Ptr(offset/int64(Widthptr) + 1)
 
 	case TARRAY:
 		if Isslice(t) {
-			proggendata(g, obj.BitsPointer)
-			proggendata(g, obj.BitsScalar)
-			proggendata(g, obj.BitsScalar)
-		} else {
-			t1 := t.Type
-			if t1.Width == 0 {
-			}
-			// ignore
-			if t.Bound <= 1 || t.Bound*t1.Width < int64(32*Widthptr) {
-				for i := int64(0); i < t.Bound; i++ {
-					gengcprog1(g, t1, xoffset)
-				}
-			} else if !haspointers(t1) {
-				n := t.Width
-				n -= -*xoffset & (int64(Widthptr) - 1) // skip to next ptr boundary
-				proggenarray(g, (n+int64(Widthptr)-1)/int64(Widthptr))
-				proggendata(g, obj.BitsScalar)
-				proggenarrayend(g)
-				*xoffset -= (n+int64(Widthptr)-1)/int64(Widthptr)*int64(Widthptr) - t.Width
-			} else {
-				proggenarray(g, t.Bound)
-				gengcprog1(g, t1, xoffset)
-				*xoffset += (t.Bound - 1) * t1.Width
-				proggenarrayend(g)
-			}
+			p.w.Ptr(offset / int64(Widthptr))
+			return
 		}
+		if t.Bound == 0 {
+			// should have been handled by haspointers check above
+			Fatal("GCProg.emit: empty array")
+		}
+
+		// Flatten array-of-array-of-array to just a big array by multiplying counts.
+		count := t.Bound
+		elem := t.Type
+		for Isfixedarray(elem) {
+			count *= elem.Bound
+			elem = elem.Type
+		}
+
+		if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
+			// Cheaper to just emit the bits.
+			for i := int64(0); i < count; i++ {
+				p.emit(elem, offset+i*elem.Width)
+			}
+			return
+		}
+		p.emit(elem, offset)
+		p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
+		p.w.Repeat(elem.Width/int64(Widthptr), count-1)
 
 	case TSTRUCT:
-		o := int64(0)
-		var fieldoffset int64
 		for t1 := t.Type; t1 != nil; t1 = t1.Down {
-			fieldoffset = t1.Width
-			proggenskip(g, *xoffset, fieldoffset-o)
-			*xoffset += fieldoffset - o
-			gengcprog1(g, t1.Type, xoffset)
-			o = fieldoffset + t1.Type.Width
+			p.emit(t1.Type, offset+t1.Width)
 		}
-
-		proggenskip(g, *xoffset, t.Width-o)
-		*xoffset += t.Width - o
-
-	default:
-		Fatal("gengcprog1: unexpected type, %v", t)
 	}
 }
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
similarity index 100%
rename from src/cmd/internal/gc/reg.go
rename to src/cmd/compile/internal/gc/reg.go
diff --git a/src/cmd/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
similarity index 100%
rename from src/cmd/internal/gc/select.go
rename to src/cmd/compile/internal/gc/select.go
diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
similarity index 97%
rename from src/cmd/internal/gc/sinit.go
rename to src/cmd/compile/internal/gc/sinit.go
index a9af9450ae..b5427a338c 100644
--- a/src/cmd/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -221,7 +221,7 @@ func init2(n *Node, out **NodeList) {
 	init2list(n.Nelse, out)
 
 	if n.Op == OCLOSURE {
-		init2list(n.Closure.Nbody, out)
+		init2list(n.Param.Closure.Nbody, out)
 	}
 	if n.Op == ODOTMETH || n.Op == OCALLPART {
 		init2(n.Type.Nname, out)
@@ -437,7 +437,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 
 	case OSTRARRAYBYTE:
 		if l.Class == PEXTERN && r.Left.Op == OLITERAL {
-			sval := r.Left.Val.U.Sval
+			sval := r.Left.Val.U.(string)
 			slicebytes(l, sval, len(sval))
 			return true
 		}
@@ -449,7 +449,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 			ta := typ(TARRAY)
 
 			ta.Type = r.Type.Type
-			ta.Bound = Mpgetfix(r.Right.Val.U.Xval)
+			ta.Bound = Mpgetfix(r.Right.Val.U.(*Mpint))
 			a := staticname(ta, 1)
 			r.Nname = a
 			n1 = *l
@@ -510,7 +510,7 @@ func staticname(t *Type, ctxt int) *Node {
 	n := newname(Lookupf("statictmp_%.4d", statuniqgen))
 	statuniqgen++
 	if ctxt == 0 {
-		n.Readonly = true
+		n.Name.Readonly = true
 	}
 	addvar(n, t, PEXTERN)
 	return n
@@ -722,7 +722,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 	// make an array type
 	t := shallow(n.Type)
 
-	t.Bound = Mpgetfix(n.Right.Val.U.Xval)
+	t.Bound = Mpgetfix(n.Right.Val.U.(*Mpint))
 	t.Width = 0
 	t.Sym = nil
 	t.Haspointers = 0
@@ -1226,7 +1226,7 @@ func oaslit(n *Node, init **NodeList) bool {
 
 func getlit(lit *Node) int {
 	if Smallintconst(lit) {
-		return int(Mpgetfix(lit.Val.U.Xval))
+		return int(Mpgetfix(lit.Val.U.(*Mpint)))
 	}
 	return -1
 }
@@ -1290,7 +1290,7 @@ func initplan(n *Node) {
 			if a.Op != OKEY || !Smallintconst(a.Left) {
 				Fatal("initplan arraylit")
 			}
-			addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.Xval), nil, a.Right)
+			addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.(*Mpint)), nil, a.Right)
 		}
 
 	case OSTRUCTLIT:
@@ -1360,19 +1360,19 @@ func iszero(n *Node) bool {
 			return true
 
 		case CTSTR:
-			return n.Val.U.Sval == ""
+			return n.Val.U.(string) == ""
 
 		case CTBOOL:
-			return !n.Val.U.Bval
+			return !n.Val.U.(bool)
 
 		case CTINT, CTRUNE:
-			return mpcmpfixc(n.Val.U.Xval, 0) == 0
+			return mpcmpfixc(n.Val.U.(*Mpint), 0) == 0
 
 		case CTFLT:
-			return mpcmpfltc(n.Val.U.Fval, 0) == 0
+			return mpcmpfltc(n.Val.U.(*Mpflt), 0) == 0
 
 		case CTCPLX:
-			return mpcmpfltc(&n.Val.U.Cval.Real, 0) == 0 && mpcmpfltc(&n.Val.U.Cval.Imag, 0) == 0
+			return mpcmpfltc(&n.Val.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val.U.(*Mpcplx).Imag, 0) == 0
 		}
 
 	case OARRAYLIT:
@@ -1510,10 +1510,10 @@ func gen_as_init(n *Node) bool {
 		gdata(&nam, nr, int(nr.Type.Width))
 
 	case TCOMPLEX64, TCOMPLEX128:
-		gdatacomplex(&nam, nr.Val.U.Cval)
+		gdatacomplex(&nam, nr.Val.U.(*Mpcplx))
 
 	case TSTRING:
-		gdatastring(&nam, nr.Val.U.Sval)
+		gdatastring(&nam, nr.Val.U.(string))
 	}
 
 	return true
diff --git a/src/cmd/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
similarity index 99%
rename from src/cmd/internal/gc/ssa.go
rename to src/cmd/compile/internal/gc/ssa.go
index bb4d278383..7f78fce17e 100644
--- a/src/cmd/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -7,9 +7,9 @@ package gc
 import (
 	"log"
 
+	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86" // TODO: remove
-	"cmd/internal/ssa"
 )
 
 func buildssa(fn *Node) *ssa.Func {
@@ -267,7 +267,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 	case OLITERAL:
 		switch n.Val.Ctype {
 		case CTINT:
-			return s.f.ConstInt(n.Type, Mpgetfix(n.Val.U.Xval))
+			return s.f.ConstInt(n.Type, Mpgetfix(n.Val.U.(*Mpint)))
 		default:
 			log.Fatalf("unhandled OLITERAL %v", n.Val.Ctype)
 			return nil
diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
similarity index 97%
rename from src/cmd/internal/gc/subr.go
rename to src/cmd/compile/internal/gc/subr.go
index 06ceff5844..ed5001a983 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -125,13 +125,6 @@ func Yyerror(format string, args ...interface{}) {
 	if strings.HasPrefix(msg, "syntax error") {
 		nsyntaxerrors++
 
-		yystate := theparser.(*yyParserImpl).state()
-		yychar := theparser.Lookahead()
-
-		if Debug['x'] != 0 {
-			fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar)
-		}
-
 		// An unexpected EOF caused a syntax error. Use the previous
 		// line number since getc generated a fake newline character.
 		if curio.eofnl != 0 {
@@ -144,14 +137,6 @@ func Yyerror(format string, args ...interface{}) {
 		}
 		yyerror_lastsyntax = int(lexlineno)
 
-		// look for parse state-specific errors in list (see go.errors).
-		for i := range yymsg {
-			if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar {
-				yyerrorl(int(lexlineno), "syntax error: %s", yymsg[i].msg)
-				return
-			}
-		}
-
 		// plain "syntax error" gets "near foo" added
 		if msg == "syntax error" {
 			yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String())
@@ -214,26 +199,32 @@ func Fatal(fmt_ string, args ...interface{}) {
 	errorexit()
 }
 
-func linehist(file string, off int32, relative int) {
+func linehistpragma(file string) {
 	if Debug['i'] != 0 {
-		if file != "" {
-			if off < 0 {
-				fmt.Printf("pragma %s", file)
-			} else if off > 0 {
-				fmt.Printf("line %s", file)
-			} else {
-				fmt.Printf("import %s", file)
-			}
-		} else {
-			fmt.Printf("end of import")
-		}
-		fmt.Printf(" at line %v\n", Ctxt.Line(int(lexlineno)))
+		fmt.Printf("pragma %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
 	}
+	Ctxt.AddImport(file)
+}
 
-	if off < 0 && file[0] != '/' && relative == 0 {
-		file = fmt.Sprintf("%s/%s", Ctxt.Pathname, file)
+func linehistpush(file string) {
+	if Debug['i'] != 0 {
+		fmt.Printf("import %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
 	}
-	obj.Linklinehist(Ctxt, int(lexlineno), file, int(off))
+	Ctxt.LineHist.Push(int(lexlineno), file)
+}
+
+func linehistpop() {
+	if Debug['i'] != 0 {
+		fmt.Printf("end of import at line %v\n", Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.LineHist.Pop(int(lexlineno))
+}
+
+func linehistupdate(file string, off int) {
+	if Debug['i'] != 0 {
+		fmt.Printf("line %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.LineHist.Update(int(lexlineno), file, off)
 }
 
 func setlineno(n *Node) int32 {
@@ -380,6 +371,12 @@ func Nod(op int, nleft *Node, nright *Node) *Node {
 	switch op {
 	case OCLOSURE, ODCLFUNC:
 		n.Func = new(Func)
+		n.Param = new(Param)
+	case ONAME:
+		n.Name = new(Name)
+		n.Param = new(Param)
+	case ODCLFIELD:
+		n.Param = new(Param)
 	}
 	return n
 }
@@ -666,8 +663,8 @@ func sortinter(t *Type) *Type {
 func Nodintconst(v int64) *Node {
 	c := Nod(OLITERAL, nil, nil)
 	c.Addable = true
-	c.Val.U.Xval = new(Mpint)
-	Mpmovecfix(c.Val.U.Xval, v)
+	c.Val.U = new(Mpint)
+	Mpmovecfix(c.Val.U.(*Mpint), v)
 	c.Val.Ctype = CTINT
 	c.Type = Types[TIDEAL]
 	ullmancalc(c)
@@ -677,8 +674,8 @@ func Nodintconst(v int64) *Node {
 func nodfltconst(v *Mpflt) *Node {
 	c := Nod(OLITERAL, nil, nil)
 	c.Addable = true
-	c.Val.U.Fval = newMpflt()
-	mpmovefltflt(c.Val.U.Fval, v)
+	c.Val.U = newMpflt()
+	mpmovefltflt(c.Val.U.(*Mpflt), v)
 	c.Val.Ctype = CTFLT
 	c.Type = Types[TIDEAL]
 	ullmancalc(c)
@@ -690,8 +687,8 @@ func Nodconst(n *Node, t *Type, v int64) {
 	n.Op = OLITERAL
 	n.Addable = true
 	ullmancalc(n)
-	n.Val.U.Xval = new(Mpint)
-	Mpmovecfix(n.Val.U.Xval, v)
+	n.Val.U = new(Mpint)
+	Mpmovecfix(n.Val.U.(*Mpint), v)
 	n.Val.Ctype = CTINT
 	n.Type = t
 
@@ -710,7 +707,7 @@ func nodnil() *Node {
 func Nodbool(b bool) *Node {
 	c := Nodintconst(0)
 	c.Val.Ctype = CTBOOL
-	c.Val.U.Bval = b
+	c.Val.U = b
 	c.Type = idealbool
 	return c
 }
@@ -724,7 +721,7 @@ func aindex(b *Node, t *Type) *Type {
 			Yyerror("array bound must be an integer expression")
 
 		case CTINT, CTRUNE:
-			bound = Mpgetfix(b.Val.U.Xval)
+			bound = Mpgetfix(b.Val.U.(*Mpint))
 			if bound < 0 {
 				Yyerror("array bound must be non negative")
 			}
@@ -739,7 +736,12 @@ func aindex(b *Node, t *Type) *Type {
 	return r
 }
 
-func treecopy(n *Node) *Node {
+// treecopy recursively copies n, with the exception of
+// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
+// Copies of iota ONONAME nodes are assigned the current
+// value of iota_. If lineno != 0, it sets the line number
+// of newly allocated nodes to lineno.
+func treecopy(n *Node, lineno int32) *Node {
 	if n == nil {
 		return nil
 	}
@@ -750,9 +752,12 @@ func treecopy(n *Node) *Node {
 		m = Nod(OXXX, nil, nil)
 		*m = *n
 		m.Orig = m
-		m.Left = treecopy(n.Left)
-		m.Right = treecopy(n.Right)
-		m.List = listtreecopy(n.List)
+		m.Left = treecopy(n.Left, lineno)
+		m.Right = treecopy(n.Right, lineno)
+		m.List = listtreecopy(n.List, lineno)
+		if lineno != -1 {
+			m.Lineno = lineno
+		}
 		if m.Defn != nil {
 			panic("abort")
 		}
@@ -767,11 +772,13 @@ func treecopy(n *Node) *Node {
 
 			*m = *n
 			m.Iota = iota_
+			if lineno != 0 {
+				m.Lineno = lineno
+			}
 			break
 		}
 		fallthrough
 
-		// fall through
 	case ONAME, OLITERAL, OTYPE:
 		m = n
 	}
@@ -1898,7 +1905,7 @@ func safeexpr(n *Node, init **NodeList) *Node {
 	case ONAME, OLITERAL:
 		return n
 
-	case ODOT:
+	case ODOT, OLEN, OCAP:
 		l := safeexpr(n.Left, init)
 		if l == n.Left {
 			return n
@@ -2359,7 +2366,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 	lineno = lexlineno
 	if genwrapper_linehistdone == 0 {
 		// All the wrappers can share the same linehist entry.
-		linehist("", 0, 0)
+		linehistpush("")
 
 		genwrapper_linehistdone = 1
 	}
@@ -2368,7 +2375,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 	markdcl()
 
 	this := Nod(ODCLFIELD, newname(Lookup(".this")), typenod(rcvr))
-	this.Left.Ntype = this.Right
+	this.Left.Param.Ntype = this.Right
 	in := structargs(getinarg(method.Type), 1)
 	out := structargs(Getoutarg(method.Type), 0)
 
@@ -2394,7 +2401,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 	fn := Nod(ODCLFUNC, nil, nil)
 	fn.Nname = newname(newnam)
 	fn.Nname.Defn = fn
-	fn.Nname.Ntype = t
+	fn.Nname.Param.Ntype = t
 	declare(fn.Nname, PFUNC)
 	funchdr(fn)
 
@@ -2422,11 +2429,11 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 
 		var v Val
 		v.Ctype = CTSTR
-		v.U.Sval = rcvr.Type.Sym.Pkg.Name // package name
+		v.U = rcvr.Type.Sym.Pkg.Name // package name
 		l = list(l, nodlit(v))
-		v.U.Sval = rcvr.Type.Sym.Name // type name
+		v.U = rcvr.Type.Sym.Name // type name
 		l = list(l, nodlit(v))
-		v.U.Sval = method.Sym.Name
+		v.U = method.Sym.Name
 		l = list(l, nodlit(v)) // method name
 		call := Nod(OCALL, syslook("panicwrap", 0), nil)
 		call.List = l
@@ -2568,7 +2575,7 @@ func genhash(sym *Sym, t *Type) {
 	fn.Nname = newname(sym)
 	fn.Nname.Class = PFUNC
 	tfn := Nod(OTFUNC, nil, nil)
-	fn.Nname.Ntype = tfn
+	fn.Nname.Param.Ntype = tfn
 
 	n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
 	tfn.List = list(tfn.List, n)
@@ -2580,7 +2587,7 @@ func genhash(sym *Sym, t *Type) {
 	tfn.Rlist = list(tfn.Rlist, n)
 
 	funchdr(fn)
-	typecheck(&fn.Nname.Ntype, Etype)
+	typecheck(&fn.Nname.Param.Ntype, Etype)
 
 	// genhash is only called for types that have equality but
 	// cannot be handled by the standard algorithms,
@@ -2820,7 +2827,7 @@ func geneq(sym *Sym, t *Type) {
 	fn.Nname = newname(sym)
 	fn.Nname.Class = PFUNC
 	tfn := Nod(OTFUNC, nil, nil)
-	fn.Nname.Ntype = tfn
+	fn.Nname.Param.Ntype = tfn
 
 	n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
 	tfn.List = list(tfn.List, n)
@@ -3096,10 +3103,10 @@ func Simsimtype(t *Type) int {
 	return et
 }
 
-func listtreecopy(l *NodeList) *NodeList {
+func listtreecopy(l *NodeList, lineno int32) *NodeList {
 	var out *NodeList
 	for ; l != nil; l = l.Next {
-		out = list(out, treecopy(l.N))
+		out = list(out, treecopy(l.N, lineno))
 	}
 	return out
 }
@@ -3139,7 +3146,7 @@ func powtwo(n *Node) int {
 		return -1
 	}
 
-	v := uint64(Mpgetfix(n.Val.U.Xval))
+	v := uint64(Mpgetfix(n.Val.U.(*Mpint)))
 	b := uint64(1)
 	for i := 0; i < 64; i++ {
 		if b == v {
diff --git a/src/cmd/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
similarity index 98%
rename from src/cmd/internal/gc/swt.go
rename to src/cmd/compile/internal/gc/swt.go
index 7cb632cebe..221b1f43eb 100644
--- a/src/cmd/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -169,10 +169,10 @@ func typecheckswitch(n *Node) {
 			if nvar != nil {
 				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
 					// single entry type switch
-					nvar.Ntype = typenod(ll.N.Type)
+					nvar.Param.Ntype = typenod(ll.N.Type)
 				} else {
 					// multiple entry type switch or default
-					nvar.Ntype = typenod(n.Type)
+					nvar.Param.Ntype = typenod(n.Type)
 				}
 
 				typecheck(&nvar, Erv|Easgn)
@@ -218,7 +218,7 @@ func (s *exprSwitch) walk(sw *Node) {
 	s.kind = switchKindExpr
 	if Isconst(sw.Ntest, CTBOOL) {
 		s.kind = switchKindTrue
-		if !sw.Ntest.Val.U.Bval {
+		if !sw.Ntest.Val.U.(bool) {
 			s.kind = switchKindFalse
 		}
 	}
@@ -755,16 +755,16 @@ func exprcmp(c1, c2 *caseClause) int {
 	// sort by constant value to enable binary search
 	switch ct {
 	case CTFLT:
-		return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval)
+		return mpcmpfltflt(n1.Val.U.(*Mpflt), n2.Val.U.(*Mpflt))
 	case CTINT, CTRUNE:
-		return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
+		return Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint))
 	case CTSTR:
 		// Sort strings by length and then by value.
 		// It is much cheaper to compare lengths than values,
 		// and all we need here is consistency.
 		// We respect this sorting in exprSwitch.walkCases.
-		a := n1.Val.U.Sval
-		b := n2.Val.U.Sval
+		a := n1.Val.U.(string)
+		b := n2.Val.U.(string)
 		if len(a) < len(b) {
 			return -1
 		}
diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
similarity index 87%
rename from src/cmd/internal/gc/syntax.go
rename to src/cmd/compile/internal/gc/syntax.go
index 7c9fb8d2b8..be4307690d 100644
--- a/src/cmd/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -23,14 +23,67 @@ type Node struct {
 	List  *NodeList
 	Rlist *NodeList
 
+	// most nodes
+	Type  *Type
+	Orig  *Node // original form, for printing, and tracking copies of ONAMEs
+	Nname *Node
+
+	// func
+	Func *Func
+
+	// ONAME
+	Name     *Name
+	Defn     *Node // ONAME: initializing assignment; OLABEL: labeled statement
+	Pack     *Node // real package for import . names
+	Curfn    *Node // function for local variables
+	Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn
+	Alloc    *Node // allocation call
+	Param    *Param
+
+	// OPACK
+	Pkg *Pkg
+
+	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
+	Initplan *InitPlan
+
+	// Escape analysis.
+	Escflowsrc *NodeList // flow(this, src)
+	Escretval  *NodeList // on OCALLxxx, list of dummy return values
+
+	Sym *Sym // various
+
+	Opt interface{} // for optimization passes
+
+	// OLITERAL
+	Val Val
+
+	Xoffset  int64
+	Stkdelta int64 // offset added by stack frame compaction phase.
+
+	// Escape analysis.
+	Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
+
+	Vargen  int32 // unique name for OTYPE/ONAME within a function.  Function outputs are numbered starting at one.
+	Lineno  int32
+	Iota    int32
+	Walkgen uint32
+
+	Funcdepth int32
+
+	// OREGISTER, OINDREG
+	Reg int16
+
+	// most nodes - smaller fields
+	Esclevel Level
+	Esc      uint16 // EscXXX
+
 	Op          uint8
 	Nointerface bool
 	Ullman      uint8 // sethi/ullman number
 	Addable     bool  // addressable
-	Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export
+	Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg
 	Bounded     bool  // bounds check unnecessary
 	Class       uint8 // PPARAM, PAUTO, PEXTERN, etc
-	Method      bool  // OCALLMETH is direct method call
 	Embedded    uint8 // ODCLFIELD embedded type
 	Colas       bool  // OAS resulting from :=
 	Diag        uint8 // already printed error about this
@@ -42,76 +95,36 @@ type Node struct {
 	Initorder   uint8
 	Used        bool
 	Isddd       bool // is the argument variadic
-	Readonly    bool
 	Implicit    bool
-	Addrtaken   bool   // address taken, even if not moved to heap
-	Assigned    bool   // is the variable ever assigned to
-	Captured    bool   // is the variable captured by a closure
-	Byval       bool   // is the variable captured by value or by reference
-	Reslice     bool   // this is a reslice x = x[0:y] or x = append(x, ...)
-	Likely      int8   // likeliness of if statement
-	Hasbreak    bool   // has break statement
-	Needzero    bool   // if it contains pointers, needs to be zeroed on function entry
-	Esc         uint16 // EscXXX
-	Funcdepth   int32
+	Addrtaken   bool // address taken, even if not moved to heap
+	Assigned    bool // is the variable ever assigned to
+	Likely      int8 // likeliness of if statement
+	Hasbreak    bool // has break statement
+}
 
-	// most nodes
-	Type  *Type
-	Orig  *Node // original form, for printing, and tracking copies of ONAMEs
-	Nname *Node
+// Name holds Node fields used only by ONAME nodes.
+type Name struct {
+	Heapaddr  *Node // temp holding heap address of param
+	Inlvar    *Node // ONAME substitute while inlining
+	Decldepth int32 // declaration loop depth, increased for every loop or label
+	Method    bool  // OCALLMETH name
+	Readonly  bool
+	Captured  bool // is the variable captured by a closure
+	Byval     bool // is the variable captured by value or by reference
+	Needzero  bool // if it contains pointers, needs to be zeroed on function entry
+}
 
-	// func
-	Func *Func
-
-	// OLITERAL
-	Val Val
-
-	// OREGISTER, OINDREG
-	Reg int16
-
-	// ONAME
-	Ntype     *Node
-	Defn      *Node // ONAME: initializing assignment; OLABEL: labeled statement
-	Pack      *Node // real package for import . names
-	Curfn     *Node // function for local variables
-	Paramfld  *Type // TFIELD for this PPARAM; also for ODOT, curfn
-	Decldepth int   // declaration loop depth, increased for every loop or label
+type Param struct {
+	Ntype *Node
 
 	// ONAME func param with PHEAP
-	Heapaddr   *Node // temp holding heap address of param
 	Outerexpr  *Node // expression copied into closure for variable
 	Stackparam *Node // OPARAM node referring to stack copy of param
-	Alloc      *Node // allocation call
 
 	// ONAME closure param with PPARAMREF
 	Outer   *Node // outer PPARAMREF in nested closure
 	Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
 	Top     int   // top context (Ecall, Eproc, etc)
-
-	// ONAME substitute while inlining
-	Inlvar *Node
-
-	// OPACK
-	Pkg *Pkg
-
-	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
-	Initplan *InitPlan
-
-	// Escape analysis.
-	Escflowsrc   *NodeList // flow(this, src)
-	Escretval    *NodeList // on OCALLxxx, list of dummy return values
-	Escloopdepth int       // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
-
-	Sym      *Sym  // various
-	Vargen   int32 // unique name for OTYPE/ONAME within a function.  Function outputs are numbered starting at one.
-	Lineno   int32
-	Xoffset  int64
-	Stkdelta int64 // offset added by stack frame compaction phase.
-	Ostk     int32 // 6g only
-	Iota     int32
-	Walkgen  uint32
-	Esclevel Level
-	Opt      interface{} // for optimization passes
 }
 
 // Func holds Node fields used only with function-like nodes.
diff --git a/src/cmd/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
similarity index 97%
rename from src/cmd/internal/gc/type.go
rename to src/cmd/compile/internal/gc/type.go
index 6f7830d70a..cf1589eb03 100644
--- a/src/cmd/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -10,7 +10,7 @@
 package gc
 
 import (
-	"cmd/internal/ssa"
+	"cmd/compile/internal/ssa"
 )
 
 func (t *Type) Size() int64 {
diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
similarity index 95%
rename from src/cmd/internal/gc/typecheck.go
rename to src/cmd/compile/internal/gc/typecheck.go
index 6daf842474..2900da8be7 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -311,8 +311,8 @@ OpSwitch:
 		break OpSwitch
 
 	case ONAME:
-		if n.Decldepth == 0 {
-			n.Decldepth = decldepth
+		if n.Name.Decldepth == 0 {
+			n.Name.Decldepth = decldepth
 		}
 		if n.Etype != 0 {
 			ok |= Ecall
@@ -392,7 +392,7 @@ OpSwitch:
 				return
 			}
 
-			t.Bound = Mpgetfix(v.U.Xval)
+			t.Bound = Mpgetfix(v.U.(*Mpint))
 			if doesoverflow(v, Types[TINT]) {
 				Yyerror("array bound is too large")
 				n.Type = nil
@@ -770,7 +770,7 @@ OpSwitch:
 		}
 
 		if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
-			if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
+			if mpcmpfixc(r.Val.U.(*Mpint), 0) == 0 {
 				Yyerror("division by zero")
 				n.Type = nil
 				return
@@ -813,8 +813,8 @@ OpSwitch:
 		var l *Node
 		for l = n.Left; l != r; l = l.Left {
 			l.Addrtaken = true
-			if l.Closure != nil {
-				l.Closure.Addrtaken = true
+			if l.Param != nil && l.Param.Closure != nil {
+				l.Param.Closure.Addrtaken = true
 			}
 		}
 
@@ -822,8 +822,8 @@ OpSwitch:
 			Fatal("found non-orig name node %v", l)
 		}
 		l.Addrtaken = true
-		if l.Closure != nil {
-			l.Closure.Addrtaken = true
+		if l.Param != nil && l.Param.Closure != nil {
+			l.Param.Closure.Addrtaken = true
 		}
 		defaultlit(&n.Left, nil)
 		l = n.Left
@@ -891,6 +891,9 @@ OpSwitch:
 			}
 
 			n.Op = ONAME
+			if n.Name == nil {
+				n.Name = new(Name)
+			}
 			n.Sym = n.Right.Sym
 			n.Type = methodfunc(n.Type, n.Left.Type)
 			n.Xoffset = 0
@@ -1024,7 +1027,7 @@ OpSwitch:
 		case TSTRING, TARRAY:
 			indexlit(&n.Right)
 			if t.Etype == TSTRING {
-				n.Type = Types[TUINT8]
+				n.Type = bytetype
 			} else {
 				n.Type = t.Type
 			}
@@ -1043,14 +1046,14 @@ OpSwitch:
 			}
 
 			if Isconst(n.Right, CTINT) {
-				x := Mpgetfix(n.Right.Val.U.Xval)
+				x := Mpgetfix(n.Right.Val.U.(*Mpint))
 				if x < 0 {
 					Yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
 				} else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound {
 					Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.Bound)
-				} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.Sval)) {
-					Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.Sval))
-				} else if Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 {
+				} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.(string))) {
+					Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.(string)))
+				} else if Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 {
 					Yyerror("invalid %s index %v (index too large)", why, n.Right)
 				}
 			}
@@ -1303,7 +1306,7 @@ OpSwitch:
 		if l.Op == OTYPE {
 			if n.Isddd || l.Type.Bound == -100 {
 				if l.Type.Broke == 0 {
-					Yyerror("invalid use of ... in type conversion", l)
+					Yyerror("invalid use of ... in type conversion to %v", l.Type)
 				}
 				n.Diag = 1
 			}
@@ -1435,9 +1438,9 @@ OpSwitch:
 			if Isconst(l, CTCPLX) {
 				r := n
 				if n.Op == OREAL {
-					n = nodfltconst(&l.Val.U.Cval.Real)
+					n = nodfltconst(&l.Val.U.(*Mpcplx).Real)
 				} else {
-					n = nodfltconst(&l.Val.U.Cval.Imag)
+					n = nodfltconst(&l.Val.U.(*Mpcplx).Imag)
 				}
 				n.Orig = r
 			}
@@ -1451,7 +1454,7 @@ OpSwitch:
 		case TSTRING:
 			if Isconst(l, CTSTR) {
 				r := Nod(OXXX, nil, nil)
-				Nodconst(r, Types[TINT], int64(len(l.Val.U.Sval)))
+				Nodconst(r, Types[TINT], int64(len(l.Val.U.(string))))
 				r.Orig = n
 				n = r
 			}
@@ -1528,7 +1531,7 @@ OpSwitch:
 		var t *Type
 		switch l.Type.Etype {
 		default:
-			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type, r.Type)
+			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
 			n.Type = nil
 			return
 
@@ -1636,17 +1639,16 @@ OpSwitch:
 		}
 
 		// Unpack multiple-return result before type-checking.
+		var funarg *Type
 		if Istype(t, TSTRUCT) && t.Funarg != 0 {
-			t = t.Type
-			if Istype(t, TFIELD) {
-				t = t.Type
-			}
+			funarg = t
+			t = t.Type.Type
 		}
 
 		n.Type = t
 		if !Isslice(t) {
 			if Isconst(args.N, CTNIL) {
-				Yyerror("first argument to append must be typed slice; have untyped nil", t)
+				Yyerror("first argument to append must be typed slice; have untyped nil")
 				n.Type = nil
 				return
 			}
@@ -1678,11 +1680,19 @@ OpSwitch:
 			break OpSwitch
 		}
 
-		for args = args.Next; args != nil; args = args.Next {
-			if args.N.Type == nil {
-				continue
+		if funarg != nil {
+			for t := funarg.Type.Down; t != nil; t = t.Down {
+				if assignop(t.Type, n.Type.Type, nil) == 0 {
+					Yyerror("cannot append %v value to []%v", t.Type, n.Type.Type)
+				}
+			}
+		} else {
+			for args = args.Next; args != nil; args = args.Next {
+				if args.N.Type == nil {
+					continue
+				}
+				args.N = assignconv(args.N, t.Type, "append")
 			}
-			args.N = assignconv(args.N, t.Type, "append")
 		}
 
 		break OpSwitch
@@ -1852,7 +1862,7 @@ OpSwitch:
 				n.Type = nil
 				return
 			}
-			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 {
+			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.(*Mpint), r.Val.U.(*Mpint)) > 0 {
 				Yyerror("len larger than cap in make(%v)", t)
 				n.Type = nil
 				return
@@ -2248,16 +2258,16 @@ func checksliceindex(l *Node, r *Node, tp *Type) int {
 	}
 
 	if r.Op == OLITERAL {
-		if Mpgetfix(r.Val.U.Xval) < 0 {
+		if Mpgetfix(r.Val.U.(*Mpint)) < 0 {
 			Yyerror("invalid slice index %v (index must be non-negative)", r)
 			return -1
-		} else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.Xval) > tp.Bound {
+		} else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.(*Mpint)) > tp.Bound {
 			Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.Bound)
 			return -1
-		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.Xval) > int64(len(l.Val.U.Sval)) {
-			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.Sval))
+		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.(*Mpint)) > int64(len(l.Val.U.(string))) {
+			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.(string)))
 			return -1
-		} else if Mpcmpfixfix(r.Val.U.Xval, Maxintval[TINT]) > 0 {
+		} else if Mpcmpfixfix(r.Val.U.(*Mpint), Maxintval[TINT]) > 0 {
 			Yyerror("invalid slice index %v (index too large)", r)
 			return -1
 		}
@@ -2267,7 +2277,7 @@ func checksliceindex(l *Node, r *Node, tp *Type) int {
 }
 
 func checksliceconst(lo *Node, hi *Node) int {
-	if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.Xval, hi.Val.U.Xval) > 0 {
+	if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.(*Mpint), hi.Val.U.(*Mpint)) > 0 {
 		Yyerror("invalid slice index: %v > %v", lo, hi)
 		return -1
 	}
@@ -2817,10 +2827,10 @@ func keydup(n *Node, hash []*Node) {
 		b = 23
 
 	case CTINT, CTRUNE:
-		b = uint32(Mpgetfix(n.Val.U.Xval))
+		b = uint32(Mpgetfix(n.Val.U.(*Mpint)))
 
 	case CTFLT:
-		d := mpgetflt(n.Val.U.Fval)
+		d := mpgetflt(n.Val.U.(*Mpflt))
 		x := math.Float64bits(d)
 		for i := 0; i < 8; i++ {
 			b = b*PRIME1 + uint32(x&0xFF)
@@ -2829,8 +2839,8 @@ func keydup(n *Node, hash []*Node) {
 
 	case CTSTR:
 		b = 0
-		s := n.Val.U.Sval
-		for i := len(n.Val.U.Sval); i > 0; i-- {
+		s := n.Val.U.(string)
+		for i := len(n.Val.U.(string)); i > 0; i-- {
 			b = b*PRIME1 + uint32(s[0])
 			s = s[1:]
 		}
@@ -2846,12 +2856,12 @@ func keydup(n *Node, hash []*Node) {
 			if Eqtype(a.Left.Type, n.Type) {
 				cmp.Right = a.Left
 				evconst(&cmp)
-				b = uint32(obj.Bool2int(cmp.Val.U.Bval))
+				b = uint32(obj.Bool2int(cmp.Val.U.(bool)))
 			}
 		} else if Eqtype(a.Type, n.Type) {
 			cmp.Right = a
 			evconst(&cmp)
-			b = uint32(obj.Bool2int(cmp.Val.U.Bval))
+			b = uint32(obj.Bool2int(cmp.Val.U.(bool)))
 		}
 
 		if b != 0 {
@@ -2869,11 +2879,11 @@ func indexdup(n *Node, hash []*Node) {
 		Fatal("indexdup: not OLITERAL")
 	}
 
-	b := uint32(Mpgetfix(n.Val.U.Xval))
+	b := uint32(Mpgetfix(n.Val.U.(*Mpint)))
 	h := uint(b % uint32(len(hash)))
 	var c uint32
 	for a := hash[h]; a != nil; a = a.Ntest {
-		c = uint32(Mpgetfix(a.Val.U.Xval))
+		c = uint32(Mpgetfix(a.Val.U.(*Mpint)))
 		if b == c {
 			Yyerror("duplicate index in array literal: %d", b)
 			return
@@ -3263,14 +3273,14 @@ func checkassign(stmt *Node, n *Node) {
 		var l *Node
 		for l = n; l != r; l = l.Left {
 			l.Assigned = true
-			if l.Closure != nil {
-				l.Closure.Assigned = true
+			if l.Param != nil && l.Param.Closure != nil {
+				l.Param.Closure.Assigned = true
 			}
 		}
 
 		l.Assigned = true
-		if l.Closure != nil {
-			l.Closure.Assigned = true
+		if l.Param != nil && l.Param.Closure != nil {
+			l.Param.Closure.Assigned = true
 		}
 	}
 
@@ -3335,7 +3345,7 @@ func typecheckas(n *Node) {
 	// so that the conversion below happens).
 	n.Left = resolve(n.Left)
 
-	if n.Left.Defn != n || n.Left.Ntype != nil {
+	if n.Left.Defn != n || n.Left.Param.Ntype != nil {
 		typecheck(&n.Left, Erv|Easgn)
 	}
 
@@ -3347,7 +3357,7 @@ func typecheckas(n *Node) {
 		}
 	}
 
-	if n.Left.Defn == n && n.Left.Ntype == nil {
+	if n.Left.Defn == n && n.Left.Param.Ntype == nil {
 		defaultlit(&n.Right, nil)
 		n.Left.Type = n.Right.Type
 	}
@@ -3360,29 +3370,6 @@ func typecheckas(n *Node) {
 	if n.Left.Typecheck == 0 {
 		typecheck(&n.Left, Erv|Easgn)
 	}
-
-	// Recognize slices being updated in place, for better code generation later.
-	// Don't rewrite if using race detector, to avoid needing to teach race detector
-	// about this optimization.
-	if n.Left != nil && n.Left.Op != OINDEXMAP && n.Right != nil && flag_race == 0 {
-		switch n.Right.Op {
-		// For x = x[0:y], x can be updated in place, without touching pointer.
-		// TODO(rsc): Reenable once it is actually updated in place without touching the pointer.
-		case OSLICE, OSLICE3, OSLICESTR:
-			if false && samesafeexpr(n.Left, n.Right.Left) && (n.Right.Right.Left == nil || iszero(n.Right.Right.Left)) {
-				n.Right.Reslice = true
-			}
-
-			// For x = append(x, ...), x can be updated in place when there is capacity,
-		// without touching the pointer; otherwise the emitted code to growslice
-		// can take care of updating the pointer, and only in that case.
-		// TODO(rsc): Reenable once the emitted code does update the pointer.
-		case OAPPEND:
-			if false && n.Right.List != nil && samesafeexpr(n.Left, n.Right.List.N) {
-				n.Right.Reslice = true
-			}
-		}
-	}
 }
 
 func checkassignto(src *Type, dst *Node) {
@@ -3399,7 +3386,7 @@ func typecheckas2(n *Node) {
 		// delicate little dance.
 		ll.N = resolve(ll.N)
 
-		if ll.N.Defn != n || ll.N.Ntype != nil {
+		if ll.N.Defn != n || ll.N.Param.Ntype != nil {
 			typecheck(&ll.N, Erv|Easgn)
 		}
 	}
@@ -3423,7 +3410,7 @@ func typecheckas2(n *Node) {
 			if ll.N.Type != nil && lr.N.Type != nil {
 				lr.N = assignconv(lr.N, ll.N.Type, "assignment")
 			}
-			if ll.N.Defn == n && ll.N.Ntype == nil {
+			if ll.N.Defn == n && ll.N.Param.Ntype == nil {
 				defaultlit(&lr.N, nil)
 				ll.N.Type = lr.N.Type
 			}
@@ -3456,7 +3443,7 @@ func typecheckas2(n *Node) {
 				if t.Type != nil && ll.N.Type != nil {
 					checkassignto(t.Type, ll.N)
 				}
-				if ll.N.Defn == n && ll.N.Ntype == nil {
+				if ll.N.Defn == n && ll.N.Param.Ntype == nil {
 					ll.N.Type = t.Type
 				}
 				t = structnext(&s)
@@ -3495,7 +3482,7 @@ func typecheckas2(n *Node) {
 			if l.Type != nil && l.Type.Etype != TBOOL {
 				checkassignto(Types[TBOOL], l)
 			}
-			if l.Defn == n && l.Ntype == nil {
+			if l.Defn == n && l.Param.Ntype == nil {
 				l.Type = Types[TBOOL]
 			}
 			goto out
@@ -3534,7 +3521,7 @@ func typecheckfunc(n *Node) {
 
 	for l := n.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
-			l.N.Decldepth = 1
+			l.N.Name.Decldepth = 1
 		}
 	}
 }
@@ -3542,10 +3529,10 @@ func typecheckfunc(n *Node) {
 func stringtoarraylit(np **Node) {
 	n := *np
 	if n.Left.Op != OLITERAL || n.Left.Val.Ctype != CTSTR {
-		Fatal("stringtoarraylit %N", n)
+		Fatal("stringtoarraylit %v", n)
 	}
 
-	s := n.Left.Val.U.Sval
+	s := n.Left.Val.U.(string)
 	var l *NodeList
 	if n.Type.Type.Etype == TUINT8 {
 		// []byte
@@ -3659,8 +3646,8 @@ func typecheckdeftype(n *Node) {
 	setlineno(n)
 	n.Type.Sym = n.Sym
 	n.Typecheck = 1
-	typecheck(&n.Ntype, Etype)
-	t := n.Ntype.Type
+	typecheck(&n.Param.Ntype, Etype)
+	t := n.Param.Ntype.Type
 	if t == nil {
 		n.Diag = 1
 		n.Type = nil
@@ -3770,10 +3757,10 @@ func typecheckdef(n *Node) *Node {
 		break
 
 	case OLITERAL:
-		if n.Ntype != nil {
-			typecheck(&n.Ntype, Etype)
-			n.Type = n.Ntype.Type
-			n.Ntype = nil
+		if n.Param.Ntype != nil {
+			typecheck(&n.Param.Ntype, Etype)
+			n.Type = n.Param.Ntype.Type
+			n.Param.Ntype = nil
 			if n.Type == nil {
 				n.Diag = 1
 				goto ret
@@ -3822,9 +3809,9 @@ func typecheckdef(n *Node) *Node {
 		n.Type = e.Type
 
 	case ONAME:
-		if n.Ntype != nil {
-			typecheck(&n.Ntype, Etype)
-			n.Type = n.Ntype.Type
+		if n.Param.Ntype != nil {
+			typecheck(&n.Param.Ntype, Etype)
+			n.Type = n.Param.Ntype.Type
 
 			if n.Type == nil {
 				n.Diag = 1
@@ -3902,12 +3889,12 @@ func checkmake(t *Type, arg string, n *Node) int {
 		switch n.Val.Ctype {
 		case CTINT, CTRUNE, CTFLT, CTCPLX:
 			n.Val = toint(n.Val)
-			if mpcmpfixc(n.Val.U.Xval, 0) < 0 {
+			if mpcmpfixc(n.Val.U.(*Mpint), 0) < 0 {
 				Yyerror("negative %s argument in make(%v)", arg, t)
 				return -1
 			}
 
-			if Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT]) > 0 {
+			if Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT]) > 0 {
 				Yyerror("%s argument too large in make(%v)", arg, t)
 				return -1
 			}
diff --git a/src/cmd/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
similarity index 98%
rename from src/cmd/internal/gc/unsafe.go
rename to src/cmd/compile/internal/gc/unsafe.go
index aa90a19308..824ecd0339 100644
--- a/src/cmd/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -140,8 +140,8 @@ ret:
 	var val Val
 	val.Ctype = CTINT
 
-	val.U.Xval = new(Mpint)
-	Mpmovecfix(val.U.Xval, v)
+	val.U = new(Mpint)
+	Mpmovecfix(val.U.(*Mpint), v)
 	n := Nod(OLITERAL, nil, nil)
 	n.Orig = nn
 	n.Val = val
diff --git a/src/cmd/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
similarity index 95%
rename from src/cmd/internal/gc/util.go
rename to src/cmd/compile/internal/gc/util.go
index 5dc6561b48..c59af0665b 100644
--- a/src/cmd/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -1,7 +1,6 @@
 package gc
 
 import (
-	"cmd/internal/obj"
 	"os"
 	"runtime"
 	"runtime/pprof"
@@ -10,7 +9,7 @@ import (
 )
 
 func (n *Node) Line() string {
-	return obj.Linklinefmt(Ctxt, int(n.Lineno), false, false)
+	return Ctxt.LineHist.LineString(int(n.Lineno))
 }
 
 func atoi(s string) int {
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
similarity index 89%
rename from src/cmd/internal/gc/walk.go
rename to src/cmd/compile/internal/gc/walk.go
index c32a8137d6..d5eb44c0bb 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -352,6 +352,20 @@ func walkstmt(np **Node) {
 	*np = n
 }
 
+func isSmallMakeSlice(n *Node) bool {
+	if n.Op != OMAKESLICE {
+		return false
+	}
+	l := n.Left
+	r := n.Right
+	if r == nil {
+		r = l
+	}
+	t := n.Type
+
+	return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.(*Mpint)) < (1<<16)/t.Type.Width)
+}
+
 /*
  * walk the whole tree of the body of an
  * expression or simple statement.
@@ -601,7 +615,7 @@ func walkexpr(np **Node, init **NodeList) {
 			n.Left.Func.Enter = nil
 
 			// Replace OCLOSURE with ONAME/PFUNC.
-			n.Left = n.Left.Closure.Nname
+			n.Left = n.Left.Param.Closure.Nname
 
 			// Update type of OCALLFUNC node.
 			// Output arguments had not changed, but their offsets could.
@@ -711,6 +725,23 @@ func walkexpr(np **Node, init **NodeList) {
 			n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
 			walkexpr(&n, init)
 			goto ret
+
+		case OAPPEND:
+			// x = append(...)
+			r := n.Right
+			if r.Isddd {
+				r = appendslice(r, init) // also works for append(slice, string).
+			} else {
+				r = walkappend(r, init, n)
+			}
+			n.Right = r
+			if r.Op == OAPPEND {
+				// Left in place for back end.
+				// Do not add a new write barrier.
+				goto ret
+			}
+			// Otherwise, lowered for race detector.
+			// Treat as ordinary assignment.
 		}
 
 		if n.Left != nil && n.Right != nil {
@@ -1189,7 +1220,7 @@ func walkexpr(np **Node, init **NodeList) {
 				Yyerror("index out of bounds")
 			}
 		} else if Isconst(n.Left, CTSTR) {
-			n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval)))
+			n.Bounded = bounded(r, int64(len(n.Left.Val.U.(string))))
 			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
 				Warn("index bounds check elided")
 			}
@@ -1200,16 +1231,16 @@ func walkexpr(np **Node, init **NodeList) {
 					// replace "abc"[1] with 'b'.
 					// delayed until now because "abc"[1] is not
 					// an ideal constant.
-					v := Mpgetfix(n.Right.Val.U.Xval)
+					v := Mpgetfix(n.Right.Val.U.(*Mpint))
 
-					Nodconst(n, n.Type, int64(n.Left.Val.U.Sval[v]))
+					Nodconst(n, n.Type, int64(n.Left.Val.U.(string)[v]))
 					n.Typecheck = 1
 				}
 			}
 		}
 
 		if Isconst(n.Right, CTINT) {
-			if Mpcmpfixfix(n.Right.Val.U.Xval, &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 {
+			if Mpcmpfixfix(n.Right.Val.U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 {
 				Yyerror("index out of bounds")
 			}
 		}
@@ -1263,56 +1294,39 @@ func walkexpr(np **Node, init **NodeList) {
 	case ORECV:
 		Fatal("walkexpr ORECV") // should see inside OAS only
 
-	case OSLICE:
-		if n.Right != nil && n.Right.Left == nil && n.Right.Right == nil { // noop
-			walkexpr(&n.Left, init)
-			n = n.Left
-			goto ret
-		}
-		fallthrough
-
-	case OSLICEARR, OSLICESTR:
-		if n.Right == nil { // already processed
-			goto ret
-		}
-
+	case OSLICE, OSLICEARR, OSLICESTR:
 		walkexpr(&n.Left, init)
-
-		// cgen_slice can't handle string literals as source
-		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
-		if (n.Op == OSLICESTR && n.Left.Op == OLITERAL) || (n.Left.Op == OINDEX) {
-			n.Left = copyexpr(n.Left, n.Left.Type, init)
-		} else {
-			n.Left = safeexpr(n.Left, init)
-		}
 		walkexpr(&n.Right.Left, init)
-		n.Right.Left = safeexpr(n.Right.Left, init)
+		if n.Right.Left != nil && iszero(n.Right.Left) {
+			// Reduce x[0:j] to x[:j].
+			n.Right.Left = nil
+		}
 		walkexpr(&n.Right.Right, init)
-		n.Right.Right = safeexpr(n.Right.Right, init)
-		n = sliceany(n, init) // chops n.Right, sets n.List
+		n = reduceSlice(n)
 		goto ret
 
 	case OSLICE3, OSLICE3ARR:
-		if n.Right == nil { // already processed
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right.Left, init)
+		if n.Right.Left != nil && iszero(n.Right.Left) {
+			// Reduce x[0:j:k] to x[:j:k].
+			n.Right.Left = nil
+		}
+		walkexpr(&n.Right.Right.Left, init)
+		walkexpr(&n.Right.Right.Right, init)
+
+		r := n.Right.Right.Right
+		if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
+			// Reduce x[i:j:cap(x)] to x[i:j].
+			n.Right.Right = n.Right.Right.Left
+			if n.Op == OSLICE3 {
+				n.Op = OSLICE
+			} else {
+				n.Op = OSLICEARR
+			}
+			n = reduceSlice(n)
 			goto ret
 		}
-
-		walkexpr(&n.Left, init)
-
-		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
-		// TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
-		if n.Left.Op == OINDEX {
-			n.Left = copyexpr(n.Left, n.Left.Type, init)
-		} else {
-			n.Left = safeexpr(n.Left, init)
-		}
-		walkexpr(&n.Right.Left, init)
-		n.Right.Left = safeexpr(n.Right.Left, init)
-		walkexpr(&n.Right.Right.Left, init)
-		n.Right.Right.Left = safeexpr(n.Right.Right.Left, init)
-		walkexpr(&n.Right.Right.Right, init)
-		n.Right.Right.Right = safeexpr(n.Right.Right.Right, init)
-		n = sliceany(n, init) // chops n.Right, sets n.List
 		goto ret
 
 	case OADDR:
@@ -1320,7 +1334,10 @@ func walkexpr(np **Node, init **NodeList) {
 		goto ret
 
 	case ONEW:
-		if n.Esc == EscNone && n.Type.Type.Width < 1<<16 {
+		if n.Esc == EscNone {
+			if n.Type.Type.Width >= 1<<16 {
+				Fatal("Large ONEW with EscNone, %v", n)
+			}
 			r := temp(n.Type.Type)
 			r = Nod(OAS, r, nil) // zero temp
 			typecheck(&r, Etop)
@@ -1338,7 +1355,7 @@ func walkexpr(np **Node, init **NodeList) {
 	// comparing the lengths instead will yield the same result
 	// without the function call.
 	case OCMPSTR:
-		if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval) == 0) {
+		if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.(string)) == 0) {
 			r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
 			typecheck(&r, Erv)
 			walkexpr(&r, init)
@@ -1400,12 +1417,8 @@ func walkexpr(np **Node, init **NodeList) {
 		goto ret
 
 	case OAPPEND:
-		if n.Isddd {
-			n = appendslice(n, init) // also works for append(slice, string).
-		} else {
-			n = walkappend(n, init)
-		}
-		goto ret
+		// order should make sure we only see OAS(node, OAPPEND), which we handle above.
+		Fatal("append outside assignment")
 
 	case OCOPY:
 		n = copyany(n, init, flag_race)
@@ -1462,7 +1475,10 @@ func walkexpr(np **Node, init **NodeList) {
 			l = r
 		}
 		t := n.Type
-		if n.Esc == EscNone && Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.Xval) < (1<<16)/t.Type.Width) {
+		if n.Esc == EscNone {
+			if !isSmallMakeSlice(n) {
+				Fatal("Non-small OMAKESLICE with EscNone, %v", n)
+			}
 			// var arr [r]T
 			// n = arr[:l]
 			t = aindex(r, t.Type) // [r]T
@@ -1647,6 +1663,22 @@ ret:
 	*np = n
 }
 
+func reduceSlice(n *Node) *Node {
+	r := n.Right.Right
+	if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
+		// Reduce x[i:len(x)] to x[i:].
+		n.Right.Right = nil
+	}
+	if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
+		// Reduce x[:] to x.
+		if Debug_slice > 0 {
+			Warn("slice: omit slice operation")
+		}
+		return n.Left
+	}
+	return n
+}
+
 func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
 	// convas will turn map assigns into function calls,
 	// making it impossible for reorder3 to work.
@@ -2108,9 +2140,8 @@ func isstack(n *Node) bool {
 	}
 
 	switch n.Op {
-	// OINDREG only ends up in walk if it's indirect of SP.
 	case OINDREG:
-		return true
+		return n.Reg == int16(Thearch.REGSP)
 
 	case ONAME:
 		switch n.Class {
@@ -2185,26 +2216,6 @@ func needwritebarrier(l *Node, r *Node) bool {
 		return false
 	}
 
-	// No write barrier for reslice: x = x[0:y] or x = append(x, ...).
-	// Both are compiled to modify x directly.
-	// In the case of append, a write barrier may still be needed
-	// if the underlying array grows, but the append code can
-	// generate the write barrier directly in that case.
-	// (It does not yet, but the cost of the write barrier will be
-	// small compared to the cost of the allocation.)
-	if r.Reslice {
-		switch r.Op {
-		case OSLICE, OSLICE3, OSLICESTR, OAPPEND:
-			break
-
-		default:
-			Dump("bad reslice-l", l)
-			Dump("bad reslice-r", r)
-		}
-
-		return false
-	}
-
 	// Otherwise, be conservative and use write barrier.
 	return true
 }
@@ -2215,65 +2226,11 @@ var applywritebarrier_bv Bvec
 
 func applywritebarrier(n *Node, init **NodeList) *Node {
 	if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
-		if Curfn != nil && Curfn.Func.Nowritebarrier {
-			Yyerror("write barrier prohibited")
-		}
-		if flag_race == 0 {
-			if Debug_wb > 1 {
-				Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
-			}
-			n.Op = OASWB
-			return n
-		}
-		// Use slow path always for race detector.
-		if Debug_wb > 0 {
-			Warnl(int(n.Lineno), "write barrier")
-		}
-		t := n.Left.Type
-		l := Nod(OADDR, n.Left, nil)
-		l.Etype = 1 // addr does not escape
-		if t.Width == int64(Widthptr) {
-			n = mkcall1(writebarrierfn("writebarrierptr", t, n.Right.Type), nil, init, l, n.Right)
-		} else if t.Etype == TSTRING {
-			n = mkcall1(writebarrierfn("writebarrierstring", t, n.Right.Type), nil, init, l, n.Right)
-		} else if Isslice(t) {
-			n = mkcall1(writebarrierfn("writebarrierslice", t, n.Right.Type), nil, init, l, n.Right)
-		} else if Isinter(t) {
-			n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right)
-		} else if t.Width <= int64(4*Widthptr) {
-			x := int64(0)
-			if applywritebarrier_bv.b == nil {
-				applywritebarrier_bv = bvalloc(4)
-			}
-			bvresetall(applywritebarrier_bv)
-			onebitwalktype1(t, &x, applywritebarrier_bv)
-			var name string
-			switch t.Width / int64(Widthptr) {
-			default:
-				Fatal("found writebarrierfat for %d-byte object of type %v", int(t.Width), t)
-
-			case 2:
-				name = fmt.Sprintf("writebarrierfat%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1))
-
-			case 3:
-				name = fmt.Sprintf("writebarrierfat%d%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1), bvget(applywritebarrier_bv, 2))
-
-			case 4:
-				name = fmt.Sprintf("writebarrierfat%d%d%d%d", bvget(applywritebarrier_bv, 0), bvget(applywritebarrier_bv, 1), bvget(applywritebarrier_bv, 2), bvget(applywritebarrier_bv, 3))
-			}
-
-			n = mkcall1(writebarrierfn(name, t, n.Right.Type), nil, init, l, Nodintconst(0), n.Right)
-		} else {
-			r := n.Right
-			for r.Op == OCONVNOP {
-				r = r.Left
-			}
-			r = Nod(OADDR, r, nil)
-			r.Etype = 1 // addr does not escape
-
-			//warnl(n->lineno, "typedmemmove %T %N", t, r);
-			n = mkcall1(writebarrierfn("typedmemmove", t, r.Left.Type), nil, init, typename(t), l, r)
+		if Debug_wb > 1 {
+			Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
 		}
+		n.Op = OASWB
+		return n
 	}
 	return n
 }
@@ -2728,10 +2685,10 @@ func paramstoheap(argin **Type, out int) *NodeList {
 		if v.Alloc == nil {
 			v.Alloc = callnew(v.Type)
 		}
-		nn = list(nn, Nod(OAS, v.Heapaddr, v.Alloc))
+		nn = list(nn, Nod(OAS, v.Name.Heapaddr, v.Alloc))
 		if v.Class&^PHEAP != PPARAMOUT {
-			as = Nod(OAS, v, v.Stackparam)
-			v.Stackparam.Typecheck = 1
+			as = Nod(OAS, v, v.Param.Stackparam)
+			v.Param.Stackparam.Typecheck = 1
 			typecheck(&as, Etop)
 			as = applywritebarrier(as, &nn)
 			nn = list(nn, as)
@@ -2754,7 +2711,7 @@ func returnsfromheap(argin **Type) *NodeList {
 		if v == nil || v.Class != PHEAP|PPARAMOUT {
 			continue
 		}
-		nn = list(nn, Nod(OAS, v.Stackparam, v))
+		nn = list(nn, Nod(OAS, v.Param.Stackparam, v))
 	}
 
 	return nn
@@ -2871,7 +2828,7 @@ func addstr(n *Node, init **NodeList) *Node {
 		sz := int64(0)
 		for l := n.List; l != nil; l = l.Next {
 			if n.Op == OLITERAL {
-				sz += int64(len(n.Val.U.Sval))
+				sz += int64(len(n.Val.U.(string)))
 			}
 		}
 
@@ -3026,7 +2983,13 @@ func appendslice(n *Node, init **NodeList) *Node {
 	return s
 }
 
-// expand append(src, a [, b]* ) to
+// Rewrite append(src, x, y, z) so that any side effects in
+// x, y, z (including runtime panics) are evaluated in
+// initialization statements before the append.
+// For normal code generation, stop there and leave the
+// rest to cgen_append.
+//
+// For race detector, expand append(src, a [, b]* ) to
 //
 //   init {
 //     s := src
@@ -3041,13 +3004,21 @@ func appendslice(n *Node, init **NodeList) *Node {
 //     ...
 //   }
 //   s
-func walkappend(n *Node, init **NodeList) *Node {
-	walkexprlistsafe(n.List, init)
+func walkappend(n *Node, init **NodeList, dst *Node) *Node {
+	if !samesafeexpr(dst, n.List.N) {
+		l := n.List
+		l.N = safeexpr(l.N, init)
+		walkexpr(&l.N, init)
+	}
+	walkexprlistsafe(n.List.Next, init)
 
 	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
 	// and n are name or literal, but those may index the slice we're
 	// modifying here.  Fix explicitly.
-	for l := n.List; l != nil; l = l.Next {
+	// Using cheapexpr also makes sure that the evaluation
+	// of all arguments (and especially any panics) happen
+	// before we begin to modify the slice in a visible way.
+	for l := n.List.Next; l != nil; l = l.Next {
 		l.N = cheapexpr(l.N, init)
 	}
 
@@ -3062,6 +3033,12 @@ func walkappend(n *Node, init **NodeList) *Node {
 		return nsrc
 	}
 
+	// General case, with no function calls left as arguments.
+	// Leave for gen, except that race detector requires old form
+	if flag_race == 0 {
+		return n
+	}
+
 	var l *NodeList
 
 	ns := temp(nsrc.Type)
@@ -3166,213 +3143,6 @@ func copyany(n *Node, init **NodeList, runtimecall int) *Node {
 	return nlen
 }
 
-// Generate frontend part for OSLICE[3][ARR|STR]
-//
-func sliceany(n *Node, init **NodeList) *Node {
-	var hb *Node
-	var cb *Node
-
-	//	print("before sliceany: %+N\n", n);
-
-	src := n.Left
-
-	lb := n.Right.Left
-	slice3 := n.Op == OSLICE3 || n.Op == OSLICE3ARR
-	if slice3 {
-		hb = n.Right.Right.Left
-		cb = n.Right.Right.Right
-	} else {
-		hb = n.Right.Right
-		cb = nil
-	}
-
-	bounded := int(n.Etype)
-
-	var bound *Node
-	if n.Op == OSLICESTR {
-		bound = Nod(OLEN, src, nil)
-	} else {
-		bound = Nod(OCAP, src, nil)
-	}
-
-	typecheck(&bound, Erv)
-	walkexpr(&bound, init) // if src is an array, bound will be a const now.
-
-	// static checks if possible
-	bv := int64(1 << 50)
-
-	if Isconst(bound, CTINT) {
-		if !Smallintconst(bound) {
-			Yyerror("array len too large")
-		} else {
-			bv = Mpgetfix(bound.Val.U.Xval)
-		}
-	}
-
-	if Isconst(cb, CTINT) {
-		cbv := Mpgetfix(cb.Val.U.Xval)
-		if cbv < 0 || cbv > bv {
-			Yyerror("slice index out of bounds")
-		}
-	}
-
-	if Isconst(hb, CTINT) {
-		hbv := Mpgetfix(hb.Val.U.Xval)
-		if hbv < 0 || hbv > bv {
-			Yyerror("slice index out of bounds")
-		}
-	}
-
-	if Isconst(lb, CTINT) {
-		lbv := Mpgetfix(lb.Val.U.Xval)
-		if lbv < 0 || lbv > bv {
-			Yyerror("slice index out of bounds")
-			lbv = -1
-		}
-
-		if lbv == 0 {
-			lb = nil
-		}
-	}
-
-	// Checking src[lb:hb:cb] or src[lb:hb].
-	// if chk0 || chk1 || chk2 { panicslice() }
-
-	// All comparisons are unsigned to avoid testing < 0.
-	bt := Types[Simtype[TUINT]]
-
-	if cb != nil && cb.Type.Width > 4 {
-		bt = Types[TUINT64]
-	}
-	if hb != nil && hb.Type.Width > 4 {
-		bt = Types[TUINT64]
-	}
-	if lb != nil && lb.Type.Width > 4 {
-		bt = Types[TUINT64]
-	}
-
-	bound = cheapexpr(conv(bound, bt), init)
-
-	var chk0 *Node // cap(src) < cb
-	if cb != nil {
-		cb = cheapexpr(conv(cb, bt), init)
-		if bounded == 0 {
-			chk0 = Nod(OLT, bound, cb)
-		}
-	} else if slice3 {
-		// When we figure out what this means, implement it.
-		Fatal("slice3 with cb == N") // rejected by parser
-	}
-
-	var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
-	if hb != nil {
-		hb = cheapexpr(conv(hb, bt), init)
-		if bounded == 0 {
-			if cb != nil {
-				chk1 = Nod(OLT, cb, hb)
-			} else {
-				chk1 = Nod(OLT, bound, hb)
-			}
-		}
-	} else if slice3 {
-		// When we figure out what this means, implement it.
-		Fatal("slice3 with hb == N") // rejected by parser
-	} else if n.Op == OSLICEARR {
-		hb = bound
-	} else {
-		hb = Nod(OLEN, src, nil)
-		typecheck(&hb, Erv)
-		walkexpr(&hb, init)
-		hb = cheapexpr(conv(hb, bt), init)
-	}
-
-	var chk2 *Node // hb < lb
-	if lb != nil {
-		lb = cheapexpr(conv(lb, bt), init)
-		if bounded == 0 {
-			chk2 = Nod(OLT, hb, lb)
-		}
-	}
-
-	if chk0 != nil || chk1 != nil || chk2 != nil {
-		chk := Nod(OIF, nil, nil)
-		chk.Nbody = list1(mkcall("panicslice", nil, init))
-		chk.Likely = -1
-		if chk0 != nil {
-			chk.Ntest = chk0
-		}
-		if chk1 != nil {
-			if chk.Ntest == nil {
-				chk.Ntest = chk1
-			} else {
-				chk.Ntest = Nod(OOROR, chk.Ntest, chk1)
-			}
-		}
-
-		if chk2 != nil {
-			if chk.Ntest == nil {
-				chk.Ntest = chk2
-			} else {
-				chk.Ntest = Nod(OOROR, chk.Ntest, chk2)
-			}
-		}
-
-		typecheck(&chk, Etop)
-		walkstmt(&chk)
-		*init = concat(*init, chk.Ninit)
-		chk.Ninit = nil
-		*init = list(*init, chk)
-	}
-
-	// prepare new cap, len and offs for backend cgen_slice
-	// cap = bound [ - lo ]
-	n.Right = nil
-
-	n.List = nil
-	if !slice3 {
-		cb = bound
-	}
-	if lb == nil {
-		bound = conv(cb, Types[Simtype[TUINT]])
-	} else {
-		bound = Nod(OSUB, conv(cb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
-	}
-	typecheck(&bound, Erv)
-	walkexpr(&bound, init)
-	n.List = list(n.List, bound)
-
-	// len = hi [ - lo]
-	if lb == nil {
-		hb = conv(hb, Types[Simtype[TUINT]])
-	} else {
-		hb = Nod(OSUB, conv(hb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]]))
-	}
-	typecheck(&hb, Erv)
-	walkexpr(&hb, init)
-	n.List = list(n.List, hb)
-
-	// offs = [width *] lo, but omit if zero
-	if lb != nil {
-		var w int64
-		if n.Op == OSLICESTR {
-			w = 1
-		} else {
-			w = n.Type.Type.Width
-		}
-		lb = conv(lb, Types[TUINTPTR])
-		if w > 1 {
-			lb = Nod(OMUL, Nodintconst(w), lb)
-		}
-		typecheck(&lb, Erv)
-		walkexpr(&lb, init)
-		n.List = list(n.List, lb)
-	}
-
-	//	print("after sliceany: %+N\n", n);
-
-	return n
-}
-
 func eqfor(t *Type, needsize *int) *Node {
 	// Should only arrive here with large memory or
 	// a struct/array containing a non-memory field/element.
@@ -3611,7 +3381,7 @@ func samecheap(a *Node, b *Node) bool {
 		case OINDEX:
 			ar = a.Right
 			br = b.Right
-			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.Xval, br.Val.U.Xval) != 0 {
+			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.(*Mpint), br.Val.U.(*Mpint)) != 0 {
 				return false
 			}
 		}
@@ -3647,9 +3417,9 @@ func walkrotate(np **Node) {
 	w := int(l.Type.Width * 8)
 
 	if Smallintconst(l.Right) && Smallintconst(r.Right) {
-		sl := int(Mpgetfix(l.Right.Val.U.Xval))
+		sl := int(Mpgetfix(l.Right.Val.U.(*Mpint)))
 		if sl >= 0 {
-			sr := int(Mpgetfix(r.Right.Val.U.Xval))
+			sr := int(Mpgetfix(r.Right.Val.U.(*Mpint)))
 			if sr >= 0 && sl+sr == w {
 				// Rewrite left shift half to left rotate.
 				if l.Op == OLSH {
@@ -3660,7 +3430,7 @@ func walkrotate(np **Node) {
 				n.Op = OLROT
 
 				// Remove rotate 0 and rotate w.
-				s := int(Mpgetfix(n.Right.Val.U.Xval))
+				s := int(Mpgetfix(n.Right.Val.U.(*Mpint)))
 
 				if s == 0 || s == w {
 					n = n.Left
@@ -3703,7 +3473,7 @@ func walkmul(np **Node, init **NodeList) {
 	// x*0 is 0 (and side effects of x).
 	var pow int
 	var w int
-	if Mpgetfix(nr.Val.U.Xval) == 0 {
+	if Mpgetfix(nr.Val.U.(*Mpint)) == 0 {
 		cheapexpr(nl, init)
 		Nodconst(n, n.Type, 0)
 		goto ret
@@ -3796,10 +3566,10 @@ func walkdiv(np **Node, init **NodeList) {
 		m.W = w
 
 		if Issigned[nl.Type.Etype] {
-			m.Sd = Mpgetfix(nr.Val.U.Xval)
+			m.Sd = Mpgetfix(nr.Val.U.(*Mpint))
 			Smagic(&m)
 		} else {
-			m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
+			m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint)))
 			Umagic(&m)
 		}
 
@@ -3993,7 +3763,7 @@ func walkdiv(np **Node, init **NodeList) {
 			// n = nl & (nr-1)
 			n.Op = OAND
 
-			Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.Xval)-1)
+			Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.(*Mpint))-1)
 		} else {
 			// n = nl >> pow
 			n.Op = ORSH
@@ -4023,7 +3793,7 @@ func bounded(n *Node, max int64) bool {
 	bits := int32(8 * n.Type.Width)
 
 	if Smallintconst(n) {
-		v := Mpgetfix(n.Val.U.Xval)
+		v := Mpgetfix(n.Val.U.(*Mpint))
 		return 0 <= v && v < max
 	}
 
@@ -4031,9 +3801,9 @@ func bounded(n *Node, max int64) bool {
 	case OAND:
 		v := int64(-1)
 		if Smallintconst(n.Left) {
-			v = Mpgetfix(n.Left.Val.U.Xval)
+			v = Mpgetfix(n.Left.Val.U.(*Mpint))
 		} else if Smallintconst(n.Right) {
-			v = Mpgetfix(n.Right.Val.U.Xval)
+			v = Mpgetfix(n.Right.Val.U.(*Mpint))
 		}
 
 		if 0 <= v && v < max {
@@ -4042,7 +3812,7 @@ func bounded(n *Node, max int64) bool {
 
 	case OMOD:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val.U.Xval)
+			v := Mpgetfix(n.Right.Val.U.(*Mpint))
 			if 0 <= v && v <= max {
 				return true
 			}
@@ -4050,7 +3820,7 @@ func bounded(n *Node, max int64) bool {
 
 	case ODIV:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val.U.Xval)
+			v := Mpgetfix(n.Right.Val.U.(*Mpint))
 			for bits > 0 && v >= 2 {
 				bits--
 				v >>= 1
@@ -4059,7 +3829,7 @@ func bounded(n *Node, max int64) bool {
 
 	case ORSH:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val.U.Xval)
+			v := Mpgetfix(n.Right.Val.U.(*Mpint))
 			if v > int64(bits) {
 				return true
 			}
@@ -4192,17 +3962,17 @@ func candiscard(n *Node) bool {
 
 		// Discardable as long as we know it's not division by zero.
 	case ODIV, OMOD:
-		if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 {
+		if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.(*Mpint), 0) != 0 {
 			break
 		}
-		if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.Fval, 0) != 0 {
+		if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.(*Mpflt), 0) != 0 {
 			break
 		}
 		return false
 
 		// Discardable as long as we know it won't fail because of a bad size.
 	case OMAKECHAN, OMAKEMAP:
-		if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 {
+		if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.(*Mpint), 0) == 0 {
 			break
 		}
 		return false
@@ -4256,7 +4026,7 @@ func walkprintfunc(np **Node, init **NodeList) {
 	buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
 	fn.Nname = newname(Lookup(buf))
 	fn.Nname.Defn = fn
-	fn.Nname.Ntype = t
+	fn.Nname.Param.Ntype = t
 	declare(fn.Nname, PFUNC)
 
 	oldfn := Curfn
diff --git a/src/cmd/internal/gc/y.go b/src/cmd/compile/internal/gc/y.go
similarity index 92%
rename from src/cmd/internal/gc/y.go
rename to src/cmd/compile/internal/gc/y.go
index f2c8b96982..56b9d04ecb 100644
--- a/src/cmd/internal/gc/y.go
+++ b/src/cmd/compile/internal/gc/y.go
@@ -5,10 +5,11 @@ import __yyfmt__ "fmt"
 
 //line go.y:21
 import (
+	"fmt"
 	"strings"
 )
 
-//line go.y:27
+//line go.y:28
 type yySymType struct {
 	yys  int
 	node *Node
@@ -153,7 +154,7 @@ const yyEofCode = 1
 const yyErrCode = 2
 const yyMaxDepth = 200
 
-//line go.y:2242
+//line go.y:2304
 func fixlbrace(lbr int) {
 	// If the opening brace was an LBODY,
 	// set up for another one now that we're done.
@@ -856,6 +857,34 @@ var yyTok3 = [...]int{
 	0,
 }
 
+var yyErrorMessages = [...]struct {
+	state int
+	token int
+	msg   string
+}{
+	{332, 76, "unexpected comma during import block"},
+	{89, 63, "missing import path; require quoted string"},
+	{390, 63, "missing { after if clause"},
+	{387, 63, "missing { after switch clause"},
+	{279, 63, "missing { after for clause"},
+	{498, 36, "missing { after for clause"},
+	{17, 68, "unexpected semicolon or newline before {"},
+	{111, 63, "unexpected semicolon or newline in type declaration"},
+	{78, 69, "unexpected } in channel type"},
+	{78, 61, "unexpected ) in channel type"},
+	{78, 76, "unexpected comma in channel type"},
+	{416, 15, "unexpected semicolon or newline before else"},
+	{329, 76, "name list not allowed in interface type"},
+	{279, 33, "var declaration not allowed in for initializer"},
+	{25, 68, "unexpected { at end of statement"},
+	{371, 68, "unexpected { at end of statement"},
+	{122, 63, "argument to go/defer must be function call"},
+	{398, 63, "need trailing comma before newline in composite literal"},
+	{414, 63, "need trailing comma before newline in composite literal"},
+	{124, 25, "nested func not allowed"},
+	{650, 63, "else must be followed by if or statement block"},
+}
+
 //line yaccpar:1
 
 /*	parser for yacc output	*/
@@ -877,7 +906,6 @@ type yyParser interface {
 
 type yyParserImpl struct {
 	lookahead func() int
-	state     func() int
 }
 
 func (p *yyParserImpl) Lookahead() int {
@@ -887,7 +915,6 @@ func (p *yyParserImpl) Lookahead() int {
 func yyNewParser() yyParser {
 	p := &yyParserImpl{
 		lookahead: func() int { return -1 },
-		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -918,6 +945,13 @@ func yyErrorMessage(state, lookAhead int) string {
 	if !yyErrorVerbose {
 		return "syntax error"
 	}
+
+	for _, e := range yyErrorMessages {
+		if e.state == state && e.token == lookAhead {
+			return "syntax error: " + e.msg
+		}
+	}
+
 	res := "syntax error: unexpected " + yyTokname(lookAhead)
 
 	// To match Bison, suggest at most four expected tokens.
@@ -1020,7 +1054,6 @@ func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int {
 	yystate := 0
 	yychar := -1
 	yytoken := -1 // yychar translated into internal numbering
-	yyrcvr.state = func() int { return yystate }
 	yyrcvr.lookahead = func() int { return yychar }
 	defer func() {
 		// Make sure we report no lookahead when not parsing.
@@ -1187,13 +1220,13 @@ yydefault:
 
 	case 1:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:127
+		//line go.y:189
 		{
 			xtop = concat(xtop, yyDollar[4].list)
 		}
 	case 2:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:133
+		//line go.y:195
 		{
 			prevlineno = lineno
 			Yyerror("package statement must be first")
@@ -1201,13 +1234,13 @@ yydefault:
 		}
 	case 3:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:139
+		//line go.y:201
 		{
 			mkpackage(yyDollar[2].sym.Name)
 		}
 	case 4:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:149
+		//line go.y:211
 		{
 			importpkg = Runtimepkg
 
@@ -1220,13 +1253,13 @@ yydefault:
 		}
 	case 5:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:161
+		//line go.y:223
 		{
 			importpkg = nil
 		}
 	case 11:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:175
+		//line go.y:237
 		{
 			ipkg := importpkg
 			my := importmyname
@@ -1263,7 +1296,7 @@ yydefault:
 		}
 	case 12:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:210
+		//line go.y:272
 		{
 			// When an invalid import path is passed to importfile,
 			// it calls Yyerror and then sets up a fake import with
@@ -1275,7 +1308,7 @@ yydefault:
 		}
 	case 15:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:226
+		//line go.y:288
 		{
 			// import with original name
 			yyVAL.i = parserline()
@@ -1284,7 +1317,7 @@ yydefault:
 		}
 	case 16:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:233
+		//line go.y:295
 		{
 			// import with given name
 			yyVAL.i = parserline()
@@ -1293,7 +1326,7 @@ yydefault:
 		}
 	case 17:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:240
+		//line go.y:302
 		{
 			// import into my name space
 			yyVAL.i = parserline()
@@ -1302,7 +1335,7 @@ yydefault:
 		}
 	case 18:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:249
+		//line go.y:311
 		{
 			if importpkg.Name == "" {
 				importpkg.Name = yyDollar[2].sym.Name
@@ -1319,7 +1352,7 @@ yydefault:
 		}
 	case 20:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:266
+		//line go.y:328
 		{
 			if yyDollar[1].sym.Name == "safe" {
 				curio.importsafe = true
@@ -1327,64 +1360,64 @@ yydefault:
 		}
 	case 21:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:273
+		//line go.y:335
 		{
 			defercheckwidth()
 		}
 	case 22:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:277
+		//line go.y:339
 		{
 			resumecheckwidth()
 			unimportfile()
 		}
 	case 23:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:286
+		//line go.y:348
 		{
 			Yyerror("empty top-level declaration")
 			yyVAL.list = nil
 		}
 	case 25:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:292
+		//line go.y:354
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 26:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:296
+		//line go.y:358
 		{
 			Yyerror("non-declaration statement outside function body")
 			yyVAL.list = nil
 		}
 	case 27:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:301
+		//line go.y:363
 		{
 			yyVAL.list = nil
 		}
 	case 28:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:307
+		//line go.y:369
 		{
 			yyVAL.list = yyDollar[2].list
 		}
 	case 29:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:311
+		//line go.y:373
 		{
 			yyVAL.list = yyDollar[3].list
 		}
 	case 30:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:315
+		//line go.y:377
 		{
 			yyVAL.list = nil
 		}
 	case 31:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:319
+		//line go.y:381
 		{
 			yyVAL.list = yyDollar[2].list
 			iota_ = -100000
@@ -1392,7 +1425,7 @@ yydefault:
 		}
 	case 32:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:325
+		//line go.y:387
 		{
 			yyVAL.list = yyDollar[3].list
 			iota_ = -100000
@@ -1400,7 +1433,7 @@ yydefault:
 		}
 	case 33:
 		yyDollar = yyS[yypt-7 : yypt+1]
-		//line go.y:331
+		//line go.y:393
 		{
 			yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list)
 			iota_ = -100000
@@ -1408,80 +1441,80 @@ yydefault:
 		}
 	case 34:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:337
+		//line go.y:399
 		{
 			yyVAL.list = nil
 			iota_ = -100000
 		}
 	case 35:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:342
+		//line go.y:404
 		{
 			yyVAL.list = list1(yyDollar[2].node)
 		}
 	case 36:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:346
+		//line go.y:408
 		{
 			yyVAL.list = yyDollar[3].list
 		}
 	case 37:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:350
+		//line go.y:412
 		{
 			yyVAL.list = nil
 		}
 	case 38:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:356
+		//line go.y:418
 		{
 			iota_ = 0
 		}
 	case 39:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:362
+		//line go.y:424
 		{
 			yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil)
 		}
 	case 40:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:366
+		//line go.y:428
 		{
 			yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
 		}
 	case 41:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:370
+		//line go.y:432
 		{
 			yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list)
 		}
 	case 42:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:376
+		//line go.y:438
 		{
 			yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
 		}
 	case 43:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:380
+		//line go.y:442
 		{
 			yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list)
 		}
 	case 45:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:387
+		//line go.y:449
 		{
 			yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil)
 		}
 	case 46:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:391
+		//line go.y:453
 		{
 			yyVAL.list = constiter(yyDollar[1].list, nil, nil)
 		}
 	case 47:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:397
+		//line go.y:459
 		{
 			// different from dclname because the name
 			// becomes visible right here, not at the end
@@ -1490,13 +1523,13 @@ yydefault:
 		}
 	case 48:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:406
+		//line go.y:468
 		{
 			yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true)
 		}
 	case 49:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:412
+		//line go.y:474
 		{
 			yyVAL.node = yyDollar[1].node
 
@@ -1512,14 +1545,14 @@ yydefault:
 		}
 	case 50:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:426
+		//line go.y:488
 		{
 			yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node)
 			yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode
 		}
 	case 51:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:431
+		//line go.y:493
 		{
 			if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil {
 				// simple
@@ -1533,7 +1566,7 @@ yydefault:
 		}
 	case 52:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:443
+		//line go.y:505
 		{
 			if yyDollar[3].list.N.Op == OTYPESW {
 				yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right)
@@ -1553,7 +1586,7 @@ yydefault:
 		}
 	case 53:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:461
+		//line go.y:523
 		{
 			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
 			yyVAL.node.Implicit = true
@@ -1561,7 +1594,7 @@ yydefault:
 		}
 	case 54:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:467
+		//line go.y:529
 		{
 			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
 			yyVAL.node.Implicit = true
@@ -1569,7 +1602,7 @@ yydefault:
 		}
 	case 55:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:475
+		//line go.y:537
 		{
 			var n, nn *Node
 
@@ -1594,7 +1627,7 @@ yydefault:
 		}
 	case 56:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:498
+		//line go.y:560
 		{
 			var n *Node
 
@@ -1614,7 +1647,7 @@ yydefault:
 		}
 	case 57:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:516
+		//line go.y:578
 		{
 			// will be converted to OCASE
 			// right will point to next case
@@ -1625,7 +1658,7 @@ yydefault:
 		}
 	case 58:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:525
+		//line go.y:587
 		{
 			var n, nn *Node
 
@@ -1646,13 +1679,13 @@ yydefault:
 		}
 	case 59:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:546
+		//line go.y:608
 		{
 			markdcl()
 		}
 	case 60:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:550
+		//line go.y:612
 		{
 			if yyDollar[3].list == nil {
 				yyVAL.node = Nod(OEMPTY, nil, nil)
@@ -1663,7 +1696,7 @@ yydefault:
 		}
 	case 61:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:561
+		//line go.y:623
 		{
 			// If the last token read by the lexer was consumed
 			// as part of the case, clear it (parser has cleared yychar).
@@ -1676,7 +1709,7 @@ yydefault:
 		}
 	case 62:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:572
+		//line go.y:634
 		{
 			// This is the only place in the language where a statement
 			// list is not allowed to drop the final semicolon, because
@@ -1696,32 +1729,32 @@ yydefault:
 		}
 	case 63:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:591
+		//line go.y:653
 		{
 			yyVAL.list = nil
 		}
 	case 64:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:595
+		//line go.y:657
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[2].node)
 		}
 	case 65:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:601
+		//line go.y:663
 		{
 			markdcl()
 		}
 	case 66:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:605
+		//line go.y:667
 		{
 			yyVAL.list = yyDollar[3].list
 			popdcl()
 		}
 	case 67:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:612
+		//line go.y:674
 		{
 			yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
 			yyVAL.node.List = yyDollar[1].list
@@ -1729,7 +1762,7 @@ yydefault:
 		}
 	case 68:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:618
+		//line go.y:680
 		{
 			yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
 			yyVAL.node.List = yyDollar[1].list
@@ -1738,14 +1771,14 @@ yydefault:
 		}
 	case 69:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:625
+		//line go.y:687
 		{
 			yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node)
 			yyVAL.node.Etype = 0 // := flag
 		}
 	case 70:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:632
+		//line go.y:694
 		{
 			// init ; test ; incr
 			if yyDollar[5].node != nil && yyDollar[5].node.Colas {
@@ -1760,7 +1793,7 @@ yydefault:
 		}
 	case 71:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:645
+		//line go.y:707
 		{
 			// normal test
 			yyVAL.node = Nod(OFOR, nil, nil)
@@ -1768,27 +1801,27 @@ yydefault:
 		}
 	case 73:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:654
+		//line go.y:716
 		{
 			yyVAL.node = yyDollar[1].node
 			yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list)
 		}
 	case 74:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:661
+		//line go.y:723
 		{
 			markdcl()
 		}
 	case 75:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:665
+		//line go.y:727
 		{
 			yyVAL.node = yyDollar[3].node
 			popdcl()
 		}
 	case 76:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:672
+		//line go.y:734
 		{
 			// test
 			yyVAL.node = Nod(OIF, nil, nil)
@@ -1796,7 +1829,7 @@ yydefault:
 		}
 	case 77:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:678
+		//line go.y:740
 		{
 			// init ; test
 			yyVAL.node = Nod(OIF, nil, nil)
@@ -1807,13 +1840,13 @@ yydefault:
 		}
 	case 78:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:690
+		//line go.y:752
 		{
 			markdcl()
 		}
 	case 79:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:694
+		//line go.y:756
 		{
 			if yyDollar[3].node.Ntest == nil {
 				Yyerror("missing condition in if statement")
@@ -1821,13 +1854,13 @@ yydefault:
 		}
 	case 80:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:700
+		//line go.y:762
 		{
 			yyDollar[3].node.Nbody = yyDollar[5].list
 		}
 	case 81:
 		yyDollar = yyS[yypt-8 : yypt+1]
-		//line go.y:704
+		//line go.y:766
 		{
 			var n *Node
 			var nn *NodeList
@@ -1845,13 +1878,13 @@ yydefault:
 		}
 	case 82:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:722
+		//line go.y:784
 		{
 			markdcl()
 		}
 	case 83:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:726
+		//line go.y:788
 		{
 			if yyDollar[4].node.Ntest == nil {
 				Yyerror("missing condition in if statement")
@@ -1861,25 +1894,25 @@ yydefault:
 		}
 	case 84:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:735
+		//line go.y:797
 		{
 			yyVAL.list = nil
 		}
 	case 85:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:739
+		//line go.y:801
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
 		}
 	case 86:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:744
+		//line go.y:806
 		{
 			yyVAL.list = nil
 		}
 	case 87:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:748
+		//line go.y:810
 		{
 			l := &NodeList{N: yyDollar[2].node}
 			l.End = l
@@ -1887,13 +1920,13 @@ yydefault:
 		}
 	case 88:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:756
+		//line go.y:818
 		{
 			markdcl()
 		}
 	case 89:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:760
+		//line go.y:822
 		{
 			var n *Node
 			n = yyDollar[3].node.Ntest
@@ -1904,7 +1937,7 @@ yydefault:
 		}
 	case 90:
 		yyDollar = yyS[yypt-7 : yypt+1]
-		//line go.y:769
+		//line go.y:831
 		{
 			yyVAL.node = yyDollar[3].node
 			yyVAL.node.Op = OSWITCH
@@ -1914,13 +1947,13 @@ yydefault:
 		}
 	case 91:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:779
+		//line go.y:841
 		{
 			typesw = Nod(OXXX, typesw, nil)
 		}
 	case 92:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:783
+		//line go.y:845
 		{
 			yyVAL.node = Nod(OSELECT, nil, nil)
 			yyVAL.node.Lineno = typesw.Lineno
@@ -1929,133 +1962,133 @@ yydefault:
 		}
 	case 94:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:796
+		//line go.y:858
 		{
 			yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 95:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:800
+		//line go.y:862
 		{
 			yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 96:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:804
+		//line go.y:866
 		{
 			yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 97:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:808
+		//line go.y:870
 		{
 			yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 98:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:812
+		//line go.y:874
 		{
 			yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 99:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:816
+		//line go.y:878
 		{
 			yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 100:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:820
+		//line go.y:882
 		{
 			yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 101:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:824
+		//line go.y:886
 		{
 			yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 102:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:828
+		//line go.y:890
 		{
 			yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 103:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:832
+		//line go.y:894
 		{
 			yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 104:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:836
+		//line go.y:898
 		{
 			yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 105:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:840
+		//line go.y:902
 		{
 			yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 106:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:844
+		//line go.y:906
 		{
 			yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 107:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:848
+		//line go.y:910
 		{
 			yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 108:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:852
+		//line go.y:914
 		{
 			yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 109:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:856
+		//line go.y:918
 		{
 			yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 110:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:860
+		//line go.y:922
 		{
 			yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 111:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:864
+		//line go.y:926
 		{
 			yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 112:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:868
+		//line go.y:930
 		{
 			yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 113:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:873
+		//line go.y:935
 		{
 			yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 115:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:880
+		//line go.y:942
 		{
 			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
 		}
 	case 116:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:884
+		//line go.y:946
 		{
 			if yyDollar[2].node.Op == OCOMPLIT {
 				// Special case for &T{...}: turn into (*T){...}.
@@ -2068,57 +2101,57 @@ yydefault:
 		}
 	case 117:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:895
+		//line go.y:957
 		{
 			yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil)
 		}
 	case 118:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:899
+		//line go.y:961
 		{
 			yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil)
 		}
 	case 119:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:903
+		//line go.y:965
 		{
 			yyVAL.node = Nod(ONOT, yyDollar[2].node, nil)
 		}
 	case 120:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:907
+		//line go.y:969
 		{
 			Yyerror("the bitwise complement operator is ^")
 			yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
 		}
 	case 121:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:912
+		//line go.y:974
 		{
 			yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
 		}
 	case 122:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:916
+		//line go.y:978
 		{
 			yyVAL.node = Nod(ORECV, yyDollar[2].node, nil)
 		}
 	case 123:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:926
+		//line go.y:988
 		{
 			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
 		}
 	case 124:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:930
+		//line go.y:992
 		{
 			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
 			yyVAL.node.List = yyDollar[3].list
 		}
 	case 125:
 		yyDollar = yyS[yypt-6 : yypt+1]
-		//line go.y:935
+		//line go.y:997
 		{
 			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
 			yyVAL.node.List = yyDollar[3].list
@@ -2126,13 +2159,13 @@ yydefault:
 		}
 	case 126:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:943
+		//line go.y:1005
 		{
 			yyVAL.node = nodlit(yyDollar[1].val)
 		}
 	case 128:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:948
+		//line go.y:1010
 		{
 			if yyDollar[1].node.Op == OPACK {
 				var s *Sym
@@ -2145,31 +2178,31 @@ yydefault:
 		}
 	case 129:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:959
+		//line go.y:1021
 		{
 			yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node)
 		}
 	case 130:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:963
+		//line go.y:1025
 		{
 			yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node)
 		}
 	case 131:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:967
+		//line go.y:1029
 		{
 			yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 132:
 		yyDollar = yyS[yypt-6 : yypt+1]
-		//line go.y:971
+		//line go.y:1033
 		{
 			yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node))
 		}
 	case 133:
 		yyDollar = yyS[yypt-8 : yypt+1]
-		//line go.y:975
+		//line go.y:1037
 		{
 			if yyDollar[5].node == nil {
 				Yyerror("middle index required in 3-index slice")
@@ -2181,7 +2214,7 @@ yydefault:
 		}
 	case 135:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:986
+		//line go.y:1048
 		{
 			// conversion
 			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
@@ -2189,7 +2222,7 @@ yydefault:
 		}
 	case 136:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:992
+		//line go.y:1054
 		{
 			yyVAL.node = yyDollar[3].node
 			yyVAL.node.Right = yyDollar[1].node
@@ -2198,7 +2231,7 @@ yydefault:
 		}
 	case 137:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:999
+		//line go.y:1061
 		{
 			yyVAL.node = yyDollar[3].node
 			yyVAL.node.Right = yyDollar[1].node
@@ -2206,7 +2239,7 @@ yydefault:
 		}
 	case 138:
 		yyDollar = yyS[yypt-7 : yypt+1]
-		//line go.y:1005
+		//line go.y:1067
 		{
 			Yyerror("cannot parenthesize type in composite literal")
 			yyVAL.node = yyDollar[5].node
@@ -2215,7 +2248,7 @@ yydefault:
 		}
 	case 140:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1014
+		//line go.y:1076
 		{
 			// composite expression.
 			// make node early so we get the right line number.
@@ -2223,13 +2256,13 @@ yydefault:
 		}
 	case 141:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1022
+		//line go.y:1084
 		{
 			yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node)
 		}
 	case 142:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1028
+		//line go.y:1090
 		{
 			// These nodes do not carry line numbers.
 			// Since a composite literal commonly spans several lines,
@@ -2244,21 +2277,21 @@ yydefault:
 		}
 	case 143:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1041
+		//line go.y:1103
 		{
 			yyVAL.node = yyDollar[2].node
 			yyVAL.node.List = yyDollar[3].list
 		}
 	case 145:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1049
+		//line go.y:1111
 		{
 			yyVAL.node = yyDollar[2].node
 			yyVAL.node.List = yyDollar[3].list
 		}
 	case 147:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1057
+		//line go.y:1119
 		{
 			yyVAL.node = yyDollar[2].node
 
@@ -2272,19 +2305,19 @@ yydefault:
 		}
 	case 151:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1078
+		//line go.y:1140
 		{
 			yyVAL.i = LBODY
 		}
 	case 152:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1082
+		//line go.y:1144
 		{
 			yyVAL.i = '{'
 		}
 	case 153:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1093
+		//line go.y:1155
 		{
 			if yyDollar[1].sym == nil {
 				yyVAL.node = nil
@@ -2294,19 +2327,19 @@ yydefault:
 		}
 	case 154:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1103
+		//line go.y:1165
 		{
 			yyVAL.node = dclname(yyDollar[1].sym)
 		}
 	case 155:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1108
+		//line go.y:1170
 		{
 			yyVAL.node = nil
 		}
 	case 157:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1115
+		//line go.y:1177
 		{
 			yyVAL.sym = yyDollar[1].sym
 			// during imports, unqualified non-exported identifiers are from builtinpkg
@@ -2316,45 +2349,45 @@ yydefault:
 		}
 	case 159:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1124
+		//line go.y:1186
 		{
 			yyVAL.sym = nil
 		}
 	case 160:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1130
+		//line go.y:1192
 		{
 			var p *Pkg
 
-			if yyDollar[2].val.U.Sval == "" {
+			if yyDollar[2].val.U.(string) == "" {
 				p = importpkg
 			} else {
-				if isbadimport(yyDollar[2].val.U.Sval) {
+				if isbadimport(yyDollar[2].val.U.(string)) {
 					errorexit()
 				}
-				p = mkpkg(yyDollar[2].val.U.Sval)
+				p = mkpkg(yyDollar[2].val.U.(string))
 			}
 			yyVAL.sym = Pkglookup(yyDollar[4].sym.Name, p)
 		}
 	case 161:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1144
+		//line go.y:1206
 		{
 			var p *Pkg
 
-			if yyDollar[2].val.U.Sval == "" {
+			if yyDollar[2].val.U.(string) == "" {
 				p = importpkg
 			} else {
-				if isbadimport(yyDollar[2].val.U.Sval) {
+				if isbadimport(yyDollar[2].val.U.(string)) {
 					errorexit()
 				}
-				p = mkpkg(yyDollar[2].val.U.Sval)
+				p = mkpkg(yyDollar[2].val.U.(string))
 			}
 			yyVAL.sym = Pkglookup("?", p)
 		}
 	case 162:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1160
+		//line go.y:1222
 		{
 			yyVAL.node = oldname(yyDollar[1].sym)
 			if yyVAL.node.Pack != nil {
@@ -2363,38 +2396,38 @@ yydefault:
 		}
 	case 164:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1181
+		//line go.y:1243
 		{
 			Yyerror("final argument in variadic function missing type")
 			yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil)
 		}
 	case 165:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1186
+		//line go.y:1248
 		{
 			yyVAL.node = Nod(ODDD, yyDollar[2].node, nil)
 		}
 	case 171:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1197
+		//line go.y:1259
 		{
 			yyVAL.node = yyDollar[2].node
 		}
 	case 175:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1206
+		//line go.y:1268
 		{
 			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
 		}
 	case 180:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1216
+		//line go.y:1278
 		{
 			yyVAL.node = yyDollar[2].node
 		}
 	case 190:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1237
+		//line go.y:1299
 		{
 			if yyDollar[1].node.Op == OPACK {
 				var s *Sym
@@ -2407,53 +2440,53 @@ yydefault:
 		}
 	case 191:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1250
+		//line go.y:1312
 		{
 			yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node)
 		}
 	case 192:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1254
+		//line go.y:1316
 		{
 			// array literal of nelem
 			yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node)
 		}
 	case 193:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1259
+		//line go.y:1321
 		{
 			yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil)
 			yyVAL.node.Etype = Cboth
 		}
 	case 194:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1264
+		//line go.y:1326
 		{
 			yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
 			yyVAL.node.Etype = Csend
 		}
 	case 195:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1269
+		//line go.y:1331
 		{
 			yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node)
 		}
 	case 198:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1277
+		//line go.y:1339
 		{
 			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
 		}
 	case 199:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1283
+		//line go.y:1345
 		{
 			yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
 			yyVAL.node.Etype = Crecv
 		}
 	case 200:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1290
+		//line go.y:1352
 		{
 			yyVAL.node = Nod(OTSTRUCT, nil, nil)
 			yyVAL.node.List = yyDollar[3].list
@@ -2461,14 +2494,14 @@ yydefault:
 		}
 	case 201:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1296
+		//line go.y:1358
 		{
 			yyVAL.node = Nod(OTSTRUCT, nil, nil)
 			fixlbrace(yyDollar[2].i)
 		}
 	case 202:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1303
+		//line go.y:1365
 		{
 			yyVAL.node = Nod(OTINTER, nil, nil)
 			yyVAL.node.List = yyDollar[3].list
@@ -2476,14 +2509,14 @@ yydefault:
 		}
 	case 203:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1309
+		//line go.y:1371
 		{
 			yyVAL.node = Nod(OTINTER, nil, nil)
 			fixlbrace(yyDollar[2].i)
 		}
 	case 204:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1320
+		//line go.y:1382
 		{
 			yyVAL.node = yyDollar[2].node
 			if yyVAL.node == nil {
@@ -2501,7 +2534,7 @@ yydefault:
 		}
 	case 205:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1338
+		//line go.y:1400
 		{
 			var t *Node
 
@@ -2527,14 +2560,14 @@ yydefault:
 			yyVAL.node = Nod(ODCLFUNC, nil, nil)
 			yyVAL.node.Nname = newfuncname(yyDollar[1].sym)
 			yyVAL.node.Nname.Defn = yyVAL.node
-			yyVAL.node.Nname.Ntype = t // TODO: check if nname already has an ntype
+			yyVAL.node.Nname.Param.Ntype = t // TODO: check if nname already has an ntype
 			declare(yyVAL.node.Nname, PFUNC)
 
 			funchdr(yyVAL.node)
 		}
 	case 206:
 		yyDollar = yyS[yypt-8 : yypt+1]
-		//line go.y:1369
+		//line go.y:1431
 		{
 			var rcvr, t *Node
 
@@ -2564,7 +2597,7 @@ yydefault:
 			yyVAL.node.Func.Shortname = newfuncname(yyDollar[4].sym)
 			yyVAL.node.Nname = methodname1(yyVAL.node.Func.Shortname, rcvr.Right)
 			yyVAL.node.Nname.Defn = yyVAL.node
-			yyVAL.node.Nname.Ntype = t
+			yyVAL.node.Nname.Param.Ntype = t
 			yyVAL.node.Nname.Nointerface = nointerface
 			declare(yyVAL.node.Nname, PFUNC)
 
@@ -2572,7 +2605,7 @@ yydefault:
 		}
 	case 207:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1407
+		//line go.y:1469
 		{
 			var s *Sym
 			var t *Type
@@ -2599,7 +2632,7 @@ yydefault:
 		}
 	case 208:
 		yyDollar = yyS[yypt-8 : yypt+1]
-		//line go.y:1432
+		//line go.y:1494
 		{
 			yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right)
 			yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list)
@@ -2617,7 +2650,7 @@ yydefault:
 		}
 	case 209:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1450
+		//line go.y:1512
 		{
 			yyDollar[3].list = checkarglist(yyDollar[3].list, 1)
 			yyVAL.node = Nod(OTFUNC, nil, nil)
@@ -2626,13 +2659,13 @@ yydefault:
 		}
 	case 210:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1458
+		//line go.y:1520
 		{
 			yyVAL.list = nil
 		}
 	case 211:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1462
+		//line go.y:1524
 		{
 			yyVAL.list = yyDollar[2].list
 			if yyVAL.list == nil {
@@ -2641,51 +2674,51 @@ yydefault:
 		}
 	case 212:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1471
+		//line go.y:1533
 		{
 			yyVAL.list = nil
 		}
 	case 213:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1475
+		//line go.y:1537
 		{
 			yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node))
 		}
 	case 214:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1479
+		//line go.y:1541
 		{
 			yyDollar[2].list = checkarglist(yyDollar[2].list, 0)
 			yyVAL.list = yyDollar[2].list
 		}
 	case 215:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1486
+		//line go.y:1548
 		{
 			closurehdr(yyDollar[1].node)
 		}
 	case 216:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1492
+		//line go.y:1554
 		{
 			yyVAL.node = closurebody(yyDollar[3].list)
 			fixlbrace(yyDollar[2].i)
 		}
 	case 217:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1497
+		//line go.y:1559
 		{
 			yyVAL.node = closurebody(nil)
 		}
 	case 218:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1508
+		//line go.y:1570
 		{
 			yyVAL.list = nil
 		}
 	case 219:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1512
+		//line go.y:1574
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
 			if nsyntaxerrors == 0 {
@@ -2698,49 +2731,49 @@ yydefault:
 		}
 	case 221:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1526
+		//line go.y:1588
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
 		}
 	case 223:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1533
+		//line go.y:1595
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
 		}
 	case 224:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1539
+		//line go.y:1601
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 225:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1543
+		//line go.y:1605
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 227:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1550
+		//line go.y:1612
 		{
 			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
 		}
 	case 228:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1556
+		//line go.y:1618
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 229:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1560
+		//line go.y:1622
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 230:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1566
+		//line go.y:1628
 		{
 			var l *NodeList
 
@@ -2766,14 +2799,14 @@ yydefault:
 		}
 	case 231:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1590
+		//line go.y:1652
 		{
 			yyDollar[1].node.Val = yyDollar[2].val
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 232:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1595
+		//line go.y:1657
 		{
 			yyDollar[2].node.Val = yyDollar[4].val
 			yyVAL.list = list1(yyDollar[2].node)
@@ -2781,7 +2814,7 @@ yydefault:
 		}
 	case 233:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1601
+		//line go.y:1663
 		{
 			yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil)
 			yyDollar[2].node.Val = yyDollar[3].val
@@ -2789,7 +2822,7 @@ yydefault:
 		}
 	case 234:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1607
+		//line go.y:1669
 		{
 			yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
 			yyDollar[3].node.Val = yyDollar[5].val
@@ -2798,7 +2831,7 @@ yydefault:
 		}
 	case 235:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1614
+		//line go.y:1676
 		{
 			yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
 			yyDollar[3].node.Val = yyDollar[5].val
@@ -2807,7 +2840,7 @@ yydefault:
 		}
 	case 236:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1623
+		//line go.y:1685
 		{
 			var n *Node
 
@@ -2819,7 +2852,7 @@ yydefault:
 		}
 	case 237:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1633
+		//line go.y:1695
 		{
 			var pkg *Pkg
 
@@ -2834,33 +2867,33 @@ yydefault:
 		}
 	case 238:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1648
+		//line go.y:1710
 		{
 			yyVAL.node = embedded(yyDollar[1].sym, localpkg)
 		}
 	case 239:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1654
+		//line go.y:1716
 		{
 			yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node)
 			ifacedcl(yyVAL.node)
 		}
 	case 240:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1659
+		//line go.y:1721
 		{
 			yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym))
 		}
 	case 241:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1663
+		//line go.y:1725
 		{
 			yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym))
 			Yyerror("cannot parenthesize embedded type")
 		}
 	case 242:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1670
+		//line go.y:1732
 		{
 			// without func keyword
 			yyDollar[2].list = checkarglist(yyDollar[2].list, 1)
@@ -2870,7 +2903,7 @@ yydefault:
 		}
 	case 244:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1684
+		//line go.y:1746
 		{
 			yyVAL.node = Nod(ONONAME, nil, nil)
 			yyVAL.node.Sym = yyDollar[1].sym
@@ -2878,7 +2911,7 @@ yydefault:
 		}
 	case 245:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1690
+		//line go.y:1752
 		{
 			yyVAL.node = Nod(ONONAME, nil, nil)
 			yyVAL.node.Sym = yyDollar[1].sym
@@ -2886,56 +2919,56 @@ yydefault:
 		}
 	case 247:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1699
+		//line go.y:1761
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 248:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1703
+		//line go.y:1765
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 249:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1708
+		//line go.y:1770
 		{
 			yyVAL.list = nil
 		}
 	case 250:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1712
+		//line go.y:1774
 		{
 			yyVAL.list = yyDollar[1].list
 		}
 	case 251:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1720
+		//line go.y:1782
 		{
 			yyVAL.node = nil
 		}
 	case 253:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1725
+		//line go.y:1787
 		{
 			yyVAL.node = liststmt(yyDollar[1].list)
 		}
 	case 255:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1730
+		//line go.y:1792
 		{
 			yyVAL.node = nil
 		}
 	case 261:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1741
+		//line go.y:1803
 		{
 			yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil)
 			yyDollar[1].node.Sym = dclstack // context, for goto restrictions
 		}
 	case 262:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1746
+		//line go.y:1808
 		{
 			var l *NodeList
 
@@ -2948,7 +2981,7 @@ yydefault:
 		}
 	case 263:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1757
+		//line go.y:1819
 		{
 			// will be converted to OFALL
 			yyVAL.node = Nod(OXFALL, nil, nil)
@@ -2956,38 +2989,38 @@ yydefault:
 		}
 	case 264:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1763
+		//line go.y:1825
 		{
 			yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil)
 		}
 	case 265:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1767
+		//line go.y:1829
 		{
 			yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil)
 		}
 	case 266:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1771
+		//line go.y:1833
 		{
 			yyVAL.node = Nod(OPROC, yyDollar[2].node, nil)
 		}
 	case 267:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1775
+		//line go.y:1837
 		{
 			yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil)
 		}
 	case 268:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1779
+		//line go.y:1841
 		{
 			yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil)
 			yyVAL.node.Sym = dclstack // context, for goto restrictions
 		}
 	case 269:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1784
+		//line go.y:1846
 		{
 			yyVAL.node = Nod(ORETURN, nil, nil)
 			yyVAL.node.List = yyDollar[2].list
@@ -3009,7 +3042,7 @@ yydefault:
 		}
 	case 270:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1806
+		//line go.y:1868
 		{
 			yyVAL.list = nil
 			if yyDollar[1].node != nil {
@@ -3018,7 +3051,7 @@ yydefault:
 		}
 	case 271:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1813
+		//line go.y:1875
 		{
 			yyVAL.list = yyDollar[1].list
 			if yyDollar[3].node != nil {
@@ -3027,163 +3060,163 @@ yydefault:
 		}
 	case 272:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1822
+		//line go.y:1884
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 273:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1826
+		//line go.y:1888
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 274:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1832
+		//line go.y:1894
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 275:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1836
+		//line go.y:1898
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 276:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1842
+		//line go.y:1904
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 277:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1846
+		//line go.y:1908
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 278:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1852
+		//line go.y:1914
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 279:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1856
+		//line go.y:1918
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 280:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1865
+		//line go.y:1927
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 281:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1869
+		//line go.y:1931
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 282:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1873
+		//line go.y:1935
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 283:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1877
+		//line go.y:1939
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 284:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1882
+		//line go.y:1944
 		{
 			yyVAL.list = nil
 		}
 	case 285:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:1886
+		//line go.y:1948
 		{
 			yyVAL.list = yyDollar[1].list
 		}
 	case 290:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1900
+		//line go.y:1962
 		{
 			yyVAL.node = nil
 		}
 	case 292:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1906
+		//line go.y:1968
 		{
 			yyVAL.list = nil
 		}
 	case 294:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1912
+		//line go.y:1974
 		{
 			yyVAL.node = nil
 		}
 	case 296:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1918
+		//line go.y:1980
 		{
 			yyVAL.list = nil
 		}
 	case 298:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1924
+		//line go.y:1986
 		{
 			yyVAL.list = nil
 		}
 	case 300:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1930
+		//line go.y:1992
 		{
 			yyVAL.list = nil
 		}
 	case 302:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:1936
+		//line go.y:1998
 		{
 			yyVAL.val.Ctype = CTxxx
 		}
 	case 304:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1946
+		//line go.y:2008
 		{
-			importimport(yyDollar[2].sym, yyDollar[3].val.U.Sval)
+			importimport(yyDollar[2].sym, yyDollar[3].val.U.(string))
 		}
 	case 305:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1950
+		//line go.y:2012
 		{
 			importvar(yyDollar[2].sym, yyDollar[3].typ)
 		}
 	case 306:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1954
+		//line go.y:2016
 		{
 			importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node)
 		}
 	case 307:
 		yyDollar = yyS[yypt-6 : yypt+1]
-		//line go.y:1958
+		//line go.y:2020
 		{
 			importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node)
 		}
 	case 308:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1962
+		//line go.y:2024
 		{
 			importtype(yyDollar[2].typ, yyDollar[3].typ)
 		}
 	case 309:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:1966
+		//line go.y:2028
 		{
 			if yyDollar[2].node == nil {
 				dclcontext = PEXTERN // since we skip the funcbody below
@@ -3196,35 +3229,35 @@ yydefault:
 			importlist = list(importlist, yyDollar[2].node)
 
 			if Debug['E'] > 0 {
-				print("import [%q] func %lN \n", importpkg.Path, yyDollar[2].node)
+				fmt.Printf("import [%q] func %v \n", importpkg.Path, yyDollar[2].node)
 				if Debug['m'] > 2 && yyDollar[2].node.Func.Inl != nil {
-					print("inl body:%+H\n", yyDollar[2].node.Func.Inl)
+					fmt.Printf("inl body:%v\n", yyDollar[2].node.Func.Inl)
 				}
 			}
 		}
 	case 310:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1987
+		//line go.y:2049
 		{
 			yyVAL.sym = yyDollar[1].sym
 			structpkg = yyVAL.sym.Pkg
 		}
 	case 311:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1994
+		//line go.y:2056
 		{
 			yyVAL.typ = pkgtype(yyDollar[1].sym)
 			importsym(yyDollar[1].sym, OTYPE)
 		}
 	case 317:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2014
+		//line go.y:2076
 		{
 			yyVAL.typ = pkgtype(yyDollar[1].sym)
 		}
 	case 318:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2018
+		//line go.y:2080
 		{
 			// predefined name like uint8
 			yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
@@ -3237,43 +3270,43 @@ yydefault:
 		}
 	case 319:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2029
+		//line go.y:2091
 		{
 			yyVAL.typ = aindex(nil, yyDollar[3].typ)
 		}
 	case 320:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2033
+		//line go.y:2095
 		{
 			yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ)
 		}
 	case 321:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:2037
+		//line go.y:2099
 		{
 			yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ)
 		}
 	case 322:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2041
+		//line go.y:2103
 		{
 			yyVAL.typ = tostruct(yyDollar[3].list)
 		}
 	case 323:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2045
+		//line go.y:2107
 		{
 			yyVAL.typ = tointerface(yyDollar[3].list)
 		}
 	case 324:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:2049
+		//line go.y:2111
 		{
 			yyVAL.typ = Ptrto(yyDollar[2].typ)
 		}
 	case 325:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:2053
+		//line go.y:2115
 		{
 			yyVAL.typ = typ(TCHAN)
 			yyVAL.typ.Type = yyDollar[2].typ
@@ -3281,7 +3314,7 @@ yydefault:
 		}
 	case 326:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2059
+		//line go.y:2121
 		{
 			yyVAL.typ = typ(TCHAN)
 			yyVAL.typ.Type = yyDollar[3].typ
@@ -3289,7 +3322,7 @@ yydefault:
 		}
 	case 327:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2065
+		//line go.y:2127
 		{
 			yyVAL.typ = typ(TCHAN)
 			yyVAL.typ.Type = yyDollar[3].typ
@@ -3297,7 +3330,7 @@ yydefault:
 		}
 	case 328:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2073
+		//line go.y:2135
 		{
 			yyVAL.typ = typ(TCHAN)
 			yyVAL.typ.Type = yyDollar[3].typ
@@ -3305,13 +3338,13 @@ yydefault:
 		}
 	case 329:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:2081
+		//line go.y:2143
 		{
 			yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list)
 		}
 	case 330:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2087
+		//line go.y:2149
 		{
 			yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ))
 			if yyDollar[1].sym != nil {
@@ -3321,7 +3354,7 @@ yydefault:
 		}
 	case 331:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2095
+		//line go.y:2157
 		{
 			var t *Type
 
@@ -3338,7 +3371,7 @@ yydefault:
 		}
 	case 332:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2112
+		//line go.y:2174
 		{
 			var s *Sym
 			var p *Pkg
@@ -3362,55 +3395,55 @@ yydefault:
 		}
 	case 333:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:2136
+		//line go.y:2198
 		{
 			yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list)))
 		}
 	case 334:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2140
+		//line go.y:2202
 		{
 			yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))
 		}
 	case 335:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line go.y:2145
+		//line go.y:2207
 		{
 			yyVAL.list = nil
 		}
 	case 337:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2152
+		//line go.y:2214
 		{
 			yyVAL.list = yyDollar[2].list
 		}
 	case 338:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2156
+		//line go.y:2218
 		{
 			yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)))
 		}
 	case 339:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2166
+		//line go.y:2228
 		{
 			yyVAL.node = nodlit(yyDollar[1].val)
 		}
 	case 340:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:2170
+		//line go.y:2232
 		{
 			yyVAL.node = nodlit(yyDollar[2].val)
 			switch yyVAL.node.Val.Ctype {
 			case CTINT, CTRUNE:
-				mpnegfix(yyVAL.node.Val.U.Xval)
+				mpnegfix(yyVAL.node.Val.U.(*Mpint))
 				break
 			case CTFLT:
-				mpnegflt(yyVAL.node.Val.U.Fval)
+				mpnegflt(yyVAL.node.Val.U.(*Mpflt))
 				break
 			case CTCPLX:
-				mpnegflt(&yyVAL.node.Val.U.Cval.Real)
-				mpnegflt(&yyVAL.node.Val.U.Cval.Imag)
+				mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Real)
+				mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Imag)
 				break
 			default:
 				Yyerror("bad negated constant")
@@ -3418,7 +3451,7 @@ yydefault:
 		}
 	case 341:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2188
+		//line go.y:2250
 		{
 			yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg))
 			if yyVAL.node.Op != OLITERAL {
@@ -3427,50 +3460,50 @@ yydefault:
 		}
 	case 343:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:2198
+		//line go.y:2260
 		{
 			if yyDollar[2].node.Val.Ctype == CTRUNE && yyDollar[4].node.Val.Ctype == CTINT {
 				yyVAL.node = yyDollar[2].node
-				mpaddfixfix(yyDollar[2].node.Val.U.Xval, yyDollar[4].node.Val.U.Xval, 0)
+				mpaddfixfix(yyDollar[2].node.Val.U.(*Mpint), yyDollar[4].node.Val.U.(*Mpint), 0)
 				break
 			}
-			yyDollar[4].node.Val.U.Cval.Real = yyDollar[4].node.Val.U.Cval.Imag
-			Mpmovecflt(&yyDollar[4].node.Val.U.Cval.Imag, 0.0)
+			yyDollar[4].node.Val.U.(*Mpcplx).Real = yyDollar[4].node.Val.U.(*Mpcplx).Imag
+			Mpmovecflt(&yyDollar[4].node.Val.U.(*Mpcplx).Imag, 0.0)
 			yyVAL.node = nodcplxlit(yyDollar[2].node.Val, yyDollar[4].node.Val)
 		}
 	case 346:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2214
+		//line go.y:2276
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 347:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2218
+		//line go.y:2280
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 348:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2224
+		//line go.y:2286
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 349:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2228
+		//line go.y:2290
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
 	case 350:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:2234
+		//line go.y:2296
 		{
 			yyVAL.list = list1(yyDollar[1].node)
 		}
 	case 351:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:2238
+		//line go.y:2300
 		{
 			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
 		}
diff --git a/src/cmd/internal/gc/y.output b/src/cmd/compile/internal/gc/y.output
similarity index 91%
rename from src/cmd/internal/gc/y.output
rename to src/cmd/compile/internal/gc/y.output
index e4a5e5c212..2821702aea 100644
--- a/src/cmd/internal/gc/y.output
+++ b/src/cmd/compile/internal/gc/y.output
@@ -3,7 +3,7 @@ state 0
 	$accept: .file $end 
 	$$4: .    (4)
 
-	.  reduce 4 (src line 148)
+	.  reduce 4 (src line 210)
 
 	file  goto 1
 	loadsys  goto 2
@@ -21,7 +21,7 @@ state 2
 	package: .    (2)
 
 	LPACKAGE  shift 5
-	.  reduce 2 (src line 131)
+	.  reduce 2 (src line 193)
 
 	package  goto 4
 
@@ -37,7 +37,7 @@ state 4
 	file:  loadsys package.imports xdcl_list 
 	imports: .    (6)
 
-	.  reduce 6 (src line 165)
+	.  reduce 6 (src line 227)
 
 	imports  goto 8
 
@@ -56,7 +56,7 @@ state 6
 	loadsys:  $$4 import_package.import_there 
 	$$21: .    (21)
 
-	.  reduce 21 (src line 272)
+	.  reduce 21 (src line 334)
 
 	import_there  goto 14
 	$$21  goto 15
@@ -74,7 +74,7 @@ state 8
 	xdcl_list: .    (218)
 
 	LIMPORT  shift 19
-	.  reduce 218 (src line 1507)
+	.  reduce 218 (src line 1569)
 
 	xdcl_list  goto 17
 	import  goto 18
@@ -89,19 +89,19 @@ state 9
 state 10
 	sym:  LNAME.    (157)
 
-	.  reduce 157 (src line 1113)
+	.  reduce 157 (src line 1175)
 
 
 state 11
 	sym:  hidden_importsym.    (158)
 
-	.  reduce 158 (src line 1122)
+	.  reduce 158 (src line 1184)
 
 
 state 12
 	sym:  '?'.    (159)
 
-	.  reduce 159 (src line 1123)
+	.  reduce 159 (src line 1185)
 
 
 state 13
@@ -115,14 +115,14 @@ state 13
 state 14
 	loadsys:  $$4 import_package import_there.    (5)
 
-	.  reduce 5 (src line 159)
+	.  reduce 5 (src line 221)
 
 
 state 15
 	import_there:  $$21.hidden_import_list '$' '$' 
 	hidden_import_list: .    (344)
 
-	.  reduce 344 (src line 2209)
+	.  reduce 344 (src line 2271)
 
 	hidden_import_list  goto 22
 
@@ -131,7 +131,7 @@ state 16
 	import_safety: .    (19)
 
 	LNAME  shift 24
-	.  reduce 19 (src line 264)
+	.  reduce 19 (src line 326)
 
 	import_safety  goto 23
 
@@ -140,7 +140,7 @@ state 17
 	xdcl_list:  xdcl_list.xdcl ';' 
 	xdcl: .    (23)
 
-	$end  reduce 1 (src line 122)
+	$end  reduce 1 (src line 184)
 	error  shift 29
 	LLITERAL  shift 68
 	LBREAK  shift 41
@@ -170,7 +170,7 @@ state 17
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 23 (src line 285)
+	';'  reduce 23 (src line 347)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -236,7 +236,7 @@ state 19
 state 20
 	package:  LPACKAGE sym ';'.    (3)
 
-	.  reduce 3 (src line 138)
+	.  reduce 3 (src line 200)
 
 
 state 21
@@ -271,7 +271,7 @@ state 23
 state 24
 	import_safety:  LNAME.    (20)
 
-	.  reduce 20 (src line 265)
+	.  reduce 20 (src line 327)
 
 
 state 25
@@ -284,25 +284,25 @@ state 25
 state 26
 	xdcl:  common_dcl.    (24)
 
-	.  reduce 24 (src line 290)
+	.  reduce 24 (src line 352)
 
 
 state 27
 	xdcl:  xfndcl.    (25)
 
-	.  reduce 25 (src line 291)
+	.  reduce 25 (src line 353)
 
 
 state 28
 	xdcl:  non_dcl_stmt.    (26)
 
-	.  reduce 26 (src line 295)
+	.  reduce 26 (src line 357)
 
 
 state 29
 	xdcl:  error.    (27)
 
-	.  reduce 27 (src line 300)
+	.  reduce 27 (src line 362)
 
 
 state 30
@@ -373,31 +373,31 @@ state 33
 state 34
 	non_dcl_stmt:  simple_stmt.    (256)
 
-	.  reduce 256 (src line 1734)
+	.  reduce 256 (src line 1796)
 
 
 state 35
 	non_dcl_stmt:  for_stmt.    (257)
 
-	.  reduce 257 (src line 1736)
+	.  reduce 257 (src line 1798)
 
 
 state 36
 	non_dcl_stmt:  switch_stmt.    (258)
 
-	.  reduce 258 (src line 1737)
+	.  reduce 258 (src line 1799)
 
 
 state 37
 	non_dcl_stmt:  select_stmt.    (259)
 
-	.  reduce 259 (src line 1738)
+	.  reduce 259 (src line 1800)
 
 
 state 38
 	non_dcl_stmt:  if_stmt.    (260)
 
-	.  reduce 260 (src line 1739)
+	.  reduce 260 (src line 1801)
 
 
 state 39
@@ -410,7 +410,7 @@ state 39
 state 40
 	non_dcl_stmt:  LFALL.    (263)
 
-	.  reduce 263 (src line 1756)
+	.  reduce 263 (src line 1818)
 
 
 state 41
@@ -420,7 +420,7 @@ state 41
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 155 (src line 1107)
+	.  reduce 155 (src line 1169)
 
 	sym  goto 119
 	new_name  goto 118
@@ -434,7 +434,7 @@ state 42
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 155 (src line 1107)
+	.  reduce 155 (src line 1169)
 
 	sym  goto 119
 	new_name  goto 118
@@ -538,7 +538,7 @@ state 46
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 292 (src line 1905)
+	.  reduce 292 (src line 1967)
 
 	sym  goto 123
 	expr  goto 129
@@ -562,7 +562,7 @@ state 46
 state 47
 	lconst:  LCONST.    (38)
 
-	.  reduce 38 (src line 354)
+	.  reduce 38 (src line 416)
 
 
 state 48
@@ -593,7 +593,7 @@ state 48
 	expr_list:  expr.    (276)
 
 	LASOP  shift 130
-	LCOLAS  reduce 276 (src line 1840)
+	LCOLAS  reduce 276 (src line 1902)
 	LANDAND  shift 134
 	LANDNOT  shift 149
 	LCOMM  shift 152
@@ -616,9 +616,9 @@ state 48
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	'='  reduce 276 (src line 1840)
-	','  reduce 276 (src line 1840)
-	.  reduce 49 (src line 410)
+	'='  reduce 276 (src line 1902)
+	','  reduce 276 (src line 1902)
+	.  reduce 49 (src line 472)
 
 
 state 49
@@ -636,7 +636,7 @@ state 50
 	for_stmt:  LFOR.$$74 for_body 
 	$$74: .    (74)
 
-	.  reduce 74 (src line 659)
+	.  reduce 74 (src line 721)
 
 	$$74  goto 156
 
@@ -644,7 +644,7 @@ state 51
 	switch_stmt:  LSWITCH.$$88 if_header $$89 LBODY caseblock_list '}' 
 	$$88: .    (88)
 
-	.  reduce 88 (src line 754)
+	.  reduce 88 (src line 816)
 
 	$$88  goto 157
 
@@ -652,7 +652,7 @@ state 52
 	select_stmt:  LSELECT.$$91 LBODY caseblock_list '}' 
 	$$91: .    (91)
 
-	.  reduce 91 (src line 777)
+	.  reduce 91 (src line 839)
 
 	$$91  goto 158
 
@@ -660,28 +660,28 @@ state 53
 	if_stmt:  LIF.$$78 if_header $$79 loop_body $$80 elseif_list else 
 	$$78: .    (78)
 
-	.  reduce 78 (src line 688)
+	.  reduce 78 (src line 750)
 
 	$$78  goto 159
 
 state 54
 	labelname:  new_name.    (163)
 
-	.  reduce 163 (src line 1167)
+	.  reduce 163 (src line 1229)
 
 
 state 55
 	expr:  uexpr.    (93)
 
-	.  reduce 93 (src line 793)
+	.  reduce 93 (src line 855)
 
 
 state 56
 	new_name:  sym.    (153)
 	name:  sym.    (162)
 
-	':'  reduce 153 (src line 1091)
-	.  reduce 162 (src line 1158)
+	':'  reduce 153 (src line 1153)
+	.  reduce 162 (src line 1220)
 
 
 state 57
@@ -699,7 +699,7 @@ state 57
 	'('  shift 160
 	'.'  shift 161
 	'['  shift 162
-	.  reduce 114 (src line 877)
+	.  reduce 114 (src line 939)
 
 
 state 58
@@ -1027,7 +1027,7 @@ state 66
 	pexpr:  pexpr_no_paren.    (146)
 
 	'{'  shift 171
-	.  reduce 146 (src line 1054)
+	.  reduce 146 (src line 1116)
 
 
 state 67
@@ -1078,19 +1078,19 @@ state 67
 state 68
 	pexpr_no_paren:  LLITERAL.    (126)
 
-	.  reduce 126 (src line 941)
+	.  reduce 126 (src line 1003)
 
 
 state 69
 	pexpr_no_paren:  name.    (127)
 
-	.  reduce 127 (src line 946)
+	.  reduce 127 (src line 1008)
 
 
 state 70
 	pexpr_no_paren:  pseudocall.    (134)
 
-	.  reduce 134 (src line 984)
+	.  reduce 134 (src line 1046)
 
 
 state 71
@@ -1112,23 +1112,23 @@ state 72
 state 73
 	pexpr_no_paren:  fnliteral.    (139)
 
-	.  reduce 139 (src line 1011)
+	.  reduce 139 (src line 1073)
 
 
 state 74
 	convtype:  fntype.    (181)
 	fnlitdcl:  fntype.    (215)
 
-	'('  reduce 181 (src line 1220)
-	.  reduce 215 (src line 1484)
+	'('  reduce 181 (src line 1282)
+	.  reduce 215 (src line 1546)
 
 
 state 75
 	convtype:  othertype.    (182)
 	comptype:  othertype.    (183)
 
-	'('  reduce 182 (src line 1222)
-	.  reduce 183 (src line 1224)
+	'('  reduce 182 (src line 1284)
+	.  reduce 183 (src line 1286)
 
 
 state 76
@@ -1167,7 +1167,7 @@ state 77
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 290 (src line 1899)
+	.  reduce 290 (src line 1961)
 
 	sym  goto 123
 	expr  goto 188
@@ -1226,13 +1226,13 @@ state 79
 state 80
 	othertype:  structtype.    (196)
 
-	.  reduce 196 (src line 1272)
+	.  reduce 196 (src line 1334)
 
 
 state 81
 	othertype:  interfacetype.    (197)
 
-	.  reduce 197 (src line 1273)
+	.  reduce 197 (src line 1335)
 
 
 state 82
@@ -1258,13 +1258,13 @@ state 83
 state 84
 	imports:  imports import ';'.    (7)
 
-	.  reduce 7 (src line 166)
+	.  reduce 7 (src line 228)
 
 
 state 85
 	import:  LIMPORT import_stmt.    (8)
 
-	.  reduce 8 (src line 168)
+	.  reduce 8 (src line 230)
 
 
 state 86
@@ -1291,7 +1291,7 @@ state 87
 	$$21: .    (21)
 
 	LPACKAGE  shift 7
-	.  reduce 21 (src line 272)
+	.  reduce 21 (src line 334)
 
 	import_package  goto 204
 	import_there  goto 205
@@ -1300,7 +1300,7 @@ state 87
 state 88
 	import_here:  LLITERAL.    (15)
 
-	.  reduce 15 (src line 224)
+	.  reduce 15 (src line 286)
 
 
 state 89
@@ -1336,7 +1336,7 @@ state 92
 state 93
 	hidden_import_list:  hidden_import_list hidden_import.    (345)
 
-	.  reduce 345 (src line 2210)
+	.  reduce 345 (src line 2272)
 
 
 state 94
@@ -1389,19 +1389,19 @@ state 98
 state 99
 	import_package:  LPACKAGE LNAME import_safety ';'.    (18)
 
-	.  reduce 18 (src line 247)
+	.  reduce 18 (src line 309)
 
 
 state 100
 	xdcl_list:  xdcl_list xdcl ';'.    (219)
 
-	.  reduce 219 (src line 1511)
+	.  reduce 219 (src line 1573)
 
 
 state 101
 	common_dcl:  LVAR vardcl.    (28)
 
-	.  reduce 28 (src line 305)
+	.  reduce 28 (src line 367)
 
 
 state 102
@@ -1458,19 +1458,19 @@ state 103
 state 104
 	dcl_name_list:  dcl_name.    (274)
 
-	.  reduce 274 (src line 1830)
+	.  reduce 274 (src line 1892)
 
 
 state 105
 	dcl_name:  sym.    (154)
 
-	.  reduce 154 (src line 1101)
+	.  reduce 154 (src line 1163)
 
 
 state 106
 	common_dcl:  lconst constdcl.    (31)
 
-	.  reduce 31 (src line 318)
+	.  reduce 31 (src line 380)
 
 
 state 107
@@ -1526,7 +1526,7 @@ state 108
 state 109
 	common_dcl:  LTYPE typedcl.    (35)
 
-	.  reduce 35 (src line 341)
+	.  reduce 35 (src line 403)
 
 
 state 110
@@ -1577,7 +1577,7 @@ state 111
 state 112
 	typedclname:  sym.    (47)
 
-	.  reduce 47 (src line 395)
+	.  reduce 47 (src line 457)
 
 
 state 113
@@ -1585,7 +1585,7 @@ state 113
 	fnbody: .    (210)
 
 	'{'  shift 242
-	.  reduce 210 (src line 1457)
+	.  reduce 210 (src line 1519)
 
 	fnbody  goto 241
 
@@ -1607,7 +1607,7 @@ state 114
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -1637,43 +1637,43 @@ state 116
 	non_dcl_stmt:  labelname ':'.$$261 stmt 
 	$$261: .    (261)
 
-	.  reduce 261 (src line 1740)
+	.  reduce 261 (src line 1802)
 
 	$$261  goto 252
 
 state 117
 	non_dcl_stmt:  LBREAK onew_name.    (264)
 
-	.  reduce 264 (src line 1762)
+	.  reduce 264 (src line 1824)
 
 
 state 118
 	onew_name:  new_name.    (156)
 
-	.  reduce 156 (src line 1111)
+	.  reduce 156 (src line 1173)
 
 
 state 119
 	new_name:  sym.    (153)
 
-	.  reduce 153 (src line 1091)
+	.  reduce 153 (src line 1153)
 
 
 state 120
 	non_dcl_stmt:  LCONTINUE onew_name.    (265)
 
-	.  reduce 265 (src line 1766)
+	.  reduce 265 (src line 1828)
 
 
 state 121
 	pexpr_no_paren:  pseudocall.    (134)
 	non_dcl_stmt:  LGO pseudocall.    (266)
 
-	'('  reduce 134 (src line 984)
-	'.'  reduce 134 (src line 984)
-	'{'  reduce 134 (src line 984)
-	'['  reduce 134 (src line 984)
-	.  reduce 266 (src line 1770)
+	'('  reduce 134 (src line 1046)
+	'.'  reduce 134 (src line 1046)
+	'{'  reduce 134 (src line 1046)
+	'['  reduce 134 (src line 1046)
+	.  reduce 266 (src line 1832)
 
 
 state 122
@@ -1696,7 +1696,7 @@ state 122
 state 123
 	name:  sym.    (162)
 
-	.  reduce 162 (src line 1158)
+	.  reduce 162 (src line 1220)
 
 
 state 124
@@ -1710,23 +1710,23 @@ state 125
 	pexpr_no_paren:  pseudocall.    (134)
 	non_dcl_stmt:  LDEFER pseudocall.    (267)
 
-	'('  reduce 134 (src line 984)
-	'.'  reduce 134 (src line 984)
-	'{'  reduce 134 (src line 984)
-	'['  reduce 134 (src line 984)
-	.  reduce 267 (src line 1774)
+	'('  reduce 134 (src line 1046)
+	'.'  reduce 134 (src line 1046)
+	'{'  reduce 134 (src line 1046)
+	'['  reduce 134 (src line 1046)
+	.  reduce 267 (src line 1836)
 
 
 state 126
 	non_dcl_stmt:  LGOTO new_name.    (268)
 
-	.  reduce 268 (src line 1778)
+	.  reduce 268 (src line 1840)
 
 
 state 127
 	non_dcl_stmt:  LRETURN oexpr_list.    (269)
 
-	.  reduce 269 (src line 1783)
+	.  reduce 269 (src line 1845)
 
 
 state 128
@@ -1734,7 +1734,7 @@ state 128
 	oexpr_list:  expr_list.    (293)
 
 	','  shift 155
-	.  reduce 293 (src line 1909)
+	.  reduce 293 (src line 1971)
 
 
 state 129
@@ -1780,7 +1780,7 @@ state 129
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 276 (src line 1840)
+	.  reduce 276 (src line 1902)
 
 
 state 130
@@ -1827,13 +1827,13 @@ state 130
 state 131
 	simple_stmt:  expr LINC.    (53)
 
-	.  reduce 53 (src line 460)
+	.  reduce 53 (src line 522)
 
 
 state 132
 	simple_stmt:  expr LDEC.    (54)
 
-	.  reduce 54 (src line 466)
+	.  reduce 54 (src line 528)
 
 
 state 133
@@ -2805,7 +2805,7 @@ state 156
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -2853,7 +2853,7 @@ state 157
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -2906,7 +2906,7 @@ state 159
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -3016,7 +3016,7 @@ state 162
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 290 (src line 1899)
+	.  reduce 290 (src line 1961)
 
 	sym  goto 123
 	expr  goto 294
@@ -3039,56 +3039,56 @@ state 162
 state 163
 	uexpr:  '*' uexpr.    (115)
 
-	.  reduce 115 (src line 879)
+	.  reduce 115 (src line 941)
 
 
 state 164
 	uexpr:  '&' uexpr.    (116)
 
-	.  reduce 116 (src line 883)
+	.  reduce 116 (src line 945)
 
 
 state 165
 	uexpr:  '+' uexpr.    (117)
 
-	.  reduce 117 (src line 894)
+	.  reduce 117 (src line 956)
 
 
 state 166
 	uexpr:  '-' uexpr.    (118)
 
-	.  reduce 118 (src line 898)
+	.  reduce 118 (src line 960)
 
 
 state 167
 	uexpr:  '!' uexpr.    (119)
 
-	.  reduce 119 (src line 902)
+	.  reduce 119 (src line 964)
 
 
 state 168
 	uexpr:  '~' uexpr.    (120)
 
-	.  reduce 120 (src line 906)
+	.  reduce 120 (src line 968)
 
 
 state 169
 	uexpr:  '^' uexpr.    (121)
 
-	.  reduce 121 (src line 911)
+	.  reduce 121 (src line 973)
 
 
 state 170
 	uexpr:  LCOMM uexpr.    (122)
 
-	.  reduce 122 (src line 915)
+	.  reduce 122 (src line 977)
 
 
 state 171
 	pexpr_no_paren:  pexpr_no_paren '{'.start_complit braced_keyval_list '}' 
 	start_complit: .    (140)
 
-	.  reduce 140 (src line 1013)
+	.  reduce 140 (src line 1075)
 
 	start_complit  goto 296
 
@@ -3143,19 +3143,19 @@ state 173
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 148 (src line 1069)
+	.  reduce 148 (src line 1131)
 
 
 state 174
 	expr_or_type:  non_expr_type.    (149)
 
-	.  reduce 149 (src line 1071)
+	.  reduce 149 (src line 1133)
 
 
 state 175
 	non_expr_type:  recvchantype.    (172)
 
-	.  reduce 172 (src line 1201)
+	.  reduce 172 (src line 1263)
 
 
 state 176
@@ -3163,11 +3163,11 @@ state 176
 	convtype:  fntype.    (181)
 	fnlitdcl:  fntype.    (215)
 
-	error  reduce 215 (src line 1484)
-	LBODY  reduce 215 (src line 1484)
-	'('  reduce 181 (src line 1220)
-	'{'  reduce 215 (src line 1484)
-	.  reduce 173 (src line 1203)
+	error  reduce 215 (src line 1546)
+	LBODY  reduce 215 (src line 1546)
+	'('  reduce 181 (src line 1282)
+	'{'  reduce 215 (src line 1546)
+	.  reduce 173 (src line 1265)
 
 
 state 177
@@ -3175,10 +3175,10 @@ state 177
 	convtype:  othertype.    (182)
 	comptype:  othertype.    (183)
 
-	LBODY  reduce 183 (src line 1224)
-	'('  reduce 182 (src line 1222)
-	'{'  reduce 183 (src line 1224)
-	.  reduce 174 (src line 1204)
+	LBODY  reduce 183 (src line 1286)
+	'('  reduce 182 (src line 1284)
+	'{'  reduce 183 (src line 1286)
+	.  reduce 174 (src line 1266)
 
 
 state 178
@@ -3310,20 +3310,20 @@ state 181
 	pexpr_no_paren:  comptype lbrace.start_complit braced_keyval_list '}' 
 	start_complit: .    (140)
 
-	.  reduce 140 (src line 1013)
+	.  reduce 140 (src line 1075)
 
 	start_complit  goto 301
 
 state 182
 	lbrace:  LBODY.    (151)
 
-	.  reduce 151 (src line 1076)
+	.  reduce 151 (src line 1138)
 
 
 state 183
 	lbrace:  '{'.    (152)
 
-	.  reduce 152 (src line 1081)
+	.  reduce 152 (src line 1143)
 
 
 state 184
@@ -3359,9 +3359,9 @@ state 184
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -3403,7 +3403,7 @@ state 184
 state 185
 	fnliteral:  fnlitdcl error.    (217)
 
-	.  reduce 217 (src line 1496)
+	.  reduce 217 (src line 1558)
 
 
 state 186
@@ -3463,13 +3463,13 @@ state 188
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 291 (src line 1903)
+	.  reduce 291 (src line 1965)
 
 
 state 189
 	othertype:  LCHAN non_recvchantype.    (193)
 
-	.  reduce 193 (src line 1258)
+	.  reduce 193 (src line 1320)
 
 
 state 190
@@ -3504,25 +3504,25 @@ state 190
 state 191
 	non_recvchantype:  fntype.    (176)
 
-	.  reduce 176 (src line 1210)
+	.  reduce 176 (src line 1272)
 
 
 state 192
 	non_recvchantype:  othertype.    (177)
 
-	.  reduce 177 (src line 1212)
+	.  reduce 177 (src line 1274)
 
 
 state 193
 	non_recvchantype:  ptrtype.    (178)
 
-	.  reduce 178 (src line 1213)
+	.  reduce 178 (src line 1275)
 
 
 state 194
 	non_recvchantype:  dotname.    (179)
 
-	.  reduce 179 (src line 1214)
+	.  reduce 179 (src line 1276)
 
 
 state 195
@@ -3588,7 +3588,7 @@ state 197
 	dotname:  name.'.' sym 
 
 	'.'  shift 314
-	.  reduce 189 (src line 1234)
+	.  reduce 189 (src line 1296)
 
 
 state 198
@@ -3665,27 +3665,27 @@ state 201
 	osemi: .    (286)
 
 	';'  shift 333
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 332
 
 state 202
 	import:  LIMPORT '(' ')'.    (10)
 
-	.  reduce 10 (src line 171)
+	.  reduce 10 (src line 233)
 
 
 state 203
 	import_stmt_list:  import_stmt.    (13)
 
-	.  reduce 13 (src line 220)
+	.  reduce 13 (src line 282)
 
 
 state 204
 	import_stmt:  import_here import_package.import_there 
 	$$21: .    (21)
 
-	.  reduce 21 (src line 272)
+	.  reduce 21 (src line 334)
 
 	import_there  goto 334
 	$$21  goto 15
@@ -3693,37 +3693,37 @@ state 204
 state 205
 	import_stmt:  import_here import_there.    (12)
 
-	.  reduce 12 (src line 209)
+	.  reduce 12 (src line 271)
 
 
 state 206
 	import_here:  sym LLITERAL.    (16)
 
-	.  reduce 16 (src line 232)
+	.  reduce 16 (src line 294)
 
 
 state 207
 	import_here:  '.' LLITERAL.    (17)
 
-	.  reduce 17 (src line 239)
+	.  reduce 17 (src line 301)
 
 
 state 208
 	hidden_importsym:  '@' LLITERAL '.' LNAME.    (160)
 
-	.  reduce 160 (src line 1128)
+	.  reduce 160 (src line 1190)
 
 
 state 209
 	hidden_importsym:  '@' LLITERAL '.' '?'.    (161)
 
-	.  reduce 161 (src line 1143)
+	.  reduce 161 (src line 1205)
 
 
 state 210
 	import_there:  $$21 hidden_import_list '$' '$'.    (22)
 
-	.  reduce 22 (src line 276)
+	.  reduce 22 (src line 338)
 
 
 state 211
@@ -3757,7 +3757,7 @@ state 212
 state 213
 	hidden_pkg_importsym:  hidden_importsym.    (310)
 
-	.  reduce 310 (src line 1985)
+	.  reduce 310 (src line 2047)
 
 
 state 214
@@ -3807,7 +3807,7 @@ state 215
 state 216
 	hidden_pkgtype:  hidden_pkg_importsym.    (311)
 
-	.  reduce 311 (src line 1992)
+	.  reduce 311 (src line 2054)
 
 
 state 217
@@ -3815,7 +3815,7 @@ state 217
 	fnbody: .    (210)
 
 	'{'  shift 242
-	.  reduce 210 (src line 1457)
+	.  reduce 210 (src line 1519)
 
 	fnbody  goto 353
 
@@ -3845,20 +3845,20 @@ state 220
 	osemi: .    (286)
 
 	';'  shift 359
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 358
 
 state 221
 	common_dcl:  LVAR '(' ')'.    (30)
 
-	.  reduce 30 (src line 314)
+	.  reduce 30 (src line 376)
 
 
 state 222
 	vardcl_list:  vardcl.    (220)
 
-	.  reduce 220 (src line 1523)
+	.  reduce 220 (src line 1585)
 
 
 state 223
@@ -3866,7 +3866,7 @@ state 223
 	vardcl:  dcl_name_list ntype.'=' expr_list 
 
 	'='  shift 360
-	.  reduce 39 (src line 360)
+	.  reduce 39 (src line 422)
 
 
 state 224
@@ -3926,31 +3926,31 @@ state 225
 state 226
 	ntype:  recvchantype.    (166)
 
-	.  reduce 166 (src line 1190)
+	.  reduce 166 (src line 1252)
 
 
 state 227
 	ntype:  fntype.    (167)
 
-	.  reduce 167 (src line 1192)
+	.  reduce 167 (src line 1254)
 
 
 state 228
 	ntype:  othertype.    (168)
 
-	.  reduce 168 (src line 1193)
+	.  reduce 168 (src line 1255)
 
 
 state 229
 	ntype:  ptrtype.    (169)
 
-	.  reduce 169 (src line 1194)
+	.  reduce 169 (src line 1256)
 
 
 state 230
 	ntype:  dotname.    (170)
 
-	.  reduce 170 (src line 1195)
+	.  reduce 170 (src line 1257)
 
 
 state 231
@@ -3995,14 +3995,14 @@ state 233
 	osemi: .    (286)
 
 	';'  shift 366
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 365
 
 state 234
 	common_dcl:  lconst '(' ')'.    (34)
 
-	.  reduce 34 (src line 336)
+	.  reduce 34 (src line 398)
 
 
 state 235
@@ -4060,32 +4060,32 @@ state 237
 	osemi: .    (286)
 
 	';'  shift 370
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 369
 
 state 238
 	common_dcl:  LTYPE '(' ')'.    (37)
 
-	.  reduce 37 (src line 349)
+	.  reduce 37 (src line 411)
 
 
 state 239
 	typedcl_list:  typedcl.    (224)
 
-	.  reduce 224 (src line 1537)
+	.  reduce 224 (src line 1599)
 
 
 state 240
 	typedcl:  typedclname ntype.    (48)
 
-	.  reduce 48 (src line 404)
+	.  reduce 48 (src line 466)
 
 
 state 241
 	xfndcl:  LFUNC fndcl fnbody.    (204)
 
-	.  reduce 204 (src line 1318)
+	.  reduce 204 (src line 1380)
 
 
 state 242
@@ -4121,9 +4121,9 @@ state 242
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -4176,20 +4176,20 @@ state 244
 	ocomma: .    (288)
 
 	','  shift 373
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 374
 
 state 245
 	arg_type_list:  arg_type.    (247)
 
-	.  reduce 247 (src line 1697)
+	.  reduce 247 (src line 1759)
 
 
 state 246
 	arg_type:  name_or_type.    (243)
 
-	.  reduce 243 (src line 1681)
+	.  reduce 243 (src line 1743)
 
 
 state 247
@@ -4210,7 +4210,7 @@ state 247
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 162 (src line 1158)
+	.  reduce 162 (src line 1220)
 
 	sym  goto 123
 	ntype  goto 249
@@ -4229,13 +4229,13 @@ state 247
 state 248
 	arg_type:  dotdotdot.    (246)
 
-	.  reduce 246 (src line 1695)
+	.  reduce 246 (src line 1757)
 
 
 state 249
 	name_or_type:  ntype.    (150)
 
-	.  reduce 150 (src line 1073)
+	.  reduce 150 (src line 1135)
 
 
 state 250
@@ -4254,7 +4254,7 @@ state 250
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 164 (src line 1179)
+	.  reduce 164 (src line 1241)
 
 	sym  goto 123
 	ntype  goto 377
@@ -4285,7 +4285,7 @@ state 251
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -4311,11 +4311,11 @@ state 252
 	error  shift 307
 	LLITERAL  shift 68
 	LBREAK  shift 41
-	LCASE  reduce 251 (src line 1719)
+	LCASE  reduce 251 (src line 1781)
 	LCHAN  shift 78
 	LCONST  shift 47
 	LCONTINUE  shift 42
-	LDEFAULT  reduce 251 (src line 1719)
+	LDEFAULT  reduce 251 (src line 1781)
 	LDEFER  shift 44
 	LFALL  shift 40
 	LFOR  shift 50
@@ -4339,9 +4339,9 @@ state 252
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -4396,7 +4396,7 @@ state 253
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -4458,7 +4458,7 @@ state 254
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 50 (src line 425)
+	.  reduce 50 (src line 487)
 
 
 state 255
@@ -4502,7 +4502,7 @@ state 255
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 94 (src line 795)
+	.  reduce 94 (src line 857)
 
 
 state 256
@@ -4545,7 +4545,7 @@ state 256
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 95 (src line 799)
+	.  reduce 95 (src line 861)
 
 
 state 257
@@ -4582,7 +4582,7 @@ state 257
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 96 (src line 803)
+	.  reduce 96 (src line 865)
 
 
 state 258
@@ -4619,7 +4619,7 @@ state 258
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 97 (src line 807)
+	.  reduce 97 (src line 869)
 
 
 state 259
@@ -4656,7 +4656,7 @@ state 259
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 98 (src line 811)
+	.  reduce 98 (src line 873)
 
 
 state 260
@@ -4693,7 +4693,7 @@ state 260
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 99 (src line 815)
+	.  reduce 99 (src line 877)
 
 
 state 261
@@ -4730,7 +4730,7 @@ state 261
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 100 (src line 819)
+	.  reduce 100 (src line 881)
 
 
 state 262
@@ -4767,7 +4767,7 @@ state 262
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 101 (src line 823)
+	.  reduce 101 (src line 885)
 
 
 state 263
@@ -4800,7 +4800,7 @@ state 263
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 102 (src line 827)
+	.  reduce 102 (src line 889)
 
 
 state 264
@@ -4833,7 +4833,7 @@ state 264
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 103 (src line 831)
+	.  reduce 103 (src line 893)
 
 
 state 265
@@ -4866,7 +4866,7 @@ state 265
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 104 (src line 835)
+	.  reduce 104 (src line 897)
 
 
 state 266
@@ -4899,7 +4899,7 @@ state 266
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 105 (src line 839)
+	.  reduce 105 (src line 901)
 
 
 state 267
@@ -4925,7 +4925,7 @@ state 267
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 106 (src line 843)
+	.  reduce 106 (src line 905)
 
 
 state 268
@@ -4951,7 +4951,7 @@ state 268
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 107 (src line 847)
+	.  reduce 107 (src line 909)
 
 
 state 269
@@ -4977,7 +4977,7 @@ state 269
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 108 (src line 851)
+	.  reduce 108 (src line 913)
 
 
 state 270
@@ -5003,7 +5003,7 @@ state 270
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 109 (src line 855)
+	.  reduce 109 (src line 917)
 
 
 state 271
@@ -5029,7 +5029,7 @@ state 271
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 110 (src line 859)
+	.  reduce 110 (src line 921)
 
 
 state 272
@@ -5055,7 +5055,7 @@ state 272
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 111 (src line 863)
+	.  reduce 111 (src line 925)
 
 
 state 273
@@ -5081,7 +5081,7 @@ state 273
 	expr:  expr LRSH expr.    (112)
 	expr:  expr.LCOMM expr 
 
-	.  reduce 112 (src line 867)
+	.  reduce 112 (src line 929)
 
 
 state 274
@@ -5126,7 +5126,7 @@ state 274
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 113 (src line 872)
+	.  reduce 113 (src line 934)
 
 
 state 275
@@ -5134,7 +5134,7 @@ state 275
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 51 (src line 430)
+	.  reduce 51 (src line 492)
 
 
 state 276
@@ -5142,7 +5142,7 @@ state 276
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 52 (src line 442)
+	.  reduce 52 (src line 504)
 
 
 state 277
@@ -5188,13 +5188,13 @@ state 277
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 277 (src line 1845)
+	.  reduce 277 (src line 1907)
 
 
 state 278
 	for_stmt:  LFOR $$74 for_body.    (75)
 
-	.  reduce 75 (src line 664)
+	.  reduce 75 (src line 726)
 
 
 state 279
@@ -5210,19 +5210,19 @@ state 280
 	for_header:  osimple_stmt.    (71)
 
 	';'  shift 383
-	.  reduce 71 (src line 644)
+	.  reduce 71 (src line 706)
 
 
 state 281
 	for_header:  range_stmt.    (72)
 
-	.  reduce 72 (src line 650)
+	.  reduce 72 (src line 712)
 
 
 state 282
 	osimple_stmt:  simple_stmt.    (295)
 
-	.  reduce 295 (src line 1915)
+	.  reduce 295 (src line 1977)
 
 
 state 283
@@ -5283,7 +5283,7 @@ state 285
 	switch_stmt:  LSWITCH $$88 if_header.$$89 LBODY caseblock_list '}' 
 	$$89: .    (89)
 
-	.  reduce 89 (src line 759)
+	.  reduce 89 (src line 821)
 
 	$$89  goto 387
 
@@ -5292,14 +5292,14 @@ state 286
 	if_header:  osimple_stmt.';' osimple_stmt 
 
 	';'  shift 388
-	.  reduce 76 (src line 670)
+	.  reduce 76 (src line 732)
 
 
 state 287
 	select_stmt:  LSELECT $$91 LBODY.caseblock_list '}' 
 	caseblock_list: .    (63)
 
-	.  reduce 63 (src line 590)
+	.  reduce 63 (src line 652)
 
 	caseblock_list  goto 389
 
@@ -5307,14 +5307,14 @@ state 288
 	if_stmt:  LIF $$78 if_header.$$79 loop_body $$80 elseif_list else 
 	$$79: .    (79)
 
-	.  reduce 79 (src line 693)
+	.  reduce 79 (src line 755)
 
 	$$79  goto 390
 
 state 289
 	pseudocall:  pexpr '(' ')'.    (123)
 
-	.  reduce 123 (src line 924)
+	.  reduce 123 (src line 986)
 
 
 state 290
@@ -5325,20 +5325,20 @@ state 290
 
 	LDDD  shift 392
 	','  shift 393
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 391
 
 state 291
 	expr_or_type_list:  expr_or_type.    (278)
 
-	.  reduce 278 (src line 1850)
+	.  reduce 278 (src line 1912)
 
 
 state 292
 	pexpr_no_paren:  pexpr '.' sym.    (128)
 
-	.  reduce 128 (src line 947)
+	.  reduce 128 (src line 1009)
 
 
 state 293
@@ -5432,7 +5432,7 @@ state 294
 	'%'  shift 147
 	'&'  shift 148
 	']'  shift 396
-	.  reduce 291 (src line 1903)
+	.  reduce 291 (src line 1965)
 
 
 state 295
@@ -5467,7 +5467,7 @@ state 296
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 284 (src line 1881)
+	.  reduce 284 (src line 1943)
 
 	sym  goto 123
 	expr  goto 402
@@ -5495,13 +5495,13 @@ state 297
 	pexpr:  '(' expr_or_type ')'.    (147)
 
 	'{'  shift 404
-	.  reduce 147 (src line 1056)
+	.  reduce 147 (src line 1118)
 
 
 state 298
 	non_expr_type:  '*' non_expr_type.    (175)
 
-	.  reduce 175 (src line 1205)
+	.  reduce 175 (src line 1267)
 
 
 state 299
@@ -5581,7 +5581,7 @@ state 300
 	'%'  shift 147
 	'&'  shift 148
 	','  shift 413
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 412
 
@@ -5609,7 +5609,7 @@ state 301
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 284 (src line 1881)
+	.  reduce 284 (src line 1943)
 
 	sym  goto 123
 	expr  goto 402
@@ -5644,38 +5644,38 @@ state 302
 state 303
 	stmt_list:  stmt.    (270)
 
-	.  reduce 270 (src line 1804)
+	.  reduce 270 (src line 1866)
 
 
 state 304
 	stmt:  compound_stmt.    (252)
 
-	.  reduce 252 (src line 1723)
+	.  reduce 252 (src line 1785)
 
 
 state 305
 	stmt:  common_dcl.    (253)
 
-	.  reduce 253 (src line 1724)
+	.  reduce 253 (src line 1786)
 
 
 state 306
 	stmt:  non_dcl_stmt.    (254)
 
-	.  reduce 254 (src line 1728)
+	.  reduce 254 (src line 1790)
 
 
 state 307
 	stmt:  error.    (255)
 
-	.  reduce 255 (src line 1729)
+	.  reduce 255 (src line 1791)
 
 
 state 308
 	compound_stmt:  '{'.$$59 stmt_list '}' 
 	$$59: .    (59)
 
-	.  reduce 59 (src line 544)
+	.  reduce 59 (src line 606)
 
 	$$59  goto 417
 
@@ -5740,7 +5740,7 @@ state 310
 state 311
 	othertype:  LCHAN LCOMM ntype.    (194)
 
-	.  reduce 194 (src line 1263)
+	.  reduce 194 (src line 1325)
 
 
 state 312
@@ -5753,7 +5753,7 @@ state 312
 state 313
 	ptrtype:  '*' ntype.    (198)
 
-	.  reduce 198 (src line 1275)
+	.  reduce 198 (src line 1337)
 
 
 state 314
@@ -5780,20 +5780,20 @@ state 316
 	osemi: .    (286)
 
 	';'  shift 424
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 423
 
 state 317
 	structtype:  LSTRUCT lbrace '}'.    (201)
 
-	.  reduce 201 (src line 1295)
+	.  reduce 201 (src line 1357)
 
 
 state 318
 	structdcl_list:  structdcl.    (226)
 
-	.  reduce 226 (src line 1547)
+	.  reduce 226 (src line 1609)
 
 
 state 319
@@ -5832,7 +5832,7 @@ state 320
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 427
 
@@ -5861,13 +5861,13 @@ state 322
 state 323
 	new_name_list:  new_name.    (272)
 
-	.  reduce 272 (src line 1820)
+	.  reduce 272 (src line 1882)
 
 
 state 324
 	embed:  packname.    (238)
 
-	.  reduce 238 (src line 1646)
+	.  reduce 238 (src line 1708)
 
 
 state 325
@@ -5875,11 +5875,11 @@ state 325
 	packname:  LNAME.    (236)
 	packname:  LNAME.'.' sym 
 
-	LLITERAL  reduce 236 (src line 1621)
-	';'  reduce 236 (src line 1621)
+	LLITERAL  reduce 236 (src line 1683)
+	';'  reduce 236 (src line 1683)
 	'.'  shift 434
-	'}'  reduce 236 (src line 1621)
-	.  reduce 157 (src line 1113)
+	'}'  reduce 236 (src line 1683)
+	.  reduce 157 (src line 1175)
 
 
 state 326
@@ -5888,20 +5888,20 @@ state 326
 	osemi: .    (286)
 
 	';'  shift 436
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 435
 
 state 327
 	interfacetype:  LINTERFACE lbrace '}'.    (203)
 
-	.  reduce 203 (src line 1308)
+	.  reduce 203 (src line 1370)
 
 
 state 328
 	interfacedcl_list:  interfacedcl.    (228)
 
-	.  reduce 228 (src line 1554)
+	.  reduce 228 (src line 1616)
 
 
 state 329
@@ -5915,7 +5915,7 @@ state 329
 state 330
 	interfacedcl:  packname.    (240)
 
-	.  reduce 240 (src line 1658)
+	.  reduce 240 (src line 1720)
 
 
 state 331
@@ -5942,7 +5942,7 @@ state 333
 	'.'  shift 90
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	import_here  goto 87
 	sym  goto 89
@@ -5952,7 +5952,7 @@ state 333
 state 334
 	import_stmt:  import_here import_package import_there.    (11)
 
-	.  reduce 11 (src line 173)
+	.  reduce 11 (src line 235)
 
 
 state 335
@@ -5972,31 +5972,31 @@ state 336
 state 337
 	hidden_type:  hidden_type_misc.    (312)
 
-	.  reduce 312 (src line 2003)
+	.  reduce 312 (src line 2065)
 
 
 state 338
 	hidden_type:  hidden_type_recv_chan.    (313)
 
-	.  reduce 313 (src line 2005)
+	.  reduce 313 (src line 2067)
 
 
 state 339
 	hidden_type:  hidden_type_func.    (314)
 
-	.  reduce 314 (src line 2006)
+	.  reduce 314 (src line 2068)
 
 
 state 340
 	hidden_type_misc:  hidden_importsym.    (317)
 
-	.  reduce 317 (src line 2012)
+	.  reduce 317 (src line 2074)
 
 
 state 341
 	hidden_type_misc:  LNAME.    (318)
 
-	.  reduce 318 (src line 2017)
+	.  reduce 318 (src line 2079)
 
 
 state 342
@@ -6131,7 +6131,7 @@ state 354
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 296 (src line 1917)
+	.  reduce 296 (src line 1979)
 
 	sym  goto 357
 	hidden_importsym  goto 11
@@ -6151,7 +6151,7 @@ state 355
 state 356
 	hidden_funarg_list:  hidden_funarg.    (346)
 
-	.  reduce 346 (src line 2212)
+	.  reduce 346 (src line 2274)
 
 
 state 357
@@ -6191,7 +6191,7 @@ state 359
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 105
 	dcl_name  goto 104
@@ -6246,13 +6246,13 @@ state 361
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 41 (src line 369)
+	.  reduce 41 (src line 431)
 
 
 state 362
 	dcl_name_list:  dcl_name_list ',' dcl_name.    (275)
 
-	.  reduce 275 (src line 1835)
+	.  reduce 275 (src line 1897)
 
 
 state 363
@@ -6305,7 +6305,7 @@ state 366
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 105
 	dcl_name  goto 104
@@ -6362,7 +6362,7 @@ state 368
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 43 (src line 379)
+	.  reduce 43 (src line 441)
 
 
 state 369
@@ -6379,7 +6379,7 @@ state 370
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 112
 	typedclname  goto 111
@@ -6412,7 +6412,7 @@ state 372
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 212 (src line 1469)
+	.  reduce 212 (src line 1531)
 
 	sym  goto 485
 	dotname  goto 493
@@ -6444,7 +6444,7 @@ state 373
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 289 (src line 1897)
+	.  reduce 289 (src line 1959)
 
 	sym  goto 247
 	ntype  goto 249
@@ -6464,25 +6464,25 @@ state 373
 state 374
 	oarg_type_list_ocomma:  arg_type_list ocomma.    (250)
 
-	.  reduce 250 (src line 1711)
+	.  reduce 250 (src line 1773)
 
 
 state 375
 	arg_type:  sym name_or_type.    (244)
 
-	.  reduce 244 (src line 1683)
+	.  reduce 244 (src line 1745)
 
 
 state 376
 	arg_type:  sym dotdotdot.    (245)
 
-	.  reduce 245 (src line 1689)
+	.  reduce 245 (src line 1751)
 
 
 state 377
 	dotdotdot:  LDDD ntype.    (165)
 
-	.  reduce 165 (src line 1185)
+	.  reduce 165 (src line 1247)
 
 
 state 378
@@ -6495,7 +6495,7 @@ state 378
 state 379
 	non_dcl_stmt:  labelname ':' $$261 stmt.    (262)
 
-	.  reduce 262 (src line 1745)
+	.  reduce 262 (src line 1807)
 
 
 state 380
@@ -6508,14 +6508,14 @@ state 380
 state 381
 	for_body:  for_header loop_body.    (73)
 
-	.  reduce 73 (src line 652)
+	.  reduce 73 (src line 714)
 
 
 state 382
 	loop_body:  LBODY.$$65 stmt_list '}' 
 	$$65: .    (65)
 
-	.  reduce 65 (src line 599)
+	.  reduce 65 (src line 661)
 
 	$$65  goto 497
 
@@ -6542,7 +6542,7 @@ state 383
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -6695,7 +6695,7 @@ state 386
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 69 (src line 624)
+	.  reduce 69 (src line 686)
 
 
 state 387
@@ -6728,7 +6728,7 @@ state 388
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -6782,7 +6782,7 @@ state 392
 	ocomma: .    (288)
 
 	','  shift 413
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 510
 
@@ -6809,7 +6809,7 @@ state 393
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 289 (src line 1897)
+	.  reduce 289 (src line 1959)
 
 	sym  goto 123
 	expr  goto 173
@@ -6848,7 +6848,7 @@ state 395
 state 396
 	pexpr_no_paren:  pexpr '[' expr ']'.    (131)
 
-	.  reduce 131 (src line 966)
+	.  reduce 131 (src line 1028)
 
 
 state 397
@@ -6875,7 +6875,7 @@ state 397
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 290 (src line 1899)
+	.  reduce 290 (src line 1961)
 
 	sym  goto 123
 	expr  goto 188
@@ -6909,20 +6909,20 @@ state 399
 	ocomma: .    (288)
 
 	','  shift 516
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 517
 
 state 400
 	keyval_list:  keyval.    (280)
 
-	.  reduce 280 (src line 1863)
+	.  reduce 280 (src line 1925)
 
 
 state 401
 	keyval_list:  bare_complitexpr.    (281)
 
-	.  reduce 281 (src line 1868)
+	.  reduce 281 (src line 1930)
 
 
 state 402
@@ -6970,14 +6970,14 @@ state 402
 	'%'  shift 147
 	'&'  shift 148
 	':'  shift 518
-	.  reduce 142 (src line 1026)
+	.  reduce 142 (src line 1088)
 
 
 state 403
 	bare_complitexpr:  '{'.start_complit braced_keyval_list '}' 
 	start_complit: .    (140)
 
-	.  reduce 140 (src line 1013)
+	.  reduce 140 (src line 1075)
 
 	start_complit  goto 519
 
@@ -6985,7 +6985,7 @@ state 404
 	pexpr_no_paren:  '(' expr_or_type ')' '{'.start_complit braced_keyval_list '}' 
 	start_complit: .    (140)
 
-	.  reduce 140 (src line 1013)
+	.  reduce 140 (src line 1075)
 
 	start_complit  goto 520
 
@@ -7022,47 +7022,47 @@ state 405
 state 406
 	recvchantype:  LCOMM LCHAN ntype.    (199)
 
-	.  reduce 199 (src line 1281)
+	.  reduce 199 (src line 1343)
 
 
 state 407
 	ntype:  fntype.    (167)
 	non_recvchantype:  fntype.    (176)
 
-	LBODY  reduce 176 (src line 1210)
-	'('  reduce 176 (src line 1210)
-	'{'  reduce 176 (src line 1210)
-	.  reduce 167 (src line 1192)
+	LBODY  reduce 176 (src line 1272)
+	'('  reduce 176 (src line 1272)
+	'{'  reduce 176 (src line 1272)
+	.  reduce 167 (src line 1254)
 
 
 state 408
 	ntype:  othertype.    (168)
 	non_recvchantype:  othertype.    (177)
 
-	LBODY  reduce 177 (src line 1212)
-	'('  reduce 177 (src line 1212)
-	'{'  reduce 177 (src line 1212)
-	.  reduce 168 (src line 1193)
+	LBODY  reduce 177 (src line 1274)
+	'('  reduce 177 (src line 1274)
+	'{'  reduce 177 (src line 1274)
+	.  reduce 168 (src line 1255)
 
 
 state 409
 	ntype:  ptrtype.    (169)
 	non_recvchantype:  ptrtype.    (178)
 
-	LBODY  reduce 178 (src line 1213)
-	'('  reduce 178 (src line 1213)
-	'{'  reduce 178 (src line 1213)
-	.  reduce 169 (src line 1194)
+	LBODY  reduce 178 (src line 1275)
+	'('  reduce 178 (src line 1275)
+	'{'  reduce 178 (src line 1275)
+	.  reduce 169 (src line 1256)
 
 
 state 410
 	ntype:  dotname.    (170)
 	non_recvchantype:  dotname.    (179)
 
-	LBODY  reduce 179 (src line 1214)
-	'('  reduce 179 (src line 1214)
-	'{'  reduce 179 (src line 1214)
-	.  reduce 170 (src line 1195)
+	LBODY  reduce 179 (src line 1276)
+	'('  reduce 179 (src line 1276)
+	'{'  reduce 179 (src line 1276)
+	.  reduce 170 (src line 1257)
 
 
 state 411
@@ -7105,7 +7105,7 @@ state 412
 state 413
 	ocomma:  ','.    (289)
 
-	.  reduce 289 (src line 1897)
+	.  reduce 289 (src line 1959)
 
 
 state 414
@@ -7118,7 +7118,7 @@ state 414
 state 415
 	fnliteral:  fnlitdcl lbrace stmt_list '}'.    (216)
 
-	.  reduce 216 (src line 1490)
+	.  reduce 216 (src line 1552)
 
 
 state 416
@@ -7128,11 +7128,11 @@ state 416
 	error  shift 307
 	LLITERAL  shift 68
 	LBREAK  shift 41
-	LCASE  reduce 251 (src line 1719)
+	LCASE  reduce 251 (src line 1781)
 	LCHAN  shift 78
 	LCONST  shift 47
 	LCONTINUE  shift 42
-	LDEFAULT  reduce 251 (src line 1719)
+	LDEFAULT  reduce 251 (src line 1781)
 	LDEFER  shift 44
 	LFALL  shift 40
 	LFOR  shift 50
@@ -7156,9 +7156,9 @@ state 416
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -7229,9 +7229,9 @@ state 417
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -7273,25 +7273,25 @@ state 417
 state 418
 	othertype:  '[' oexpr ']' ntype.    (191)
 
-	.  reduce 191 (src line 1248)
+	.  reduce 191 (src line 1310)
 
 
 state 419
 	othertype:  '[' LDDD ']' ntype.    (192)
 
-	.  reduce 192 (src line 1253)
+	.  reduce 192 (src line 1315)
 
 
 state 420
 	non_recvchantype:  '(' ntype ')'.    (180)
 
-	.  reduce 180 (src line 1215)
+	.  reduce 180 (src line 1277)
 
 
 state 421
 	dotname:  name '.' sym.    (190)
 
-	.  reduce 190 (src line 1236)
+	.  reduce 190 (src line 1298)
 
 
 state 422
@@ -7339,7 +7339,7 @@ state 424
 	'('  shift 321
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 119
 	packname  goto 324
@@ -7354,7 +7354,7 @@ state 425
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 529
 
@@ -7373,13 +7373,13 @@ state 426
 state 427
 	structdcl:  embed oliteral.    (231)
 
-	.  reduce 231 (src line 1589)
+	.  reduce 231 (src line 1651)
 
 
 state 428
 	oliteral:  LLITERAL.    (303)
 
-	.  reduce 303 (src line 1939)
+	.  reduce 303 (src line 2001)
 
 
 state 429
@@ -7403,7 +7403,7 @@ state 431
 	packname:  LNAME.'.' sym 
 
 	'.'  shift 434
-	.  reduce 236 (src line 1621)
+	.  reduce 236 (src line 1683)
 
 
 state 432
@@ -7411,7 +7411,7 @@ state 432
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 533
 
@@ -7450,7 +7450,7 @@ state 436
 	'('  shift 331
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 119
 	packname  goto 330
@@ -7461,7 +7461,7 @@ state 436
 state 437
 	interfacedcl:  new_name indcl.    (239)
 
-	.  reduce 239 (src line 1652)
+	.  reduce 239 (src line 1714)
 
 
 state 438
@@ -7481,7 +7481,7 @@ state 438
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -7510,25 +7510,25 @@ state 439
 state 440
 	import:  LIMPORT '(' import_stmt_list osemi ')'.    (9)
 
-	.  reduce 9 (src line 170)
+	.  reduce 9 (src line 232)
 
 
 state 441
 	import_stmt_list:  import_stmt_list ';' import_stmt.    (14)
 
-	.  reduce 14 (src line 222)
+	.  reduce 14 (src line 284)
 
 
 state 442
 	hidden_import:  LIMPORT LNAME LLITERAL ';'.    (304)
 
-	.  reduce 304 (src line 1944)
+	.  reduce 304 (src line 2006)
 
 
 state 443
 	hidden_import:  LVAR hidden_pkg_importsym hidden_type ';'.    (305)
 
-	.  reduce 305 (src line 1949)
+	.  reduce 305 (src line 2011)
 
 
 state 444
@@ -7587,7 +7587,7 @@ state 447
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 298 (src line 1923)
+	.  reduce 298 (src line 1985)
 
 	sym  goto 546
 	hidden_importsym  goto 11
@@ -7610,7 +7610,7 @@ state 448
 	'['  shift 342
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 300 (src line 1929)
+	.  reduce 300 (src line 1991)
 
 	sym  goto 550
 	hidden_importsym  goto 553
@@ -7625,13 +7625,13 @@ state 448
 state 449
 	hidden_type_misc:  '*' hidden_type.    (324)
 
-	.  reduce 324 (src line 2048)
+	.  reduce 324 (src line 2110)
 
 
 state 450
 	hidden_type_misc:  LCHAN hidden_type_non_recv_chan.    (325)
 
-	.  reduce 325 (src line 2052)
+	.  reduce 325 (src line 2114)
 
 
 state 451
@@ -7666,13 +7666,13 @@ state 452
 state 453
 	hidden_type_non_recv_chan:  hidden_type_misc.    (315)
 
-	.  reduce 315 (src line 2008)
+	.  reduce 315 (src line 2070)
 
 
 state 454
 	hidden_type_non_recv_chan:  hidden_type_func.    (316)
 
-	.  reduce 316 (src line 2010)
+	.  reduce 316 (src line 2072)
 
 
 state 455
@@ -7703,7 +7703,7 @@ state 456
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 296 (src line 1917)
+	.  reduce 296 (src line 1979)
 
 	sym  goto 357
 	hidden_importsym  goto 11
@@ -7721,7 +7721,7 @@ state 457
 state 458
 	hidden_constant:  hidden_literal.    (342)
 
-	.  reduce 342 (src line 2195)
+	.  reduce 342 (src line 2257)
 
 
 state 459
@@ -7741,7 +7741,7 @@ state 459
 state 460
 	hidden_literal:  LLITERAL.    (339)
 
-	.  reduce 339 (src line 2164)
+	.  reduce 339 (src line 2226)
 
 
 state 461
@@ -7754,7 +7754,7 @@ state 461
 state 462
 	hidden_literal:  sym.    (341)
 
-	.  reduce 341 (src line 2187)
+	.  reduce 341 (src line 2249)
 
 
 state 463
@@ -7776,13 +7776,13 @@ state 463
 state 464
 	hidden_import:  LTYPE hidden_pkgtype hidden_type ';'.    (308)
 
-	.  reduce 308 (src line 1961)
+	.  reduce 308 (src line 2023)
 
 
 state 465
 	hidden_import:  LFUNC hidden_fndcl fnbody ';'.    (309)
 
-	.  reduce 309 (src line 1965)
+	.  reduce 309 (src line 2027)
 
 
 state 466
@@ -7797,7 +7797,7 @@ state 467
 	hidden_funarg_list:  hidden_funarg_list.',' hidden_funarg 
 
 	','  shift 469
-	.  reduce 297 (src line 1921)
+	.  reduce 297 (src line 1983)
 
 
 state 468
@@ -7828,7 +7828,7 @@ state 470
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 565
 
@@ -7856,13 +7856,13 @@ state 471
 state 472
 	common_dcl:  LVAR '(' vardcl_list osemi ')'.    (29)
 
-	.  reduce 29 (src line 310)
+	.  reduce 29 (src line 372)
 
 
 state 473
 	vardcl_list:  vardcl_list ';' vardcl.    (221)
 
-	.  reduce 221 (src line 1525)
+	.  reduce 221 (src line 1587)
 
 
 state 474
@@ -7870,19 +7870,19 @@ state 474
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 40 (src line 365)
+	.  reduce 40 (src line 427)
 
 
 state 475
 	ntype:  '(' ntype ')'.    (171)
 
-	.  reduce 171 (src line 1196)
+	.  reduce 171 (src line 1258)
 
 
 state 476
 	common_dcl:  lconst '(' constdcl osemi ')'.    (32)
 
-	.  reduce 32 (src line 324)
+	.  reduce 32 (src line 386)
 
 
 state 477
@@ -7891,20 +7891,20 @@ state 477
 	osemi: .    (286)
 
 	';'  shift 568
-	.  reduce 286 (src line 1893)
+	.  reduce 286 (src line 1955)
 
 	osemi  goto 567
 
 state 478
 	constdcl_list:  constdcl1.    (222)
 
-	.  reduce 222 (src line 1530)
+	.  reduce 222 (src line 1592)
 
 
 state 479
 	constdcl1:  constdcl.    (44)
 
-	.  reduce 44 (src line 384)
+	.  reduce 44 (src line 446)
 
 
 state 480
@@ -7928,7 +7928,7 @@ state 480
 	'?'  shift 12
 	'@'  shift 13
 	','  shift 225
-	.  reduce 46 (src line 390)
+	.  reduce 46 (src line 452)
 
 	sym  goto 123
 	ntype  goto 569
@@ -7947,25 +7947,25 @@ state 481
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 42 (src line 374)
+	.  reduce 42 (src line 436)
 
 
 state 482
 	common_dcl:  LTYPE '(' typedcl_list osemi ')'.    (36)
 
-	.  reduce 36 (src line 345)
+	.  reduce 36 (src line 407)
 
 
 state 483
 	typedcl_list:  typedcl_list ';' typedcl.    (225)
 
-	.  reduce 225 (src line 1542)
+	.  reduce 225 (src line 1604)
 
 
 state 484
 	fnbody:  '{' stmt_list '}'.    (211)
 
-	.  reduce 211 (src line 1461)
+	.  reduce 211 (src line 1523)
 
 
 state 485
@@ -7973,19 +7973,19 @@ state 485
 	fndcl:  '(' oarg_type_list_ocomma ')' sym.'(' oarg_type_list_ocomma ')' fnres 
 
 	'('  shift 570
-	.  reduce 162 (src line 1158)
+	.  reduce 162 (src line 1220)
 
 
 state 486
 	fntype:  LFUNC '(' oarg_type_list_ocomma ')' fnres.    (209)
 
-	.  reduce 209 (src line 1448)
+	.  reduce 209 (src line 1510)
 
 
 state 487
 	fnres:  fnret_type.    (213)
 
-	.  reduce 213 (src line 1474)
+	.  reduce 213 (src line 1536)
 
 
 state 488
@@ -8005,7 +8005,7 @@ state 488
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -8027,37 +8027,37 @@ state 488
 state 489
 	fnret_type:  recvchantype.    (184)
 
-	.  reduce 184 (src line 1227)
+	.  reduce 184 (src line 1289)
 
 
 state 490
 	fnret_type:  fntype.    (185)
 
-	.  reduce 185 (src line 1229)
+	.  reduce 185 (src line 1291)
 
 
 state 491
 	fnret_type:  othertype.    (186)
 
-	.  reduce 186 (src line 1230)
+	.  reduce 186 (src line 1292)
 
 
 state 492
 	fnret_type:  ptrtype.    (187)
 
-	.  reduce 187 (src line 1231)
+	.  reduce 187 (src line 1293)
 
 
 state 493
 	fnret_type:  dotname.    (188)
 
-	.  reduce 188 (src line 1232)
+	.  reduce 188 (src line 1294)
 
 
 state 494
 	arg_type_list:  arg_type_list ',' arg_type.    (248)
 
-	.  reduce 248 (src line 1702)
+	.  reduce 248 (src line 1764)
 
 
 state 495
@@ -8076,7 +8076,7 @@ state 495
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 212 (src line 1469)
+	.  reduce 212 (src line 1531)
 
 	sym  goto 123
 	dotname  goto 493
@@ -8107,7 +8107,7 @@ state 496
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 212 (src line 1469)
+	.  reduce 212 (src line 1531)
 
 	sym  goto 123
 	dotname  goto 493
@@ -8155,9 +8155,9 @@ state 497
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -8289,33 +8289,33 @@ state 501
 	switch_stmt:  LSWITCH $$88 if_header $$89 LBODY.caseblock_list '}' 
 	caseblock_list: .    (63)
 
-	.  reduce 63 (src line 590)
+	.  reduce 63 (src line 652)
 
 	caseblock_list  goto 577
 
 state 502
 	if_header:  osimple_stmt ';' osimple_stmt.    (77)
 
-	.  reduce 77 (src line 677)
+	.  reduce 77 (src line 739)
 
 
 state 503
 	caseblock_list:  caseblock_list caseblock.    (64)
 
-	.  reduce 64 (src line 594)
+	.  reduce 64 (src line 656)
 
 
 state 504
 	select_stmt:  LSELECT $$91 LBODY caseblock_list '}'.    (92)
 
-	.  reduce 92 (src line 782)
+	.  reduce 92 (src line 844)
 
 
 state 505
 	caseblock:  case.$$61 stmt_list 
 	$$61: .    (61)
 
-	.  reduce 61 (src line 559)
+	.  reduce 61 (src line 621)
 
 	$$61  goto 578
 
@@ -8377,14 +8377,14 @@ state 508
 	if_stmt:  LIF $$78 if_header $$79 loop_body.$$80 elseif_list else 
 	$$80: .    (80)
 
-	.  reduce 80 (src line 699)
+	.  reduce 80 (src line 761)
 
 	$$80  goto 581
 
 state 509
 	pseudocall:  pexpr '(' expr_or_type_list ocomma ')'.    (124)
 
-	.  reduce 124 (src line 929)
+	.  reduce 124 (src line 991)
 
 
 state 510
@@ -8397,19 +8397,19 @@ state 510
 state 511
 	expr_or_type_list:  expr_or_type_list ',' expr_or_type.    (279)
 
-	.  reduce 279 (src line 1855)
+	.  reduce 279 (src line 1917)
 
 
 state 512
 	pexpr_no_paren:  pexpr '.' '(' expr_or_type ')'.    (129)
 
-	.  reduce 129 (src line 958)
+	.  reduce 129 (src line 1020)
 
 
 state 513
 	pexpr_no_paren:  pexpr '.' '(' LTYPE ')'.    (130)
 
-	.  reduce 130 (src line 962)
+	.  reduce 130 (src line 1024)
 
 
 state 514
@@ -8424,7 +8424,7 @@ state 514
 state 515
 	pexpr_no_paren:  pexpr_no_paren '{' start_complit braced_keyval_list '}'.    (137)
 
-	.  reduce 137 (src line 998)
+	.  reduce 137 (src line 1060)
 
 
 state 516
@@ -8452,7 +8452,7 @@ state 516
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 289 (src line 1897)
+	.  reduce 289 (src line 1959)
 
 	sym  goto 123
 	expr  goto 402
@@ -8476,7 +8476,7 @@ state 516
 state 517
 	braced_keyval_list:  keyval_list ocomma.    (285)
 
-	.  reduce 285 (src line 1885)
+	.  reduce 285 (src line 1947)
 
 
 state 518
@@ -8546,7 +8546,7 @@ state 519
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 284 (src line 1881)
+	.  reduce 284 (src line 1943)
 
 	sym  goto 123
 	expr  goto 402
@@ -8593,7 +8593,7 @@ state 520
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 284 (src line 1881)
+	.  reduce 284 (src line 1943)
 
 	sym  goto 123
 	expr  goto 402
@@ -8627,19 +8627,19 @@ state 521
 state 522
 	pexpr_no_paren:  convtype '(' expr ocomma ')'.    (135)
 
-	.  reduce 135 (src line 985)
+	.  reduce 135 (src line 1047)
 
 
 state 523
 	pexpr_no_paren:  comptype lbrace start_complit braced_keyval_list '}'.    (136)
 
-	.  reduce 136 (src line 991)
+	.  reduce 136 (src line 1053)
 
 
 state 524
 	stmt_list:  stmt_list ';' stmt.    (271)
 
-	.  reduce 271 (src line 1812)
+	.  reduce 271 (src line 1874)
 
 
 state 525
@@ -8654,31 +8654,31 @@ state 525
 state 526
 	othertype:  LMAP '[' ntype ']' ntype.    (195)
 
-	.  reduce 195 (src line 1268)
+	.  reduce 195 (src line 1330)
 
 
 state 527
 	structtype:  LSTRUCT lbrace structdcl_list osemi '}'.    (200)
 
-	.  reduce 200 (src line 1288)
+	.  reduce 200 (src line 1350)
 
 
 state 528
 	structdcl_list:  structdcl_list ';' structdcl.    (227)
 
-	.  reduce 227 (src line 1549)
+	.  reduce 227 (src line 1611)
 
 
 state 529
 	structdcl:  new_name_list ntype oliteral.    (230)
 
-	.  reduce 230 (src line 1564)
+	.  reduce 230 (src line 1626)
 
 
 state 530
 	new_name_list:  new_name_list ',' new_name.    (273)
 
-	.  reduce 273 (src line 1825)
+	.  reduce 273 (src line 1887)
 
 
 state 531
@@ -8686,7 +8686,7 @@ state 531
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 594
 
@@ -8700,7 +8700,7 @@ state 532
 state 533
 	structdcl:  '*' embed oliteral.    (233)
 
-	.  reduce 233 (src line 1600)
+	.  reduce 233 (src line 1662)
 
 
 state 534
@@ -8713,19 +8713,19 @@ state 534
 state 535
 	packname:  LNAME '.' sym.    (237)
 
-	.  reduce 237 (src line 1632)
+	.  reduce 237 (src line 1694)
 
 
 state 536
 	interfacetype:  LINTERFACE lbrace interfacedcl_list osemi '}'.    (202)
 
-	.  reduce 202 (src line 1301)
+	.  reduce 202 (src line 1363)
 
 
 state 537
 	interfacedcl_list:  interfacedcl_list ';' interfacedcl.    (229)
 
-	.  reduce 229 (src line 1559)
+	.  reduce 229 (src line 1621)
 
 
 state 538
@@ -8738,13 +8738,13 @@ state 538
 state 539
 	interfacedcl:  '(' packname ')'.    (241)
 
-	.  reduce 241 (src line 1662)
+	.  reduce 241 (src line 1724)
 
 
 state 540
 	hidden_type_misc:  '[' ']' hidden_type.    (319)
 
-	.  reduce 319 (src line 2028)
+	.  reduce 319 (src line 2090)
 
 
 state 541
@@ -8787,13 +8787,13 @@ state 544
 	hidden_structdcl_list:  hidden_structdcl_list.';' hidden_structdcl 
 
 	';'  shift 601
-	.  reduce 299 (src line 1927)
+	.  reduce 299 (src line 1989)
 
 
 state 545
 	hidden_structdcl_list:  hidden_structdcl.    (348)
 
-	.  reduce 348 (src line 2222)
+	.  reduce 348 (src line 2284)
 
 
 state 546
@@ -8829,13 +8829,13 @@ state 548
 	hidden_interfacedcl_list:  hidden_interfacedcl_list.';' hidden_interfacedcl 
 
 	';'  shift 604
-	.  reduce 301 (src line 1933)
+	.  reduce 301 (src line 1995)
 
 
 state 549
 	hidden_interfacedcl_list:  hidden_interfacedcl.    (350)
 
-	.  reduce 350 (src line 2232)
+	.  reduce 350 (src line 2294)
 
 
 state 550
@@ -8848,23 +8848,23 @@ state 550
 state 551
 	hidden_interfacedcl:  hidden_type.    (334)
 
-	.  reduce 334 (src line 2139)
+	.  reduce 334 (src line 2201)
 
 
 state 552
 	sym:  LNAME.    (157)
 	hidden_type_misc:  LNAME.    (318)
 
-	'('  reduce 157 (src line 1113)
-	.  reduce 318 (src line 2017)
+	'('  reduce 157 (src line 1175)
+	.  reduce 318 (src line 2079)
 
 
 state 553
 	sym:  hidden_importsym.    (158)
 	hidden_type_misc:  hidden_importsym.    (317)
 
-	'('  reduce 158 (src line 1122)
-	.  reduce 317 (src line 2012)
+	'('  reduce 158 (src line 1184)
+	.  reduce 317 (src line 2074)
 
 
 state 554
@@ -8877,13 +8877,13 @@ state 554
 state 555
 	hidden_type_misc:  LCHAN LCOMM hidden_type.    (327)
 
-	.  reduce 327 (src line 2064)
+	.  reduce 327 (src line 2126)
 
 
 state 556
 	hidden_type_recv_chan:  LCOMM LCHAN hidden_type.    (328)
 
-	.  reduce 328 (src line 2071)
+	.  reduce 328 (src line 2133)
 
 
 state 557
@@ -8896,7 +8896,7 @@ state 557
 state 558
 	hidden_import:  LCONST hidden_pkg_importsym '=' hidden_constant ';'.    (306)
 
-	.  reduce 306 (src line 1953)
+	.  reduce 306 (src line 2015)
 
 
 state 559
@@ -8909,7 +8909,7 @@ state 559
 state 560
 	hidden_literal:  '-' LLITERAL.    (340)
 
-	.  reduce 340 (src line 2169)
+	.  reduce 340 (src line 2231)
 
 
 state 561
@@ -8934,7 +8934,7 @@ state 562
 	'('  shift 612
 	'['  shift 342
 	'@'  shift 13
-	.  reduce 335 (src line 2144)
+	.  reduce 335 (src line 2206)
 
 	hidden_importsym  goto 340
 	hidden_funres  goto 611
@@ -8954,13 +8954,13 @@ state 563
 state 564
 	hidden_funarg_list:  hidden_funarg_list ',' hidden_funarg.    (347)
 
-	.  reduce 347 (src line 2217)
+	.  reduce 347 (src line 2279)
 
 
 state 565
 	hidden_funarg:  sym hidden_type oliteral.    (330)
 
-	.  reduce 330 (src line 2085)
+	.  reduce 330 (src line 2147)
 
 
 state 566
@@ -8968,7 +8968,7 @@ state 566
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 615
 
@@ -8986,7 +8986,7 @@ state 568
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 287 (src line 1894)
+	.  reduce 287 (src line 1956)
 
 	sym  goto 105
 	dcl_name  goto 104
@@ -9000,7 +9000,7 @@ state 569
 	constdcl1:  dcl_name_list ntype.    (45)
 
 	'='  shift 367
-	.  reduce 45 (src line 386)
+	.  reduce 45 (src line 448)
 
 
 state 570
@@ -9020,7 +9020,7 @@ state 570
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 249 (src line 1707)
+	.  reduce 249 (src line 1769)
 
 	sym  goto 247
 	ntype  goto 249
@@ -9049,7 +9049,7 @@ state 571
 state 572
 	fndcl:  sym '(' oarg_type_list_ocomma ')' fnres.    (205)
 
-	.  reduce 205 (src line 1336)
+	.  reduce 205 (src line 1398)
 
 
 state 573
@@ -9084,7 +9084,7 @@ state 574
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -9149,7 +9149,7 @@ state 575
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 67 (src line 610)
+	.  reduce 67 (src line 672)
 
 
 state 576
@@ -9195,7 +9195,7 @@ state 576
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 68 (src line 617)
+	.  reduce 68 (src line 679)
 
 
 state 577
@@ -9217,11 +9217,11 @@ state 578
 	error  shift 307
 	LLITERAL  shift 68
 	LBREAK  shift 41
-	LCASE  reduce 251 (src line 1719)
+	LCASE  reduce 251 (src line 1781)
 	LCHAN  shift 78
 	LCONST  shift 47
 	LCONTINUE  shift 42
-	LDEFAULT  reduce 251 (src line 1719)
+	LDEFAULT  reduce 251 (src line 1781)
 	LDEFER  shift 44
 	LFALL  shift 40
 	LFOR  shift 50
@@ -9245,9 +9245,9 @@ state 578
 	'*'  shift 58
 	'&'  shift 59
 	'('  shift 67
-	';'  reduce 251 (src line 1719)
+	';'  reduce 251 (src line 1781)
 	'{'  shift 308
-	'}'  reduce 251 (src line 1719)
+	'}'  reduce 251 (src line 1781)
 	'!'  shift 62
 	'~'  shift 63
 	'['  shift 77
@@ -9302,27 +9302,27 @@ state 579
 state 580
 	case:  LDEFAULT ':'.    (58)
 
-	.  reduce 58 (src line 524)
+	.  reduce 58 (src line 586)
 
 
 state 581
 	if_stmt:  LIF $$78 if_header $$79 loop_body $$80.elseif_list else 
 	elseif_list: .    (84)
 
-	.  reduce 84 (src line 734)
+	.  reduce 84 (src line 796)
 
 	elseif_list  goto 628
 
 state 582
 	pseudocall:  pexpr '(' expr_or_type_list LDDD ocomma ')'.    (125)
 
-	.  reduce 125 (src line 934)
+	.  reduce 125 (src line 996)
 
 
 state 583
 	pexpr_no_paren:  pexpr '[' oexpr ':' oexpr ']'.    (132)
 
-	.  reduce 132 (src line 970)
+	.  reduce 132 (src line 1032)
 
 
 state 584
@@ -9348,7 +9348,7 @@ state 584
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 290 (src line 1899)
+	.  reduce 290 (src line 1961)
 
 	sym  goto 123
 	expr  goto 188
@@ -9371,19 +9371,19 @@ state 584
 state 585
 	keyval_list:  keyval_list ',' keyval.    (282)
 
-	.  reduce 282 (src line 1872)
+	.  reduce 282 (src line 1934)
 
 
 state 586
 	keyval_list:  keyval_list ',' bare_complitexpr.    (283)
 
-	.  reduce 283 (src line 1876)
+	.  reduce 283 (src line 1938)
 
 
 state 587
 	keyval:  expr ':' complitexpr.    (141)
 
-	.  reduce 141 (src line 1020)
+	.  reduce 141 (src line 1082)
 
 
 state 588
@@ -9429,14 +9429,14 @@ state 588
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 144 (src line 1046)
+	.  reduce 144 (src line 1108)
 
 
 state 589
 	complitexpr:  '{'.start_complit braced_keyval_list '}' 
 	start_complit: .    (140)
 
-	.  reduce 140 (src line 1013)
+	.  reduce 140 (src line 1075)
 
 	start_complit  goto 630
 
@@ -9458,22 +9458,22 @@ state 592
 	ntype:  '(' ntype ')'.    (171)
 	non_recvchantype:  '(' ntype ')'.    (180)
 
-	LBODY  reduce 180 (src line 1215)
-	'('  reduce 180 (src line 1215)
-	'{'  reduce 180 (src line 1215)
-	.  reduce 171 (src line 1196)
+	LBODY  reduce 180 (src line 1277)
+	'('  reduce 180 (src line 1277)
+	'{'  reduce 180 (src line 1277)
+	.  reduce 171 (src line 1258)
 
 
 state 593
 	compound_stmt:  '{' $$59 stmt_list '}'.    (60)
 
-	.  reduce 60 (src line 549)
+	.  reduce 60 (src line 611)
 
 
 state 594
 	structdcl:  '(' embed ')' oliteral.    (232)
 
-	.  reduce 232 (src line 1594)
+	.  reduce 232 (src line 1656)
 
 
 state 595
@@ -9481,7 +9481,7 @@ state 595
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 633
 
@@ -9490,7 +9490,7 @@ state 596
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 634
 
@@ -9510,7 +9510,7 @@ state 597
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 212 (src line 1469)
+	.  reduce 212 (src line 1531)
 
 	sym  goto 123
 	dotname  goto 493
@@ -9528,7 +9528,7 @@ state 597
 state 598
 	hidden_type_misc:  '[' LLITERAL ']' hidden_type.    (320)
 
-	.  reduce 320 (src line 2032)
+	.  reduce 320 (src line 2094)
 
 
 state 599
@@ -9555,7 +9555,7 @@ state 599
 state 600
 	hidden_type_misc:  LSTRUCT '{' ohidden_structdcl_list '}'.    (322)
 
-	.  reduce 322 (src line 2040)
+	.  reduce 322 (src line 2102)
 
 
 state 601
@@ -9575,14 +9575,14 @@ state 602
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 638
 
 state 603
 	hidden_type_misc:  LINTERFACE '{' ohidden_interfacedcl_list '}'.    (323)
 
-	.  reduce 323 (src line 2044)
+	.  reduce 323 (src line 2106)
 
 
 state 604
@@ -9616,7 +9616,7 @@ state 605
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 296 (src line 1917)
+	.  reduce 296 (src line 1979)
 
 	sym  goto 357
 	hidden_importsym  goto 11
@@ -9627,7 +9627,7 @@ state 605
 state 606
 	hidden_type_misc:  LCHAN '(' hidden_type_recv_chan ')'.    (326)
 
-	.  reduce 326 (src line 2058)
+	.  reduce 326 (src line 2120)
 
 
 state 607
@@ -9645,7 +9645,7 @@ state 607
 	'('  shift 612
 	'['  shift 342
 	'@'  shift 13
-	.  reduce 335 (src line 2144)
+	.  reduce 335 (src line 2206)
 
 	hidden_importsym  goto 340
 	hidden_funres  goto 611
@@ -9672,19 +9672,19 @@ state 608
 state 609
 	hidden_import:  LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'.    (307)
 
-	.  reduce 307 (src line 1957)
+	.  reduce 307 (src line 2019)
 
 
 state 610
 	hidden_fndcl:  hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres.    (207)
 
-	.  reduce 207 (src line 1405)
+	.  reduce 207 (src line 1467)
 
 
 state 611
 	ohidden_funres:  hidden_funres.    (336)
 
-	.  reduce 336 (src line 2148)
+	.  reduce 336 (src line 2210)
 
 
 state 612
@@ -9694,7 +9694,7 @@ state 612
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 296 (src line 1917)
+	.  reduce 296 (src line 1979)
 
 	sym  goto 357
 	hidden_importsym  goto 11
@@ -9705,7 +9705,7 @@ state 612
 state 613
 	hidden_funres:  hidden_type.    (338)
 
-	.  reduce 338 (src line 2155)
+	.  reduce 338 (src line 2217)
 
 
 state 614
@@ -9715,7 +9715,7 @@ state 614
 	LNAME  shift 10
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 296 (src line 1917)
+	.  reduce 296 (src line 1979)
 
 	sym  goto 357
 	hidden_importsym  goto 11
@@ -9726,19 +9726,19 @@ state 614
 state 615
 	hidden_funarg:  sym LDDD hidden_type oliteral.    (331)
 
-	.  reduce 331 (src line 2094)
+	.  reduce 331 (src line 2156)
 
 
 state 616
 	common_dcl:  lconst '(' constdcl ';' constdcl_list osemi ')'.    (33)
 
-	.  reduce 33 (src line 330)
+	.  reduce 33 (src line 392)
 
 
 state 617
 	constdcl_list:  constdcl_list ';' constdcl1.    (223)
 
-	.  reduce 223 (src line 1532)
+	.  reduce 223 (src line 1594)
 
 
 state 618
@@ -9751,25 +9751,25 @@ state 618
 state 619
 	fnres:  '(' oarg_type_list_ocomma ')'.    (214)
 
-	.  reduce 214 (src line 1478)
+	.  reduce 214 (src line 1540)
 
 
 state 620
 	loop_body:  LBODY $$65 stmt_list '}'.    (66)
 
-	.  reduce 66 (src line 604)
+	.  reduce 66 (src line 666)
 
 
 state 621
 	for_header:  osimple_stmt ';' osimple_stmt ';' osimple_stmt.    (70)
 
-	.  reduce 70 (src line 630)
+	.  reduce 70 (src line 692)
 
 
 state 622
 	switch_stmt:  LSWITCH $$88 if_header $$89 LBODY caseblock_list '}'.    (90)
 
-	.  reduce 90 (src line 768)
+	.  reduce 90 (src line 830)
 
 
 state 623
@@ -9777,13 +9777,13 @@ state 623
 	stmt_list:  stmt_list.';' stmt 
 
 	';'  shift 416
-	.  reduce 62 (src line 571)
+	.  reduce 62 (src line 633)
 
 
 state 624
 	case:  LCASE expr_or_type_list ':'.    (55)
 
-	.  reduce 55 (src line 473)
+	.  reduce 55 (src line 535)
 
 
 state 625
@@ -9918,7 +9918,7 @@ state 628
 	else: .    (86)
 
 	LELSE  shift 650
-	.  reduce 86 (src line 743)
+	.  reduce 86 (src line 805)
 
 	elseif  goto 649
 	else  goto 648
@@ -9954,7 +9954,7 @@ state 630
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 284 (src line 1881)
+	.  reduce 284 (src line 1943)
 
 	sym  goto 123
 	expr  goto 402
@@ -9980,55 +9980,55 @@ state 630
 state 631
 	bare_complitexpr:  '{' start_complit braced_keyval_list '}'.    (143)
 
-	.  reduce 143 (src line 1040)
+	.  reduce 143 (src line 1102)
 
 
 state 632
 	pexpr_no_paren:  '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'.    (138)
 
-	.  reduce 138 (src line 1004)
+	.  reduce 138 (src line 1066)
 
 
 state 633
 	structdcl:  '(' '*' embed ')' oliteral.    (234)
 
-	.  reduce 234 (src line 1606)
+	.  reduce 234 (src line 1668)
 
 
 state 634
 	structdcl:  '*' '(' embed ')' oliteral.    (235)
 
-	.  reduce 235 (src line 1613)
+	.  reduce 235 (src line 1675)
 
 
 state 635
 	indcl:  '(' oarg_type_list_ocomma ')' fnres.    (242)
 
-	.  reduce 242 (src line 1668)
+	.  reduce 242 (src line 1730)
 
 
 state 636
 	hidden_type_misc:  LMAP '[' hidden_type ']' hidden_type.    (321)
 
-	.  reduce 321 (src line 2036)
+	.  reduce 321 (src line 2098)
 
 
 state 637
 	hidden_structdcl_list:  hidden_structdcl_list ';' hidden_structdcl.    (349)
 
-	.  reduce 349 (src line 2227)
+	.  reduce 349 (src line 2289)
 
 
 state 638
 	hidden_structdcl:  sym hidden_type oliteral.    (332)
 
-	.  reduce 332 (src line 2110)
+	.  reduce 332 (src line 2172)
 
 
 state 639
 	hidden_interfacedcl_list:  hidden_interfacedcl_list ';' hidden_interfacedcl.    (351)
 
-	.  reduce 351 (src line 2237)
+	.  reduce 351 (src line 2299)
 
 
 state 640
@@ -10041,7 +10041,7 @@ state 640
 state 641
 	hidden_type_func:  LFUNC '(' ohidden_funarg_list ')' ohidden_funres.    (329)
 
-	.  reduce 329 (src line 2079)
+	.  reduce 329 (src line 2141)
 
 
 state 642
@@ -10081,7 +10081,7 @@ state 645
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 212 (src line 1469)
+	.  reduce 212 (src line 1531)
 
 	sym  goto 123
 	dotname  goto 493
@@ -10193,13 +10193,13 @@ state 647
 state 648
 	if_stmt:  LIF $$78 if_header $$79 loop_body $$80 elseif_list else.    (81)
 
-	.  reduce 81 (src line 703)
+	.  reduce 81 (src line 765)
 
 
 state 649
 	elseif_list:  elseif_list elseif.    (85)
 
-	.  reduce 85 (src line 738)
+	.  reduce 85 (src line 800)
 
 
 state 650
@@ -10215,7 +10215,7 @@ state 650
 state 651
 	pexpr_no_paren:  pexpr '[' oexpr ':' oexpr ':' oexpr ']'.    (133)
 
-	.  reduce 133 (src line 974)
+	.  reduce 133 (src line 1036)
 
 
 state 652
@@ -10240,7 +10240,7 @@ state 653
 	'('  shift 612
 	'['  shift 342
 	'@'  shift 13
-	.  reduce 335 (src line 2144)
+	.  reduce 335 (src line 2206)
 
 	hidden_importsym  goto 340
 	hidden_funres  goto 611
@@ -10253,13 +10253,13 @@ state 653
 state 654
 	hidden_constant:  '(' hidden_literal '+' hidden_literal ')'.    (343)
 
-	.  reduce 343 (src line 2197)
+	.  reduce 343 (src line 2259)
 
 
 state 655
 	hidden_funres:  '(' ohidden_funarg_list ')'.    (337)
 
-	.  reduce 337 (src line 2150)
+	.  reduce 337 (src line 2212)
 
 
 state 656
@@ -10277,7 +10277,7 @@ state 656
 	'('  shift 612
 	'['  shift 342
 	'@'  shift 13
-	.  reduce 335 (src line 2144)
+	.  reduce 335 (src line 2206)
 
 	hidden_importsym  goto 340
 	hidden_funres  goto 611
@@ -10290,51 +10290,51 @@ state 656
 state 657
 	fndcl:  '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres.    (206)
 
-	.  reduce 206 (src line 1368)
+	.  reduce 206 (src line 1430)
 
 
 state 658
 	case:  LCASE expr_or_type_list '=' expr ':'.    (56)
 
-	.  reduce 56 (src line 497)
+	.  reduce 56 (src line 559)
 
 
 state 659
 	case:  LCASE expr_or_type_list LCOLAS expr ':'.    (57)
 
-	.  reduce 57 (src line 515)
+	.  reduce 57 (src line 577)
 
 
 state 660
 	elseif:  LELSE LIF.$$82 if_header loop_body 
 	$$82: .    (82)
 
-	.  reduce 82 (src line 720)
+	.  reduce 82 (src line 782)
 
 	$$82  goto 665
 
 state 661
 	else:  LELSE compound_stmt.    (87)
 
-	.  reduce 87 (src line 747)
+	.  reduce 87 (src line 809)
 
 
 state 662
 	complitexpr:  '{' start_complit braced_keyval_list '}'.    (145)
 
-	.  reduce 145 (src line 1048)
+	.  reduce 145 (src line 1110)
 
 
 state 663
 	hidden_interfacedcl:  sym '(' ohidden_funarg_list ')' ohidden_funres.    (333)
 
-	.  reduce 333 (src line 2134)
+	.  reduce 333 (src line 2196)
 
 
 state 664
 	hidden_fndcl:  '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres.    (208)
 
-	.  reduce 208 (src line 1431)
+	.  reduce 208 (src line 1493)
 
 
 state 665
@@ -10360,7 +10360,7 @@ state 665
 	'['  shift 77
 	'?'  shift 12
 	'@'  shift 13
-	.  reduce 294 (src line 1911)
+	.  reduce 294 (src line 1973)
 
 	sym  goto 123
 	expr  goto 48
@@ -10394,7 +10394,7 @@ state 666
 state 667
 	elseif:  LELSE LIF $$82 if_header loop_body.    (83)
 
-	.  reduce 83 (src line 725)
+	.  reduce 83 (src line 787)
 
 
 76 terminals, 142 nonterminals
diff --git a/src/cmd/9g/cgen.go b/src/cmd/compile/internal/ppc64/cgen.go
similarity index 98%
rename from src/cmd/9g/cgen.go
rename to src/cmd/compile/internal/ppc64/cgen.go
index 5d24a6ff67..37dd6cefb2 100644
--- a/src/cmd/9g/cgen.go
+++ b/src/cmd/compile/internal/ppc64/cgen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 )
diff --git a/src/cmd/9g/galign.go b/src/cmd/compile/internal/ppc64/galign.go
similarity index 96%
rename from src/cmd/9g/galign.go
rename to src/cmd/compile/internal/ppc64/galign.go
index a2f4a0ef89..73aef6fde9 100644
--- a/src/cmd/9g/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 )
@@ -45,7 +45,7 @@ func betypeinit() {
 	gc.Widthreg = 8
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -72,6 +72,7 @@ func main() {
 	gc.Thearch.Expandchecks = expandchecks
 	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
diff --git a/src/cmd/9g/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
similarity index 97%
rename from src/cmd/9g/ggen.go
rename to src/cmd/compile/internal/ppc64/ggen.go
index 28ebd9cc01..1b936b8a5f 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
@@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) {
 	// iterate through declarations - they are sorted in decreasing xoffset order.
 	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if !n.Needzero {
+		if !n.Name.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -141,9 +141,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
diff --git a/src/cmd/9g/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go
similarity index 94%
rename from src/cmd/9g/gsubr.go
rename to src/cmd/compile/internal/ppc64/gsubr.go
index 8223fe70b1..2501972846 100644
--- a/src/cmd/9g/gsubr.go
+++ b/src/cmd/compile/internal/ppc64/gsubr.go
@@ -28,10 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
@@ -116,29 +117,55 @@ func ginscon2(as int, n2 *gc.Node, c int64) {
 	gc.Regfree(&ntmp)
 }
 
-/*
- * set up nodes representing 2^63
- */
-var bigi gc.Node
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
 
-var bigf gc.Node
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int())
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		rawgins(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
 
-var bignodes_did int
+// set up nodes representing 2^63
+var (
+	bigi         gc.Node
+	bigf         gc.Node
+	bignodes_did bool
+)
 
 func bignodes() {
-	if bignodes_did != 0 {
+	if bignodes_did {
 		return
 	}
-	bignodes_did = 1
+	bignodes_did = true
 
-	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1)
-	gc.Mpshiftfix(bigi.Val.U.Xval, 63)
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
 
-	bigf = bigi
-	bigf.Type = gc.Types[gc.TFLOAT64]
-	bigf.Val.Ctype = gc.CTFLT
-	bigf.Val.U.Fval = new(gc.Mpflt)
-	gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval)
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+
+	bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
 }
 
 /*
@@ -173,13 +200,13 @@ func gmove(f *gc.Node, t *gc.Node) {
 		var con gc.Node
 		switch tt {
 		default:
-			gc.Convconst(&con, t.Type, &f.Val)
+			f.Convconst(&con, t.Type)
 
 		case gc.TINT32,
 			gc.TINT16,
 			gc.TINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TINT64])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(ppc64.AMOVD, &con, &r1)
@@ -191,7 +218,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 			gc.TUINT16,
 			gc.TUINT8:
 			var con gc.Node
-			gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
+			f.Convconst(&con, gc.Types[gc.TUINT64])
 			var r1 gc.Node
 			gc.Regalloc(&r1, con.Type, t)
 			gins(ppc64.AMOVD, &con, &r1)
@@ -519,14 +546,13 @@ hard:
 }
 
 func intLiteral(n *gc.Node) (x int64, ok bool) {
-	if n == nil || n.Op != gc.OLITERAL {
+	switch {
+	case n == nil:
 		return
-	}
-	switch n.Val.Ctype {
-	case gc.CTINT, gc.CTRUNE:
-		return gc.Mpgetfix(n.Val.U.Xval), true
-	case gc.CTBOOL:
-		return int64(obj.Bool2int(n.Val.U.Bval)), true
+	case gc.Isconst(n, gc.CTINT):
+		return n.Int(), true
+	case gc.Isconst(n, gc.CTBOOL):
+		return int64(obj.Bool2int(n.Bool())), true
 	}
 	return
 }
diff --git a/src/cmd/9g/opt.go b/src/cmd/compile/internal/ppc64/opt.go
similarity index 96%
rename from src/cmd/9g/opt.go
rename to src/cmd/compile/internal/ppc64/opt.go
index 4a134f134f..1704f63c48 100644
--- a/src/cmd/9g/opt.go
+++ b/src/cmd/compile/internal/ppc64/opt.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package ppc64
 
 // Many Power ISA arithmetic and logical instructions come in four
 // standard variants.  These bits let us map between variants.
diff --git a/src/cmd/9g/peep.go b/src/cmd/compile/internal/ppc64/peep.go
similarity index 99%
rename from src/cmd/9g/peep.go
rename to src/cmd/compile/internal/ppc64/peep.go
index 94c9b1554b..16eeb39097 100644
--- a/src/cmd/9g/peep.go
+++ b/src/cmd/compile/internal/ppc64/peep.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
diff --git a/src/cmd/9g/prog.go b/src/cmd/compile/internal/ppc64/prog.go
similarity index 99%
rename from src/cmd/9g/prog.go
rename to src/cmd/compile/internal/ppc64/prog.go
index e28e389fac..c7e182769d 100644
--- a/src/cmd/9g/prog.go
+++ b/src/cmd/compile/internal/ppc64/prog.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 )
diff --git a/src/cmd/9g/reg.go b/src/cmd/compile/internal/ppc64/reg.go
similarity index 98%
rename from src/cmd/9g/reg.go
rename to src/cmd/compile/internal/ppc64/reg.go
index fb0c2e37ec..fa1cb71975 100644
--- a/src/cmd/9g/reg.go
+++ b/src/cmd/compile/internal/ppc64/reg.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 import "cmd/internal/obj/ppc64"
-import "cmd/internal/gc"
+import "cmd/compile/internal/gc"
 
 const (
 	NREGVAR = 64 /* 32 general + 32 floating */
diff --git a/src/cmd/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO
similarity index 100%
rename from src/cmd/internal/ssa/TODO
rename to src/cmd/compile/internal/ssa/TODO
diff --git a/src/cmd/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
similarity index 100%
rename from src/cmd/internal/ssa/block.go
rename to src/cmd/compile/internal/ssa/block.go
diff --git a/src/cmd/internal/ssa/blockkind_string.go b/src/cmd/compile/internal/ssa/blockkind_string.go
similarity index 100%
rename from src/cmd/internal/ssa/blockkind_string.go
rename to src/cmd/compile/internal/ssa/blockkind_string.go
diff --git a/src/cmd/internal/ssa/cgen.go b/src/cmd/compile/internal/ssa/cgen.go
similarity index 100%
rename from src/cmd/internal/ssa/cgen.go
rename to src/cmd/compile/internal/ssa/cgen.go
diff --git a/src/cmd/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
similarity index 100%
rename from src/cmd/internal/ssa/check.go
rename to src/cmd/compile/internal/ssa/check.go
diff --git a/src/cmd/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
similarity index 100%
rename from src/cmd/internal/ssa/compile.go
rename to src/cmd/compile/internal/ssa/compile.go
diff --git a/src/cmd/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
similarity index 100%
rename from src/cmd/internal/ssa/config.go
rename to src/cmd/compile/internal/ssa/config.go
diff --git a/src/cmd/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go
similarity index 100%
rename from src/cmd/internal/ssa/copyelim.go
rename to src/cmd/compile/internal/ssa/copyelim.go
diff --git a/src/cmd/internal/ssa/critical.go b/src/cmd/compile/internal/ssa/critical.go
similarity index 100%
rename from src/cmd/internal/ssa/critical.go
rename to src/cmd/compile/internal/ssa/critical.go
diff --git a/src/cmd/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
similarity index 100%
rename from src/cmd/internal/ssa/cse.go
rename to src/cmd/compile/internal/ssa/cse.go
diff --git a/src/cmd/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
similarity index 100%
rename from src/cmd/internal/ssa/deadcode.go
rename to src/cmd/compile/internal/ssa/deadcode.go
diff --git a/src/cmd/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go
similarity index 100%
rename from src/cmd/internal/ssa/deadcode_test.go
rename to src/cmd/compile/internal/ssa/deadcode_test.go
diff --git a/src/cmd/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go
similarity index 100%
rename from src/cmd/internal/ssa/dom.go
rename to src/cmd/compile/internal/ssa/dom.go
diff --git a/src/cmd/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
similarity index 100%
rename from src/cmd/internal/ssa/export_test.go
rename to src/cmd/compile/internal/ssa/export_test.go
diff --git a/src/cmd/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
similarity index 100%
rename from src/cmd/internal/ssa/func.go
rename to src/cmd/compile/internal/ssa/func.go
diff --git a/src/cmd/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go
similarity index 100%
rename from src/cmd/internal/ssa/func_test.go
rename to src/cmd/compile/internal/ssa/func_test.go
diff --git a/src/cmd/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
similarity index 100%
rename from src/cmd/internal/ssa/fuse.go
rename to src/cmd/compile/internal/ssa/fuse.go
diff --git a/src/cmd/internal/ssa/generic.go b/src/cmd/compile/internal/ssa/generic.go
similarity index 100%
rename from src/cmd/internal/ssa/generic.go
rename to src/cmd/compile/internal/ssa/generic.go
diff --git a/src/cmd/internal/ssa/id.go b/src/cmd/compile/internal/ssa/id.go
similarity index 100%
rename from src/cmd/internal/ssa/id.go
rename to src/cmd/compile/internal/ssa/id.go
diff --git a/src/cmd/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
similarity index 100%
rename from src/cmd/internal/ssa/layout.go
rename to src/cmd/compile/internal/ssa/layout.go
diff --git a/src/cmd/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go
similarity index 100%
rename from src/cmd/internal/ssa/location.go
rename to src/cmd/compile/internal/ssa/location.go
diff --git a/src/cmd/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go
similarity index 100%
rename from src/cmd/internal/ssa/lower.go
rename to src/cmd/compile/internal/ssa/lower.go
diff --git a/src/cmd/internal/ssa/lowerAmd64.go b/src/cmd/compile/internal/ssa/lowerAmd64.go
similarity index 100%
rename from src/cmd/internal/ssa/lowerAmd64.go
rename to src/cmd/compile/internal/ssa/lowerAmd64.go
diff --git a/src/cmd/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
similarity index 100%
rename from src/cmd/internal/ssa/op.go
rename to src/cmd/compile/internal/ssa/op.go
diff --git a/src/cmd/internal/ssa/op_string.go b/src/cmd/compile/internal/ssa/op_string.go
similarity index 100%
rename from src/cmd/internal/ssa/op_string.go
rename to src/cmd/compile/internal/ssa/op_string.go
diff --git a/src/cmd/internal/ssa/opamd64.go b/src/cmd/compile/internal/ssa/opamd64.go
similarity index 100%
rename from src/cmd/internal/ssa/opamd64.go
rename to src/cmd/compile/internal/ssa/opamd64.go
diff --git a/src/cmd/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go
similarity index 100%
rename from src/cmd/internal/ssa/opt.go
rename to src/cmd/compile/internal/ssa/opt.go
diff --git a/src/cmd/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go
similarity index 100%
rename from src/cmd/internal/ssa/phielim.go
rename to src/cmd/compile/internal/ssa/phielim.go
diff --git a/src/cmd/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go
similarity index 100%
rename from src/cmd/internal/ssa/print.go
rename to src/cmd/compile/internal/ssa/print.go
diff --git a/src/cmd/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
similarity index 100%
rename from src/cmd/internal/ssa/regalloc.go
rename to src/cmd/compile/internal/ssa/regalloc.go
diff --git a/src/cmd/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
similarity index 100%
rename from src/cmd/internal/ssa/rewrite.go
rename to src/cmd/compile/internal/ssa/rewrite.go
diff --git a/src/cmd/internal/ssa/rulegen/generic.rules b/src/cmd/compile/internal/ssa/rulegen/generic.rules
similarity index 100%
rename from src/cmd/internal/ssa/rulegen/generic.rules
rename to src/cmd/compile/internal/ssa/rulegen/generic.rules
diff --git a/src/cmd/internal/ssa/rulegen/lower_amd64.rules b/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules
similarity index 100%
rename from src/cmd/internal/ssa/rulegen/lower_amd64.rules
rename to src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules
diff --git a/src/cmd/internal/ssa/rulegen/rulegen.go b/src/cmd/compile/internal/ssa/rulegen/rulegen.go
similarity index 100%
rename from src/cmd/internal/ssa/rulegen/rulegen.go
rename to src/cmd/compile/internal/ssa/rulegen/rulegen.go
diff --git a/src/cmd/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
similarity index 100%
rename from src/cmd/internal/ssa/schedule.go
rename to src/cmd/compile/internal/ssa/schedule.go
diff --git a/src/cmd/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go
similarity index 100%
rename from src/cmd/internal/ssa/sparseset.go
rename to src/cmd/compile/internal/ssa/sparseset.go
diff --git a/src/cmd/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
similarity index 100%
rename from src/cmd/internal/ssa/stackalloc.go
rename to src/cmd/compile/internal/ssa/stackalloc.go
diff --git a/src/cmd/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go
similarity index 100%
rename from src/cmd/internal/ssa/type.go
rename to src/cmd/compile/internal/ssa/type.go
diff --git a/src/cmd/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
similarity index 100%
rename from src/cmd/internal/ssa/value.go
rename to src/cmd/compile/internal/ssa/value.go
diff --git a/src/cmd/8g/cgen.go b/src/cmd/compile/internal/x86/cgen.go
similarity index 96%
rename from src/cmd/8g/cgen.go
rename to src/cmd/compile/internal/x86/cgen.go
index dfbdafefe3..1768674e42 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/compile/internal/x86/cgen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -17,7 +17,7 @@ import (
  */
 func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
 	if !gc.Is64(n.Type) {
-		if n.Addable {
+		if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) {
 			// nothing to do.
 			*res = *n
 		} else {
diff --git a/src/cmd/8g/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go
similarity index 97%
rename from src/cmd/8g/cgen64.go
rename to src/cmd/compile/internal/x86/cgen64.go
index a682e2fb44..0b061ffb60 100644
--- a/src/cmd/8g/cgen64.go
+++ b/src/cmd/compile/internal/x86/cgen64.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -162,7 +162,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	//	shld hi:lo, c
 	//	shld lo:t, c
 	case gc.OLROT:
-		v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+		v := uint64(r.Int())
 
 		if v >= 32 {
 			// reverse during load to do the first 32 bits of rotate
@@ -189,7 +189,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 	case gc.OLSH:
 		if r.Op == gc.OLITERAL {
-			v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+			v := uint64(r.Int())
 			if v >= 64 {
 				if gc.Is64(r.Type) {
 					splitclean()
@@ -278,7 +278,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 	case gc.ORSH:
 		if r.Op == gc.OLITERAL {
-			v := uint64(gc.Mpgetfix(r.Val.U.Xval))
+			v := uint64(r.Int())
 			if v >= 64 {
 				if gc.Is64(r.Type) {
 					splitclean()
@@ -400,9 +400,8 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 		if lo2.Op == gc.OLITERAL {
 			// special cases for constants.
-			lv := uint32(gc.Mpgetfix(lo2.Val.U.Xval))
-
-			hv := uint32(gc.Mpgetfix(hi2.Val.U.Xval))
+			lv := uint32(lo2.Int())
+			hv := uint32(hi2.Int())
 			splitclean() // right side
 			split64(res, &lo2, &hi2)
 			switch n.Op {
diff --git a/src/cmd/8g/galign.go b/src/cmd/compile/internal/x86/galign.go
similarity index 96%
rename from src/cmd/8g/galign.go
rename to src/cmd/compile/internal/x86/galign.go
index e96b628dcc..2b602e1bb3 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
@@ -39,7 +39,7 @@ func betypeinit() {
 	gc.Widthreg = 4
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -81,6 +81,7 @@ func main() {
 	gc.Thearch.Expandchecks = expandchecks
 	gc.Thearch.Getg = getg
 	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
 	gc.Thearch.Ginscon = ginscon
 	gc.Thearch.Ginsnop = ginsnop
 	gc.Thearch.Gmove = gmove
diff --git a/src/cmd/8g/ggen.go b/src/cmd/compile/internal/x86/ggen.go
similarity index 98%
rename from src/cmd/8g/ggen.go
rename to src/cmd/compile/internal/x86/ggen.go
index 59025525fa..dabc139f30 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
@@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) {
 	ax := uint32(0)
 	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if !n.Needzero {
+		if !n.Name.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -216,9 +216,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.N
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1<= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			gins(a, ncon(uint32(w)-1), &n1)
diff --git a/src/cmd/8g/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
similarity index 95%
rename from src/cmd/8g/gsubr.go
rename to src/cmd/compile/internal/x86/gsubr.go
index 34ddfe0619..baf251781c 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/compile/internal/x86/gsubr.go
@@ -28,10 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
@@ -582,6 +583,45 @@ func ginscon(as int, c int64, n2 *gc.Node) {
 	gins(as, &n1, n2)
 }
 
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] || int(t.Etype) == gc.Tptr {
+		if (n1.Op == gc.OLITERAL || n1.Op == gc.OADDR && n1.Left.Op == gc.ONAME) && n2.Op != gc.OLITERAL {
+			// Reverse comparison to place constant (including address constant) last.
+			op = gc.Brrev(op)
+			n1, n2 = n2, n1
+		}
+	}
+
+	// General case.
+	var r1, r2, g1, g2 gc.Node
+	if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+		r1 = *n1
+	} else {
+		gc.Regalloc(&r1, t, n1)
+		gc.Regalloc(&g1, n1.Type, &r1)
+		gc.Cgen(n1, &g1)
+		gmove(&g1, &r1)
+	}
+	if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN {
+		r2 = *n2
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+	}
+	gins(optoas(gc.OCMP, t), &r1, &r2)
+	if r1.Op == gc.OREGISTER {
+		gc.Regfree(&g1)
+		gc.Regfree(&r1)
+	}
+	if r2.Op == gc.OREGISTER {
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
 /*
  * swap node contents
  */
@@ -602,7 +642,7 @@ func ncon(i uint32) *gc.Node {
 	if ncon_n.Type == nil {
 		gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
 	}
-	gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i))
+	ncon_n.SetInt(int64(i))
 	return &ncon_n
 }
 
@@ -638,7 +678,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 		case gc.ONAME:
 			if n.Class == gc.PPARAMREF {
 				var n1 gc.Node
-				gc.Cgen(n.Heapaddr, &n1)
+				gc.Cgen(n.Name.Heapaddr, &n1)
 				sclean[nsclean-1] = n1
 				n = &n1
 			}
@@ -660,8 +700,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 
 	case gc.OLITERAL:
 		var n1 gc.Node
-		gc.Convconst(&n1, n.Type, &n.Val)
-		i := gc.Mpgetfix(n1.Val.U.Xval)
+		n.Convconst(&n1, n.Type)
+		i := n1.Int()
 		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
 		i >>= 32
 		if n.Type.Etype == gc.TINT64 {
@@ -682,36 +722,36 @@ func splitclean() {
 	}
 }
 
-/*
- * set up nodes representing fp constants
- */
-var zerof gc.Node
-
-var two64f gc.Node
-
-var two63f gc.Node
-
-var bignodes_did int
+// set up nodes representing fp constants
+var (
+	zerof        gc.Node
+	two63f       gc.Node
+	two64f       gc.Node
+	bignodes_did bool
+)
 
 func bignodes() {
-	if bignodes_did != 0 {
+	if bignodes_did {
 		return
 	}
-	bignodes_did = 1
+	bignodes_did = true
 
-	two64f = *ncon(0)
-	two64f.Type = gc.Types[gc.TFLOAT64]
-	two64f.Val.Ctype = gc.CTFLT
-	two64f.Val.U.Fval = new(gc.Mpflt)
-	gc.Mpmovecflt(two64f.Val.U.Fval, 18446744073709551616.)
+	gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0)
+	zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64])
 
-	two63f = two64f
-	two63f.Val.U.Fval = new(gc.Mpflt)
-	gc.Mpmovecflt(two63f.Val.U.Fval, 9223372036854775808.)
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
+	var bigi gc.Node
 
-	zerof = two64f
-	zerof.Val.U.Fval = new(gc.Mpflt)
-	gc.Mpmovecflt(zerof.Val.U.Fval, 0)
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+	bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64])
+
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	i.Lsh(&i, 1)
+	bigi.SetBigInt(&i)
+	bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64])
 }
 
 func memname(n *gc.Node, t *gc.Type) {
@@ -750,7 +790,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	// convert constant to desired type
 	if f.Op == gc.OLITERAL {
 		var con gc.Node
-		gc.Convconst(&con, t.Type, &f.Val)
+		f.Convconst(&con, t.Type)
 		f = &con
 		ft = gc.Simsimtype(con.Type)
 	}
@@ -1021,7 +1061,7 @@ func floatmove(f *gc.Node, t *gc.Node) {
 	// convert constant to desired type
 	if f.Op == gc.OLITERAL {
 		var con gc.Node
-		gc.Convconst(&con, t.Type, &f.Val)
+		f.Convconst(&con, t.Type)
 		f = &con
 		ft = gc.Simsimtype(con.Type)
 
diff --git a/src/cmd/8g/peep.go b/src/cmd/compile/internal/x86/peep.go
similarity index 99%
rename from src/cmd/8g/peep.go
rename to src/cmd/compile/internal/x86/peep.go
index e309aea785..8b50eab077 100644
--- a/src/cmd/8g/peep.go
+++ b/src/cmd/compile/internal/x86/peep.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
diff --git a/src/cmd/8g/prog.go b/src/cmd/compile/internal/x86/prog.go
similarity index 99%
rename from src/cmd/8g/prog.go
rename to src/cmd/compile/internal/x86/prog.go
index 1346c20f2b..f96a1aa945 100644
--- a/src/cmd/8g/prog.go
+++ b/src/cmd/compile/internal/x86/prog.go
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package x86
 
 import (
-	"cmd/internal/gc"
+	"cmd/compile/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
diff --git a/src/cmd/8g/reg.go b/src/cmd/compile/internal/x86/reg.go
similarity index 98%
rename from src/cmd/8g/reg.go
rename to src/cmd/compile/internal/x86/reg.go
index 50b5b97ab1..8c97171e47 100644
--- a/src/cmd/8g/reg.go
+++ b/src/cmd/compile/internal/x86/reg.go
@@ -28,10 +28,10 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 import "cmd/internal/obj/x86"
-import "cmd/internal/gc"
+import "cmd/compile/internal/gc"
 
 const (
 	NREGVAR = 16 /* 8 integer + 8 floating */
diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go
new file mode 100644
index 0000000000..7b69c34424
--- /dev/null
+++ b/src/cmd/compile/main.go
@@ -0,0 +1,34 @@
+// Copyright 2015 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 main
+
+import (
+	"cmd/compile/internal/amd64"
+	"cmd/compile/internal/arm"
+	"cmd/compile/internal/arm64"
+	"cmd/compile/internal/ppc64"
+	"cmd/compile/internal/x86"
+	"cmd/internal/obj"
+	"fmt"
+	"os"
+)
+
+func main() {
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		x86.Main()
+	case "amd64", "amd64p32":
+		amd64.Main()
+	case "arm":
+		arm.Main()
+	case "arm64":
+		arm64.Main()
+	case "ppc64", "ppc64le":
+		ppc64.Main()
+	}
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 64b2399972..0cdb7d69f7 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -20,7 +20,6 @@ var (
 	goarch           string
 	gobin            string
 	gohostarch       string
-	gohostchar       string
 	gohostos         string
 	goos             string
 	goarm            string
@@ -30,10 +29,8 @@ var (
 	goextlinkenabled string
 	workdir          string
 	tooldir          string
-	gochar           string
 	oldgoos          string
 	oldgoarch        string
-	oldgochar        string
 	slash            string
 	exe              string
 	defaultcc        string
@@ -48,17 +45,13 @@ var (
 	vflag int  // verbosity
 )
 
-// The known architecture letters.
-var gochars = "5667899"
-
 // The known architectures.
 var okgoarch = []string{
-	// same order as gochars
-	"arm",
+	"386",
 	"amd64",
 	"amd64p32",
+	"arm",
 	"arm64",
-	"386",
 	"ppc64",
 	"ppc64le",
 }
@@ -147,22 +140,18 @@ func xinit() {
 		gohostarch = b
 	}
 
-	i := find(gohostarch, okgoarch)
-	if i < 0 {
+	if find(gohostarch, okgoarch) < 0 {
 		fatal("unknown $GOHOSTARCH %s", gohostarch)
 	}
-	gohostchar = gochars[i : i+1]
 
 	b = os.Getenv("GOARCH")
 	if b == "" {
 		b = gohostarch
 	}
 	goarch = b
-	i = find(goarch, okgoarch)
-	if i < 0 {
+	if find(goarch, okgoarch) < 0 {
 		fatal("unknown $GOARCH %s", goarch)
 	}
-	gochar = gochars[i : i+1]
 
 	b = os.Getenv("GO_EXTLINK_ENABLED")
 	if b != "" {
@@ -374,7 +363,7 @@ var oldtool = []string{
 // Unreleased directories (relative to $GOROOT) that should
 // not be in release branches.
 var unreleased = []string{
-	"src/cmd/link",
+	"src/cmd/newlink",
 	"src/cmd/objwriter",
 	"src/debug/goobj",
 	"src/old",
@@ -436,7 +425,7 @@ func setup() {
 	}
 
 	// If $GOBIN is set and has a Go compiler, it must be cleaned.
-	for _, char := range gochars {
+	for _, char := range "56789" {
 		if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
 			for _, old := range oldtool {
 				xremove(pathf("%s/%s", gobin, old))
@@ -540,7 +529,7 @@ func install(dir string) {
 		if elem == "go" {
 			elem = "go_bootstrap"
 		}
-		link = []string{fmt.Sprintf("%s/%sl", tooldir, gochar), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
+		link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
 		targ = len(link) - 1
 	}
 	ttarg := mtime(link[targ])
@@ -675,7 +664,7 @@ func install(dir string) {
 	} else {
 		archive = b
 	}
-	compile := []string{pathf("%s/%sg", tooldir, gochar), "-pack", "-o", b, "-p", pkg}
+	compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
 	if dir == "runtime" {
 		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
 	}
@@ -703,11 +692,7 @@ func install(dir string) {
 		b := pathf("%s/%s", workdir, filepath.Base(p))
 
 		// Change the last character of the output file (which was c or s).
-		if gohostos == "plan9" {
-			b = b[:len(b)-1] + gohostchar
-		} else {
-			b = b[:len(b)-1] + "o"
-		}
+		b = b[:len(b)-1] + "o"
 		compile = append(compile, "-o", b, p)
 		bgrun(path, compile...)
 
@@ -897,17 +882,9 @@ var buildorder = []string{
 // compilers but build only the $GOARCH ones.
 var cleantab = []string{
 	// Commands and C libraries.
-	"cmd/5g",
-	"cmd/5l",
-	"cmd/6g",
-	"cmd/6l",
-	"cmd/7g",
-	"cmd/7l",
-	"cmd/8g",
-	"cmd/8l",
-	"cmd/9g",
-	"cmd/9l",
+	"cmd/compile",
 	"cmd/go",
+	"cmd/link",
 	"cmd/old5a",
 	"cmd/old6a",
 	"cmd/old8a",
@@ -1043,7 +1020,6 @@ func cmdenv() {
 	xprintf(format, "GOHOSTARCH", gohostarch)
 	xprintf(format, "GOHOSTOS", gohostos)
 	xprintf(format, "GOTOOLDIR", tooldir)
-	xprintf(format, "GOCHAR", gochar)
 	if goarch == "arm" {
 		xprintf(format, "GOARM", goarm)
 	}
@@ -1088,10 +1064,8 @@ func cmdbootstrap() {
 	// For the main bootstrap, building for host os/arch.
 	oldgoos = goos
 	oldgoarch = goarch
-	oldgochar = gochar
 	goos = gohostos
 	goarch = gohostarch
-	gochar = gohostchar
 	os.Setenv("GOHOSTARCH", gohostarch)
 	os.Setenv("GOHOSTOS", gohostos)
 	os.Setenv("GOARCH", goarch)
@@ -1105,37 +1079,22 @@ func cmdbootstrap() {
 	// than in a standard release like Go 1.4, so don't do this rebuild by default.
 	if false {
 		xprintf("##### Building Go toolchain using itself.\n")
-		for _, pattern := range buildorder {
-			if pattern == "cmd/go" {
+		for _, dir := range buildorder {
+			if dir == "cmd/go" {
 				break
 			}
-			dir := pattern
-			if strings.Contains(pattern, "%s") {
-				dir = fmt.Sprintf(pattern, gohostchar)
-			}
 			install(dir)
-			if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
-				install(fmt.Sprintf(pattern, oldgochar))
-			}
 		}
 		xprintf("\n")
 	}
 
 	xprintf("##### Building compilers and go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
-	for _, pattern := range buildorder {
-		dir := pattern
-		if strings.Contains(pattern, "%s") {
-			dir = fmt.Sprintf(pattern, gohostchar)
-		}
+	for _, dir := range buildorder {
 		install(dir)
-		if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
-			install(fmt.Sprintf(pattern, oldgochar))
-		}
 	}
 
 	goos = oldgoos
 	goarch = oldgoarch
-	gochar = oldgochar
 	os.Setenv("GOARCH", goarch)
 	os.Setenv("GOOS", goos)
 
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index f5037fab88..7988129868 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -23,31 +23,34 @@ import (
 // which are commands, and entries beginning with internal/, which are
 // packages supporting the commands.
 var bootstrapDirs = []string{
-	"5g",
-	"5l",
-	"6g",
-	"6l",
-	"7g",
-	"7l",
-	"8g",
-	"8l",
-	"9g",
-	"9l",
 	"asm",
 	"asm/internal/arch",
 	"asm/internal/asm",
 	"asm/internal/flags",
 	"asm/internal/lex",
+	"compile",
+	"compile/internal/amd64",
+	"compile/internal/arm",
+	"compile/internal/arm64",
+	"compile/internal/big",
+	"compile/internal/gc",
+	"compile/internal/ppc64",
+	"compile/internal/ssa",
+	"compile/internal/x86",
 	"internal/asm",
-	"internal/gc/big",
-	"internal/gc",
-	"internal/ld",
+	"internal/gcprog",
 	"internal/obj",
 	"internal/obj/arm",
 	"internal/obj/arm64",
 	"internal/obj/ppc64",
 	"internal/obj/x86",
-	"internal/ssa",
+	"link",
+	"link/internal/amd64",
+	"link/internal/arm",
+	"link/internal/arm64",
+	"link/internal/ld",
+	"link/internal/ppc64",
+	"link/internal/x86",
 	"old5a",
 	"old6a",
 	"old8a",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 1ed099583e..f5a0dc50f1 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -14,6 +14,7 @@ import (
 	"os/exec"
 	"path/filepath"
 	"regexp"
+	"runtime"
 	"strconv"
 	"strings"
 	"time"
@@ -23,8 +24,11 @@ func cmdtest() {
 	var t tester
 	flag.BoolVar(&t.listMode, "list", false, "list available tests")
 	flag.BoolVar(&t.noRebuild, "no-rebuild", false, "don't rebuild std and cmd packages")
+	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
 	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
-	flag.StringVar(&t.runRxStr, "run", "", "run only those tests matching the regular expression; empty means to run all")
+	flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
+		"run only those tests matching the regular expression; empty means to run all. "+
+			"Special exception: if the string begins with '!', the match is inverted.")
 	xflagparse(0)
 	t.run()
 }
@@ -33,8 +37,10 @@ func cmdtest() {
 type tester struct {
 	listMode  bool
 	noRebuild bool
+	keepGoing bool
 	runRxStr  string
 	runRx     *regexp.Regexp
+	runRxWant bool
 	banner    string // prefix, or "" for none
 
 	goroot     string
@@ -129,6 +135,19 @@ func (t *tester) run() {
 	}
 
 	if t.runRxStr != "" {
+		// Temporary (2015-05-14) special case for "std",
+		// which the plan9 builder was using for ages. Delete
+		// this once we update dashboard/builders.go to use a
+		// regexp instead.
+		if runtime.GOOS == "plan9" && t.runRxStr == "std" {
+			t.runRxStr = "^go_test:"
+		}
+		if t.runRxStr[0] == '!' {
+			t.runRxWant = false
+			t.runRxStr = t.runRxStr[1:]
+		} else {
+			t.runRxWant = true
+		}
 		t.runRx = regexp.MustCompile(t.runRxStr)
 	}
 
@@ -146,8 +165,9 @@ func (t *tester) run() {
 	os.Unsetenv("GOROOT_FINAL")
 
 	var lastHeading string
+	ok := true
 	for _, dt := range t.tests {
-		if t.runRx != nil && !t.runRx.MatchString(dt.name) {
+		if t.runRx != nil && (t.runRx.MatchString(dt.name) != t.runRxWant) {
 			t.partial = true
 			continue
 		}
@@ -159,10 +179,18 @@ func (t *tester) run() {
 			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
 		}
 		if err := dt.fn(); err != nil {
-			log.Fatalf("Failed: %v", err)
+			ok = false
+			if t.keepGoing {
+				log.Printf("Failed: %v", err)
+			} else {
+				log.Fatalf("Failed: %v", err)
+			}
 		}
 	}
-	if t.partial {
+	if !ok {
+		fmt.Println("\nFAILED")
+		os.Exit(1)
+	} else if t.partial {
 		fmt.Println("\nALL TESTS PASSED (some were excluded)")
 	} else {
 		fmt.Println("\nALL TESTS PASSED")
@@ -173,52 +201,71 @@ func (t *tester) timeout(sec int) string {
 	return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale))
 }
 
-func (t *tester) registerTests() {
-	// Register a separate logical test for each package in the standard library
-	// but actually group them together at execution time to share the cost of
-	// building packages shared between them.
-	all, err := exec.Command("go", "list", "std", "cmd").Output()
-	if err != nil {
-		log.Fatalf("Error running go list std cmd: %v", err)
-	}
-	// ranGoTest and stdMatches are state closed over by the
-	// stdlib testing func below. The tests are run sequentially,
-	// so there's no need for locks.
-	var (
-		ranGoTest  bool
-		stdMatches []string
-	)
-	for _, pkg := range strings.Fields(string(all)) {
-		testName := "go_test:" + pkg
-		if t.runRx == nil || t.runRx.MatchString(testName) {
-			stdMatches = append(stdMatches, pkg)
-		}
-		t.tests = append(t.tests, distTest{
-			name:    testName,
-			heading: "Testing packages.",
-			fn: func() error {
-				if ranGoTest {
-					return nil
-				}
-				ranGoTest = true
-				cmd := exec.Command("go", append([]string{
-					"test",
-					"-short",
-					t.timeout(120),
-					"-gcflags=" + os.Getenv("GO_GCFLAGS"),
-				}, stdMatches...)...)
-				cmd.Stdout = os.Stdout
-				cmd.Stderr = os.Stderr
-				return cmd.Run()
-			},
-		})
-	}
+// ranGoTest and stdMatches are state closed over by the stdlib
+// testing func in registerStdTest below. The tests are run
+// sequentially, so there's no need for locks.
+var (
+	ranGoTest  bool
+	stdMatches []string
+)
 
-	// Old hack for when Plan 9 on GCE was too slow.
-	// We're keeping this until test sharding (Issue 10029) is finished, though.
-	if os.Getenv("GOTESTONLY") == "std" {
-		t.partial = true
-		return
+func (t *tester) registerStdTest(pkg string) {
+	testName := "go_test:" + pkg
+	if t.runRx == nil || t.runRx.MatchString(testName) {
+		stdMatches = append(stdMatches, pkg)
+	}
+	t.tests = append(t.tests, distTest{
+		name:    testName,
+		heading: "Testing packages.",
+		fn: func() error {
+			if ranGoTest {
+				return nil
+			}
+			ranGoTest = true
+			cmd := exec.Command("go", append([]string{
+				"test",
+				"-short",
+				t.timeout(120),
+				"-gcflags=" + os.Getenv("GO_GCFLAGS"),
+			}, stdMatches...)...)
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			return cmd.Run()
+		},
+	})
+}
+
+// validStdPkg reports whether pkg looks like a standard library package name.
+// Notably, it's not blank and doesn't contain regexp characters.
+func validStdPkg(pkg string) bool {
+	if pkg == "" {
+		return false
+	}
+	for _, r := range pkg {
+		switch {
+		case 'a' <= r && r <= 'z':
+		case 'A' <= r && r <= 'Z':
+		case '0' <= r && r <= '9':
+		case r == '_':
+		case r == '/':
+		default:
+			return false
+		}
+	}
+	return true
+}
+
+func (t *tester) registerTests() {
+	// Fast path to avoid the ~1 second of `go list std cmd` when
+	// the caller passed -run=^go_test:foo/bar$ (as the continuous
+	// build coordinator does).
+	if strings.HasPrefix(t.runRxStr, "^go_test:") && strings.HasSuffix(t.runRxStr, "$") {
+		pkg := strings.TrimPrefix(t.runRxStr, "^go_test:")
+		pkg = strings.TrimSuffix(pkg, "$")
+		if validStdPkg(pkg) {
+			t.registerStdTest(pkg)
+			return
+		}
 	}
 
 	// Runtime CPU tests.
@@ -244,9 +291,7 @@ func (t *tester) registerTests() {
 		},
 	})
 
-	iOS := t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
-
-	if t.cgoEnabled && t.goos != "android" && !iOS {
+	if t.cgoEnabled && t.goos != "android" && !t.iOS() {
 		// Disabled on android and iOS. golang.org/issue/8345
 		t.tests = append(t.tests, distTest{
 			name:    "cgo_stdio",
@@ -265,7 +310,7 @@ func (t *tester) registerTests() {
 			},
 		})
 	}
-	if t.cgoEnabled && t.goos != "android" && !iOS {
+	if t.cgoEnabled && t.goos != "android" && !t.iOS() {
 		// TODO(crawshaw): reenable on android and iOS
 		// golang.org/issue/8345
 		//
@@ -295,7 +340,7 @@ func (t *tester) registerTests() {
 				heading: "../misc/cgo/testso",
 				fn:      t.cgoTestSOWindows,
 			})
-		} else if t.hasBash() && t.goos != "android" && !iOS {
+		} else if t.hasBash() && t.goos != "android" && !t.iOS() {
 			t.registerTest("testso", "../misc/cgo/testso", "./test.bash")
 		}
 		if t.supportedBuildmode("c-archive") {
@@ -305,28 +350,28 @@ func (t *tester) registerTests() {
 			t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
 		}
 		if t.supportedBuildmode("shared") {
-			t.registerTest("testshared", "../misc/cgo/testshared", "./test.bash")
+			t.registerTest("testshared", "../misc/cgo/testshared", "go", "test")
 		}
 		if t.gohostos == "linux" && t.goarch == "amd64" {
 			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
 		}
-		if t.hasBash() && t.goos != "android" && !iOS && t.gohostos != "windows" {
+		if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" {
 			t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash")
 		}
 		if t.gohostos == "linux" && t.extLink() {
 			t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
 		}
 	}
-	if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !iOS {
+	if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !t.iOS() {
 		t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
 		t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
 		t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
 		t.registerTest("shootout", "../test/bench/shootout", "time", "./timing.sh", "-test")
 	}
-	if t.goos != "android" && !iOS {
+	if t.goos != "android" && !t.iOS() {
 		t.registerTest("bench_go1", "../test/bench/go1", "go", "test")
 	}
-	if t.goos != "android" && !iOS {
+	if t.goos != "android" && !t.iOS() {
 		// TODO(bradfitz): shard down into these tests, as
 		// this is one of the slowest (and most shardable)
 		// tests.
@@ -336,7 +381,7 @@ func (t *tester) registerTests() {
 			fn:      t.testDirTest,
 		})
 	}
-	if t.goos != "nacl" && t.goos != "android" && !iOS {
+	if t.goos != "nacl" && t.goos != "android" && !t.iOS() {
 		t.tests = append(t.tests, distTest{
 			name:    "api",
 			heading: "API check",
@@ -346,6 +391,44 @@ func (t *tester) registerTests() {
 		})
 	}
 
+	// Register the standard library tests lasts, to avoid the ~1 second latency
+	// of running `go list std cmd` if we're running a specific test.
+	// Now we know the names of all the other tests registered so far.
+	if !t.wantSpecificRegisteredTest() {
+		all, err := exec.Command("go", "list", "std", "cmd").Output()
+		if err != nil {
+			log.Fatalf("Error running go list std cmd: %v", err)
+		}
+		// Put the standard library tests first.
+		orig := t.tests
+		t.tests = nil
+		for _, pkg := range strings.Fields(string(all)) {
+			t.registerStdTest(pkg)
+		}
+		t.tests = append(t.tests, orig...)
+	}
+}
+
+// wantSpecificRegisteredTest reports whether the caller is requesting a
+// run of a specific test via the flag -run=^TESTNAME$ (as is done by the
+// continuous build coordinator).
+func (t *tester) wantSpecificRegisteredTest() bool {
+	if !strings.HasPrefix(t.runRxStr, "^") || !strings.HasSuffix(t.runRxStr, "$") {
+		return false
+	}
+	test := t.runRxStr[1 : len(t.runRxStr)-1]
+	return t.isRegisteredTestName(test)
+}
+
+// isRegisteredTestName reports whether a test named testName has already
+// been registered.
+func (t *tester) isRegisteredTestName(testName string) bool {
+	for _, tt := range t.tests {
+		if tt.name == testName {
+			return true
+		}
+	}
+	return false
 }
 
 func (t *tester) registerTest(name, dirBanner, bin string, args ...string) {
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index b3be2a975b..18dafc298c 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -132,11 +132,12 @@ func parseArgs() (*build.Package, string, string) {
 	// slash+1: if there's no slash, the value is -1 and start is 0; otherwise
 	// start is the byte after the slash.
 	for start := slash + 1; start < len(arg); start = period + 1 {
-		period = start + strings.Index(arg[start:], ".")
+		period = strings.Index(arg[start:], ".")
 		symbol := ""
 		if period < 0 {
 			period = len(arg)
 		} else {
+			period += start
 			symbol = arg[period+1:]
 		}
 		// Have we identified a package already?
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index 3a0aa7ff89..5c8976b663 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -115,7 +115,7 @@ func (pkg *Package) emit(comment string, node ast.Node) {
 			log.Fatal(err)
 		}
 		if comment != "" {
-			pkg.newlines(1)
+			pkg.newlines(2) // Guarantee blank line before comment.
 			doc.ToText(&pkg.buf, comment, "    ", "\t", 80)
 		}
 		pkg.newlines(1)
@@ -190,6 +190,7 @@ func (pkg *Package) packageDoc() {
 	pkg.valueSummary(pkg.doc.Vars)
 	pkg.funcSummary(pkg.doc.Funcs)
 	pkg.typeSummary()
+	pkg.bugs()
 }
 
 // packageClause prints the package clause.
@@ -253,6 +254,18 @@ func (pkg *Package) typeSummary() {
 	}
 }
 
+// bugs prints the BUGS information for the package.
+// TODO: Provide access to TODOs and NOTEs as well (very noisy so off by default)?
+func (pkg *Package) bugs() {
+	if pkg.doc.Notes["BUG"] == nil {
+		return
+	}
+	pkg.Printf("\n")
+	for _, note := range pkg.doc.Notes["BUG"] {
+		pkg.Printf("%s: %v\n", "BUG", note.Body)
+	}
+}
+
 // findValues finds the doc.Values that describe the symbol.
 func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) {
 	for _, value := range docValues {
@@ -332,13 +345,16 @@ func (pkg *Package) symbolDoc(symbol string) {
 		}
 		decl := typ.Decl
 		spec := pkg.findTypeSpec(decl, typ.Name)
-		trimUnexportedFields(spec)
+		trimUnexportedElems(spec)
 		// If there are multiple types defined, reduce to just this one.
 		if len(decl.Specs) > 1 {
 			decl.Specs = []ast.Spec{spec}
 		}
 		pkg.emit(typ.Doc, decl)
 		// Show associated methods, constants, etc.
+		if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
+			pkg.Printf("\n")
+		}
 		pkg.valueSummary(typ.Consts)
 		pkg.valueSummary(typ.Vars)
 		pkg.funcSummary(typ.Funcs)
@@ -353,22 +369,26 @@ func (pkg *Package) symbolDoc(symbol string) {
 	}
 }
 
-// trimUnexportedFields modifies spec in place to elide unexported fields (unless
-// the unexported flag is set). If spec is not a structure declartion, nothing happens.
-func trimUnexportedFields(spec *ast.TypeSpec) {
+// trimUnexportedElems modifies spec in place to elide unexported fields from
+// structs and methods from interfaces (unless the unexported flag is set).
+func trimUnexportedElems(spec *ast.TypeSpec) {
 	if *unexported {
-		// We're printing all fields.
 		return
 	}
-	// It must be a struct for us to care. (We show unexported methods in interfaces.)
-	structType, ok := spec.Type.(*ast.StructType)
-	if !ok {
-		return
+	switch typ := spec.Type.(type) {
+	case *ast.StructType:
+		typ.Fields = trimUnexportedFields(typ.Fields, "fields")
+	case *ast.InterfaceType:
+		typ.Methods = trimUnexportedFields(typ.Methods, "methods")
 	}
+}
+
+// trimUnexportedFields returns the field list trimmed of unexported fields.
+func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
 	trimmed := false
-	list := make([]*ast.Field, 0, len(structType.Fields.List))
-	for _, field := range structType.Fields.List {
-		// Trims if any is unexported. Fine in practice.
+	list := make([]*ast.Field, 0, len(fields.List))
+	for _, field := range fields.List {
+		// Trims if any is unexported. Good enough in practice.
 		ok := true
 		for _, name := range field.Names {
 			if !isExported(name.Name) {
@@ -381,19 +401,23 @@ func trimUnexportedFields(spec *ast.TypeSpec) {
 			list = append(list, field)
 		}
 	}
-	if trimmed {
-		unexportedField := &ast.Field{
-			Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type.
-			Comment: &ast.CommentGroup{
-				List: []*ast.Comment{
-					&ast.Comment{
-						Text: "// Has unexported fields.\n",
-					},
+	if !trimmed {
+		return fields
+	}
+	unexportedField := &ast.Field{
+		Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type.
+		Comment: &ast.CommentGroup{
+			List: []*ast.Comment{
+				&ast.Comment{
+					Text: fmt.Sprintf("// Has unexported %s.\n", what),
 				},
 			},
-		}
-		list = append(list, unexportedField)
-		structType.Fields.List = list
+		},
+	}
+	return &ast.FieldList{
+		Opening: fields.Opening,
+		List:    append(list, unexportedField),
+		Closing: fields.Closing,
 	}
 }
 
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index e0d4a6c0fe..2b1cbf98ec 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -503,6 +503,7 @@ syntax of package template.  The default output is equivalent to -f
         Name          string // package name
         Doc           string // package documentation string
         Target        string // install path
+        Shlib         string // the shared library that contains this package (only set when -linkshared)
         Goroot        bool   // is this package in the Go root?
         Standard      bool   // is this package part of the standard Go library?
         Stale         bool   // would 'go install' do anything for this package?
@@ -1053,7 +1054,7 @@ environment variable (see 'go help gopath').
 If no import paths are given, the action applies to the
 package in the current directory.
 
-There are three reserved names for paths that should not be used
+There are four reserved names for paths that should not be used
 for packages to be built with the go tool:
 
 - "main" denotes the top-level package in a stand-alone executable.
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index fda126b008..17ff7e0cbb 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -547,9 +547,6 @@ var (
 	goarch    string
 	goos      string
 	exeSuffix string
-
-	archCharVal string
-	archCharErr error
 )
 
 func init() {
@@ -558,16 +555,6 @@ func init() {
 	if goos == "windows" {
 		exeSuffix = ".exe"
 	}
-	archCharVal, archCharErr = build.ArchChar(goarch)
-}
-
-// archChar returns the architecture character.  This is only needed
-// for the gc toolchain, so only fail if we actually need it.
-func archChar() string {
-	if archCharErr != nil {
-		fatalf("%s", archCharErr)
-	}
-	return archCharVal
 }
 
 // A builder holds global state about a build.
@@ -782,8 +769,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 			b.actionCache[key] = a
 			return a
 		}
-		pkgs := readpkglist(filepath.Join(p.build.PkgTargetRoot, shlib))
-		a = b.libaction(shlib, pkgs, modeInstall, depMode)
+		pkgs := readpkglist(shlib)
+		a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode)
 		b.actionCache[key2] = a
 		b.actionCache[key] = a
 		return a
@@ -1208,7 +1195,7 @@ func (b *builder) build(a *action) (err error) {
 		fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
 	}
 
-	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" && archChar() != "" &&
+	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
 		(!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") ||
 			!hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) {
 		return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
@@ -1371,15 +1358,8 @@ func (b *builder) build(a *action) (err error) {
 		}
 	}
 
-	var objExt string
-	if _, ok := buildToolchain.(gccgoToolchain); ok {
-		objExt = "o"
-	} else {
-		objExt = archChar()
-	}
-
 	for _, file := range cfiles {
-		out := file[:len(file)-len(".c")] + "." + objExt
+		out := file[:len(file)-len(".c")] + ".o"
 		if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -1388,7 +1368,7 @@ func (b *builder) build(a *action) (err error) {
 
 	// Assemble .s files.
 	for _, file := range sfiles {
-		out := file[:len(file)-len(".s")] + "." + objExt
+		out := file[:len(file)-len(".s")] + ".o"
 		if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -1532,7 +1512,7 @@ func (b *builder) linkShared(a *action) (err error) {
 		}
 		ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
 	}
-	return b.run(".", a.target, nil, buildToolExec, tool(archChar()+"l"), "-o", a.target, importArgs, ldflags)
+	return b.run(".", a.target, nil, buildToolExec, tool("link"), "-o", a.target, importArgs, ldflags)
 }
 
 // install is the action for installing a single package or executable.
@@ -2109,18 +2089,18 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
 type gcToolchain struct{}
 
 func (gcToolchain) compiler() string {
-	return tool(archChar() + "g")
+	return tool("compile")
 }
 
 func (gcToolchain) linker() string {
-	return tool(archChar() + "l")
+	return tool("link")
 }
 
 func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
 	if archive != "" {
 		ofile = archive
 	} else {
-		out := "_go_." + archChar()
+		out := "_go_.o"
 		ofile = obj + out
 	}
 
@@ -2152,7 +2132,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
 		gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
 	}
 
-	args := []interface{}{buildToolExec, tool(archChar() + "g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
+	args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
 	if ofile == archive {
 		args = append(args, "-pack")
 	}
@@ -2182,9 +2162,22 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
 	}
 	// Disable checks when additional flags are passed, as the old assemblers
 	// don't implement some of them (e.g., -shared).
-	if verifyAsm && goarch != "arm64" && len(buildAsmflags) == 0 {
-		if err := toolVerify(b, p, "old"+archChar()+"a", ofile, args); err != nil {
-			return err
+	if verifyAsm && len(buildAsmflags) == 0 {
+		old := ""
+		switch goarch {
+		case "arm":
+			old = "old5a"
+		case "amd64", "amd64p32":
+			old = "old6a"
+		case "386":
+			old = "old8a"
+		case "ppc64", "ppc64le":
+			old = "old9a"
+		}
+		if old != "" {
+			if err := toolVerify(b, p, old, ofile, args); err != nil {
+				return err
+			}
 		}
 	}
 	return nil
@@ -2333,7 +2326,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
 	ldflags = setextld(ldflags, compiler)
 	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
 	ldflags = append(ldflags, buildLdflags...)
-	return b.run(".", p.ImportPath, nil, buildToolExec, tool(archChar()+"l"), "-o", out, importArgs, ldflags, mainpkg)
+	return b.run(".", p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
 }
 
 func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -2785,13 +2778,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	cgoflags := []string{}
 	// TODO: make cgo not depend on $GOARCH?
 
-	var objExt string
-	if _, ok := buildToolchain.(gccgoToolchain); ok {
-		objExt = "o"
-	} else {
-		objExt = archChar()
-	}
-
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
 	}
@@ -2836,7 +2822,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	// cc _cgo_defun.c
 	_, gccgo := buildToolchain.(gccgoToolchain)
 	if gccgo {
-		defunObj := obj + "_cgo_defun." + objExt
+		defunObj := obj + "_cgo_defun.o"
 		if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
 			return nil, nil, err
 		}
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 863eb4d26e..8d427b37c2 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -49,10 +49,6 @@ func mkEnv() []envVar {
 		{"TERM", "dumb"},
 	}
 
-	if archCharErr == nil {
-		env = append(env, envVar{"GOCHAR", archChar()})
-	}
-
 	if goos != "plan9" {
 		cmd := b.gccCmd(".")
 		env = append(env, envVar{"CC", cmd[0]})
diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go
index 65dc3ca599..1722b9d568 100644
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -4,6 +4,11 @@
 
 package main
 
+import (
+	"os"
+	"path/filepath"
+)
+
 func init() {
 	addBuildFlagsNX(cmdFmt)
 }
@@ -29,10 +34,31 @@ See also: go fix, go vet.
 }
 
 func runFmt(cmd *Command, args []string) {
+	gofmt := gofmtPath()
 	for _, pkg := range packages(args) {
 		// Use pkg.gofiles instead of pkg.Dir so that
 		// the command only applies to this package,
 		// not to packages in subdirectories.
-		run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
+		run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
 	}
 }
+
+func gofmtPath() string {
+	gofmt := "gofmt"
+	if toolIsWindows {
+		gofmt += toolWindowsExtension
+	}
+
+	gofmtPath := filepath.Join(gobin, gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	gofmtPath = filepath.Join(goroot, "bin", gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	// fallback to looking for gofmt in $PATH
+	return "gofmt"
+}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 56e8493e1a..2062f0c4ee 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -47,7 +47,7 @@ environment variable (see 'go help gopath').
 If no import paths are given, the action applies to the
 package in the current directory.
 
-There are three reserved names for paths that should not be used
+There are four reserved names for paths that should not be used
 for packages to be built with the go tool:
 
 - "main" denotes the top-level package in a stand-alone executable.
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 9466aad6a6..601c30362f 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -394,25 +394,17 @@ const (
 
 // goTools is a map of Go program import path to install target directory.
 var goTools = map[string]targetDir{
-	"cmd/5g":                               toTool,
-	"cmd/5l":                               toTool,
-	"cmd/6g":                               toTool,
-	"cmd/6l":                               toTool,
-	"cmd/7g":                               toTool,
-	"cmd/7l":                               toTool,
-	"cmd/8g":                               toTool,
-	"cmd/8l":                               toTool,
-	"cmd/9g":                               toTool,
-	"cmd/9l":                               toTool,
 	"cmd/addr2line":                        toTool,
 	"cmd/api":                              toTool,
 	"cmd/asm":                              toTool,
+	"cmd/compile":                          toTool,
 	"cmd/cgo":                              toTool,
 	"cmd/cover":                            toTool,
 	"cmd/dist":                             toTool,
 	"cmd/doc":                              toTool,
 	"cmd/fix":                              toTool,
 	"cmd/link":                             toTool,
+	"cmd/newlink":                          toTool,
 	"cmd/nm":                               toTool,
 	"cmd/objdump":                          toTool,
 	"cmd/old5a":                            toTool,
@@ -536,7 +528,8 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 			shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
 			shlib, err := ioutil.ReadFile(shlibnamefile)
 			if err == nil {
-				p.Shlib = strings.TrimSpace(string(shlib))
+				libname := strings.TrimSpace(string(shlib))
+				p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
 			} else if !os.IsNotExist(err) {
 				fatalf("unexpected error reading %s: %v", shlibnamefile, err)
 			}
@@ -680,10 +673,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	p.Target = p.target
 
 	// The gc toolchain only permits C source files with cgo.
-	if len(p.CFiles) > 0 && !p.usesCgo() && buildContext.Compiler == "gc" {
+	if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" {
 		p.Error = &PackageError{
 			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
+			Err:         fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
 		}
 		return p
 	}
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 408104d776..2179000afd 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -115,8 +115,12 @@ var vcsGit = &vcsCmd{
 	tagLookupCmd: []tagCmd{
 		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
 	},
-	tagSyncCmd:     "checkout {tag}",
-	tagSyncDefault: "checkout master",
+	tagSyncCmd: "checkout {tag}",
+	// both createCmd and downloadCmd update the working dir.
+	// No need to do more here. We used to 'checkout master'
+	// but that doesn't work if the default branch is not named master.
+	// See golang.org/issue/9032.
+	tagSyncDefault: "",
 
 	scheme:     []string{"git", "https", "http", "git+ssh"},
 	pingCmd:    "ls-remote {scheme}://{repo}",
diff --git a/src/cmd/internal/asm/lexbody.go b/src/cmd/internal/asm/lexbody.go
index b5e5d1eee2..a1519c8566 100644
--- a/src/cmd/internal/asm/lexbody.go
+++ b/src/cmd/internal/asm/lexbody.go
@@ -149,7 +149,7 @@ func newfile(s string, f *os.File) {
 	}
 
 	fi.P = nil
-	obj.Linklinehist(Ctxt, int(Lineno), s, 0)
+	Ctxt.LineHist.Push(int(Lineno), s)
 }
 
 var thetext *obj.LSym
@@ -630,7 +630,7 @@ loop:
 	n, _ = i.F.Read(i.B[:])
 	if n == 0 {
 		i.F.Close()
-		obj.Linklinehist(Ctxt, int(Lineno), "", 0)
+		Ctxt.LineHist.Pop(int(Lineno))
 		goto pop
 	}
 	fi.P = i.B[1:n]
diff --git a/src/cmd/internal/asm/macbody.go b/src/cmd/internal/asm/macbody.go
index c488ea1e56..4565d3a37f 100644
--- a/src/cmd/internal/asm/macbody.go
+++ b/src/cmd/internal/asm/macbody.go
@@ -32,7 +32,6 @@ package asm
 
 import (
 	"bytes"
-	"cmd/internal/obj"
 	"fmt"
 	"os"
 	"strings"
@@ -683,7 +682,7 @@ func maclin() {
 	}
 
 nn:
-	obj.Linklinehist(Ctxt, int(Lineno), symb, int(n))
+	Ctxt.LineHist.Update(int(Lineno), symb, int(n))
 	return
 
 bad:
@@ -796,7 +795,7 @@ func macprag() {
 		/*
 		 * put pragma-line in as a funny history
 		 */
-		obj.Linklinehist(Ctxt, int(Lineno), symb, -1)
+		Ctxt.AddImport(symb)
 		return
 	}
 	if s != nil && s.Name == "pack" {
diff --git a/src/cmd/internal/gc/go.errors b/src/cmd/internal/gc/go.errors
deleted file mode 100644
index 8370a2007d..0000000000
--- a/src/cmd/internal/gc/go.errors
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See yaccerrors.go.
-
-package gc
-
-var yymsg = []struct {
-	yystate int
-	yychar  int
-	msg     string
-}{
-	// Each line of the form % token list
-	// is converted by yaccerrors.go into the yystate and yychar caused
-	// by that token list.
-
-	% loadsys package LIMPORT '(' LLITERAL import_package import_there ','
-		"unexpected comma during import block"},
-
-	% loadsys package LIMPORT LNAME ';'
-		"missing import path; require quoted string"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
-		"missing { after if clause"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
-		"missing { after switch clause"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
-		"missing { after for clause"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
-		"missing { after for clause"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' ';' '{'
-		"unexpected semicolon or newline before {"},
-
-	% loadsys package imports LTYPE LNAME ';'
-		"unexpected semicolon or newline in type declaration"},
-
-	% loadsys package imports LCHAN '}'
-		"unexpected } in channel type"},
-
-	% loadsys package imports LCHAN ')'
-		"unexpected ) in channel type"},
-
-	% loadsys package imports LCHAN ','
-		"unexpected comma in channel type"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
-		"unexpected semicolon or newline before else"},
-
-	% loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
-		"name list not allowed in interface type"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
-		"var declaration not allowed in for initializer"},
-
-	% loadsys package imports LVAR LNAME '[' ']' LNAME '{'
-		"unexpected { at end of statement"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
-		"unexpected { at end of statement"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
-		"argument to go/defer must be function call"},
-
-	% loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
-		"need trailing comma before newline in composite literal"},
-
-	% loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';'
-		"need trailing comma before newline in composite literal"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
-		"nested func not allowed"},
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
-		"else must be followed by if or statement block"},
-}
diff --git a/src/cmd/internal/gc/yaccerrors.go b/src/cmd/internal/gc/yaccerrors.go
deleted file mode 100644
index 9dc54d9c8c..0000000000
--- a/src/cmd/internal/gc/yaccerrors.go
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2010 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.
-
-// +build ignore
-
-// This program implements the core idea from
-//
-//	Clinton L. Jeffery, Generating LR syntax error messages from examples,
-//	ACM TOPLAS 25(5) (September 2003).  http://doi.acm.org/10.1145/937563.937566
-//
-// It reads Bison's summary of a grammar followed by a file
-// like go.errors, replacing lines beginning with % by the
-// yystate and yychar that will be active when an error happens
-// while parsing that line.
-//
-// Unlike the system described in the paper, the lines in go.errors
-// give grammar symbol name lists, not actual program fragments.
-// This is a little less programmer-friendly but doesn't require being
-// able to run the text through lex.c.
-
-package main
-
-import (
-	"bufio"
-	"fmt"
-	"io"
-	"log"
-	"os"
-	"strconv"
-	"strings"
-)
-
-func xatoi(s string) int {
-	n, err := strconv.Atoi(s)
-	if err != nil {
-		log.Fatal(err)
-	}
-	return n
-}
-
-func trimParen(s string) string {
-	s = strings.TrimPrefix(s, "(")
-	s = strings.TrimSuffix(s, ")")
-	return s
-}
-
-type action struct {
-	token string
-	n     int
-}
-
-var shift = map[int][]action{}
-var reduce = map[int][]action{}
-
-type rule struct {
-	lhs  string
-	size int
-}
-
-var rules = map[int]rule{}
-
-func readYaccOutput() {
-	r, err := os.Open("y.output")
-	if err != nil {
-		log.Fatal(err)
-	}
-	defer r.Close()
-
-	var state int
-
-	scanner := bufio.NewScanner(r)
-	for scanner.Scan() {
-		f := strings.Fields(scanner.Text())
-		nf := len(f)
-
-		if nf >= 4 && f[1] == "terminals," && f[3] == "nonterminals" {
-			// We're done.
-			break
-		}
-
-		if nf >= 2 && f[0] == "state" {
-			state = xatoi(f[1])
-			continue
-		}
-		if nf >= 3 && (f[1] == "shift" || f[1] == "goto") {
-			shift[state] = append(shift[state], action{f[0], xatoi(f[2])})
-			continue
-		}
-		if nf >= 3 && f[1] == "reduce" {
-			reduce[state] = append(reduce[state], action{f[0], xatoi(f[2])})
-			continue
-		}
-		if nf >= 3 && strings.HasSuffix(f[0], ":") && strings.HasPrefix(f[nf-1], "(") && strings.HasSuffix(f[nf-1], ")") {
-			n := xatoi(trimParen(f[nf-1]))
-
-			size := nf - 2
-			if size == 1 && f[1] == "." {
-				size = 0
-			}
-
-			rules[n] = rule{strings.TrimSuffix(f[0], ":"), size}
-			continue
-		}
-	}
-}
-
-func runMachine(w io.Writer, s string) {
-	f := strings.Fields(s)
-
-	// Run it through the LR machine and print the induced "yystate, yychar,"
-	// at the point where the error happens.
-
-	var stack []int
-	state := 0
-	i := 1
-	tok := ""
-
-Loop:
-	if tok == "" && i < len(f) {
-		tok = f[i]
-		i++
-	}
-
-	for _, a := range shift[state] {
-		if a.token == tok {
-			if false {
-				fmt.Println("SHIFT ", tok, " ", state, " -> ", a)
-			}
-			stack = append(stack, state)
-			state = a.n
-			tok = ""
-			goto Loop
-		}
-	}
-
-	for _, a := range reduce[state] {
-		if a.token == tok || a.token == "." {
-			stack = append(stack, state)
-			rule, ok := rules[a.n]
-			if !ok {
-				log.Fatal("missing rule")
-			}
-			stack = stack[:len(stack)-rule.size]
-			state = stack[len(stack)-1]
-			stack = stack[:len(stack)-1]
-			if tok != "" {
-				i--
-			}
-			tok = rule.lhs
-			if false {
-				fmt.Println("REDUCE ", stack, " ", state, " ", tok, " rule ", rule)
-			}
-			goto Loop
-		}
-	}
-
-	// No shift or reduce applied - found the error.
-	fmt.Fprintf(w, "\t{%d, %s,\n", state, tok)
-}
-
-func processGoErrors() {
-	r, err := os.Open("go.errors")
-	if err != nil {
-		log.Fatal(err)
-	}
-	defer r.Close()
-
-	w, err := os.Create("yymsg.go")
-	if err != nil {
-		log.Fatal(err)
-	}
-	defer w.Close()
-
-	fmt.Fprintf(w, "// DO NOT EDIT - generated with go generate\n\n")
-
-	scanner := bufio.NewScanner(r)
-	for scanner.Scan() {
-		s := scanner.Text()
-
-		// Treat % as first field on line as introducing a pattern (token sequence).
-		if strings.HasPrefix(strings.TrimSpace(s), "%") {
-			runMachine(w, s)
-			continue
-		}
-
-		fmt.Fprintln(w, s)
-	}
-}
-
-func main() {
-	readYaccOutput()
-	processGoErrors()
-}
diff --git a/src/cmd/internal/gc/yymsg.go b/src/cmd/internal/gc/yymsg.go
deleted file mode 100644
index cb45cb8d1b..0000000000
--- a/src/cmd/internal/gc/yymsg.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// DO NOT EDIT - generated with go generate
-
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See yaccerrors.go.
-
-package gc
-
-var yymsg = []struct {
-	yystate int
-	yychar  int
-	msg     string
-}{
-	// Each line of the form % token list
-	// is converted by yaccerrors.go into the yystate and yychar caused
-	// by that token list.
-
-	{332, ',',
-		"unexpected comma during import block"},
-
-	{89, ';',
-		"missing import path; require quoted string"},
-
-	{390, ';',
-		"missing { after if clause"},
-
-	{387, ';',
-		"missing { after switch clause"},
-
-	{279, ';',
-		"missing { after for clause"},
-
-	{498, LBODY,
-		"missing { after for clause"},
-
-	{17, '{',
-		"unexpected semicolon or newline before {"},
-
-	{111, ';',
-		"unexpected semicolon or newline in type declaration"},
-
-	{78, '}',
-		"unexpected } in channel type"},
-
-	{78, ')',
-		"unexpected ) in channel type"},
-
-	{78, ',',
-		"unexpected comma in channel type"},
-
-	{416, LELSE,
-		"unexpected semicolon or newline before else"},
-
-	{329, ',',
-		"name list not allowed in interface type"},
-
-	{279, LVAR,
-		"var declaration not allowed in for initializer"},
-
-	{25, '{',
-		"unexpected { at end of statement"},
-
-	{371, '{',
-		"unexpected { at end of statement"},
-
-	{122, ';',
-		"argument to go/defer must be function call"},
-
-	{398, ';',
-		"need trailing comma before newline in composite literal"},
-
-	{414, ';',
-		"need trailing comma before newline in composite literal"},
-
-	{124, LNAME,
-		"nested func not allowed"},
-
-	{650, ';',
-		"else must be followed by if or statement block"},
-}
diff --git a/src/cmd/internal/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go
new file mode 100644
index 0000000000..5845f7d65e
--- /dev/null
+++ b/src/cmd/internal/gcprog/gcprog.go
@@ -0,0 +1,298 @@
+// Copyright 2015 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 gcprog implements an encoder for packed GC pointer bitmaps,
+// known as GC programs.
+//
+// Program Format
+//
+// The GC program encodes a sequence of 0 and 1 bits indicating scalar or pointer words in an object.
+// The encoding is a simple Lempel-Ziv program, with codes to emit literal bits and to repeat the
+// last n bits c times.
+//
+// The possible codes are:
+//
+//	00000000: stop
+//	0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes, least significant bit first
+//	10000000 n c: repeat the previous n bits c times; n, c are varints
+//	1nnnnnnn c: repeat the previous n bits c times; c is a varint
+//
+// The numbers n and c, when they follow a code, are encoded as varints
+// using the same encoding as encoding/binary's Uvarint.
+//
+package gcprog
+
+import (
+	"fmt"
+	"io"
+)
+
+const progMaxLiteral = 127 // maximum n for literal n bit code
+
+// A Writer is an encoder for GC programs.
+//
+// The typical use of a Writer is to call Init, maybe call Debug,
+// make a sequence of Ptr, Advance, Repeat, and Append calls
+// to describe the data type, and then finally call End.
+type Writer struct {
+	writeByte func(byte)
+	symoff    int
+	index     int64
+	b         [progMaxLiteral]byte
+	nb        int
+	debug     io.Writer
+	debugBuf  []byte
+}
+
+// Init initializes w to write a new GC program
+// by calling writeByte for each byte in the program.
+func (w *Writer) Init(writeByte func(byte)) {
+	w.writeByte = writeByte
+}
+
+// Debug causes the writer to print a debugging trace to out
+// during future calls to methods like Ptr, Advance, and End.
+// It also enables debugging checks during the encoding.
+func (w *Writer) Debug(out io.Writer) {
+	w.debug = out
+}
+
+// BitIndex returns the number of bits written to the bit stream so far.
+func (w *Writer) BitIndex() int64 {
+	return w.index
+}
+
+// byte writes the byte x to the output.
+func (w *Writer) byte(x byte) {
+	if w.debug != nil {
+		w.debugBuf = append(w.debugBuf, x)
+	}
+	w.writeByte(x)
+}
+
+// End marks the end of the program, writing any remaining bytes.
+func (w *Writer) End() {
+	w.flushlit()
+	w.byte(0)
+	if w.debug != nil {
+		index := progbits(w.debugBuf)
+		if index != w.index {
+			println("gcprog: End wrote program for", index, "bits, but current index is", w.index)
+			panic("gcprog: out of sync")
+		}
+	}
+}
+
+// Ptr emits a 1 into the bit stream at the given bit index.
+// that is, it records that the index'th word in the object memory is a pointer.
+// Any bits between the current index and the new index
+// are set to zero, meaning the corresponding words are scalars.
+func (w *Writer) Ptr(index int64) {
+	if index < w.index {
+		println("gcprog: Ptr at index", index, "but current index is", w.index)
+		panic("gcprog: invalid Ptr index")
+	}
+	w.ZeroUntil(index)
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: ptr at %d\n", index)
+	}
+	w.lit(1)
+}
+
+// ShouldRepeat reports whether it would be worthwhile to
+// use a Repeat to describe c elements of n bits each,
+// compared to just emitting c copies of the n-bit description.
+func (w *Writer) ShouldRepeat(n, c int64) bool {
+	// Should we lay out the bits directly instead of
+	// encoding them as a repetition? Certainly if count==1,
+	// since there's nothing to repeat, but also if the total
+	// size of the plain pointer bits for the type will fit in
+	// 4 or fewer bytes, since using a repetition will require
+	// flushing the current bits plus at least one byte for
+	// the repeat size and one for the repeat count.
+	return c > 1 && c*n > 4*8
+}
+
+// Repeat emits an instruction to repeat the description
+// of the last n words c times (including the initial description, c+1 times in total).
+func (w *Writer) Repeat(n, c int64) {
+	if n == 0 || c == 0 {
+		return
+	}
+	w.flushlit()
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: repeat %d × %d\n", n, c)
+	}
+	if n < 128 {
+		w.byte(0x80 | byte(n))
+	} else {
+		w.byte(0x80)
+		w.varint(n)
+	}
+	w.varint(c)
+	w.index += n * c
+}
+
+// ZeroUntil adds zeros to the bit stream until reaching the given index;
+// that is, it records that the words from the most recent pointer until
+// the index'th word are scalars.
+// ZeroUntil is usually called in preparation for a call to Repeat, Append, or End.
+func (w *Writer) ZeroUntil(index int64) {
+	if index < w.index {
+		println("gcprog: Advance", index, "but index is", w.index)
+		panic("gcprog: invalid Advance index")
+	}
+	skip := (index - w.index)
+	if skip == 0 {
+		return
+	}
+	if skip < 4*8 {
+		if w.debug != nil {
+			fmt.Fprintf(w.debug, "gcprog: advance to %d by literals\n", index)
+		}
+		for i := int64(0); i < skip; i++ {
+			w.lit(0)
+		}
+		return
+	}
+
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: advance to %d by repeat\n", index)
+	}
+	w.lit(0)
+	w.flushlit()
+	w.Repeat(1, skip-1)
+}
+
+// Append emits the given GC program into the current output.
+// The caller asserts that the program emits n bits (describes n words),
+// and Append panics if that is not true.
+func (w *Writer) Append(prog []byte, n int64) {
+	w.flushlit()
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: append prog for %d ptrs\n", n)
+		fmt.Fprintf(w.debug, "\t")
+	}
+	n1 := progbits(prog)
+	if n1 != n {
+		panic("gcprog: wrong bit count in append")
+	}
+	// The last byte of the prog terminates the program.
+	// Don't emit that, or else our own program will end.
+	for i, x := range prog[:len(prog)-1] {
+		if w.debug != nil {
+			if i > 0 {
+				fmt.Fprintf(w.debug, " ")
+			}
+			fmt.Fprintf(w.debug, "%02x", x)
+		}
+		w.byte(x)
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "\n")
+	}
+	w.index += n
+}
+
+// progbits returns the length of the bit stream encoded by the program p.
+func progbits(p []byte) int64 {
+	var n int64
+	for len(p) > 0 {
+		x := p[0]
+		p = p[1:]
+		if x == 0 {
+			break
+		}
+		if x&0x80 == 0 {
+			count := x &^ 0x80
+			n += int64(count)
+			p = p[(count+7)/8:]
+			continue
+		}
+		nbit := int64(x &^ 0x80)
+		if nbit == 0 {
+			nbit, p = readvarint(p)
+		}
+		var count int64
+		count, p = readvarint(p)
+		n += nbit * count
+	}
+	if len(p) > 0 {
+		println("gcprog: found end instruction after", n, "ptrs, with", len(p), "bytes remaining")
+		panic("gcprog: extra data at end of program")
+	}
+	return n
+}
+
+// readvarint reads a varint from p, returning the value and the remainder of p.
+func readvarint(p []byte) (int64, []byte) {
+	var v int64
+	var nb uint
+	for {
+		c := p[0]
+		p = p[1:]
+		v |= int64(c&^0x80) << nb
+		nb += 7
+		if c&0x80 == 0 {
+			break
+		}
+	}
+	return v, p
+}
+
+// lit adds a single literal bit to w.
+func (w *Writer) lit(x byte) {
+	if w.nb == progMaxLiteral {
+		w.flushlit()
+	}
+	w.b[w.nb] = x
+	w.nb++
+	w.index++
+}
+
+// varint emits the varint encoding of x.
+func (w *Writer) varint(x int64) {
+	if x < 0 {
+		panic("gcprog: negative varint")
+	}
+	for x >= 0x80 {
+		w.byte(byte(0x80 | x))
+		x >>= 7
+	}
+	w.byte(byte(x))
+}
+
+// flushlit flushes any pending literal bits.
+func (w *Writer) flushlit() {
+	if w.nb == 0 {
+		return
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: flush %d literals\n", w.nb)
+		fmt.Fprintf(w.debug, "\t%v\n", w.b[:w.nb])
+		fmt.Fprintf(w.debug, "\t%02x", byte(w.nb))
+	}
+	w.byte(byte(w.nb))
+	var bits uint8
+	for i := 0; i < w.nb; i++ {
+		bits |= w.b[i] << uint(i%8)
+		if (i+1)%8 == 0 {
+			if w.debug != nil {
+				fmt.Fprintf(w.debug, " %02x", bits)
+			}
+			w.byte(bits)
+			bits = 0
+		}
+	}
+	if w.nb%8 != 0 {
+		if w.debug != nil {
+			fmt.Fprintf(w.debug, " %02x", bits)
+		}
+		w.byte(bits)
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "\n")
+	}
+	w.nb = 0
+}
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 6e00cb55ab..9e643932be 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -2677,8 +2677,8 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 59: /* stxr/stlxr */
 		o1 = opstore(ctxt, int(p.As))
 
-		if p.To2.Type != obj.TYPE_NONE {
-			o1 |= uint32(p.To2.Reg&31) << 16
+		if p.RegTo2 != obj.REG_NONE {
+			o1 |= uint32(p.RegTo2&31) << 16
 		} else {
 			o1 |= 0x1F << 16
 		}
diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go
index dde5d64e17..5486f0d648 100644
--- a/src/cmd/internal/obj/line_test.go
+++ b/src/cmd/internal/obj/line_test.go
@@ -13,13 +13,13 @@ func TestLineHist(t *testing.T) {
 	ctxt := new(Link)
 	ctxt.Hash = make(map[SymVer]*LSym)
 
-	Linklinehist(ctxt, 1, "a.c", 0)
-	Linklinehist(ctxt, 3, "a.h", 0)
-	Linklinehist(ctxt, 5, "", 0)
-	Linklinehist(ctxt, 7, "linedir", 2)
-	Linklinehist(ctxt, 9, "", 0)
-	Linklinehist(ctxt, 11, "b.c", 0)
-	Linklinehist(ctxt, 13, "", 0)
+	ctxt.LineHist.Push(1, "a.c")
+	ctxt.LineHist.Push(3, "a.h")
+	ctxt.LineHist.Pop(5)
+	ctxt.LineHist.Update(7, "linedir", 2)
+	ctxt.LineHist.Pop(9)
+	ctxt.LineHist.Push(11, "b.c")
+	ctxt.LineHist.Pop(13)
 
 	var expect = []string{
 		0:  "??:0",
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 9f5e87b4c3..2fc12c1eb1 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -206,7 +206,6 @@ type Prog struct {
 	From     Addr
 	From3    Addr
 	To       Addr
-	To2      Addr
 	Opt      interface{}
 	Forwd    *Prog
 	Pcond    *Prog
@@ -217,12 +216,12 @@ type Prog struct {
 	Spadj    int32
 	As       int16
 	Reg      int16
+	RegTo2   int16 // 2nd register output operand
 	Mark     uint16
 	Optab    uint16
 	Scond    uint8
 	Back     uint8
 	Ft       uint8
-	F3t      uint8
 	Tt       uint8
 	Isize    uint8
 	Printed  uint8
diff --git a/src/cmd/internal/obj/mgc0.go b/src/cmd/internal/obj/mgc0.go
index 2407deaf32..a385d607bb 100644
--- a/src/cmd/internal/obj/mgc0.go
+++ b/src/cmd/internal/obj/mgc0.go
@@ -21,16 +21,6 @@ package obj
 
 // Used by cmd/gc.
 
-const (
-	GcBits          = 4
-	BitsPerPointer  = 2
-	BitsDead        = 0
-	BitsScalar      = 1
-	BitsPointer     = 2
-	BitsMask        = 3
-	PointersPerByte = 8 / BitsPerPointer
-)
-
 const (
 	InsData = 1 + iota
 	InsArray
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index 39db2396e7..af3290d3a5 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -241,12 +241,6 @@ func (h *LineHist) LineString(lineno int) string {
 	return text
 }
 
-// TODO(rsc): Replace call sites with use of ctxt.LineHist.
-// Note that all call sites use showAll=false, showFullPath=false.
-func Linklinefmt(ctxt *Link, lineno int, showAll, showFullPath bool) string {
-	return ctxt.LineHist.LineString(lineno)
-}
-
 // FileLine returns the file name and line number
 // at the top of the stack for the given lineno.
 func (h *LineHist) FileLine(lineno int) (file string, line int) {
@@ -287,30 +281,3 @@ func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) {
 func Linkprfile(ctxt *Link, line int) {
 	fmt.Printf("%s ", ctxt.LineHist.LineString(line))
 }
-
-// Linklinehist pushes, amends, or pops an entry on the line history stack.
-// If f != "" and n == 0, the call pushes the start of a new file named f at lineno.
-// If f != "" and n > 0, the call amends the top of the stack to record that lineno
-// now corresponds to f at line n.
-// If f == "", the call pops the topmost entry from the stack, picking up
-// the parent file at the line following the one where the corresponding push occurred.
-//
-// If n < 0, linklinehist records f as a package required by the current compilation
-// (nothing to do with line numbers).
-//
-// TODO(rsc): Replace uses with direct calls to ctxt.Hist methods.
-func Linklinehist(ctxt *Link, lineno int, f string, n int) {
-	switch {
-	case n < 0:
-		ctxt.AddImport(f)
-
-	case f == "":
-		ctxt.LineHist.Pop(lineno)
-
-	case n == 0:
-		ctxt.LineHist.Push(lineno, f)
-
-	default:
-		ctxt.LineHist.Update(lineno, f, n)
-	}
-}
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index b0b209184f..efecae62ac 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -213,10 +213,17 @@ func Getgoos() string {
 }
 
 func Getgoarm() string {
-	return envOr("GOARM", defaultGOARM)
+	switch v := envOr("GOARM", defaultGOARM); v {
+	case "5", "6", "7":
+		return v
+	}
+	// Fail here, rather than validate at multiple call sites.
+	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
+	panic("unreachable")
 }
 
 func Getgo386() string {
+	// Validated by cmd/8g.
 	return envOr("GO386", defaultGO386)
 }
 
@@ -234,7 +241,7 @@ func Atoi(s string) int {
 }
 
 func (p *Prog) Line() string {
-	return Linklinefmt(p.Ctxt, int(p.Lineno), false, false)
+	return p.Ctxt.LineHist.LineString(int(p.Lineno))
 }
 
 var armCondCode = []string{
@@ -320,8 +327,8 @@ func (p *Prog) String() string {
 	if p.To.Type != TYPE_NONE {
 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
 	}
-	if p.To2.Type != TYPE_NONE {
-		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To2))
+	if p.RegTo2 != REG_NONE {
+		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
 	}
 	return buf.String()
 }
@@ -333,7 +340,7 @@ func (ctxt *Link) NewProg() *Prog {
 }
 
 func (ctxt *Link) Line(n int) string {
-	return Linklinefmt(ctxt, n, false, false)
+	return ctxt.LineHist.LineString(n)
 }
 
 func Getcallerpc(interface{}) uintptr {
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 0c0cc04548..2b9c2670df 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2974,15 +2974,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 	if p.Ft == 0 {
 		p.Ft = uint8(oclass(ctxt, p, &p.From))
 	}
-	if p.F3t == 0 {
-		p.F3t = uint8(oclass(ctxt, p, &p.From3))
-	}
 	if p.Tt == 0 {
 		p.Tt = uint8(oclass(ctxt, p, &p.To))
 	}
 
 	ft := int(p.Ft) * Ymax
-	f3t := int(p.F3t) * Ymax
+	f3t := oclass(ctxt, p, &p.From3) * Ymax
 	tt := int(p.Tt) * Ymax
 
 	xo := obj.Bool2int(o.op[0] == 0x0f)
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 7a4fc128e6..4798c8f7fb 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -350,9 +350,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		if p.From3.Name == obj.NAME_EXTERN {
 			ctxt.Diag("don't know how to handle %v with -dynlink", p)
 		}
-		if p.To2.Name == obj.NAME_EXTERN {
-			ctxt.Diag("don't know how to handle %v with -dynlink", p)
-		}
 		var source *obj.Addr
 		if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
 			if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go
index a6cd02b930..7371c0d9d1 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -13,6 +13,8 @@ import (
 	"sort"
 )
 
+const stabTypeMask = 0xe0
+
 type machoFile struct {
 	macho *macho.File
 }
@@ -34,12 +36,19 @@ func (f *machoFile) symbols() ([]Sym, error) {
 	// We infer the size of a symbol by looking at where the next symbol begins.
 	var addrs []uint64
 	for _, s := range f.macho.Symtab.Syms {
-		addrs = append(addrs, s.Value)
+		// Skip stab debug info.
+		if s.Type&stabTypeMask == 0 {
+			addrs = append(addrs, s.Value)
+		}
 	}
 	sort.Sort(uint64s(addrs))
 
 	var syms []Sym
 	for _, s := range f.macho.Symtab.Syms {
+		if s.Type&stabTypeMask != 0 {
+			// Skip stab debug info.
+			continue
+		}
 		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
 		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
 		if i < len(addrs) {
diff --git a/src/cmd/6l/asm.go b/src/cmd/link/internal/amd64/asm.go
similarity index 89%
rename from src/cmd/6l/asm.go
rename to src/cmd/link/internal/amd64/asm.go
index a025ce6ea6..74ec9dd3ea 100644
--- a/src/cmd/6l/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -28,11 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"debug/elf"
 	"fmt"
 	"log"
@@ -44,24 +44,6 @@ func PADDR(x uint32) uint32 {
 
 var zeroes string
 
-func needlib(name string) int {
-	if name[0] == '\x00' {
-		return 0
-	}
-
-	/* reuse hash code in symbol table */
-	p := fmt.Sprintf(".elfload.%s", name)
-
-	s := ld.Linklookup(ld.Ctxt, p, 0)
-
-	if s.Type == 0 {
-		s.Type = 100 // avoid SDATA, etc.
-		return 1
-	}
-
-	return 0
-}
-
 func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
 	s.Reachable = true
 	i := s.Size
@@ -292,7 +274,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			break
 		}
 		if ld.Iself {
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
 			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
 			if r.Siz == 8 {
@@ -316,7 +298,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			// just in case the C code assigns to the variable,
 			// and of course it only works for single pointers,
 			// but we only need to support cgo and that's all it needs.
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 
 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
 			s.Type = got.Type | obj.SSUB
@@ -423,9 +405,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 		v = uint32(rs.Dynid)
 		v |= 1 << 27 // external relocation
 	} else {
-		v = uint32((rs.Sect.(*ld.Section)).Extnum)
+		v = uint32(rs.Sect.Extnum)
 		if v == 0 {
-			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
 			return -1
 		}
 	}
@@ -544,7 +526,7 @@ func addpltsym(s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ld.Ctxt, s)
+	ld.Adddynsym(ld.Ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
@@ -612,7 +594,7 @@ func addgotsym(s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ld.Ctxt, s)
+	ld.Adddynsym(ld.Ctxt, s)
 	got := ld.Linklookup(ld.Ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint64(ld.Ctxt, got, 0)
@@ -629,80 +611,6 @@ func addgotsym(s *ld.LSym) {
 	}
 }
 
-func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	if s.Dynid >= 0 {
-		return
-	}
-
-	if ld.Iself {
-		s.Dynid = int32(ld.Nelfsym)
-		ld.Nelfsym++
-
-		d := ld.Linklookup(ctxt, ".dynsym", 0)
-
-		name := s.Extname
-		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
-
-		/* type */
-		t := ld.STB_GLOBAL << 4
-
-		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
-			t |= ld.STT_FUNC
-		} else {
-			t |= ld.STT_OBJECT
-		}
-		ld.Adduint8(ctxt, d, uint8(t))
-
-		/* reserved */
-		ld.Adduint8(ctxt, d, 0)
-
-		/* section where symbol is defined */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
-		} else {
-			ld.Adduint16(ctxt, d, 1)
-		}
-
-		/* value */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint64(ctxt, d, 0)
-		} else {
-			ld.Addaddr(ctxt, d, s)
-		}
-
-		/* size of object */
-		ld.Adduint64(ctxt, d, uint64(s.Size))
-
-		if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 {
-			ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
-		}
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
-	} else if ld.HEADTYPE == obj.Hwindows {
-	} else // already taken care of
-	{
-		ld.Diag("adddynsym: unsupported binary format")
-	}
-}
-
-func adddynlib(lib string) {
-	if needlib(lib) == 0 {
-		return
-	}
-
-	if ld.Iself {
-		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
-		if s.Size == 0 {
-			ld.Addstring(s, "")
-		}
-		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Machoadddynlib(lib)
-	} else {
-		ld.Diag("adddynlib: unsupported binary format")
-	}
-}
-
 func asmb() {
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
@@ -802,7 +710,7 @@ func asmb() {
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
 		case obj.Hdarwin:
-			symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
+			symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
 
 		case obj.Hlinux,
 			obj.Hfreebsd,
diff --git a/src/cmd/6l/l.go b/src/cmd/link/internal/amd64/l.go
similarity index 96%
rename from src/cmd/6l/l.go
rename to src/cmd/link/internal/amd64/l.go
index 6b42088de3..2537419eff 100644
--- a/src/cmd/6l/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 const (
 	thechar   = '6'
@@ -40,7 +40,8 @@ const (
 	MINLC = 1
 )
 
-/* Used by ../ld/dwarf.c */
+/* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 7
+	DWARFREGLR = 16
 )
diff --git a/src/cmd/6l/obj.go b/src/cmd/link/internal/amd64/obj.go
similarity index 91%
rename from src/cmd/6l/obj.go
rename to src/cmd/link/internal/amd64/obj.go
index 9e6dc60e2d..1aa4422ed9 100644
--- a/src/cmd/6l/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -28,18 +28,18 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package amd64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
 // Reading object files.
 
-func main() {
+func Main() {
 	linkarchinit()
 	ld.Ldmain()
 }
@@ -59,10 +59,9 @@ func linkarchinit() {
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
+	ld.Thearch.Dwarfreglr = DWARFREGLR
 
-	ld.Thearch.Adddynlib = adddynlib
 	ld.Thearch.Adddynrel = adddynrel
-	ld.Thearch.Adddynsym = adddynsym
 	ld.Thearch.Archinit = archinit
 	ld.Thearch.Archreloc = archreloc
 	ld.Thearch.Archrelocvariant = archrelocvariant
@@ -91,7 +90,7 @@ func archinit() {
 		ld.Linkmode = ld.LinkInternal
 	}
 
-	if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
+	if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
 		ld.Linkmode = ld.LinkExternal
 	}
 
@@ -169,14 +168,6 @@ func archinit() {
 		ld.Elfinit()
 
 		ld.HEADR = ld.ELFRESERVE
-		if ld.Buildmode == ld.BuildmodeShared {
-			// When building a shared library we write a package list
-			// note that can get quite large. The external linker will
-			// re-layout all the sections anyway, so making this larger
-			// just wastes a little space in the intermediate object
-			// file, not the final shared library.
-			ld.HEADR *= 3
-		}
 		if ld.INITTEXT == -1 {
 			ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
 		}
diff --git a/src/cmd/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go
new file mode 100644
index 0000000000..f70035b9e3
--- /dev/null
+++ b/src/cmd/link/internal/amd64/z.go
@@ -0,0 +1 @@
+package amd64
diff --git a/src/cmd/5l/asm.go b/src/cmd/link/internal/arm/asm.go
similarity index 87%
rename from src/cmd/5l/asm.go
rename to src/cmd/link/internal/arm/asm.go
index 85ea684fc7..39d4550917 100644
--- a/src/cmd/5l/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -28,33 +28,15 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
-func needlib(name string) int {
-	if name[0] == '\x00' {
-		return 0
-	}
-
-	/* reuse hash code in symbol table */
-	p := fmt.Sprintf(".dynlib.%s", name)
-
-	s := ld.Linklookup(ld.Ctxt, p, 0)
-
-	if s.Type == 0 {
-		s.Type = 100 // avoid SDATA, etc.
-		return 1
-	}
-
-	return 0
-}
-
 func gentext() {
 }
 
@@ -194,7 +176,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			break
 		}
 		if ld.Iself {
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc
@@ -297,9 +279,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 		v = uint32(rs.Dynid)
 		v |= 1 << 27 // external relocation
 	} else {
-		v = uint32((rs.Sect.(*ld.Section)).Extnum)
+		v = uint32(rs.Sect.Extnum)
 		if v == 0 {
-			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
 			return -1
 		}
 	}
@@ -440,7 +422,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -495,7 +477,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 	got := ld.Linklookup(ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint32(ctxt, got, 0)
@@ -509,72 +491,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 	}
 }
 
-func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	if s.Dynid >= 0 {
-		return
-	}
-
-	if ld.Iself {
-		s.Dynid = int32(ld.Nelfsym)
-		ld.Nelfsym++
-
-		d := ld.Linklookup(ctxt, ".dynsym", 0)
-
-		/* name */
-		name := s.Extname
-
-		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
-
-		/* value */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint32(ctxt, d, 0)
-		} else {
-			ld.Addaddr(ctxt, d, s)
-		}
-
-		/* size */
-		ld.Adduint32(ctxt, d, 0)
-
-		/* type */
-		t := ld.STB_GLOBAL << 4
-
-		if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&obj.SMASK == obj.STEXT {
-			t |= ld.STT_FUNC
-		} else {
-			t |= ld.STT_OBJECT
-		}
-		ld.Adduint8(ctxt, d, uint8(t))
-		ld.Adduint8(ctxt, d, 0)
-
-		/* shndx */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
-		} else {
-			ld.Adduint16(ctxt, d, 1)
-		}
-	} else {
-		ld.Diag("adddynsym: unsupported binary format")
-	}
-}
-
-func adddynlib(lib string) {
-	if needlib(lib) == 0 {
-		return
-	}
-
-	if ld.Iself {
-		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
-		if s.Size == 0 {
-			ld.Addstring(s, "")
-		}
-		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Machoadddynlib(lib)
-	} else {
-		ld.Diag("adddynlib: unsupported binary format")
-	}
-}
-
 func asmb() {
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
@@ -617,14 +533,12 @@ func asmb() {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
 
-		if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support
-			dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
-			ld.Cseek(int64(dwarfoff))
+		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+		ld.Cseek(int64(dwarfoff))
 
-			ld.Segdwarf.Fileoff = uint64(ld.Cpos())
-			ld.Dwarfemitdebugsections()
-			ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
-		}
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
 
 		machlink = uint32(ld.Domacholink())
 	}
@@ -651,7 +565,7 @@ func asmb() {
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
 		case obj.Hdarwin:
-			symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
 		}
 
 		ld.Cseek(int64(symo))
diff --git a/src/cmd/5l/l.go b/src/cmd/link/internal/arm/l.go
similarity index 98%
rename from src/cmd/5l/l.go
rename to src/cmd/link/internal/arm/l.go
index a52154594d..4973772163 100644
--- a/src/cmd/5l/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 // Writing object files.
 
@@ -72,7 +72,8 @@ const (
 	MINLC     = 4
 )
 
-/* Used by ../ld/dwarf.c */
+/* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 13
+	DWARFREGLR = 14
 )
diff --git a/src/cmd/5l/obj.go b/src/cmd/link/internal/arm/obj.go
similarity index 97%
rename from src/cmd/5l/obj.go
rename to src/cmd/link/internal/arm/obj.go
index fa74908005..14fe7a64eb 100644
--- a/src/cmd/5l/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -28,18 +28,18 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
 // Reading object files.
 
-func main() {
+func Main() {
 	linkarchinit()
 	ld.Ldmain()
 }
@@ -56,10 +56,9 @@ func linkarchinit() {
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
+	ld.Thearch.Dwarfreglr = DWARFREGLR
 
-	ld.Thearch.Adddynlib = adddynlib
 	ld.Thearch.Adddynrel = adddynrel
-	ld.Thearch.Adddynsym = adddynsym
 	ld.Thearch.Archinit = archinit
 	ld.Thearch.Archreloc = archreloc
 	ld.Thearch.Archrelocvariant = archrelocvariant
diff --git a/src/cmd/7l/asm.go b/src/cmd/link/internal/arm64/asm.go
similarity index 88%
rename from src/cmd/7l/asm.go
rename to src/cmd/link/internal/arm64/asm.go
index a17899dcf0..3aebd8a223 100644
--- a/src/cmd/7l/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -28,11 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"encoding/binary"
 	"fmt"
 	"log"
@@ -40,24 +40,6 @@ import (
 
 func gentext() {}
 
-func needlib(name string) int {
-	if name[0] == '\x00' {
-		return 0
-	}
-
-	/* reuse hash code in symbol table */
-	p := fmt.Sprintf(".dynlib.%s", name)
-
-	s := ld.Linklookup(ld.Ctxt, p, 0)
-
-	if s.Type == 0 {
-		s.Type = 100 // avoid SDATA, etc.
-		return 1
-	}
-
-	return 0
-}
-
 func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
 	log.Fatalf("adddynrela not implemented")
 }
@@ -125,9 +107,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 		v = uint32(rs.Dynid)
 		v |= 1 << 27 // external relocation
 	} else {
-		v = uint32((rs.Sect.(*ld.Section)).Extnum)
+		v = uint32(rs.Sect.Extnum)
 		if v == 0 {
-			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
 			return -1
 		}
 	}
@@ -293,28 +275,6 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
 	return -1
 }
 
-func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	// TODO(minux): implement when needed.
-}
-
-func adddynlib(lib string) {
-	if needlib(lib) == 0 {
-		return
-	}
-
-	if ld.Iself {
-		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
-		if s.Size == 0 {
-			ld.Addstring(s, "")
-		}
-		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Machoadddynlib(lib)
-	} else {
-		ld.Diag("adddynlib: unsupported binary format")
-	}
-}
-
 func asmb() {
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
@@ -357,14 +317,12 @@ func asmb() {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
 
-		if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support
-			dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
-			ld.Cseek(int64(dwarfoff))
+		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+		ld.Cseek(int64(dwarfoff))
 
-			ld.Segdwarf.Fileoff = uint64(ld.Cpos())
-			ld.Dwarfemitdebugsections()
-			ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
-		}
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
 
 		machlink = uint32(ld.Domacholink())
 	}
@@ -391,7 +349,7 @@ func asmb() {
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
 		case obj.Hdarwin:
-			symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink))
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
 		}
 
 		ld.Cseek(int64(symo))
diff --git a/src/cmd/7l/l.go b/src/cmd/link/internal/arm64/l.go
similarity index 98%
rename from src/cmd/7l/l.go
rename to src/cmd/link/internal/arm64/l.go
index 6f90acb107..8d0d57e72a 100644
--- a/src/cmd/7l/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 // Writing object files.
 
@@ -71,7 +71,8 @@ const (
 	MINLC     = 4
 )
 
-/* Used by ../ld/dwarf.c */
+/* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 31
+	DWARFREGLR = 30
 )
diff --git a/src/cmd/7l/obj.go b/src/cmd/link/internal/arm64/obj.go
similarity index 97%
rename from src/cmd/7l/obj.go
rename to src/cmd/link/internal/arm64/obj.go
index f8ac7d33ea..56f5815903 100644
--- a/src/cmd/7l/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -28,18 +28,18 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package arm64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
 // Reading object files.
 
-func main() {
+func Main() {
 	linkarchinit()
 	ld.Ldmain()
 }
@@ -56,10 +56,9 @@ func linkarchinit() {
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
+	ld.Thearch.Dwarfreglr = DWARFREGLR
 
-	ld.Thearch.Adddynlib = adddynlib
 	ld.Thearch.Adddynrel = adddynrel
-	ld.Thearch.Adddynsym = adddynsym
 	ld.Thearch.Archinit = archinit
 	ld.Thearch.Archreloc = archreloc
 	ld.Thearch.Archrelocvariant = archrelocvariant
diff --git a/src/cmd/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
similarity index 100%
rename from src/cmd/internal/ld/ar.go
rename to src/cmd/link/internal/ld/ar.go
diff --git a/src/cmd/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go
similarity index 100%
rename from src/cmd/internal/ld/arch.go
rename to src/cmd/link/internal/ld/arch.go
diff --git a/src/cmd/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
similarity index 88%
rename from src/cmd/internal/ld/data.go
rename to src/cmd/link/internal/ld/data.go
index 3194bd568e..fd1cdd64bb 100644
--- a/src/cmd/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -32,9 +32,11 @@
 package ld
 
 import (
+	"cmd/internal/gcprog"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
+	"os"
 	"strings"
 )
 
@@ -520,7 +522,7 @@ func relocsym(s *LSym) {
 				} else if HEADTYPE == obj.Hdarwin {
 					if r.Type == obj.R_CALL {
 						if rs.Type != obj.SHOSTOBJ {
-							o += int64(uint64(Symaddr(rs)) - (rs.Sect.(*Section)).Vaddr)
+							o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
 						}
 						o -= int64(r.Off) // relative to section offset, not symbol
 					} else {
@@ -532,7 +534,7 @@ func relocsym(s *LSym) {
 					o += int64(r.Siz)
 					// GNU ld always add VirtualAddress of the .text section to the
 					// relocated address, compensate that.
-					o -= int64(s.Sect.(*Section).Vaddr - PEBASE)
+					o -= int64(s.Sect.Vaddr - PEBASE)
 				} else {
 					Diag("unhandled pcrel relocation for %s", headstring)
 				}
@@ -963,6 +965,22 @@ func Addstring(s *LSym, str string) int64 {
 	return int64(r)
 }
 
+// addgostring adds str, as a Go string value, to s. symname is the name of the
+// symbol used to define the string data and must be unique per linked object.
+func addgostring(s *LSym, symname, str string) {
+	sym := Linklookup(Ctxt, symname, 0)
+	if sym.Type != obj.Sxxx {
+		Diag("duplicate symname in addgostring: %s", symname)
+	}
+	sym.Reachable = true
+	sym.Local = true
+	sym.Type = obj.SRODATA
+	sym.Size = int64(len(str))
+	sym.P = []byte(str)
+	Addaddr(Ctxt, s, sym)
+	adduint(Ctxt, s, uint64(len(str)))
+}
+
 func addinitarrdata(s *LSym) {
 	p := s.Name + ".ptr"
 	sp := Linklookup(Ctxt, p, 0)
@@ -1028,165 +1046,65 @@ func maxalign(s *LSym, type_ int) int32 {
 	return max
 }
 
-// Helper object for building GC type programs.
-type ProgGen struct {
-	s        *LSym
-	datasize int32
-	data     [256 / obj.PointersPerByte]uint8
-	pos      int64
+const debugGCProg = false
+
+type GCProg struct {
+	sym *LSym
+	w   gcprog.Writer
 }
 
-func proggeninit(g *ProgGen, s *LSym) {
-	g.s = s
-	g.datasize = 0
-	g.pos = 0
-	g.data = [256 / obj.PointersPerByte]uint8{}
-}
-
-func proggenemit(g *ProgGen, v uint8) {
-	Adduint8(Ctxt, g.s, v)
-}
-
-// Writes insData block from g->data.
-func proggendataflush(g *ProgGen) {
-	if g.datasize == 0 {
-		return
-	}
-	proggenemit(g, obj.InsData)
-	proggenemit(g, uint8(g.datasize))
-	s := (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte
-	for i := int32(0); i < s; i++ {
-		proggenemit(g, g.data[i])
-	}
-	g.datasize = 0
-	g.data = [256 / obj.PointersPerByte]uint8{}
-}
-
-func proggendata(g *ProgGen, d uint8) {
-	g.data[g.datasize/obj.PointersPerByte] |= d << uint((g.datasize%obj.PointersPerByte)*obj.BitsPerPointer)
-	g.datasize++
-	if g.datasize == 255 {
-		proggendataflush(g)
+func (p *GCProg) Init(name string) {
+	p.sym = Linklookup(Ctxt, name, 0)
+	p.w.Init(p.writeByte)
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
+		p.w.Debug(os.Stderr)
 	}
 }
 
-// Skip v bytes due to alignment, etc.
-func proggenskip(g *ProgGen, off int64, v int64) {
-	for i := off; i < off+v; i++ {
-		if (i % int64(Thearch.Ptrsize)) == 0 {
-			proggendata(g, obj.BitsScalar)
-		}
+func (p *GCProg) writeByte(x byte) {
+	Adduint8(Ctxt, p.sym, x)
+}
+
+func (p *GCProg) End(size int64) {
+	p.w.ZeroUntil(size / int64(Thearch.Ptrsize))
+	p.w.End()
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
 	}
 }
 
-// Emit insArray instruction.
-func proggenarray(g *ProgGen, length int64) {
-	var i int32
-
-	proggendataflush(g)
-	proggenemit(g, obj.InsArray)
-	for i = 0; i < int32(Thearch.Ptrsize); i, length = i+1, length>>8 {
-		proggenemit(g, uint8(length))
-	}
-}
-
-func proggenarrayend(g *ProgGen) {
-	proggendataflush(g)
-	proggenemit(g, obj.InsArrayEnd)
-}
-
-func proggenfini(g *ProgGen, size int64) {
-	proggenskip(g, g.pos, size-g.pos)
-	proggendataflush(g)
-	proggenemit(g, obj.InsEnd)
-}
-
-// This function generates GC pointer info for global variables.
-func proggenaddsym(g *ProgGen, s *LSym) {
-	if s.Size == 0 {
-		return
-	}
-
-	// Skip alignment hole from the previous symbol.
-	proggenskip(g, g.pos, s.Value-g.pos)
-
-	g.pos += s.Value - g.pos
-
-	// The test for names beginning with . here is meant
-	// to keep .dynamic and .dynsym from turning up as
-	// conservative symbols. They should be marked SELFSECT
-	// and not SDATA, but sometimes that doesn't happen.
-	// Leave debugging the SDATA issue for the Go rewrite.
-
-	if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) && s.Name[0] != '.' {
-		// conservative scan
+func (p *GCProg) AddSym(s *LSym) {
+	typ := s.Gotype
+	// Things without pointers should be in SNOPTRDATA or SNOPTRBSS;
+	// everything we see should have pointers and should therefore have a type.
+	if typ == nil {
 		Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size))
-
-		if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
-			Diag("proggenaddsym: unaligned conservative symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
-		}
-		size := (s.Size + int64(Thearch.Ptrsize) - 1) / int64(Thearch.Ptrsize) * int64(Thearch.Ptrsize)
-		if size < int64(32*Thearch.Ptrsize) {
-			// Emit small symbols as data.
-			for i := int64(0); i < size/int64(Thearch.Ptrsize); i++ {
-				proggendata(g, obj.BitsPointer)
-			}
-		} else {
-			// Emit large symbols as array.
-			proggenarray(g, size/int64(Thearch.Ptrsize))
-
-			proggendata(g, obj.BitsPointer)
-			proggenarrayend(g)
-		}
-
-		g.pos = s.Value + size
-	} else if s.Gotype == nil || decodetype_noptr(s.Gotype) != 0 || s.Size < int64(Thearch.Ptrsize) || s.Name[0] == '.' {
-		// no scan
-		if s.Size < int64(32*Thearch.Ptrsize) {
-			// Emit small symbols as data.
-			// This case also handles unaligned and tiny symbols, so tread carefully.
-			for i := s.Value; i < s.Value+s.Size; i++ {
-				if (i % int64(Thearch.Ptrsize)) == 0 {
-					proggendata(g, obj.BitsScalar)
-				}
-			}
-		} else {
-			// Emit large symbols as array.
-			if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
-				Diag("proggenaddsym: unaligned noscan symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
-			}
-			proggenarray(g, s.Size/int64(Thearch.Ptrsize))
-			proggendata(g, obj.BitsScalar)
-			proggenarrayend(g)
-		}
-
-		g.pos = s.Value + s.Size
-	} else if decodetype_usegcprog(s.Gotype) != 0 {
-		// gc program, copy directly
-		proggendataflush(g)
-
-		gcprog := decodetype_gcprog(s.Gotype)
-		size := decodetype_size(s.Gotype)
-		if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
-			Diag("proggenaddsym: unaligned gcprog symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
-		}
-		for i := int64(0); i < int64(len(gcprog.P)-1); i++ {
-			proggenemit(g, uint8(gcprog.P[i]))
-		}
-		g.pos = s.Value + size
-	} else {
-		// gc mask, it's small so emit as data
-		mask := decodetype_gcmask(s.Gotype)
-
-		size := decodetype_size(s.Gotype)
-		if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
-			Diag("proggenaddsym: unaligned gcmask symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
-		}
-		for i := int64(0); i < size; i += int64(Thearch.Ptrsize) {
-			proggendata(g, uint8((mask[i/int64(Thearch.Ptrsize)/2]>>uint64((i/int64(Thearch.Ptrsize)%2)*4+2))&obj.BitsMask))
-		}
-		g.pos = s.Value + size
+		return
 	}
+
+	ptrsize := int64(Thearch.Ptrsize)
+	nptr := decodetype_ptrdata(typ) / ptrsize
+
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
+	}
+
+	if decodetype_usegcprog(typ) == 0 {
+		// Copy pointers from mask into program.
+		mask := decodetype_gcmask(typ)
+		for i := int64(0); i < nptr; i++ {
+			if (mask[i/8]>>uint(i%8))&1 != 0 {
+				p.w.Ptr(s.Value/ptrsize + i)
+			}
+		}
+		return
+	}
+
+	// Copy program.
+	prog := decodetype_gcprog(typ)
+	p.w.ZeroUntil(s.Value / ptrsize)
+	p.w.Append(prog[4:], nptr)
 }
 
 func growdatsize(datsizep *int64, s *LSym) {
@@ -1394,15 +1312,13 @@ func dodata() {
 
 	/* data */
 	sect = addsection(&Segdata, ".data", 06)
-
 	sect.Align = maxalign(s, obj.SBSS-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.data", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
-	gcdata := Linklookup(Ctxt, "runtime.gcdata", 0)
-	var gen ProgGen
-	proggeninit(&gen, gcdata)
+	var gc GCProg
+	gc.Init("runtime.gcdata")
 	for ; s != nil && s.Type < obj.SBSS; s = s.Next {
 		if s.Type == obj.SINITARR {
 			Ctxt.Cursym = s
@@ -1413,33 +1329,30 @@ func dodata() {
 		s.Type = obj.SDATA
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		proggenaddsym(&gen, s) // gc
+		gc.AddSym(s)
 		growdatsize(&datsize, s)
 	}
-
 	sect.Length = uint64(datsize) - sect.Vaddr
-	proggenfini(&gen, int64(sect.Length)) // gc
+	gc.End(int64(sect.Length))
 
 	/* bss */
 	sect = addsection(&Segdata, ".bss", 06)
-
 	sect.Align = maxalign(s, obj.SNOPTRBSS-1)
 	datsize = Rnd(datsize, int64(sect.Align))
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
-	gcbss := Linklookup(Ctxt, "runtime.gcbss", 0)
-	proggeninit(&gen, gcbss)
+	gc = GCProg{}
+	gc.Init("runtime.gcbss")
 	for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next {
 		s.Sect = sect
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		proggenaddsym(&gen, s) // gc
+		gc.AddSym(s)
 		growdatsize(&datsize, s)
 	}
-
 	sect.Length = uint64(datsize) - sect.Vaddr
-	proggenfini(&gen, int64(sect.Length)) // gc
+	gc.End(int64(sect.Length))
 
 	/* pointer-free bss */
 	sect = addsection(&Segdata, ".noptrbss", 06)
@@ -1768,13 +1681,20 @@ func address() {
 	for sym := datap; sym != nil; sym = sym.Next {
 		Ctxt.Cursym = sym
 		if sym.Sect != nil {
-			sym.Value += int64((sym.Sect.(*Section)).Vaddr)
+			sym.Value += int64(sym.Sect.Vaddr)
 		}
 		for sub = sym.Sub; sub != nil; sub = sub.Sub {
 			sub.Value += sym.Value
 		}
 	}
 
+	if Buildmode == BuildmodeShared {
+		s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		sectSym := Linklookup(Ctxt, ".note.go.abihash", 0)
+		s.Sect = sectSym.Sect
+		s.Value = int64(sectSym.Sect.Vaddr + 16)
+	}
+
 	xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
 	xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
 	xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
similarity index 76%
rename from src/cmd/internal/ld/decodesym.go
rename to src/cmd/link/internal/ld/decodesym.go
index 754c89f12b..c1cf4d7181 100644
--- a/src/cmd/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -4,7 +4,10 @@
 
 package ld
 
-import "cmd/internal/obj"
+import (
+	"cmd/internal/obj"
+	"debug/elf"
+)
 
 // Decoding the type.* symbols.	 This has to be in sync with
 // ../../runtime/type.go, or more specifically, with what
@@ -44,7 +47,7 @@ func decode_inuxi(p []byte, sz int) uint64 {
 // commonsize returns the size of the common prefix for all type
 // structures (runtime._type).
 func commonsize() int {
-	return 9*Thearch.Ptrsize + 8
+	return 8*Thearch.Ptrsize + 8
 }
 
 // Type.commonType.kind
@@ -67,14 +70,43 @@ func decodetype_size(s *LSym) int64 {
 	return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
 }
 
-// Type.commonType.gc
-func decodetype_gcprog(s *LSym) *LSym {
-	if s.Type == obj.SDYNIMPORT {
-		// The gcprog for "type.$name" is calle "type..gcprog.$name".
-		x := "type..gcprog." + s.Name[5:]
-		return Linklookup(Ctxt, x, 0)
+// Type.commonType.ptrdata
+func decodetype_ptrdata(s *LSym) int64 {
+	return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
+}
+
+// Find the elf.Section of a given shared library that contains a given address.
+func findShlibSection(path string, addr uint64) *elf.Section {
+	for _, shlib := range Ctxt.Shlibs {
+		if shlib.Path == path {
+			for _, sect := range shlib.File.Sections {
+				if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
+					return sect
+				}
+			}
+		}
 	}
-	return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
+	return nil
+}
+
+// Type.commonType.gc
+func decodetype_gcprog(s *LSym) []byte {
+	if s.Type == obj.SDYNIMPORT {
+		addr := decodetype_gcprog_shlib(s)
+		sect := findShlibSection(s.File, addr)
+		if sect != nil {
+			// A gcprog is a 4-byte uint32 indicating length, followed by
+			// the actual program.
+			progsize := make([]byte, 4)
+			sect.ReadAt(progsize, int64(addr-sect.Addr))
+			progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize))
+			sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+			return append(progsize, progbytes...)
+		}
+		Exitf("cannot find gcprog for %s", s.Name)
+		return nil
+	}
+	return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
 }
 
 func decodetype_gcprog_shlib(s *LSym) uint64 {
@@ -83,9 +115,16 @@ func decodetype_gcprog_shlib(s *LSym) uint64 {
 
 func decodetype_gcmask(s *LSym) []byte {
 	if s.Type == obj.SDYNIMPORT {
-		// ldshlibsyms makes special efforts to read the value
-		// of gcmask for types defined in that shared library.
-		return s.gcmask
+		addr := decodetype_gcprog_shlib(s)
+		ptrdata := decodetype_ptrdata(s)
+		sect := findShlibSection(s.File, addr)
+		if sect != nil {
+			r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+			sect.ReadAt(r, int64(addr-sect.Addr))
+			return r
+		}
+		Exitf("cannot find gcmask for %s", s.Name)
+		return nil
 	}
 	mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
 	return mask.P
diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
similarity index 93%
rename from src/cmd/internal/ld/dwarf.go
rename to src/cmd/link/internal/ld/dwarf.go
index 6d90404b13..b8fb2e6b55 100644
--- a/src/cmd/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -17,6 +17,7 @@ package ld
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"os"
 	"strings"
 )
 
@@ -240,6 +241,7 @@ var abbrevs = [DW_NABRV]DWAbbrev{
 			{DW_AT_low_pc, DW_FORM_addr},
 			{DW_AT_high_pc, DW_FORM_addr},
 			{DW_AT_stmt_list, DW_FORM_data4},
+			{DW_AT_comp_dir, DW_FORM_string},
 		},
 	},
 
@@ -694,6 +696,9 @@ func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64)
 	if Iself && Thearch.Thechar == '6' {
 		addend = 0
 	}
+	if HEADTYPE == obj.Hdarwin {
+		addend += sym.Value
+	}
 	switch siz {
 	case 4:
 		Thearch.Lput(uint32(addend))
@@ -1547,6 +1552,13 @@ func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_len
 	}
 }
 
+func getCompilationDir() string {
+	if dir, err := os.Getwd(); err == nil {
+		return dir
+	}
+	return "/"
+}
+
 func writelines() {
 	if linesec == nil {
 		linesec = Linklookup(Ctxt, ".dwarfline", 0)
@@ -1571,6 +1583,9 @@ func writelines() {
 	newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0)
 	newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0)
 	newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+	// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
+	compDir := getCompilationDir()
+	newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir)
 
 	// Write .debug_line Line Number Program Header (sec 6.2.4)
 	// Fields marked with (*) must be changed for 64-bit dwarf
@@ -1692,11 +1707,17 @@ func writelines() {
 			switch a.Name {
 			case obj.A_AUTO:
 				dt = DW_ABRV_AUTO
-				offs = int64(a.Aoffset) - int64(Thearch.Ptrsize)
+				offs = int64(a.Aoffset)
+				if !haslinkregister() {
+					offs -= int64(Thearch.Ptrsize)
+				}
 
 			case obj.A_PARAM:
 				dt = DW_ABRV_PARAM
 				offs = int64(a.Aoffset)
+				if haslinkregister() {
+					offs += int64(Thearch.Ptrsize)
+				}
 
 			default:
 				continue
@@ -1749,7 +1770,6 @@ func writelines() {
 const (
 	CIERESERVE          = 16
 	DATAALIGNMENTFACTOR = -4
-	FAKERETURNCOLUMN    = 16 // TODO gdb6 doesn't like > 15?
 )
 
 func putpccfadelta(deltapc int64, cfa int64) {
@@ -1778,21 +1798,30 @@ func writeframes() {
 	frameo = Cpos()
 
 	// Emit the CIE, Section 6.4.1
-	Thearch.Lput(CIERESERVE)        // initial length, must be multiple of thearch.ptrsize
-	Thearch.Lput(0xffffffff)        // cid.
-	Cput(3)                         // dwarf version (appendix F)
-	Cput(0)                         // augmentation ""
-	uleb128put(1)                   // code_alignment_factor
-	sleb128put(DATAALIGNMENTFACTOR) // guess
-	uleb128put(FAKERETURNCOLUMN)    // return_address_register
+	Thearch.Lput(CIERESERVE)              // initial length, must be multiple of thearch.ptrsize
+	Thearch.Lput(0xffffffff)              // cid.
+	Cput(3)                               // dwarf version (appendix F)
+	Cput(0)                               // augmentation ""
+	uleb128put(1)                         // code_alignment_factor
+	sleb128put(DATAALIGNMENTFACTOR)       // guess
+	uleb128put(int64(Thearch.Dwarfreglr)) // return_address_register
 
 	Cput(DW_CFA_def_cfa)
 
 	uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h)
-	uleb128put(int64(Thearch.Ptrsize))    // offset
+	if haslinkregister() {
+		uleb128put(int64(0)) // offset
+	} else {
+		uleb128put(int64(Thearch.Ptrsize)) // offset
+	}
 
-	Cput(DW_CFA_offset + FAKERETURNCOLUMN)                    // return address
-	uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
+	Cput(DW_CFA_offset_extended)
+	uleb128put(int64(Thearch.Dwarfreglr)) // return address
+	if haslinkregister() {
+		uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0
+	} else {
+		uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
+	}
 
 	// 4 is to exclude the length field.
 	pad := CIERESERVE + frameo + 4 - Cpos()
@@ -1834,7 +1863,11 @@ func writeframes() {
 				}
 			}
 
-			putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+			if haslinkregister() {
+				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
+			} else {
+				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+			}
 		}
 
 		fdesize = Cpos() - fdeo - 4 // exclude the length field.
@@ -2065,6 +2098,14 @@ func writedwarfreloc(s *LSym) int64 {
 	return start
 }
 
+func addmachodwarfsect(prev *Section, name string) *Section {
+	sect := addsection(&Segdwarf, name, 04)
+	sect.Extnum = prev.Extnum + 1
+	sym := Linklookup(Ctxt, name, 0)
+	sym.Sect = sect
+	return sect
+}
+
 /*
  * This is the main entry point for generating dwarf.  After emitting
  * the mandatory debug_abbrev section, it calls writelines() to set up
@@ -2079,8 +2120,33 @@ func Dwarfemitdebugsections() {
 		return
 	}
 
-	if Linkmode == LinkExternal && !Iself {
-		return
+	if Linkmode == LinkExternal {
+		if !Iself && HEADTYPE != obj.Hdarwin {
+			return
+		}
+		if HEADTYPE == obj.Hdarwin {
+			sect := Segdata.Sect
+			// find the last section.
+			for sect.Next != nil {
+				sect = sect.Next
+			}
+			sect = addmachodwarfsect(sect, ".debug_abbrev")
+			sect = addmachodwarfsect(sect, ".debug_line")
+			sect = addmachodwarfsect(sect, ".debug_frame")
+			sect = addmachodwarfsect(sect, ".debug_info")
+
+			infosym = Linklookup(Ctxt, ".debug_info", 0)
+			infosym.Hide = 1
+
+			abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
+			abbrevsym.Hide = 1
+
+			linesym = Linklookup(Ctxt, ".debug_line", 0)
+			linesym.Hide = 1
+
+			framesym = Linklookup(Ctxt, ".debug_frame", 0)
+			framesym.Hide = 1
+		}
 	}
 
 	// For diagnostic messages.
@@ -2173,6 +2239,15 @@ func Dwarfemitdebugsections() {
 	for Cpos()&7 != 0 {
 		Cput(0)
 	}
+	if HEADTYPE != obj.Hdarwin {
+		dwarfemitreloc()
+	}
+}
+
+func dwarfemitreloc() {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
 	inforeloco = writedwarfreloc(infosec)
 	inforelocsize = Cpos() - inforeloco
 	align(inforelocsize)
@@ -2402,14 +2477,15 @@ func dwarfaddelfheaders() {
 /*
  * Macho
  */
-func dwarfaddmachoheaders() {
+func dwarfaddmachoheaders(ms *MachoSeg) {
 	if Debug['w'] != 0 { // disable dwarf
 		return
 	}
 
 	// Zero vsize segments won't be loaded in memory, even so they
 	// have to be page aligned in the file.
-	fakestart := abbrevo &^ 0xfff
+	fakestart := Rnd(int64(Segdwarf.Fileoff), 0x1000)
+	addr := Segdata.Vaddr + Segdata.Length
 
 	nsect := 4
 	if pubnamessize > 0 {
@@ -2425,57 +2501,94 @@ func dwarfaddmachoheaders() {
 		nsect++
 	}
 
-	ms := newMachoSeg("__DWARF", nsect)
-	ms.fileoffset = uint64(fakestart)
-	ms.filesize = uint64(abbrevo) - uint64(fakestart)
-	ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff
+	if Linkmode != LinkExternal {
+		ms = newMachoSeg("__DWARF", nsect)
+		ms.fileoffset = uint64(fakestart)
+		ms.filesize = Segdwarf.Filelen
+		ms.vaddr = addr
+	}
 
 	msect := newMachoSect(ms, "__debug_abbrev", "__DWARF")
 	msect.off = uint32(abbrevo)
 	msect.size = uint64(abbrevsize)
-	msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-	ms.filesize += msect.size
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if abbrevsym != nil {
+		abbrevsym.Value = int64(msect.addr)
+	}
 
 	msect = newMachoSect(ms, "__debug_line", "__DWARF")
 	msect.off = uint32(lineo)
 	msect.size = uint64(linesize)
-	msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-	ms.filesize += msect.size
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if linesym != nil {
+		linesym.Value = int64(msect.addr)
+	}
+	if linerelocsize > 0 {
+		msect.nreloc = uint32(len(linesec.R))
+		msect.reloc = uint32(linereloco)
+	}
 
 	msect = newMachoSect(ms, "__debug_frame", "__DWARF")
 	msect.off = uint32(frameo)
 	msect.size = uint64(framesize)
-	msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-	ms.filesize += msect.size
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if framesym != nil {
+		framesym.Value = int64(msect.addr)
+	}
+	if framerelocsize > 0 {
+		msect.nreloc = uint32(len(framesec.R))
+		msect.reloc = uint32(framereloco)
+	}
 
 	msect = newMachoSect(ms, "__debug_info", "__DWARF")
 	msect.off = uint32(infoo)
 	msect.size = uint64(infosize)
-	msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-	ms.filesize += msect.size
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if infosym != nil {
+		infosym.Value = int64(msect.addr)
+	}
+	if inforelocsize > 0 {
+		msect.nreloc = uint32(len(infosec.R))
+		msect.reloc = uint32(inforeloco)
+	}
 
 	if pubnamessize > 0 {
 		msect := newMachoSect(ms, "__debug_pubnames", "__DWARF")
 		msect.off = uint32(pubnameso)
 		msect.size = uint64(pubnamessize)
-		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-		ms.filesize += msect.size
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
 	}
 
 	if pubtypessize > 0 {
 		msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF")
 		msect.off = uint32(pubtypeso)
 		msect.size = uint64(pubtypessize)
-		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-		ms.filesize += msect.size
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
 	}
 
 	if arangessize > 0 {
 		msect := newMachoSect(ms, "__debug_aranges", "__DWARF")
 		msect.off = uint32(arangeso)
 		msect.size = uint64(arangessize)
-		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-		ms.filesize += msect.size
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
+		if arangesrelocsize > 0 {
+			msect.nreloc = uint32(len(arangessec.R))
+			msect.reloc = uint32(arangesreloco)
+		}
 	}
 
 	// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
@@ -2483,8 +2596,9 @@ func dwarfaddmachoheaders() {
 		msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
 		msect.off = uint32(gdbscripto)
 		msect.size = uint64(gdbscriptsize)
-		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
-		ms.filesize += msect.size
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
 	}
 }
 
diff --git a/src/cmd/internal/ld/dwarf_defs.go b/src/cmd/link/internal/ld/dwarf_defs.go
similarity index 100%
rename from src/cmd/internal/ld/dwarf_defs.go
rename to src/cmd/link/internal/ld/dwarf_defs.go
diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
similarity index 92%
rename from src/cmd/internal/ld/elf.go
rename to src/cmd/link/internal/ld/elf.go
index 5c17b2da6f..68d21f415c 100644
--- a/src/cmd/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -6,8 +6,12 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"crypto/sha1"
 	"encoding/binary"
 	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
 )
 
 /*
@@ -1199,32 +1203,15 @@ func elfwritebuildinfo() int {
 	return int(sh.size)
 }
 
-// Go package list note
+// Go specific notes
 const (
 	ELF_NOTE_GOPKGLIST_TAG = 1
+	ELF_NOTE_GOABIHASH_TAG = 2
+	ELF_NOTE_GODEPS_TAG    = 3
 )
 
 var ELF_NOTE_GO_NAME = []byte("GO\x00\x00")
 
-func elfgopkgnote(sh *ElfShdr, startva uint64, resoff uint64) int {
-	n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(pkglistfornote)), 4))
-	return elfnote(sh, startva, resoff, n, false)
-}
-
-func elfwritegopkgnote() int {
-	sh := elfwritenotehdr(".note.go.pkg-list", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(pkglistfornote)), ELF_NOTE_GOPKGLIST_TAG)
-	if sh == nil {
-		return 0
-	}
-
-	Cwrite(ELF_NOTE_GO_NAME)
-	Cwrite(pkglistfornote)
-	var zero = make([]byte, 4)
-	Cwrite(zero[:int(Rnd(int64(len(pkglistfornote)), 4)-int64(len(pkglistfornote)))])
-
-	return int(sh.size)
-}
-
 var elfverneed int
 
 type Elfaux struct {
@@ -1455,6 +1442,24 @@ func elfshalloc(sect *Section) *ElfShdr {
 
 func elfshbits(sect *Section) *ElfShdr {
 	sh := elfshalloc(sect)
+	// If this section has already been set up as a note, we assume type_ and
+	// flags are already correct, but the other fields still need filling in.
+	if sh.type_ == SHT_NOTE {
+		if Linkmode != LinkExternal {
+			// TODO(mwhudson): the approach here will work OK when
+			// linking internally for notes that we want to be included
+			// in a loadable segment (e.g. the abihash note) but not for
+			// notes that we do not want to be mapped (e.g. the package
+			// list note). The real fix is probably to define new values
+			// for LSym.Type corresponding to mapped and unmapped notes
+			// and handle them in dodata().
+			Diag("sh.type_ == SHT_NOTE in elfshbits when linking internally")
+		}
+		sh.addralign = uint64(sect.Align)
+		sh.size = sect.Length
+		sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+		return sh
+	}
 	if sh.type_ > 0 {
 		return sh
 	}
@@ -1490,13 +1495,16 @@ func elfshbits(sect *Section) *ElfShdr {
 
 func elfshreloc(sect *Section) *ElfShdr {
 	// If main section is SHT_NOBITS, nothing to relocate.
-	// Also nothing to relocate in .shstrtab.
+	// Also nothing to relocate in .shstrtab or notes.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
 		return nil
 	}
 	if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
 		return nil
 	}
+	if sect.Elfsect.type_ == SHT_NOTE {
+		return nil
+	}
 
 	var prefix string
 	var typ int
@@ -1517,7 +1525,7 @@ func elfshreloc(sect *Section) *ElfShdr {
 		sh.entsize += uint64(Thearch.Regsize)
 	}
 	sh.link = uint32(elfshname(".symtab").shnum)
-	sh.info = uint32((sect.Elfsect.(*ElfShdr)).shnum)
+	sh.info = uint32(sect.Elfsect.shnum)
 	sh.off = sect.Reloff
 	sh.size = sect.Rellen
 	sh.addralign = uint64(Thearch.Regsize)
@@ -1596,6 +1604,29 @@ func Elfemitreloc() {
 	}
 }
 
+func addgonote(sectionName string, tag uint32, desc []byte) {
+	s := Linklookup(Ctxt, sectionName, 0)
+	s.Reachable = true
+	s.Type = obj.SELFROSECT
+	// namesz
+	Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
+	// descsz
+	Adduint32(Ctxt, s, uint32(len(desc)))
+	// tag
+	Adduint32(Ctxt, s, tag)
+	// name + padding
+	s.P = append(s.P, ELF_NOTE_GO_NAME...)
+	for len(s.P)%4 != 0 {
+		s.P = append(s.P, 0)
+	}
+	// desc + padding
+	s.P = append(s.P, desc...)
+	for len(s.P)%4 != 0 {
+		s.P = append(s.P, 0)
+	}
+	s.Size = int64(len(s.P))
+}
+
 func doelf() {
 	if !Iself {
 		return
@@ -1632,9 +1663,6 @@ func doelf() {
 	if len(buildinfo) > 0 {
 		Addstring(shstrtab, ".note.gnu.build-id")
 	}
-	if Buildmode == BuildmodeShared {
-		Addstring(shstrtab, ".note.go.pkg-list")
-	}
 	Addstring(shstrtab, ".elfdata")
 	Addstring(shstrtab, ".rodata")
 	Addstring(shstrtab, ".typelink")
@@ -1668,6 +1696,12 @@ func doelf() {
 
 		// add a .note.GNU-stack section to mark the stack as non-executable
 		Addstring(shstrtab, ".note.GNU-stack")
+
+		if Buildmode == BuildmodeShared {
+			Addstring(shstrtab, ".note.go.abihash")
+			Addstring(shstrtab, ".note.go.pkg-list")
+			Addstring(shstrtab, ".note.go.deps")
+		}
 	}
 
 	hasinitarr := Linkshared
@@ -1856,6 +1890,30 @@ func doelf() {
 		// size of .rel(a).plt section.
 		Elfwritedynent(s, DT_DEBUG, 0)
 	}
+
+	if Buildmode == BuildmodeShared {
+		// The go.link.abihashbytes symbol will be pointed at the appropriate
+		// part of the .note.go.abihash section in data.go:func address().
+		s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		s.Local = true
+		s.Type = obj.SRODATA
+		s.Special = 1
+		s.Reachable = true
+		s.Size = int64(sha1.Size)
+
+		sort.Sort(byPkg(Ctxt.Library))
+		h := sha1.New()
+		for _, l := range Ctxt.Library {
+			h.Write(l.hash)
+		}
+		addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
+		addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, []byte(pkglistfornote))
+		var deplist []string
+		for _, shlib := range Ctxt.Shlibs {
+			deplist = append(deplist, filepath.Base(shlib.Path))
+		}
+		addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
+	}
 }
 
 // Do not write DT_NULL.  elfdynhash will finish it.
@@ -1922,15 +1980,13 @@ func Asmbelf(symo int64) {
 		eh.phentsize = 0
 
 		if Buildmode == BuildmodeShared {
-			// The package list note we make space for here can get quite
-			// large. The external linker will re-layout all the sections
-			// anyway, so making this larger just wastes a little space
-			// in the intermediate object file, not the final shared
-			// library.
-			elfreserve *= 3
-			resoff = elfreserve
 			sh := elfshname(".note.go.pkg-list")
-			resoff -= int64(elfgopkgnote(sh, uint64(startva), uint64(resoff)))
+			sh.type_ = SHT_NOTE
+			sh = elfshname(".note.go.abihash")
+			sh.type_ = SHT_NOTE
+			sh.flags = SHF_ALLOC
+			sh = elfshname(".note.go.deps")
+			sh.type_ = SHT_NOTE
 		}
 		goto elfobj
 	}
@@ -2340,15 +2396,99 @@ elfobj:
 			a += int64(elfwritebuildinfo())
 		}
 	}
-	if Buildmode == BuildmodeShared {
-		a += int64(elfwritegopkgnote())
-	}
 
 	if a > elfreserve {
 		Diag("ELFRESERVE too small: %d > %d", a, elfreserve)
 	}
 }
 
+func Elfadddynsym(ctxt *Link, s *LSym) {
+	if elf64 {
+		s.Dynid = int32(Nelfsym)
+		Nelfsym++
+
+		d := Linklookup(ctxt, ".dynsym", 0)
+
+		name := s.Extname
+		Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+
+		/* type */
+		t := STB_GLOBAL << 4
+
+		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else {
+			t |= STT_OBJECT
+		}
+		Adduint8(ctxt, d, uint8(t))
+
+		/* reserved */
+		Adduint8(ctxt, d, 0)
+
+		/* section where symbol is defined */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint16(ctxt, d, SHN_UNDEF)
+		} else {
+			Adduint16(ctxt, d, 1)
+		}
+
+		/* value */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint64(ctxt, d, 0)
+		} else {
+			Addaddr(ctxt, d, s)
+		}
+
+		/* size of object */
+		Adduint64(ctxt, d, uint64(s.Size))
+
+		if Thearch.Thechar == '6' && s.Cgoexport&CgoExportDynamic == 0 && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
+			Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
+		}
+	} else {
+		s.Dynid = int32(Nelfsym)
+		Nelfsym++
+
+		d := Linklookup(ctxt, ".dynsym", 0)
+
+		/* name */
+		name := s.Extname
+
+		Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+
+		/* value */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint32(ctxt, d, 0)
+		} else {
+			Addaddr(ctxt, d, s)
+		}
+
+		/* size */
+		Adduint32(ctxt, d, 0)
+
+		/* type */
+		t := STB_GLOBAL << 4
+
+		// TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386.
+		if Thearch.Thechar == '8' && s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else if Thearch.Thechar == '5' && s.Cgoexport&CgoExportDynamic != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else {
+			t |= STT_OBJECT
+		}
+		Adduint8(ctxt, d, uint8(t))
+		Adduint8(ctxt, d, 0)
+
+		/* shndx */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint16(ctxt, d, SHN_UNDEF)
+		} else {
+			Adduint16(ctxt, d, 1)
+		}
+	}
+}
+
 func ELF32_R_SYM(info uint32) uint32 {
 	return info >> 8
 }
diff --git a/src/cmd/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
similarity index 93%
rename from src/cmd/internal/ld/go.go
rename to src/cmd/link/internal/ld/go.go
index 0223bfae9d..80a6c6ed7d 100644
--- a/src/cmd/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -416,7 +416,11 @@ func loadcgo(file string, pkg string, p string) {
 				// to force a link of foo.so.
 				havedynamic = 1
 
-				Thearch.Adddynlib(lib)
+				if HEADTYPE == obj.Hdarwin {
+					Machoadddynlib(lib)
+				} else {
+					dynlib = append(dynlib, lib)
+				}
 				continue
 			}
 
@@ -534,6 +538,41 @@ err:
 	nerrors++
 }
 
+var seenlib = make(map[string]bool)
+
+func adddynlib(lib string) {
+	if seenlib[lib] || Linkmode == LinkExternal {
+		return
+	}
+	seenlib[lib] = true
+
+	if Iself {
+		s := Linklookup(Ctxt, ".dynstr", 0)
+		if s.Size == 0 {
+			Addstring(s, "")
+		}
+		Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
+	} else {
+		Diag("adddynlib: unsupported binary format")
+	}
+}
+
+func Adddynsym(ctxt *Link, s *LSym) {
+	if s.Dynid >= 0 || Linkmode == LinkExternal {
+		return
+	}
+
+	if Iself {
+		Elfadddynsym(ctxt, s)
+	} else if HEADTYPE == obj.Hdarwin {
+		Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
+	} else if HEADTYPE == obj.Hwindows {
+		// already taken care of
+	} else {
+		Diag("adddynsym: unsupported binary format")
+	}
+}
+
 var markq *LSym
 
 var emarkq *LSym
@@ -614,15 +653,14 @@ func deadcode() {
 	}
 
 	if Buildmode == BuildmodeShared {
-		// Mark all symbols as reachable when building a
-		// shared library.
+		// Mark all symbols defined in this library as reachable when
+		// building a shared library.
 		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-			if s.Type != 0 {
+			if s.Type != 0 && s.Type != obj.SDYNIMPORT {
 				mark(s)
 			}
 		}
-		mark(Linkrlookup(Ctxt, "main.main", 0))
-		mark(Linkrlookup(Ctxt, "main.init", 0))
+		markflood()
 	} else {
 		mark(Linklookup(Ctxt, INITENTRY, 0))
 		if Linkshared && Buildmode == BuildmodeExe {
@@ -737,8 +775,11 @@ func addexport() {
 		return
 	}
 
-	for i := 0; i < len(dynexp); i++ {
-		Thearch.Adddynsym(Ctxt, dynexp[i])
+	for _, exp := range dynexp {
+		Adddynsym(Ctxt, exp)
+	}
+	for _, lib := range dynlib {
+		adddynlib(lib)
 	}
 }
 
diff --git a/src/cmd/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
similarity index 97%
rename from src/cmd/internal/ld/ld.go
rename to src/cmd/link/internal/ld/ld.go
index 7242301d0f..1068bdd767 100644
--- a/src/cmd/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -109,8 +109,8 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
 		fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
 	}
 
-	ctxt.Library = append(ctxt.Library, Library{})
-	l := &ctxt.Library[len(ctxt.Library)-1]
+	ctxt.Library = append(ctxt.Library, &Library{})
+	l := ctxt.Library[len(ctxt.Library)-1]
 	l.Objref = objref
 	l.Srcref = srcref
 	l.File = file
diff --git a/src/cmd/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
similarity index 100%
rename from src/cmd/internal/ld/ldelf.go
rename to src/cmd/link/internal/ld/ldelf.go
diff --git a/src/cmd/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
similarity index 100%
rename from src/cmd/internal/ld/ldmacho.go
rename to src/cmd/link/internal/ld/ldmacho.go
diff --git a/src/cmd/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
similarity index 100%
rename from src/cmd/internal/ld/ldpe.go
rename to src/cmd/link/internal/ld/ldpe.go
diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
similarity index 88%
rename from src/cmd/internal/ld/lib.go
rename to src/cmd/link/internal/ld/lib.go
index 184175e026..d87f1801f0 100644
--- a/src/cmd/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -34,7 +34,9 @@ import (
 	"bufio"
 	"bytes"
 	"cmd/internal/obj"
+	"crypto/sha1"
 	"debug/elf"
+	"encoding/binary"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -86,15 +88,14 @@ type Arch struct {
 	Maxalign         int
 	Minlc            int
 	Dwarfregsp       int
+	Dwarfreglr       int
 	Linuxdynld       string
 	Freebsddynld     string
 	Netbsddynld      string
 	Openbsddynld     string
 	Dragonflydynld   string
 	Solarisdynld     string
-	Adddynlib        func(string)
 	Adddynrel        func(*LSym, *Reloc)
-	Adddynsym        func(*Link, *LSym)
 	Archinit         func()
 	Archreloc        func(*Reloc, *LSym, *int64) int
 	Archrelocvariant func(*Reloc, *LSym, int64) int64
@@ -162,7 +163,7 @@ type Section struct {
 	Length  uint64
 	Next    *Section
 	Seg     *Segment
-	Elfsect interface{}
+	Elfsect *ElfShdr
 	Reloff  uint64
 	Rellen  uint64
 }
@@ -178,6 +179,7 @@ var (
 	Thelinkarch        *LinkArch
 	outfile            string
 	dynexp             []*LSym
+	dynlib             []string
 	ldflag             []string
 	havedynamic        int
 	Funcalign          int
@@ -473,7 +475,7 @@ func loadlib() {
 		if Ctxt.Library[i].Shlib != "" {
 			ldshlibsyms(Ctxt.Library[i].Shlib)
 		} else {
-			objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+			objfile(Ctxt.Library[i])
 		}
 	}
 
@@ -519,7 +521,7 @@ func loadlib() {
 				if DynlinkingGo() {
 					Exitf("cannot implicitly include runtime/cgo in a shared library")
 				}
-				objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+				objfile(Ctxt.Library[i])
 			}
 		}
 	}
@@ -630,18 +632,18 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
 	return int64(arsize) + SAR_HDR
 }
 
-func objfile(file string, pkg string) {
-	pkg = pathtoprefix(pkg)
+func objfile(lib *Library) {
+	pkg := pathtoprefix(lib.Pkg)
 
 	if Debug['v'] > 1 {
-		fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), file, pkg)
+		fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
 	}
 	Bso.Flush()
 	var err error
 	var f *obj.Biobuf
-	f, err = obj.Bopenr(file)
+	f, err = obj.Bopenr(lib.File)
 	if err != nil {
-		Exitf("cannot open file %s: %v", file, err)
+		Exitf("cannot open file %s: %v", lib.File, err)
 	}
 
 	magbuf := make([]byte, len(ARMAG))
@@ -650,7 +652,7 @@ func objfile(file string, pkg string) {
 		l := obj.Bseek(f, 0, 2)
 
 		obj.Bseek(f, 0, 0)
-		ldobj(f, pkg, l, file, file, FileObj)
+		ldobj(f, pkg, l, lib.File, lib.File, FileObj)
 		obj.Bterm(f)
 
 		return
@@ -663,7 +665,7 @@ func objfile(file string, pkg string) {
 	l := nextar(f, off, &arhdr)
 	var pname string
 	if l <= 0 {
-		Diag("%s: short read on archive file symbol header", file)
+		Diag("%s: short read on archive file symbol header", lib.File)
 		goto out
 	}
 
@@ -671,20 +673,29 @@ func objfile(file string, pkg string) {
 		off += l
 		l = nextar(f, off, &arhdr)
 		if l <= 0 {
-			Diag("%s: short read on archive file symbol header", file)
+			Diag("%s: short read on archive file symbol header", lib.File)
 			goto out
 		}
 	}
 
 	if !strings.HasPrefix(arhdr.name, pkgname) {
-		Diag("%s: cannot find package header", file)
+		Diag("%s: cannot find package header", lib.File)
 		goto out
 	}
 
+	if Buildmode == BuildmodeShared {
+		before := obj.Boffset(f)
+		pkgdefBytes := make([]byte, atolwhex(arhdr.size))
+		obj.Bread(f, pkgdefBytes)
+		hash := sha1.Sum(pkgdefBytes)
+		lib.hash = hash[:]
+		obj.Bseek(f, before, 0)
+	}
+
 	off += l
 
 	if Debug['u'] != 0 {
-		ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef)
+		ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
 	}
 
 	/*
@@ -705,14 +716,14 @@ func objfile(file string, pkg string) {
 			break
 		}
 		if l < 0 {
-			Exitf("%s: malformed archive", file)
+			Exitf("%s: malformed archive", lib.File)
 		}
 
 		off += l
 
-		pname = fmt.Sprintf("%s(%s)", file, arhdr.name)
+		pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
 		l = atolwhex(arhdr.size)
-		ldobj(f, pkg, l, pname, file, ArchiveObj)
+		ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
 	}
 
 out:
@@ -912,7 +923,7 @@ func hostlink() {
 	}
 
 	if HEADTYPE == obj.Hdarwin {
-		argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000")
+		argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000,-headerpad,1144")
 	}
 	if HEADTYPE == obj.Hopenbsd {
 		argv = append(argv, "-Wl,-nopie")
@@ -972,15 +983,35 @@ func hostlink() {
 	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
 
 	if Linkshared {
-		for _, shlib := range Ctxt.Shlibs {
-			dir, base := filepath.Split(shlib)
-			argv = append(argv, "-L"+dir)
-			if !rpath.set {
-				argv = append(argv, "-Wl,-rpath="+dir)
+		seenDirs := make(map[string]bool)
+		seenLibs := make(map[string]bool)
+		addshlib := func(path string) {
+			dir, base := filepath.Split(path)
+			if !seenDirs[dir] {
+				argv = append(argv, "-L"+dir)
+				if !rpath.set {
+					argv = append(argv, "-Wl,-rpath="+dir)
+				}
+				seenDirs[dir] = true
 			}
 			base = strings.TrimSuffix(base, ".so")
 			base = strings.TrimPrefix(base, "lib")
-			argv = append(argv, "-l"+base)
+			if !seenLibs[base] {
+				argv = append(argv, "-l"+base)
+				seenLibs[base] = true
+			}
+		}
+		for _, shlib := range Ctxt.Shlibs {
+			addshlib(shlib.Path)
+			for _, dep := range shlib.Deps {
+				if dep == "" {
+					continue
+				}
+				libpath := findshlib(dep)
+				if libpath != "" {
+					addshlib(libpath)
+				}
+			}
 		}
 	}
 
@@ -1018,6 +1049,31 @@ func hostlink() {
 
 	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
 		Exitf("running %s failed: %v\n%s", argv[0], err, out)
+	} else if Debug['v'] != 0 && len(out) > 0 {
+		fmt.Fprintf(&Bso, "%s", out)
+		Bso.Flush()
+	}
+
+	if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin {
+		// Skip combining dwarf on arm.
+		if Thearch.Thechar != '5' && Thearch.Thechar != '7' {
+			dsym := fmt.Sprintf("%s/go.dwarf", tmpdir)
+			if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
+			}
+			combinedOutput := fmt.Sprintf("%s/go.combined", tmpdir)
+			if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
+			}
+			origOutput := fmt.Sprintf("%s/go.orig", tmpdir)
+			os.Rename(outfile, origOutput)
+			if err := os.Rename(combinedOutput, outfile); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: rename(%s, %s) failed: %v", os.Args[0], combinedOutput, outfile, err)
+			}
+		}
 	}
 }
 
@@ -1119,22 +1175,86 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
 	ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
 }
 
-func ldshlibsyms(shlib string) {
-	found := false
-	libpath := ""
-	for _, libdir := range Ctxt.Libdir {
-		libpath = filepath.Join(libdir, shlib)
-		if _, err := os.Stat(libpath); err == nil {
-			found = true
-			break
+func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
+	data := make([]byte, sym.Size)
+	sect := f.Sections[sym.Section]
+	if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
+		Diag("reading %s from non-data section", sym.Name)
+	}
+	n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
+	if uint64(n) != sym.Size {
+		Diag("reading contents of %s: %v", sym.Name, err)
+	}
+	return data
+}
+
+func readwithpad(r io.Reader, sz int32) ([]byte, error) {
+	data := make([]byte, Rnd(int64(sz), 4))
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, noteType int32
+			err := binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, ¬eType)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed:", err)
+			}
+			noteName, err := readwithpad(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed:", err)
+			}
+			desc, err := readwithpad(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed:", err)
+			}
+			if string(name) == string(noteName) && typ == noteType {
+				return desc, nil
+			}
 		}
 	}
-	if !found {
-		Diag("cannot find shared library: %s", shlib)
+	return nil, nil
+}
+
+func findshlib(shlib string) string {
+	for _, libdir := range Ctxt.Libdir {
+		libpath := filepath.Join(libdir, shlib)
+		if _, err := os.Stat(libpath); err == nil {
+			return libpath
+		}
+	}
+	Diag("cannot find shared library: %s", shlib)
+	return ""
+}
+
+func ldshlibsyms(shlib string) {
+	libpath := findshlib(shlib)
+	if libpath == "" {
 		return
 	}
-	for _, processedname := range Ctxt.Shlibs {
-		if processedname == libpath {
+	for _, processedlib := range Ctxt.Shlibs {
+		if processedlib.Path == libpath {
 			return
 		}
 	}
@@ -1148,85 +1268,48 @@ func ldshlibsyms(shlib string) {
 		Diag("cannot open shared library: %s", libpath)
 		return
 	}
-	defer f.Close()
-	syms, err := f.Symbols()
+
+	hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
+	if err != nil {
+		Diag("cannot read ABI hash from shared library %s: %v", libpath, err)
+		return
+	}
+
+	depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
+	if err != nil {
+		Diag("cannot read dep list from shared library %s: %v", libpath, err)
+		return
+	}
+	deps := strings.Split(string(depsbytes), "\n")
+
+	syms, err := f.DynamicSymbols()
 	if err != nil {
 		Diag("cannot read symbols from shared library: %s", libpath)
 		return
 	}
-	// If a package has a global variable of a type defined in another shared
-	// library, we need to know the gcmask used by the type, if any.  To support
-	// this, we read all the runtime.gcbits.* symbols, keep a map of address to
-	// gcmask, and after we're read all the symbols, read the addresses of the
-	// gcmasks symbols out of the type data to look up the gcmask for each type.
-	// This depends on the fact that the runtime.gcbits.* symbols are local (so
-	// the address is actually present in the type data and we don't have to
-	// search all relocations to find the ones which correspond to gcmasks) and
-	// also that the shared library we are linking against has not had the symbol
-	// table removed.
-	gcmasks := make(map[uint64][]byte)
-	types := []*LSym{}
 	for _, s := range syms {
 		if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION {
 			continue
 		}
-		if s.Section == elf.SHN_UNDEF {
-			continue
-		}
-		if strings.HasPrefix(s.Name, "_") {
-			continue
-		}
-		if strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
-			data := make([]byte, s.Size)
-			sect := f.Sections[s.Section]
-			if sect.Type == elf.SHT_PROGBITS {
-				n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
-				if uint64(n) != s.Size {
-					Diag("Error reading contents of %s: %v", s.Name, err)
-				}
-			}
-			gcmasks[s.Value] = data
-		}
-		if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
-			continue
-		}
 		lsym := Linklookup(Ctxt, s.Name, 0)
-		if lsym.Type != 0 && lsym.Dupok == 0 {
+		if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 {
 			Diag(
 				"Found duplicate symbol %s reading from %s, first found in %s",
 				s.Name, shlib, lsym.File)
 		}
 		lsym.Type = obj.SDYNIMPORT
 		lsym.ElfType = elf.ST_TYPE(s.Info)
-		lsym.File = libpath
-		if strings.HasPrefix(lsym.Name, "type.") {
-			data := make([]byte, s.Size)
-			sect := f.Sections[s.Section]
-			if sect.Type == elf.SHT_PROGBITS {
-				n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
-				if uint64(n) != s.Size {
-					Diag("Error reading contents of %s: %v", s.Name, err)
-				}
-				lsym.P = data
-			}
-			if !strings.HasPrefix(lsym.Name, "type..") {
-				types = append(types, lsym)
+		if s.Section != elf.SHN_UNDEF {
+			// Set .File for the library that actually defines the symbol.
+			lsym.File = libpath
+			// The decodetype_* functions in decodetype.go need access to
+			// the type data.
+			if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
+				lsym.P = readelfsymboldata(f, &s)
 			}
 		}
 	}
 
-	for _, t := range types {
-		if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 {
-			continue
-		}
-		addr := decodetype_gcprog_shlib(t)
-		tgcmask, ok := gcmasks[addr]
-		if !ok {
-			Diag("bits not found for %s at %d", t.Name, addr)
-		}
-		t.gcmask = tgcmask
-	}
-
 	// We might have overwritten some functions above (this tends to happen for the
 	// autogenerated type equality/hashing functions) and we don't want to generated
 	// pcln table entries for these any more so unstitch them from the Textp linked
@@ -1254,7 +1337,7 @@ func ldshlibsyms(shlib string) {
 		Ctxt.Etextp = last
 	}
 
-	Ctxt.Shlibs = append(Ctxt.Shlibs, libpath)
+	Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
 }
 
 func mywhatsys() {
@@ -1572,12 +1655,11 @@ func Cflush() {
 }
 
 func Cpos() int64 {
-	Cflush()
 	off, err := coutbuf.f.Seek(0, 1)
 	if err != nil {
 		Exitf("seeking in output [0, 1]: %v", err)
 	}
-	return off
+	return off + int64(coutbuf.Buffered())
 }
 
 func Cseek(p int64) {
@@ -1596,7 +1678,7 @@ func Cput(c uint8) {
 }
 
 func usage() {
-	fmt.Fprintf(os.Stderr, "usage: %cl [options] obj.%c\n", Thearch.Thechar, Thearch.Thechar)
+	fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
 	obj.Flagprint(2)
 	Exit(2)
 }
diff --git a/src/cmd/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
similarity index 94%
rename from src/cmd/internal/ld/link.go
rename to src/cmd/link/internal/ld/link.go
index 03da52a981..33b17c5985 100644
--- a/src/cmd/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -34,6 +34,7 @@ import (
 	"cmd/internal/obj"
 	"debug/elf"
 	"encoding/binary"
+	"fmt"
 )
 
 type LSym struct {
@@ -77,13 +78,19 @@ type LSym struct {
 	File        string
 	Dynimplib   string
 	Dynimpvers  string
-	Sect        interface{}
+	Sect        *Section
 	Autom       *Auto
 	Pcln        *Pcln
 	P           []byte
 	R           []Reloc
 	Local       bool
-	gcmask      []byte
+}
+
+func (s *LSym) String() string {
+	if s.Version == 0 {
+		return s.Name
+	}
+	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
 }
 
 type Reloc struct {
@@ -106,6 +113,13 @@ type Auto struct {
 	Gotype  *LSym
 }
 
+type Shlib struct {
+	Path string
+	Hash []byte
+	Deps []string
+	File *elf.File
+}
+
 type Link struct {
 	Thechar   int32
 	Thestring string
@@ -122,8 +136,8 @@ type Link struct {
 	Nsymbol   int32
 	Tlsg      *LSym
 	Libdir    []string
-	Library   []Library
-	Shlibs    []string
+	Library   []*Library
+	Shlibs    []Shlib
 	Tlsoffset int
 	Diag      func(string, ...interface{})
 	Cursym    *LSym
@@ -149,6 +163,7 @@ type Library struct {
 	File   string
 	Pkg    string
 	Shlib  string
+	hash   []byte
 }
 
 type Pcln struct {
diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
similarity index 98%
rename from src/cmd/internal/ld/macho.go
rename to src/cmd/link/internal/ld/macho.go
index ceeb7b0f5d..3a8a881d97 100644
--- a/src/cmd/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -443,7 +443,8 @@ func Asmbmacho() {
 		ms = newMachoSeg("", 40)
 
 		ms.fileoffset = Segtext.Fileoff
-		ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
+		ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
+		ms.vsize = ms.filesize
 	}
 
 	/* segment for zero page */
@@ -561,8 +562,8 @@ func Asmbmacho() {
 	}
 
 	// TODO: dwarf headers go in ms too
-	if Debug['s'] == 0 && Linkmode != LinkExternal {
-		dwarfaddmachoheaders()
+	if Debug['s'] == 0 {
+		dwarfaddmachoheaders(ms)
 	}
 
 	a := machowrite()
@@ -705,7 +706,7 @@ func machosymtab() {
 				Diag("missing section for %s", s.Name)
 				Adduint8(Ctxt, symtab, 0)
 			} else {
-				Adduint8(Ctxt, symtab, uint8((o.Sect.(*Section)).Extnum))
+				Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
 			}
 			Adduint16(Ctxt, symtab, 0) // desc
 			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
@@ -850,4 +851,5 @@ func Machoemitreloc() {
 	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		machorelocsect(sect, datap)
 	}
+	dwarfemitreloc()
 }
diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go
new file mode 100644
index 0000000000..9134373a52
--- /dev/null
+++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go
@@ -0,0 +1,369 @@
+// Copyright 2015 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 ld
+
+import (
+	"bytes"
+	"debug/macho"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"unsafe"
+)
+
+var fakedwarf, realdwarf, linkseg *macho.Segment
+var dwarfstart, linkstart int64
+var linkoffset uint32
+var machHeader *macho.FileHeader
+var mappedHeader []byte
+
+const (
+	LC_LOAD_DYLINKER        = 0xe
+	LC_PREBOUND_DYLIB       = 0x10
+	LC_LOAD_WEAK_DYLIB      = 0x18
+	LC_UUID                 = 0x1b
+	LC_RPATH                = 0x8000001c
+	LC_CODE_SIGNATURE       = 0x1d
+	LC_SEGMENT_SPLIT_INFO   = 0x1e
+	LC_REEXPORT_DYLIB       = 0x8000001f
+	LC_ENCRYPTION_INFO      = 0x21
+	LC_DYLD_INFO            = 0x22
+	LC_DYLD_INFO_ONLY       = 0x80000022
+	LC_VERSION_MIN_MACOSX   = 0x24
+	LC_VERSION_MIN_IPHONEOS = 0x25
+	LC_FUNCTION_STARTS      = 0x26
+	LC_MAIN                 = 0x80000028
+	LC_DATA_IN_CODE         = 0x29
+	LC_SOURCE_VERSION       = 0x2A
+	LC_DYLIB_CODE_SIGN_DRS  = 0x2B
+	LC_ENCRYPTION_INFO_64   = 0x2C
+
+	dwarfMinAlign = 6  // 64 = 1 << 6
+	pageAlign     = 12 // 4096 = 1 << 12
+)
+
+type loadCmd struct {
+	Cmd macho.LoadCmd
+	Len uint32
+}
+
+type dyldInfoCmd struct {
+	Cmd                      macho.LoadCmd
+	Len                      uint32
+	RebaseOff, RebaseLen     uint32
+	BindOff, BindLen         uint32
+	WeakBindOff, WeakBindLen uint32
+	LazyBindOff, LazyBindLen uint32
+	ExportOff, ExportLen     uint32
+}
+
+type linkEditDataCmd struct {
+	Cmd              macho.LoadCmd
+	Len              uint32
+	DataOff, DataLen uint32
+}
+
+type encryptionInfoCmd struct {
+	Cmd                macho.LoadCmd
+	Len                uint32
+	CryptOff, CryptLen uint32
+	CryptId            uint32
+}
+
+type loadCmdReader struct {
+	offset, next int64
+	f            *os.File
+	order        binary.ByteOrder
+}
+
+func (r *loadCmdReader) Next() (cmd loadCmd, err error) {
+	r.offset = r.next
+	if _, err = r.f.Seek(r.offset, 0); err != nil {
+		return
+	}
+	if err = binary.Read(r.f, r.order, &cmd); err != nil {
+		return
+	}
+	r.next = r.offset + int64(cmd.Len)
+	return
+}
+
+func (r loadCmdReader) ReadAt(offset int64, data interface{}) error {
+	if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
+		return err
+	}
+	return binary.Read(r.f, r.order, data)
+}
+
+func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
+	if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
+		return err
+	}
+	return binary.Write(r.f, r.order, data)
+}
+
+// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
+// With internal linking, DWARF is embedded into the executable, this lets us do the
+// same for external linking.
+// inexe is the path to the executable with no DWARF. It must have enough room in the macho
+// header to add the DWARF sections. (Use ld's -headerpad option)
+// dsym is the path to the macho file containing DWARF from dsymutil.
+// outexe is the path where the combined executable should be saved.
+func machoCombineDwarf(inexe, dsym, outexe string) error {
+	exef, err := os.Open(inexe)
+	if err != nil {
+		return err
+	}
+	dwarff, err := os.Open(dsym)
+	if err != nil {
+		return err
+	}
+	outf, err := os.Create(outexe)
+	if err != nil {
+		return err
+	}
+	outf.Chmod(0755)
+
+	exem, err := macho.NewFile(exef)
+	if err != nil {
+		return err
+	}
+	dwarfm, err := macho.NewFile(dwarff)
+	if err != nil {
+		return err
+	}
+
+	// The string table needs to be the last thing in the file
+	// for code signing to work. So we'll need to move the
+	// linkedit section, but all the others can be copied directly.
+	linkseg = exem.Segment("__LINKEDIT")
+	if linkseg == nil {
+		return fmt.Errorf("missing __LINKEDIT segment")
+	}
+
+	if _, err = exef.Seek(0, 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil {
+		return err
+	}
+
+	realdwarf = dwarfm.Segment("__DWARF")
+	if realdwarf == nil {
+		return fmt.Errorf("missing __DWARF segment")
+	}
+
+	// Now copy the dwarf data into the output.
+	maxalign := uint32(dwarfMinAlign) //
+	for _, sect := range dwarfm.Sections {
+		if sect.Align > maxalign {
+			maxalign = sect.Align
+		}
+	}
+	dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign)
+	if _, err = outf.Seek(dwarfstart, 0); err != nil {
+		return err
+	}
+
+	if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
+		return err
+	}
+
+	// And finally the linkedit section.
+	if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil {
+		return err
+	}
+	linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign)
+	linkoffset = uint32(linkstart - int64(linkseg.Offset))
+	if _, err = outf.Seek(linkstart, 0); err != nil {
+		return err
+	}
+	if _, err := io.Copy(outf, exef); err != nil {
+		return err
+	}
+
+	// Now we need to update the headers.
+	cmdOffset := unsafe.Sizeof(exem.FileHeader)
+	is64bit := exem.Magic == macho.Magic64
+	if is64bit {
+		// mach_header_64 has one extra uint32.
+		cmdOffset += unsafe.Sizeof(exem.Magic)
+	}
+
+	textsect := exem.Section("__text")
+	if linkseg == nil {
+		return fmt.Errorf("missing __text section")
+	}
+
+	dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz)
+	availablePadding := int64(textsect.Offset) - dwarfCmdOffset
+	if availablePadding < int64(realdwarf.Len) {
+		return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding)
+	}
+	// First, copy the dwarf load command into the header
+	if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil {
+		return err
+	}
+
+	if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil {
+		return err
+	}
+	if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil {
+		return err
+	}
+	if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil {
+		return err
+	}
+
+	reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder}
+	for i := uint32(0); i < exem.Ncmd; i++ {
+		cmd, err := reader.Next()
+		if err != nil {
+			return err
+		}
+		switch cmd.Cmd {
+		case macho.LoadCmdSegment64:
+			err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{})
+		case macho.LoadCmdSegment:
+			err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{})
+		case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
+			err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
+		case macho.LoadCmdSymtab:
+			err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff")
+		case macho.LoadCmdDysymtab:
+			err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff")
+		case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS:
+			err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff")
+		case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
+			err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff")
+		case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH:
+			// Nothing to update
+		default:
+			err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return machoUpdateDwarfHeader(&reader)
+}
+
+// machoUpdateSegment updates the load command for a moved segment.
+// Only the linkedit segment should move, and it should have 0 sections.
+// seg should be a macho.Segment32 or macho.Segment64 as appropriate.
+// sect should be a macho.Section32 or macho.Section64 as appropriate.
+func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error {
+	if err := r.ReadAt(0, seg); err != nil {
+		return err
+	}
+	segValue := reflect.ValueOf(seg)
+	offset := reflect.Indirect(segValue).FieldByName("Offset")
+
+	// Only the linkedit segment moved, any thing before that is fine.
+	if offset.Uint() < linkseg.Offset {
+		return nil
+	}
+	offset.SetUint(offset.Uint() + uint64(linkoffset))
+	if err := r.WriteAt(0, seg); err != nil {
+		return err
+	}
+	// There shouldn't be any sections, but just to make sure...
+	return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset))
+}
+
+func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error {
+	iseg := reflect.Indirect(seg)
+	nsect := iseg.FieldByName("Nsect").Uint()
+	if nsect == 0 {
+		return nil
+	}
+	sectOffset := int64(iseg.Type().Size())
+
+	isect := reflect.Indirect(sect)
+	offsetField := isect.FieldByName("Offset")
+	reloffField := isect.FieldByName("Reloff")
+	sectSize := int64(isect.Type().Size())
+	for i := uint64(0); i < nsect; i++ {
+		if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
+			return err
+		}
+		if offsetField.Uint() != 0 {
+			offsetField.SetUint(offsetField.Uint() + delta)
+		}
+		if reloffField.Uint() != 0 {
+			reloffField.SetUint(reloffField.Uint() + delta)
+		}
+		if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
+			return err
+		}
+		sectOffset += sectSize
+	}
+	return nil
+}
+
+// machoUpdateDwarfHeader updates the DWARF segment load command.
+func machoUpdateDwarfHeader(r *loadCmdReader) error {
+	var seg, sect interface{}
+	cmd, err := r.Next()
+	if err != nil {
+		return err
+	}
+	if cmd.Cmd == macho.LoadCmdSegment64 {
+		seg = new(macho.Segment64)
+		sect = new(macho.Section64)
+	} else {
+		seg = new(macho.Segment32)
+		sect = new(macho.Section32)
+	}
+	if err := r.ReadAt(0, seg); err != nil {
+		return err
+	}
+	segValue := reflect.ValueOf(seg)
+	offset := reflect.Indirect(segValue).FieldByName("Offset")
+
+	delta := uint64(dwarfstart) - realdwarf.Offset
+	offset.SetUint(offset.Uint() + delta)
+	if err := r.WriteAt(0, seg); err != nil {
+		return err
+	}
+	return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta)
+}
+
+func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error {
+	if err := r.ReadAt(0, cmd); err != nil {
+		return err
+	}
+	value := reflect.Indirect(reflect.ValueOf(cmd))
+
+	for _, name := range fields {
+		field := value.FieldByName(name)
+		fieldval := field.Uint()
+		if fieldval >= linkseg.Offset {
+			field.SetUint(fieldval + uint64(linkoffset))
+		}
+	}
+	if err := r.WriteAt(0, cmd); err != nil {
+		return err
+	}
+	return nil
+}
+
+func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 {
+	align := uint64(1 << alignExp)
+	if (origAddr % align) == (newAddr % align) {
+		return int64(newAddr)
+	}
+	padding := (align - (newAddr % align))
+	padding += origAddr % align
+	return int64(padding + newAddr)
+}
diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
similarity index 99%
rename from src/cmd/internal/ld/objfile.go
rename to src/cmd/link/internal/ld/objfile.go
index 3d59323dba..613fcb2a40 100644
--- a/src/cmd/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -347,7 +347,7 @@ func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
 			s.Reachable = false
 		}
 	}
-	if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
+	if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.") {
 		s.Local = true
 	}
 	return s
diff --git a/src/cmd/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
similarity index 100%
rename from src/cmd/internal/ld/pcln.go
rename to src/cmd/link/internal/ld/pcln.go
diff --git a/src/cmd/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
similarity index 100%
rename from src/cmd/internal/ld/pe.go
rename to src/cmd/link/internal/ld/pe.go
diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
similarity index 98%
rename from src/cmd/internal/ld/pobj.go
rename to src/cmd/link/internal/ld/pobj.go
index 8568744c3d..5b24428059 100644
--- a/src/cmd/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -160,10 +160,9 @@ func Ldmain() {
 	}
 
 	if outfile == "" {
+		outfile = "a.out"
 		if HEADTYPE == obj.Hwindows {
-			outfile = fmt.Sprintf("%c.out.exe", Thearch.Thechar)
-		} else {
-			outfile = fmt.Sprintf("%c.out", Thearch.Thechar)
+			outfile += ".exe"
 		}
 	}
 
diff --git a/src/cmd/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
similarity index 100%
rename from src/cmd/internal/ld/sym.go
rename to src/cmd/link/internal/ld/sym.go
diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
similarity index 87%
rename from src/cmd/internal/ld/symtab.go
rename to src/cmd/link/internal/ld/symtab.go
index d6e79dc00f..7ceb64f941 100644
--- a/src/cmd/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -32,6 +32,8 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"fmt"
+	"path/filepath"
 	"strings"
 )
 
@@ -128,12 +130,12 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 			Diag("missing section in putelfsym")
 			return
 		}
-		if xo.Sect.(*Section).Elfsect == nil {
+		if xo.Sect.Elfsect == nil {
 			Ctxt.Cursym = x
 			Diag("missing ELF section in putelfsym")
 			return
 		}
-		elfshnum = xo.Sect.(*Section).Elfsect.(*ElfShdr).shnum
+		elfshnum = xo.Sect.Elfsect.shnum
 	}
 
 	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
@@ -159,7 +161,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 
 	off := putelfstr(s)
 	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
-		addr -= int64(xo.Sect.(*Section).Vaddr)
+		addr -= int64(xo.Sect.Vaddr)
 	}
 	other := STV_DEFAULT
 	if x.Type&obj.SHIDDEN != 0 {
@@ -294,6 +296,20 @@ func Vputl(v uint64) {
 	Lputl(uint32(v >> 32))
 }
 
+type byPkg []*Library
+
+func (libs byPkg) Len() int {
+	return len(libs)
+}
+
+func (libs byPkg) Less(a, b int) bool {
+	return libs[a].Pkg < libs[b].Pkg
+}
+
+func (libs byPkg) Swap(a, b int) {
+	libs[a], libs[b] = libs[b], libs[a]
+}
+
 func symtab() {
 	dosymtype()
 
@@ -410,6 +426,15 @@ func symtab() {
 		}
 	}
 
+	if Buildmode == BuildmodeShared {
+		abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0)
+		abihashgostr.Reachable = true
+		abihashgostr.Type = obj.SRODATA
+		hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		Addaddr(Ctxt, abihashgostr, hashsym)
+		adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
+	}
+
 	// Information about the layout of the executable image for the
 	// runtime to use. Any changes here must be matched by changes to
 	// the definition of moduledata in runtime/symtab.go.
@@ -454,6 +479,38 @@ func symtab() {
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
 	adduint(Ctxt, moduledata, uint64(ntypelinks))
 	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	if len(Ctxt.Shlibs) > 0 {
+		thismodulename := filepath.Base(outfile)
+		if Buildmode == BuildmodeExe {
+			// When linking an executable, outfile is just "a.out". Make
+			// it something slightly more comprehensible.
+			thismodulename = "the executable"
+		}
+		addgostring(moduledata, "go.link.thismodulename", thismodulename)
+
+		modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0)
+		modulehashes.Reachable = true
+		modulehashes.Local = true
+		modulehashes.Type = obj.SRODATA
+
+		for i, shlib := range Ctxt.Shlibs {
+			// modulehashes[i].modulename
+			modulename := filepath.Base(shlib.Path)
+			addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
+
+			// modulehashes[i].linktimehash
+			addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
+
+			// modulehashes[i].runtimehash
+			abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0)
+			abihash.Reachable = true
+			Addaddr(Ctxt, modulehashes, abihash)
+		}
+
+		Addaddr(Ctxt, moduledata, modulehashes)
+		adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
+		adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
+	}
 	// The rest of moduledata is zero initialized.
 	// When linking an object that does not contain the runtime we are
 	// creating the moduledata from scratch and it does not have a
diff --git a/src/cmd/internal/ld/textflag.go b/src/cmd/link/internal/ld/textflag.go
similarity index 100%
rename from src/cmd/internal/ld/textflag.go
rename to src/cmd/link/internal/ld/textflag.go
diff --git a/src/cmd/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
similarity index 100%
rename from src/cmd/internal/ld/util.go
rename to src/cmd/link/internal/ld/util.go
diff --git a/src/cmd/9l/asm.go b/src/cmd/link/internal/ppc64/asm.go
similarity index 92%
rename from src/cmd/9l/asm.go
rename to src/cmd/link/internal/ppc64/asm.go
index 257f23e2ab..f070921ecf 100644
--- a/src/cmd/9l/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -28,34 +28,16 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"encoding/binary"
 	"fmt"
 	"log"
 )
 
-func needlib(name string) int {
-	if name[0] == '\x00' {
-		return 0
-	}
-
-	/* reuse hash code in symbol table */
-	p := fmt.Sprintf(".dynlib.%s", name)
-
-	s := ld.Linklookup(ld.Ctxt, p, 0)
-
-	if s.Type == 0 {
-		s.Type = 100 // avoid SDATA, etc.
-		return 1
-	}
-
-	return 0
-}
-
 func gentext() {
 	var s *ld.LSym
 	var stub *ld.LSym
@@ -240,7 +222,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 		r.Type = obj.R_ADDR
 		if targ.Type == obj.SDYNIMPORT {
 			// These happen in .toc sections
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 
 			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
 			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
@@ -520,7 +502,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -622,70 +604,6 @@ func ensureglinkresolver() *ld.LSym {
 	return glink
 }
 
-func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	if s.Dynid >= 0 {
-		return
-	}
-
-	if ld.Iself {
-		s.Dynid = int32(ld.Nelfsym)
-		ld.Nelfsym++
-
-		d := ld.Linklookup(ctxt, ".dynsym", 0)
-
-		name := s.Extname
-		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
-
-		/* type */
-		t := ld.STB_GLOBAL << 4
-
-		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
-			t |= ld.STT_FUNC
-		} else {
-			t |= ld.STT_OBJECT
-		}
-		ld.Adduint8(ctxt, d, uint8(t))
-
-		/* reserved */
-		ld.Adduint8(ctxt, d, 0)
-
-		/* section where symbol is defined */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
-		} else {
-			ld.Adduint16(ctxt, d, 1)
-		}
-
-		/* value */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint64(ctxt, d, 0)
-		} else {
-			ld.Addaddr(ctxt, d, s)
-		}
-
-		/* size of object */
-		ld.Adduint64(ctxt, d, uint64(s.Size))
-	} else {
-		ld.Diag("adddynsym: unsupported binary format")
-	}
-}
-
-func adddynlib(lib string) {
-	if needlib(lib) == 0 {
-		return
-	}
-
-	if ld.Iself {
-		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
-		if s.Size == 0 {
-			ld.Addstring(s, "")
-		}
-		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else {
-		ld.Diag("adddynlib: unsupported binary format")
-	}
-}
-
 func asmb() {
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
diff --git a/src/cmd/9l/l.go b/src/cmd/link/internal/ppc64/l.go
similarity index 98%
rename from src/cmd/9l/l.go
rename to src/cmd/link/internal/ppc64/l.go
index e7dc102af2..1275a34dbb 100644
--- a/src/cmd/9l/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 // Writing object files.
 
@@ -71,7 +71,8 @@ const (
 	MINLC     = 4
 )
 
-/* Used by ../ld/dwarf.c */
+/* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 1
+	DWARFREGLR = 65
 )
diff --git a/src/cmd/9l/obj.go b/src/cmd/link/internal/ppc64/obj.go
similarity index 97%
rename from src/cmd/9l/obj.go
rename to src/cmd/link/internal/ppc64/obj.go
index 46a92396e4..d663b6ebae 100644
--- a/src/cmd/9l/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -28,18 +28,18 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package ppc64
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
 // Reading object files.
 
-func main() {
+func Main() {
 	linkarchinit()
 	ld.Ldmain()
 }
@@ -60,10 +60,9 @@ func linkarchinit() {
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
+	ld.Thearch.Dwarfreglr = DWARFREGLR
 
-	ld.Thearch.Adddynlib = adddynlib
 	ld.Thearch.Adddynrel = adddynrel
-	ld.Thearch.Adddynsym = adddynsym
 	ld.Thearch.Archinit = archinit
 	ld.Thearch.Archreloc = archreloc
 	ld.Thearch.Archrelocvariant = archrelocvariant
diff --git a/src/cmd/8l/asm.go b/src/cmd/link/internal/x86/asm.go
similarity index 87%
rename from src/cmd/8l/asm.go
rename to src/cmd/link/internal/x86/asm.go
index 7231379108..d30bd48b4e 100644
--- a/src/cmd/8l/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -28,33 +28,15 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
-func needlib(name string) int {
-	if name[0] == '\x00' {
-		return 0
-	}
-
-	/* reuse hash code in symbol table */
-	p := fmt.Sprintf(".dynlib.%s", name)
-
-	s := ld.Linklookup(ld.Ctxt, p, 0)
-
-	if s.Type == 0 {
-		s.Type = 100 // avoid SDATA, etc.
-		return 1
-	}
-
-	return 0
-}
-
 func gentext() {
 }
 
@@ -202,7 +184,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			break
 		}
 		if ld.Iself {
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
@@ -222,7 +204,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			// just in case the C code assigns to the variable,
 			// and of course it only works for single pointers,
 			// but we only need to support cgo and that's all it needs.
-			adddynsym(ld.Ctxt, targ)
+			ld.Adddynsym(ld.Ctxt, targ)
 
 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
 			s.Type = got.Type | obj.SSUB
@@ -294,9 +276,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 		v = uint32(rs.Dynid)
 		v |= 1 << 27 // external relocation
 	} else {
-		v = uint32((rs.Sect.(*ld.Section)).Extnum)
+		v = uint32(rs.Sect.Extnum)
 		if v == 0 {
-			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, (rs.Sect.(*ld.Section)).Name, rs.Type)
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
 			return -1
 		}
 	}
@@ -420,7 +402,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -480,7 +462,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 	got := ld.Linklookup(ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint32(ctxt, got, 0)
@@ -496,76 +478,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 	}
 }
 
-func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	if s.Dynid >= 0 {
-		return
-	}
-
-	if ld.Iself {
-		s.Dynid = int32(ld.Nelfsym)
-		ld.Nelfsym++
-
-		d := ld.Linklookup(ctxt, ".dynsym", 0)
-
-		/* name */
-		name := s.Extname
-
-		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
-
-		/* value */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint32(ctxt, d, 0)
-		} else {
-			ld.Addaddr(ctxt, d, s)
-		}
-
-		/* size */
-		ld.Adduint32(ctxt, d, 0)
-
-		/* type */
-		t := ld.STB_GLOBAL << 4
-
-		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
-			t |= ld.STT_FUNC
-		} else {
-			t |= ld.STT_OBJECT
-		}
-		ld.Adduint8(ctxt, d, uint8(t))
-		ld.Adduint8(ctxt, d, 0)
-
-		/* shndx */
-		if s.Type == obj.SDYNIMPORT {
-			ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
-		} else {
-			ld.Adduint16(ctxt, d, 1)
-		}
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
-	} else if ld.HEADTYPE == obj.Hwindows {
-	} else // already taken care of
-	{
-		ld.Diag("adddynsym: unsupported binary format")
-	}
-}
-
-func adddynlib(lib string) {
-	if needlib(lib) == 0 {
-		return
-	}
-
-	if ld.Iself {
-		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
-		if s.Size == 0 {
-			ld.Addstring(s, "")
-		}
-		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
-	} else if ld.HEADTYPE == obj.Hdarwin {
-		ld.Machoadddynlib(lib)
-	} else if ld.HEADTYPE != obj.Hwindows {
-		ld.Diag("adddynlib: unsupported binary format")
-	}
-}
-
 func asmb() {
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
@@ -639,7 +551,7 @@ func asmb() {
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
 		case obj.Hdarwin:
-			symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink))
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
 
 		case obj.Hwindows:
 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
diff --git a/src/cmd/8l/l.go b/src/cmd/link/internal/x86/l.go
similarity index 96%
rename from src/cmd/8l/l.go
rename to src/cmd/link/internal/x86/l.go
index 60050857c4..8a811ff0a2 100644
--- a/src/cmd/8l/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 const (
 	thechar   = '8'
@@ -40,7 +40,8 @@ const (
 	MINLC     = 1
 )
 
-/* Used by ../ld/dwarf.c */
+/* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 4
+	DWARFREGLR = 8
 )
diff --git a/src/cmd/8l/obj.go b/src/cmd/link/internal/x86/obj.go
similarity index 97%
rename from src/cmd/8l/obj.go
rename to src/cmd/link/internal/x86/obj.go
index 7b490ae87c..ee408f70c6 100644
--- a/src/cmd/8l/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -28,18 +28,18 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-package main
+package x86
 
 import (
-	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"cmd/link/internal/ld"
 	"fmt"
 	"log"
 )
 
 // Reading object files.
 
-func main() {
+func Main() {
 	linkarchinit()
 	ld.Ldmain()
 }
@@ -56,10 +56,9 @@ func linkarchinit() {
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
+	ld.Thearch.Dwarfreglr = DWARFREGLR
 
-	ld.Thearch.Adddynlib = adddynlib
 	ld.Thearch.Adddynrel = adddynrel
-	ld.Thearch.Adddynsym = adddynsym
 	ld.Thearch.Archinit = archinit
 	ld.Thearch.Archreloc = archreloc
 	ld.Thearch.Archrelocvariant = archrelocvariant
diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go
index b23f3f87b0..0e6c34ee0a 100644
--- a/src/cmd/link/main.go
+++ b/src/cmd/link/main.go
@@ -1,9 +1,34 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// Copyright 2015 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.
 
-// Placeholder to keep build building.
-
 package main
 
-func main() {}
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/amd64"
+	"cmd/link/internal/arm"
+	"cmd/link/internal/arm64"
+	"cmd/link/internal/ppc64"
+	"cmd/link/internal/x86"
+	"fmt"
+	"os"
+)
+
+func main() {
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		x86.Main()
+	case "amd64", "amd64p32":
+		amd64.Main()
+	case "arm":
+		arm.Main()
+	case "arm64":
+		arm64.Main()
+	case "ppc64", "ppc64le":
+		ppc64.Main()
+	}
+}
diff --git a/src/cmd/link/auto.go b/src/cmd/newlink/auto.go
similarity index 100%
rename from src/cmd/link/auto.go
rename to src/cmd/newlink/auto.go
diff --git a/src/cmd/link/auto_test.go b/src/cmd/newlink/auto_test.go
similarity index 100%
rename from src/cmd/link/auto_test.go
rename to src/cmd/newlink/auto_test.go
diff --git a/src/cmd/link/dead.go b/src/cmd/newlink/dead.go
similarity index 100%
rename from src/cmd/link/dead.go
rename to src/cmd/newlink/dead.go
diff --git a/src/cmd/link/dead_test.go b/src/cmd/newlink/dead_test.go
similarity index 100%
rename from src/cmd/link/dead_test.go
rename to src/cmd/newlink/dead_test.go
diff --git a/src/cmd/link/debug.go b/src/cmd/newlink/debug.go
similarity index 100%
rename from src/cmd/link/debug.go
rename to src/cmd/newlink/debug.go
diff --git a/src/cmd/link/hex_test.go b/src/cmd/newlink/hex_test.go
similarity index 100%
rename from src/cmd/link/hex_test.go
rename to src/cmd/newlink/hex_test.go
diff --git a/src/cmd/link/layout.go b/src/cmd/newlink/layout.go
similarity index 100%
rename from src/cmd/link/layout.go
rename to src/cmd/newlink/layout.go
diff --git a/src/cmd/link/layout_test.go b/src/cmd/newlink/layout_test.go
similarity index 100%
rename from src/cmd/link/layout_test.go
rename to src/cmd/newlink/layout_test.go
diff --git a/src/cmd/link/link_test.go b/src/cmd/newlink/link_test.go
similarity index 100%
rename from src/cmd/link/link_test.go
rename to src/cmd/newlink/link_test.go
diff --git a/src/cmd/link/load.go b/src/cmd/newlink/load.go
similarity index 100%
rename from src/cmd/link/load.go
rename to src/cmd/newlink/load.go
diff --git a/src/cmd/link/macho.go b/src/cmd/newlink/macho.go
similarity index 100%
rename from src/cmd/link/macho.go
rename to src/cmd/newlink/macho.go
diff --git a/src/cmd/link/macho_test.go b/src/cmd/newlink/macho_test.go
similarity index 100%
rename from src/cmd/link/macho_test.go
rename to src/cmd/newlink/macho_test.go
diff --git a/src/cmd/newlink/main.go b/src/cmd/newlink/main.go
new file mode 100644
index 0000000000..b23f3f87b0
--- /dev/null
+++ b/src/cmd/newlink/main.go
@@ -0,0 +1,9 @@
+// Copyright 2014 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.
+
+// Placeholder to keep build building.
+
+package main
+
+func main() {}
diff --git a/src/cmd/link/pclntab.go b/src/cmd/newlink/pclntab.go
similarity index 100%
rename from src/cmd/link/pclntab.go
rename to src/cmd/newlink/pclntab.go
diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/newlink/pclntab_test.go
similarity index 100%
rename from src/cmd/link/pclntab_test.go
rename to src/cmd/newlink/pclntab_test.go
diff --git a/src/cmd/link/prog.go b/src/cmd/newlink/prog.go
similarity index 100%
rename from src/cmd/link/prog.go
rename to src/cmd/newlink/prog.go
diff --git a/src/cmd/link/prog_test.go b/src/cmd/newlink/prog_test.go
similarity index 100%
rename from src/cmd/link/prog_test.go
rename to src/cmd/newlink/prog_test.go
diff --git a/src/cmd/link/runtime.go b/src/cmd/newlink/runtime.go
similarity index 100%
rename from src/cmd/link/runtime.go
rename to src/cmd/newlink/runtime.go
diff --git a/src/cmd/link/scan.go b/src/cmd/newlink/scan.go
similarity index 100%
rename from src/cmd/link/scan.go
rename to src/cmd/newlink/scan.go
diff --git a/src/cmd/link/testdata/Makefile b/src/cmd/newlink/testdata/Makefile
similarity index 100%
rename from src/cmd/link/testdata/Makefile
rename to src/cmd/newlink/testdata/Makefile
diff --git a/src/cmd/link/testdata/autosection.6 b/src/cmd/newlink/testdata/autosection.6
similarity index 100%
rename from src/cmd/link/testdata/autosection.6
rename to src/cmd/newlink/testdata/autosection.6
diff --git a/src/cmd/link/testdata/autosection.s b/src/cmd/newlink/testdata/autosection.s
similarity index 100%
rename from src/cmd/link/testdata/autosection.s
rename to src/cmd/newlink/testdata/autosection.s
diff --git a/src/cmd/link/testdata/autoweak.6 b/src/cmd/newlink/testdata/autoweak.6
similarity index 100%
rename from src/cmd/link/testdata/autoweak.6
rename to src/cmd/newlink/testdata/autoweak.6
diff --git a/src/cmd/link/testdata/autoweak.s b/src/cmd/newlink/testdata/autoweak.s
similarity index 100%
rename from src/cmd/link/testdata/autoweak.s
rename to src/cmd/newlink/testdata/autoweak.s
diff --git a/src/cmd/link/testdata/dead.6 b/src/cmd/newlink/testdata/dead.6
similarity index 100%
rename from src/cmd/link/testdata/dead.6
rename to src/cmd/newlink/testdata/dead.6
diff --git a/src/cmd/link/testdata/dead.s b/src/cmd/newlink/testdata/dead.s
similarity index 100%
rename from src/cmd/link/testdata/dead.s
rename to src/cmd/newlink/testdata/dead.s
diff --git a/src/cmd/link/testdata/genpcln.go b/src/cmd/newlink/testdata/genpcln.go
similarity index 100%
rename from src/cmd/link/testdata/genpcln.go
rename to src/cmd/newlink/testdata/genpcln.go
diff --git a/src/cmd/link/testdata/hello.6 b/src/cmd/newlink/testdata/hello.6
similarity index 100%
rename from src/cmd/link/testdata/hello.6
rename to src/cmd/newlink/testdata/hello.6
diff --git a/src/cmd/link/testdata/hello.s b/src/cmd/newlink/testdata/hello.s
similarity index 100%
rename from src/cmd/link/testdata/hello.s
rename to src/cmd/newlink/testdata/hello.s
diff --git a/src/cmd/link/testdata/layout.6 b/src/cmd/newlink/testdata/layout.6
similarity index 100%
rename from src/cmd/link/testdata/layout.6
rename to src/cmd/newlink/testdata/layout.6
diff --git a/src/cmd/link/testdata/layout.s b/src/cmd/newlink/testdata/layout.s
similarity index 100%
rename from src/cmd/link/testdata/layout.s
rename to src/cmd/newlink/testdata/layout.s
diff --git a/src/cmd/link/testdata/link.hello.darwin.amd64 b/src/cmd/newlink/testdata/link.hello.darwin.amd64
similarity index 100%
rename from src/cmd/link/testdata/link.hello.darwin.amd64
rename to src/cmd/newlink/testdata/link.hello.darwin.amd64
diff --git a/src/cmd/link/testdata/macho.amd64.exit9 b/src/cmd/newlink/testdata/macho.amd64.exit9
similarity index 100%
rename from src/cmd/link/testdata/macho.amd64.exit9
rename to src/cmd/newlink/testdata/macho.amd64.exit9
diff --git a/src/cmd/link/testdata/macho.amd64.hello b/src/cmd/newlink/testdata/macho.amd64.hello
similarity index 100%
rename from src/cmd/link/testdata/macho.amd64.hello
rename to src/cmd/newlink/testdata/macho.amd64.hello
diff --git a/src/cmd/link/testdata/macho.amd64.helloro b/src/cmd/newlink/testdata/macho.amd64.helloro
similarity index 100%
rename from src/cmd/link/testdata/macho.amd64.helloro
rename to src/cmd/newlink/testdata/macho.amd64.helloro
diff --git a/src/cmd/link/testdata/pclntab.6 b/src/cmd/newlink/testdata/pclntab.6
similarity index 100%
rename from src/cmd/link/testdata/pclntab.6
rename to src/cmd/newlink/testdata/pclntab.6
diff --git a/src/cmd/link/testdata/pclntab.s b/src/cmd/newlink/testdata/pclntab.s
similarity index 100%
rename from src/cmd/link/testdata/pclntab.s
rename to src/cmd/newlink/testdata/pclntab.s
diff --git a/src/cmd/link/util.go b/src/cmd/newlink/util.go
similarity index 100%
rename from src/cmd/link/util.go
rename to src/cmd/newlink/util.go
diff --git a/src/cmd/link/write.go b/src/cmd/newlink/write.go
similarity index 100%
rename from src/cmd/link/write.go
rename to src/cmd/newlink/write.go
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index 9c33f4f98b..cd32020501 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -13,7 +13,6 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"testing"
 	"time"
@@ -223,16 +222,14 @@ func TestHello(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	char := findChar(t, dir)
-
 	run := func(args ...string) string {
 		return doRun(t, dir, args...)
 	}
 
 	run("go", "build", "cmd/pack") // writes pack binary to dir
-	run("go", "tool", char+"g", "hello.go")
-	run("./pack", "grc", "hello.a", "hello."+char)
-	run("go", "tool", char+"l", "-o", "a.out", "hello.a")
+	run("go", "tool", "compile", "hello.go")
+	run("./pack", "grc", "hello.a", "hello.o")
+	run("go", "tool", "link", "-o", "a.out", "hello.a")
 	out := run("./a.out")
 	if out != "hello world\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
@@ -297,17 +294,15 @@ func TestLargeDefs(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	char := findChar(t, dir)
-
 	run := func(args ...string) string {
 		return doRun(t, dir, args...)
 	}
 
 	run("go", "build", "cmd/pack") // writes pack binary to dir
-	run("go", "tool", char+"g", "large.go")
-	run("./pack", "grc", "large.a", "large."+char)
-	run("go", "tool", char+"g", "-I", ".", "main.go")
-	run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char)
+	run("go", "tool", "compile", "large.go")
+	run("./pack", "grc", "large.a", "large.o")
+	run("go", "tool", "compile", "-I", ".", "main.go")
+	run("go", "tool", "link", "-L", ".", "-o", "a.out", "main.o")
 	out := run("./a.out")
 	if out != "ok\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
@@ -325,20 +320,6 @@ func doRun(t *testing.T, dir string, args ...string) string {
 	return string(out)
 }
 
-// findChar returns the architecture character for the go command.
-func findChar(t *testing.T, dir string) string {
-	out := doRun(t, dir, "go", "env")
-	re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	fields := re.FindStringSubmatch(out)
-	if fields == nil {
-		t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
-	}
-	return fields[1]
-}
-
 // Fake implementation of files.
 
 var helloFile = &FakeFile{
diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go
index bfc8110e45..e4c92cdd19 100644
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ b/src/cmd/pprof/internal/profile/legacy_profile.go
@@ -554,9 +554,10 @@ func parseHeap(b []byte) (p *Profile, err error) {
 			}
 		}
 
-		if l = strings.TrimSpace(l); l == "" {
+		if isSpaceOrComment(l) {
 			continue
 		}
+		l = strings.TrimSpace(l)
 
 		if sectionTrigger(l) != unrecognizedSection {
 			break
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 5c7b0b71b1..53c0fab174 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -128,6 +128,7 @@ const (
 	TYPEDEF
 	TYPENAME
 	UNION
+	ERROR
 )
 
 const ENDFILE = 0
@@ -325,8 +326,24 @@ var resrv = []Resrv{
 	{"type", TYPEDEF},
 	{"union", UNION},
 	{"struct", UNION},
+	{"error", ERROR},
 }
 
+type Error struct {
+	lineno int
+	tokens []string
+	msg    string
+}
+
+var errors []Error
+
+type Row struct {
+	actions       []int
+	defaultAction int
+}
+
+var stateTable []Row
+
 var zznewstate = 0
 
 const EOF = -1
@@ -402,6 +419,27 @@ outer:
 			}
 			start = chfind(1, tokname)
 
+		case ERROR:
+			lno := lineno
+			var tokens []string
+			for {
+				t := gettok()
+				if t == ':' {
+					break
+				}
+				if t != IDENTIFIER && t != IDENTCOLON {
+					errorf("bad syntax in %%error")
+				}
+				tokens = append(tokens, tokname)
+				if t == IDENTCOLON {
+					break
+				}
+			}
+			if gettok() != IDENTIFIER {
+				errorf("bad syntax in %%error")
+			}
+			errors = append(errors, Error{lno, tokens, tokname})
+
 		case TYPEDEF:
 			t = gettok()
 			if t != TYPENAME {
@@ -2155,6 +2193,10 @@ func output() {
 	}
 	fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
 
+	if len(errors) > 0 {
+		stateTable = make([]Row, nstate)
+	}
+
 	noset := mkset()
 
 	// output the stuff for state i
@@ -2368,6 +2410,15 @@ func wrstate(i int) {
 	var j0, j1, u int
 	var pp, qq int
 
+	if len(errors) > 0 {
+		actions := append([]int(nil), temp1...)
+		defaultAction := ERRCODE
+		if lastred != 0 {
+			defaultAction = -lastred
+		}
+		stateTable[i] = Row{actions, defaultAction}
+	}
+
 	if foutput == nil {
 		return
 	}
@@ -2914,6 +2965,20 @@ func others() {
 	}
 	fmt.Fprintf(ftable, "%d,\n}\n", 0)
 
+	// Custom error messages.
+	fmt.Fprintf(ftable, "\n")
+	fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
+	fmt.Fprintf(ftable, "\tstate int\n")
+	fmt.Fprintf(ftable, "\ttoken int\n")
+	fmt.Fprintf(ftable, "\tmsg   string\n")
+	fmt.Fprintf(ftable, "}{\n")
+	for _, error := range errors {
+		lineno = error.lineno
+		state, token := runMachine(error.tokens)
+		fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
+	}
+	fmt.Fprintf(ftable, "}\n")
+
 	// copy parser text
 	ch := getrune(finput)
 	for ch != EOF {
@@ -2932,6 +2997,59 @@ func others() {
 	fmt.Fprintf(ftable, "%v", parts[1])
 }
 
+func runMachine(tokens []string) (state, token int) {
+	var stack []int
+	i := 0
+	token = -1
+
+Loop:
+	if token < 0 {
+		token = chfind(2, tokens[i])
+		i++
+	}
+
+	row := stateTable[state]
+
+	c := token
+	if token >= NTBASE {
+		c = token - NTBASE + ntokens
+	}
+	action := row.actions[c]
+	if action == 0 {
+		action = row.defaultAction
+	}
+
+	switch {
+	case action == ACCEPTCODE:
+		errorf("tokens are accepted")
+		return
+	case action == ERRCODE:
+		if token >= NTBASE {
+			errorf("error at non-terminal token %s", symnam(token))
+		}
+		return
+	case action > 0:
+		// Shift to state action.
+		stack = append(stack, state)
+		state = action
+		token = -1
+		goto Loop
+	default:
+		// Reduce by production -action.
+		prod := prdptr[-action]
+		if rhsLen := len(prod) - 2; rhsLen > 0 {
+			n := len(stack) - rhsLen
+			state = stack[n]
+			stack = stack[:n]
+		}
+		if token >= 0 {
+			i--
+		}
+		token = prod[0]
+		goto Loop
+	}
+}
+
 func arout(s string, v []int, n int) {
 	s = prefix + s
 	fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
@@ -3212,7 +3330,6 @@ type $$Parser interface {
 
 type $$ParserImpl struct {
 	lookahead func() int
-	state     func() int
 }
 
 func (p *$$ParserImpl) Lookahead() int {
@@ -3222,7 +3339,6 @@ func (p *$$ParserImpl) Lookahead() int {
 func $$NewParser() $$Parser {
 	p := &$$ParserImpl{
 		lookahead: func() int { return -1 },
-		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -3253,6 +3369,13 @@ func $$ErrorMessage(state, lookAhead int) string {
 	if !$$ErrorVerbose {
 		return "syntax error"
 	}
+
+	for _, e := range $$ErrorMessages {
+		if e.state == state && e.token == lookAhead {
+			return "syntax error: " + e.msg
+		}
+	}
+
 	res := "syntax error: unexpected " + $$Tokname(lookAhead)
 
 	// To match Bison, suggest at most four expected tokens.
@@ -3355,7 +3478,6 @@ func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
 	$$state := 0
 	$$char := -1
 	$$token := -1 // $$char translated into internal numbering
-	$$rcvr.state = func() int { return $$state }
 	$$rcvr.lookahead = func() int { return $$char }
 	defer func() {
 		// Make sure we report no lookahead when not parsing.
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 6855a65bbe..c6943a631a 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -49,7 +49,7 @@ func dotest(self bool) bool {
 	// the resulting binary looks like it was built from pclinetest.s,
 	// but we have renamed it to keep it away from the go tool.
 	pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
-	command := fmt.Sprintf("go tool asm -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
+	command := fmt.Sprintf("go tool asm -o %s.o pclinetest.asm && go tool link -H linux -E main -o %s %s.o",
 		pclinetestBinary, pclinetestBinary, pclinetestBinary)
 	cmd := exec.Command("sh", "-c", command)
 	cmd.Stdout = os.Stdout
diff --git a/src/encoding/gob/doc.go b/src/encoding/gob/doc.go
index d0acaba1ad..31223b6d43 100644
--- a/src/encoding/gob/doc.go
+++ b/src/encoding/gob/doc.go
@@ -6,7 +6,7 @@
 Package gob manages streams of gobs - binary values exchanged between an
 Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
 arguments and results of remote procedure calls (RPCs) such as those provided by
-package "rpc".
+package "net/rpc".
 
 The implementation compiles a custom codec for each data type in the stream and
 is most efficient when a single Encoder is used to transmit a stream of values,
@@ -83,7 +83,7 @@ allocated. Regardless, the length of the resulting slice reports the number of
 elements decoded.
 
 Functions and channels will not be sent in a gob. Attempting to encode such a value
-at top the level will fail. A struct field of chan or func type is treated exactly
+at the top level will fail. A struct field of chan or func type is treated exactly
 like an unexported field and is ignored.
 
 Gob can encode a value of any type implementing the GobEncoder or
@@ -111,11 +111,11 @@ A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
 upward contain the value; bit 0 says whether they should be complemented upon
 receipt.  The encode algorithm looks like this:
 
-	uint u;
+	var u uint
 	if i < 0 {
-		u = (^i << 1) | 1	// complement i, bit 0 is 1
+		u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1
 	} else {
-		u = (i << 1)	// do not complement i, bit 0 is 0
+		u = (uint(i) << 1) // do not complement i, bit 0 is 0
 	}
 	encodeUnsigned(u)
 
@@ -137,9 +137,9 @@ All other slices and arrays are sent as an unsigned count followed by that many
 elements using the standard gob encoding for their type, recursively.
 
 Maps are sent as an unsigned count followed by that many key, element
-pairs. Empty but non-nil maps are sent, so if the sender has allocated
-a map, the receiver will allocate a map even if no elements are
-transmitted.
+pairs. Empty but non-nil maps are sent, so if the receiver has not allocated
+one already, one will always be allocated on receipt unless the transmitted map
+is nil and not at the top level.
 
 Structs are sent as a sequence of (field number, field value) pairs.  The field
 value is sent using the standard gob encoding for its type, recursively.  If a
@@ -246,7 +246,7 @@ where * signifies zero or more repetitions and the type id of a value must
 be predefined or be defined before the value in the stream.
 
 See "Gobs of data" for a design discussion of the gob wire format:
-http://golang.org/doc/articles/gobs_of_data.html
+http://blog.golang.org/gobs-of-data
 */
 package gob
 
diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go
index a340e47b5e..62d0f42e81 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -5,6 +5,7 @@
 package gob
 
 import (
+	"errors"
 	"io"
 	"reflect"
 	"sync"
@@ -65,6 +66,11 @@ func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) {
 	// it by hand.
 	message := b.Bytes()
 	messageLen := len(message) - maxLength
+	// Length cannot be bigger than the decoder can handle.
+	if messageLen >= tooBig {
+		enc.setError(errors.New("gob: encoder: message too big"))
+		return
+	}
 	// Encode the length.
 	enc.countState.b.Reset()
 	enc.countState.encodeUint(uint64(messageLen))
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index c0bd379c93..8a72a3118c 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -976,3 +976,21 @@ func TestBadData(t *testing.T) {
 		}
 	}
 }
+
+// TestHugeWriteFails tests that enormous messages trigger an error.
+func TestHugeWriteFails(t *testing.T) {
+	if testing.Short() {
+		// Requires allocating a monster, so don't do this from all.bash.
+		t.Skip("skipping huge allocation in short mode")
+	}
+	huge := make([]byte, tooBig)
+	huge[0] = 7 // Make sure it's not all zeros.
+	buf := new(bytes.Buffer)
+	err := NewEncoder(buf).Encode(huge)
+	if err == nil {
+		t.Fatalf("expected error for huge slice")
+	}
+	if !strings.Contains(err.Error(), "message too big") {
+		t.Fatalf("expected 'too big' error; got %s\n", err.Error())
+	}
+}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index f26a7d49f0..613641afbb 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -739,7 +739,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		default:
 			d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 		case reflect.Slice:
-			if v.Type() != byteSliceType {
+			if v.Type().Elem().Kind() != reflect.Uint8 {
 				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 				break
 			}
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 7ecc8f4402..f208ee8a7c 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -1207,7 +1207,28 @@ func TestStringKind(t *testing.T) {
 	if !reflect.DeepEqual(m1, m2) {
 		t.Error("Items should be equal after encoding and then decoding")
 	}
+}
 
+// Custom types with []byte as underlying type could not be marshalled
+// and then unmarshalled.
+// Issue 8962.
+func TestByteKind(t *testing.T) {
+	type byteKind []byte
+
+	a := byteKind("hello")
+
+	data, err := Marshal(a)
+	if err != nil {
+		t.Error(err)
+	}
+	var b byteKind
+	err = Unmarshal(data, &b)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(a, b) {
+		t.Errorf("expected %v == %v", a, b)
+	}
 }
 
 var decodeTypeErrorTests = []struct {
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 4db9f35e69..7789bb5141 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -275,8 +275,6 @@ func (e *encodeState) error(err error) {
 	panic(err)
 }
 
-var byteSliceType = reflect.TypeOf([]byte(nil))
-
 func isEmptyValue(v reflect.Value) bool {
 	switch v.Kind() {
 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index 7880342902..66383ef0ef 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -209,6 +209,7 @@ var benchScan scanner
 
 func BenchmarkSkipValue(b *testing.B) {
 	initBig()
+	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		nextValue(jsonBig, &benchScan)
 	}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 4e4279069f..060660248e 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -31,7 +31,7 @@
 		fmt.Println("ip has value ", *ip)
 		fmt.Println("flagvar has value ", flagvar)
 
-	After parsing, the arguments after the flag are available as the
+	After parsing, the arguments following the flags are available as the
 	slice flag.Args() or individually as flag.Arg(i).
 	The arguments are indexed from 0 through flag.NArg()-1.
 
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index ba99cb0f6a..93121bb3d0 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -557,10 +557,13 @@ var fmtTests = []struct {
 	{"%0.100f", 1.0, zeroFill("1.", 100, "")},
 	{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
 
-	// Used to panic: integer function didn't look at f.prec or f.unicode.
+	// Used to panic: integer function didn't look at f.prec or f.unicode or f.width.
 	{"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
 	{"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
 	{"%#.80U", 'æ—¥', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 'æ—¥'"},
+	{"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+	{"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
+	{"%  +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
 
 	// Comparison of padding rules with C printf.
 	/*
@@ -949,11 +952,13 @@ var mallocTest = []struct {
 var _ bytes.Buffer
 
 func TestCountMallocs(t *testing.T) {
-	if testing.Short() {
+	switch {
+	case testing.Short():
 		t.Skip("skipping malloc count in short mode")
-	}
-	if runtime.GOMAXPROCS(0) > 1 {
+	case runtime.GOMAXPROCS(0) > 1:
 		t.Skip("skipping; GOMAXPROCS>1")
+	case raceenabled:
+		t.Skip("skipping malloc count under race detector")
 	}
 	for _, mt := range mallocTest {
 		mallocs := testing.AllocsPerRun(100, mt.fn)
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 099f8a5e00..ba984cf84f 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -163,7 +163,7 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 	}
 
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent || f.precPresent {
+	if f.widPresent || f.precPresent || f.plus || f.space {
 		width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
 		if base == 16 && f.sharp {
 			// Also adds "0x".
@@ -177,6 +177,11 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 				width += 1 + 1 + utf8.UTFMax + 1
 			}
 		}
+		if f.plus {
+			width++
+		} else if f.space {
+			width++
+		}
 		if width > nByte {
 			// We're going to need a bigger boat.
 			buf = make([]byte, width)
diff --git a/src/fmt/norace_test.go b/src/fmt/norace_test.go
new file mode 100644
index 0000000000..1267cc34ee
--- /dev/null
+++ b/src/fmt/norace_test.go
@@ -0,0 +1,9 @@
+// Copyright 2015 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.
+
+// +build !race
+
+package fmt_test
+
+const raceenabled = false
diff --git a/src/fmt/race_test.go b/src/fmt/race_test.go
new file mode 100644
index 0000000000..ae3147a5b0
--- /dev/null
+++ b/src/fmt/race_test.go
@@ -0,0 +1,9 @@
+// Copyright 2015 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.
+
+// +build race
+
+package fmt_test
+
+const raceenabled = true
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 124da40d3b..db6bdcf923 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -296,11 +296,7 @@ func defaultContext() Context {
 	// in all releases >= Go 1.x. Code that requires Go 1.x or later should
 	// say "+build go1.x", and code that should only be built before Go 1.x
 	// (perhaps it is the stub to use in that case) should say "+build !go1.x".
-	//
-	// When we reach Go 1.5 the line will read
-	//	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
-	// and so on.
-	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
 
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -1328,7 +1324,7 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
 	// build tag "linux" in that file. For Go 1.4 and beyond, we require this
 	// auto-tagging to apply only to files with a non-empty prefix, so
 	// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
-	// sytems, such as android, to arrive without breaking existing code with
+	// systems, such as android, to arrive without breaking existing code with
 	// innocuous source code in "android.go". The easiest fix: cut everything
 	// in the name before the initial _.
 	i := strings.Index(name, "_")
@@ -1395,20 +1391,11 @@ func IsLocalImport(path string) bool {
 		strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
 }
 
-// ArchChar returns the architecture character for the given goarch.
-// For example, ArchChar("amd64") returns "6".
+// ArchChar returns "?" and an error.
+// In earlier versions of Go, the returned string was used to derive
+// the compiler and linker tool names, the default object file suffix,
+// and the default linker output name. As of Go 1.5, those strings
+// no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
 func ArchChar(goarch string) (string, error) {
-	switch goarch {
-	case "386":
-		return "8", nil
-	case "amd64", "amd64p32":
-		return "6", nil
-	case "arm":
-		return "5", nil
-	case "arm64":
-		return "7", nil
-	case "ppc64", "ppc64le":
-		return "9", nil
-	}
-	return "", errors.New("unsupported GOARCH " + goarch)
+	return "?", errors.New("architecture letter no longer used")
 }
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 84c1e2ab31..8e985aa05b 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -184,42 +184,43 @@ var pkgDeps = map[string][]string{
 	},
 
 	// One of a kind.
-	"archive/tar":         {"L4", "OS", "syscall"},
-	"archive/zip":         {"L4", "OS", "compress/flate"},
-	"compress/bzip2":      {"L4"},
-	"compress/flate":      {"L4"},
-	"compress/gzip":       {"L4", "compress/flate"},
-	"compress/lzw":        {"L4"},
-	"compress/zlib":       {"L4", "compress/flate"},
-	"database/sql":        {"L4", "container/list", "database/sql/driver"},
-	"database/sql/driver": {"L4", "time"},
-	"debug/dwarf":         {"L4"},
-	"debug/elf":           {"L4", "OS", "debug/dwarf"},
-	"debug/gosym":         {"L4"},
-	"debug/macho":         {"L4", "OS", "debug/dwarf"},
-	"debug/pe":            {"L4", "OS", "debug/dwarf"},
-	"encoding":            {"L4"},
-	"encoding/ascii85":    {"L4"},
-	"encoding/asn1":       {"L4", "math/big"},
-	"encoding/csv":        {"L4"},
-	"encoding/gob":        {"L4", "OS", "encoding"},
-	"encoding/hex":        {"L4"},
-	"encoding/json":       {"L4", "encoding"},
-	"encoding/pem":        {"L4"},
-	"encoding/xml":        {"L4", "encoding"},
-	"flag":                {"L4", "OS"},
-	"go/build":            {"L4", "OS", "GOPARSER"},
-	"html":                {"L4"},
-	"image/draw":          {"L4", "image/internal/imageutil"},
-	"image/gif":           {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-	"image/jpeg":          {"L4", "image/internal/imageutil"},
-	"image/png":           {"L4", "compress/zlib"},
-	"index/suffixarray":   {"L4", "regexp"},
-	"math/big":            {"L4"},
-	"mime":                {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
-	"net/url":             {"L4"},
-	"text/scanner":        {"L4", "OS"},
-	"text/template/parse": {"L4"},
+	"archive/tar":          {"L4", "OS", "syscall"},
+	"archive/zip":          {"L4", "OS", "compress/flate"},
+	"compress/bzip2":       {"L4"},
+	"compress/flate":       {"L4"},
+	"compress/gzip":        {"L4", "compress/flate"},
+	"compress/lzw":         {"L4"},
+	"compress/zlib":        {"L4", "compress/flate"},
+	"database/sql":         {"L4", "container/list", "database/sql/driver"},
+	"database/sql/driver":  {"L4", "time"},
+	"debug/dwarf":          {"L4"},
+	"debug/elf":            {"L4", "OS", "debug/dwarf"},
+	"debug/gosym":          {"L4"},
+	"debug/macho":          {"L4", "OS", "debug/dwarf"},
+	"debug/pe":             {"L4", "OS", "debug/dwarf"},
+	"encoding":             {"L4"},
+	"encoding/ascii85":     {"L4"},
+	"encoding/asn1":        {"L4", "math/big"},
+	"encoding/csv":         {"L4"},
+	"encoding/gob":         {"L4", "OS", "encoding"},
+	"encoding/hex":         {"L4"},
+	"encoding/json":        {"L4", "encoding"},
+	"encoding/pem":         {"L4"},
+	"encoding/xml":         {"L4", "encoding"},
+	"flag":                 {"L4", "OS"},
+	"go/build":             {"L4", "OS", "GOPARSER"},
+	"html":                 {"L4"},
+	"image/draw":           {"L4", "image/internal/imageutil"},
+	"image/gif":            {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+	"image/jpeg":           {"L4", "image/internal/imageutil"},
+	"image/png":            {"L4", "compress/zlib"},
+	"index/suffixarray":    {"L4", "regexp"},
+	"math/big":             {"L4"},
+	"mime":                 {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
+	"mime/quotedprintable": {"L4"},
+	"net/url":              {"L4"},
+	"text/scanner":         {"L4", "OS"},
+	"text/template/parse":  {"L4"},
 
 	"html/template": {
 		"L4", "OS", "encoding/json", "html", "text/template",
@@ -243,7 +244,7 @@ var pkgDeps = map[string][]string{
 	// Basic networking.
 	// Because net must be used by any package that wants to
 	// do networking portably, it must have a small dependency set: just L1+basic os.
-	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
+	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/unix", "internal/syscall/windows", "internal/singleflight"},
 
 	// NET enables use of basic network-related packages.
 	"NET": {
@@ -255,7 +256,7 @@ var pkgDeps = map[string][]string{
 
 	// Uses of networking.
 	"log/syslog":    {"L4", "OS", "net"},
-	"net/mail":      {"L4", "NET", "OS", "internal/mime"},
+	"net/mail":      {"L4", "NET", "OS", "mime"},
 	"net/textproto": {"L4", "OS", "net"},
 
 	// Core crypto.
@@ -340,20 +341,18 @@ var pkgDeps = map[string][]string{
 	// dependencies.  Do not simply update them in situ.
 	"container/heap":                    {"sort"},
 	"debug/plan9obj":                    {"encoding/binary", "errors", "fmt", "io", "os"},
-	"go/constants":                      {"fmt", "go/token", "math/big", "strconv"},
+	"go/constant":                       {"fmt", "go/token", "math/big", "strconv"},
 	"go/format":                         {"bytes", "fmt", "go/ast", "go/parser", "go/printer", "go/token", "internal/format", "io"},
 	"go/importer":                       {"go/internal/gcimporter", "go/types", "io", "runtime"},
-	"go/internal/gcimporter":            {"bufio", "errors", "fmt", "go/build", "go/constants", "go/token", "go/types", "io", "os", "path/filepath", "strconv", "strings", "text/scanner"},
-	"go/types":                          {"bytes", "container/heap", "fmt", "go/ast", "go/constants", "go/parser", "go/token", "io", "math", "path", "sort", "strconv", "strings", "sync", "unicode"},
+	"go/internal/gcimporter":            {"bufio", "errors", "fmt", "go/build", "go/constant", "go/token", "go/types", "io", "os", "path/filepath", "strconv", "strings", "text/scanner"},
+	"go/types":                          {"bytes", "container/heap", "fmt", "go/ast", "go/constant", "go/parser", "go/token", "io", "math", "path", "sort", "strconv", "strings", "sync", "unicode"},
 	"image/internal/imageutil":          {"image"},
 	"internal/format":                   {"bytes", "go/ast", "go/parser", "go/printer", "go/token", "strings"},
-	"internal/mime":                     {"bytes", "encoding/base64", "errors", "fmt", "io", "io/ioutil", "strconv", "strings", "unicode"},
 	"internal/singleflight":             {"sync"},
 	"internal/syscall/unix":             {"runtime", "sync/atomic", "syscall", "unsafe"},
 	"internal/syscall/windows":          {"syscall", "unsafe"},
 	"internal/syscall/windows/registry": {"errors", "io", "syscall", "unicode/utf16", "unsafe"},
 	"internal/trace":                    {"bufio", "bytes", "fmt", "io", "os", "os/exec", "sort", "strconv", "strings"},
-	"mime/quotedprintable":              {"bufio", "bytes", "fmt", "io"},
 	"net/http/cookiejar":                {"errors", "fmt", "net", "net/http", "net/url", "sort", "strings", "sync", "time", "unicode/utf8"},
 	"net/http/internal":                 {"bufio", "bytes", "errors", "fmt", "io"},
 	"net/internal/socktest":             {"fmt", "sync", "syscall"},
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 78e17b220a..233f8b989d 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -101,6 +101,7 @@
 //	- "go1.2", from Go version 1.2 onward
 //	- "go1.3", from Go version 1.3 onward
 //	- "go1.4", from Go version 1.4 onward
+//	- "go1.5", from Go version 1.5 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/go/constants/go13.go b/src/go/constant/go13.go
similarity index 96%
rename from src/go/constants/go13.go
rename to src/go/constant/go13.go
index f445b82154..a4a838a290 100644
--- a/src/go/constants/go13.go
+++ b/src/go/constant/go13.go
@@ -4,7 +4,7 @@
 
 // +build !go1.4
 
-package constants
+package constant
 
 import (
 	"math"
diff --git a/src/go/constants/go14.go b/src/go/constant/go14.go
similarity index 93%
rename from src/go/constants/go14.go
rename to src/go/constant/go14.go
index c698fa6de9..2ab6da02f6 100644
--- a/src/go/constants/go14.go
+++ b/src/go/constant/go14.go
@@ -4,7 +4,7 @@
 
 // +build go1.4
 
-package constants
+package constant
 
 import "math/big"
 
diff --git a/src/go/constants/value.go b/src/go/constant/value.go
similarity index 99%
rename from src/go/constants/value.go
rename to src/go/constant/value.go
index ad4533c900..79a80af1ab 100644
--- a/src/go/constants/value.go
+++ b/src/go/constant/value.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package constants implements Values representing untyped
+// Package constant implements Values representing untyped
 // Go constants and the corresponding operations. Values
 // and operations may have arbitrary or unlimited precision.
 //
@@ -11,7 +11,7 @@
 // values produce unknown values unless specified
 // otherwise.
 //
-package constants // import "go/constants"
+package constant // import "go/constant"
 
 import (
 	"fmt"
diff --git a/src/go/constants/value_test.go b/src/go/constant/value_test.go
similarity index 99%
rename from src/go/constants/value_test.go
rename to src/go/constant/value_test.go
index 6a74e2d13c..08cdd5e625 100644
--- a/src/go/constants/value_test.go
+++ b/src/go/constant/value_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package constants
+package constant
 
 import (
 	"go/token"
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index ee83a725fa..7278c0c0a0 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -18,14 +18,14 @@ import (
 	"strings"
 	"text/scanner"
 
-	exact "go/constants"
+	exact "go/constant"
 	"go/types"
 )
 
 // debugging/development support
 const debug = false
 
-var pkgExts = [...]string{".a", ".5", ".6", ".7", ".8", ".9"}
+var pkgExts = [...]string{".a", ".o"}
 
 // FindPkg returns the filename and unique package id for an import
 // path based on package information provided by build.Import (using
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index 5d4de39712..fe4a758cd4 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -50,9 +50,8 @@ func compile(t *testing.T, dirname, filename string) string {
 		t.Logf("%s", out)
 		t.Fatalf("%s %s failed: %s", gcPath, filename, err)
 	}
-	archCh, _ := build.ArchChar(runtime.GOARCH)
 	// filename should end with ".go"
-	return filepath.Join(dirname, filename[:len(filename)-2]+archCh)
+	return filepath.Join(dirname, filename[:len(filename)-2]+"o")
 }
 
 // Use the same global imports map for all tests. The effect is
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index 49103058b5..f3bc4b9cc8 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
 	var p parser
 	defer func() {
 		if e := recover(); e != nil {
-			_ = e.(bailout) // re-panics if it's not a bailout
+			// resume same panic if it's not a bailout
+			if _, ok := e.(bailout); !ok {
+				panic(e)
+			}
 		}
 
 		// set result values
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 0095d7facf..18278ba4b7 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -412,14 +412,17 @@ func (p *parser) expectSemi() {
 	}
 }
 
-func (p *parser) atComma(context string) bool {
+func (p *parser) atComma(context string, follow token.Token) bool {
 	if p.tok == token.COMMA {
 		return true
 	}
-	if p.tok == token.SEMICOLON && p.lit == "\n" {
-		p.error(p.pos, "missing ',' before newline in "+context)
-		return true // "insert" the comma and continue
-
+	if p.tok != follow {
+		msg := "missing ','"
+		if p.tok == token.SEMICOLON && p.lit == "\n" {
+			msg += " before newline"
+		}
+		p.error(p.pos, msg+" in "+context)
+		return true // "insert" comma and continue
 	}
 	return false
 }
@@ -825,7 +828,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 		// parameter or result variable is the function body.
 		p.declare(field, nil, scope, ast.Var, idents...)
 		p.resolve(typ)
-		if !p.atComma("parameter list") {
+		if !p.atComma("parameter list", token.RPAREN) {
 			return
 		}
 		p.next()
@@ -838,7 +841,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 			// parameter or result variable is the function body.
 			p.declare(field, nil, scope, ast.Var, idents...)
 			p.resolve(typ)
-			if !p.atComma("parameter list") {
+			if !p.atComma("parameter list", token.RPAREN) {
 				break
 			}
 			p.next()
@@ -1248,7 +1251,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 			ellipsis = p.pos
 			p.next()
 		}
-		if !p.atComma("argument list") {
+		if !p.atComma("argument list", token.RPAREN) {
 			break
 		}
 		p.next()
@@ -1323,7 +1326,7 @@ func (p *parser) parseElementList() (list []ast.Expr) {
 
 	for p.tok != token.RBRACE && p.tok != token.EOF {
 		list = append(list, p.parseElement())
-		if !p.atComma("composite literal") {
+		if !p.atComma("composite literal", token.RBRACE) {
 			break
 		}
 		p.next()
@@ -1469,7 +1472,8 @@ L:
 				pos := p.pos
 				p.errorExpected(pos, "selector or type assertion")
 				p.next() // make progress
-				x = &ast.BadExpr{From: pos, To: p.pos}
+				sel := &ast.Ident{NamePos: pos, Name: "_"}
+				x = &ast.SelectorExpr{X: x, Sel: sel}
 			}
 		case token.LBRACK:
 			if lhs {
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index 4b960d9e57..c7bb36d789 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -492,3 +492,42 @@ func TestIssue9979(t *testing.T) {
 		})
 	}
 }
+
+// TestIncompleteSelection ensures that an incomplete selector
+// expression is parsed as a (blank) *ast.SelectorExpr, not a
+// *ast.BadExpr.
+func TestIncompleteSelection(t *testing.T) {
+	for _, src := range []string{
+		"package p; var _ = fmt.",             // at EOF
+		"package p; var _ = fmt.\ntype X int", // not at EOF
+	} {
+		fset := token.NewFileSet()
+		f, err := ParseFile(fset, "", src, 0)
+		if err == nil {
+			t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
+			continue
+		}
+
+		const wantErr = "expected selector or type assertion"
+		if !strings.Contains(err.Error(), wantErr) {
+			t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
+		}
+
+		var sel *ast.SelectorExpr
+		ast.Inspect(f, func(n ast.Node) bool {
+			if n, ok := n.(*ast.SelectorExpr); ok {
+				sel = n
+			}
+			return true
+		})
+		if sel == nil {
+			t.Error("found no *ast.SelectorExpr")
+			continue
+		}
+		const wantSel = "&{fmt _}"
+		if fmt.Sprint(sel) != wantSel {
+			t.Errorf("found selector %s, want %s", sel, wantSel)
+			continue
+		}
+	}
+}
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index 970ef2d3fa..ef2ffadbd9 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -99,8 +99,9 @@ var invalids = []string{
 	`package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`,
 	`package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
 	`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
-	`package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
-	`package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool)`,         // issue 8656
+	`package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
+	`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
+	`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,           // issue 8656
 	`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639
 	`package p; const x /* ERROR "missing constant value" */ ;`,                      // issue 9639
 	`package p; const x /* ERROR "missing constant value" */ int;`,                   // issue 9639
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index cec82ea10e..e9476c4dee 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -706,13 +706,14 @@ scanAgain:
 					s.insertSemi = false // newline consumed
 					return pos, token.SEMICOLON, "\n"
 				}
-				lit = s.scanComment()
+				comment := s.scanComment()
 				if s.mode&ScanComments == 0 {
 					// skip comment
 					s.insertSemi = false // newline consumed
 					goto scanAgain
 				}
 				tok = token.COMMENT
+				lit = comment
 			} else {
 				tok = s.switch2(token.QUO, token.QUO_ASSIGN)
 			}
diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
index fc450d8a6e..0d21905166 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -734,6 +734,41 @@ func TestScanErrors(t *testing.T) {
 	}
 }
 
+// Verify that no comments show up as literal values when skipping comments.
+func TestIssue10213(t *testing.T) {
+	var src = `
+		var (
+			A = 1 // foo
+		)
+
+		var (
+			B = 2
+			// foo
+		)
+
+		var C = 3 // foo
+
+		var D = 4
+		// foo
+
+		func anycode() {
+		// foo
+		}
+	`
+	var s Scanner
+	s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0)
+	for {
+		pos, tok, lit := s.Scan()
+		class := tokenclass(tok)
+		if lit != "" && class != keyword && class != literal && tok != token.SEMICOLON {
+			t.Errorf("%s: tok = %s, lit = %q", fset.Position(pos), tok, lit)
+		}
+		if tok <= token.EOF {
+			break
+		}
+	}
+}
+
 func BenchmarkScan(b *testing.B) {
 	b.StopTimer()
 	fset := token.NewFileSet()
diff --git a/src/go/types.bash b/src/go/types.bash
deleted file mode 100644
index 1a384d410a..0000000000
--- a/src/go/types.bash
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/bin/bash
-
-# Copyright 2015 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.
-
-# Run this script to update the packages ./exact and ./types
-# in the $GOROOT/src/go directory. They are vendored from the
-# original sources in x/tools. Imports are renamed as needed.
-#
-# Delete this script once go/exact and go/types don't exist anymore in x/tools.
-#
-# NOTE(adonovan): the standard packages have intentionally diverged
-# from x/tools, so this script is a unlikely to be useful.  Upstream
-# changes should be cherry-picked in to the standard library.
-
-set -e
-
-### Safety first.
-if [ ! -d "$GOPATH" ]; then
-	echo 2>&1 '$GOPATH must be set.'
-	exit 1
-fi
-if [ ! -d "$GOROOT" ]; then
-	echo 2>&1 '$GOROOT must be set.'
-	exit 1
-fi
-
-GODIR=$GOROOT/src/go
-
-function vendor() (
-	SRCDIR=$GOPATH/src/golang.org/x/tools/$1
-	DSTDIR=$GODIR/$2
-
-	echo 2>&1 "vendoring $SRCDIR => $DSTDIR"
-
-	# create directory
-	rm -rf $DSTDIR
-	mkdir -p $DSTDIR
-	cd $DSTDIR
-
-	# copy go sources and update import paths
-	for f in $SRCDIR/*.go; do
-		# copy $f and update imports
-		sed -e 's|"golang.org/x/tools/go/exact"|"go/exact"|' \
-		    -e 's|"golang.org/x/tools/go/types"|"go/types"|' \
-		    -e 's|"golang.org/x/tools/go/gcimporter"|"go/internal/gcimporter"|' \
-		    $f | gofmt > tmp.go
-		mv -f tmp.go `basename $f`
-	done
-
-	# copy testdata, if any
-	if [ -e $SRCDIR/testdata ]; then
-		cp -R $SRCDIR/testdata/ $DSTDIR/testdata/
-	fi
-)
-
-function install() (
-	PKG=$GODIR/$1
-
-	echo 2>&1 "installing $PKG"
-	cd $PKG
-	go install
-)
-
-function test() (
-	PKG=$GODIR/$1
-
-	echo 2>&1 "testing $PKG"
-	cd $PKG
-	if ! go test; then
-		echo 2>&1 "TESTING $PKG FAILED"
-		exit 1
-	fi
-)
-
-### go/exact
-vendor go/exact exact
-test exact
-install exact
-
-### go/types
-vendor go/types types
-# cannot test w/o gcimporter
-install types
-
-### go/gcimporter
-vendor go/gcimporter internal/gcimporter
-test internal/gcimporter
-install internal/gcimporter
-
-### test go/types (requires gcimporter)
-test types
-
-# All done.
-echo 2>&1 "DONE"
-exit 0
diff --git a/src/go/types/api.go b/src/go/types/api.go
index a2a55e31e7..ad9baa9527 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -28,7 +28,7 @@ import (
 	"bytes"
 	"fmt"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index 203a9c196d..c224699e3c 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -8,7 +8,7 @@ package types
 
 import (
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/check.go b/src/go/types/check.go
index b4c356a6ed..7ae81eb2d0 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -8,7 +8,7 @@ package types
 
 import (
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 0cf9953c4f..da65f4276e 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -6,7 +6,7 @@
 
 package types
 
-import exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+import exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 
 // Conversion type-checks the conversion T(x).
 // The result is in x.
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index c2c18ecd06..4af5b57798 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -6,7 +6,7 @@ package types
 
 import (
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go
index bc27a8bb23..36e1cb954e 100644
--- a/src/go/types/eval_test.go
+++ b/src/go/types/eval_test.go
@@ -14,7 +14,6 @@ import (
 	"strings"
 	"testing"
 
-	_ "go/internal/gcimporter"
 	. "go/types"
 )
 
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index f91d89e8b8..425ae91bb4 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -9,7 +9,7 @@ package types
 import (
 	"fmt"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 	"math"
 )
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 2404753b36..829e7a96b3 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -8,7 +8,7 @@ import (
 	"bytes"
 	"fmt"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index 88c387058e..8d167067d5 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -9,7 +9,7 @@ package types
 import (
 	"bytes"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index be46b59f11..64dcebe216 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -7,7 +7,7 @@ package types
 import (
 	"fmt"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 	pathLib "path"
 	"strconv"
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
index 85dc6ae0ec..4ff4e4d4a8 100644
--- a/src/go/types/self_test.go
+++ b/src/go/types/self_test.go
@@ -15,7 +15,6 @@ import (
 	"testing"
 	"time"
 
-	_ "go/internal/gcimporter"
 	. "go/types"
 )
 
@@ -31,7 +30,7 @@ func TestSelf(t *testing.T) {
 	conf := Config{Importer: importer.Default()}
 	_, err = conf.Check("go/types", fset, files, nil)
 	if err != nil {
-		// Importing go/constants doesn't work in the
+		// Importing go/constant doesn't work in the
 		// build dashboard environment. Don't report an error
 		// for now so that the build remains green.
 		// TODO(gri) fix this
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index d04dd71e4f..28a66cebe3 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -146,6 +146,7 @@ func TestStdFixed(t *testing.T) {
 		"bug459.go",    // possibly incorrect test - see issue 6703 (pending spec clarification)
 		"issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
 		"issue6889.go", // gc-specific test
+		"issue7746.go", // large constants - consumes too much memory
 	)
 }
 
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index 8b59df3eb6..586f6cc15c 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -9,7 +9,7 @@ package types
 import (
 	"fmt"
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 )
 
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
index d08e0fd878..595a6342b7 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -71,3 +71,27 @@ func issue9473(a []int, b ...int) {
 	append_(f0(), f1()... /* ERROR cannot use */ )
 	append_(f0(), f2()... /* ERROR cannot use */ )
 }
+
+// Check that embedding a non-interface type in an interface results in a good error message.
+func issue10979() {
+	type _ interface {
+		int /* ERROR int is not an interface */
+	}
+	type T struct{}
+	type _ interface {
+		T /* ERROR T is not an interface */
+	}
+	type _ interface {
+		nosuchtype /* ERROR undeclared name: nosuchtype */
+	}
+	type _ interface {
+		fmt /* ERROR Nosuchtype not declared by package fmt */ .Nosuchtype
+	}
+	type _ interface {
+		nosuchpkg /* ERROR undeclared name: nosuchpkg */ .Nosuchtype
+	}
+	type I interface {
+		I /* ERROR I\.m \(value of type func\(I\)\) is not a type */ .m
+		m()
+	}
+}
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index afd1dabc06..3fc1574e80 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -8,7 +8,7 @@ package types
 
 import (
 	"go/ast"
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 	"sort"
 	"strconv"
@@ -525,20 +525,14 @@ func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
 	for _, e := range embedded {
 		pos := e.Pos()
 		typ := check.typExpr(e, nil, path)
+		// Determine underlying embedded (possibly incomplete) type
+		// by following its forward chain.
 		named, _ := typ.(*Named)
-		if named == nil {
-			if typ != Typ[Invalid] {
-				check.invalidAST(pos, "%s is not named type", typ)
-			}
-			continue
-		}
-		// determine underlying (possibly incomplete) type
-		// by following its forward chain
-		u := underlying(named)
-		embed, _ := u.(*Interface)
+		under := underlying(named)
+		embed, _ := under.(*Interface)
 		if embed == nil {
-			if u != Typ[Invalid] {
-				check.errorf(pos, "%s is not an interface", named)
+			if typ != Typ[Invalid] {
+				check.errorf(pos, "%s is not an interface", typ)
 			}
 			continue
 		}
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
index c02543e951..5e445e2838 100644
--- a/src/go/types/universe.go
+++ b/src/go/types/universe.go
@@ -7,7 +7,7 @@
 package types
 
 import (
-	exact "go/constants" // Renamed to reduce diffs from x/tools.  TODO: remove
+	exact "go/constant" // Renamed to reduce diffs from x/tools.  TODO: remove
 	"go/token"
 	"strings"
 )
diff --git a/src/html/escape.go b/src/html/escape.go
index dd5dfa7cd7..f50a4b937a 100644
--- a/src/html/escape.go
+++ b/src/html/escape.go
@@ -6,7 +6,6 @@
 package html
 
 import (
-	"bytes"
 	"strings"
 	"unicode/utf8"
 )
@@ -187,52 +186,20 @@ func unescape(b []byte) []byte {
 	return b
 }
 
-const escapedChars = `&'<>"`
-
-func escape(w writer, s string) error {
-	i := strings.IndexAny(s, escapedChars)
-	for i != -1 {
-		if _, err := w.WriteString(s[:i]); err != nil {
-			return err
-		}
-		var esc string
-		switch s[i] {
-		case '&':
-			esc = "&"
-		case '\'':
-			// "'" is shorter than "'" and apos was not in HTML until HTML5.
-			esc = "'"
-		case '<':
-			esc = "<"
-		case '>':
-			esc = ">"
-		case '"':
-			// """ is shorter than """.
-			esc = """
-		default:
-			panic("unrecognized escape character")
-		}
-		s = s[i+1:]
-		if _, err := w.WriteString(esc); err != nil {
-			return err
-		}
-		i = strings.IndexAny(s, escapedChars)
-	}
-	_, err := w.WriteString(s)
-	return err
-}
+var htmlEscaper = strings.NewReplacer(
+	`&`, "&",
+	`'`, "'", // "'" is shorter than "'" and apos was not in HTML until HTML5.
+	`<`, "<",
+	`>`, ">",
+	`"`, """, // """ is shorter than """.
+)
 
 // EscapeString escapes special characters like "<" to become "<". It
 // escapes only five such characters: <, >, &, ' and ".
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func EscapeString(s string) string {
-	if strings.IndexAny(s, escapedChars) == -1 {
-		return s
-	}
-	var buf bytes.Buffer
-	escape(&buf, s)
-	return buf.String()
+	return htmlEscaper.Replace(s)
 }
 
 // UnescapeString unescapes entities like "<" to become "<". It unescapes a
@@ -241,10 +208,8 @@ func EscapeString(s string) string {
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func UnescapeString(s string) string {
-	for _, c := range s {
-		if c == '&' {
-			return string(unescape([]byte(s)))
-		}
+	if !strings.Contains(s, "&") {
+		return s
 	}
-	return s
+	return string(unescape([]byte(s)))
 }
diff --git a/src/html/escape_test.go b/src/html/escape_test.go
index 2d7ad8ac26..3702626a3d 100644
--- a/src/html/escape_test.go
+++ b/src/html/escape_test.go
@@ -4,7 +4,10 @@
 
 package html
 
-import "testing"
+import (
+	"strings"
+	"testing"
+)
 
 type unescapeTest struct {
 	// A short description of the test case.
@@ -113,3 +116,38 @@ func TestUnescapeEscape(t *testing.T) {
 		}
 	}
 }
+
+var (
+	benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100)
+	benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100)
+)
+
+func BenchmarkEscape(b *testing.B) {
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(EscapeString(benchEscapeData))
+	}
+}
+
+func BenchmarkEscapeNone(b *testing.B) {
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(EscapeString(benchEscapeNone))
+	}
+}
+
+func BenchmarkUnescape(b *testing.B) {
+	s := EscapeString(benchEscapeData)
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(UnescapeString(s))
+	}
+}
+
+func BenchmarkUnescapeNone(b *testing.B) {
+	s := EscapeString(benchEscapeNone)
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(UnescapeString(s))
+	}
+}
diff --git a/src/html/template/css.go b/src/html/template/css.go
index 634f183f79..318464835f 100644
--- a/src/html/template/css.go
+++ b/src/html/template/css.go
@@ -157,56 +157,20 @@ func isCSSSpace(b byte) bool {
 func cssEscaper(args ...interface{}) string {
 	s, _ := stringify(args...)
 	var b bytes.Buffer
-	written := 0
-	for i, r := range s {
+	r, w, written := rune(0), 0, 0
+	for i := 0; i < len(s); i += w {
+		// See comment in htmlEscaper.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		var repl string
-		switch r {
-		case 0:
-			repl = `\0`
-		case '\t':
-			repl = `\9`
-		case '\n':
-			repl = `\a`
-		case '\f':
-			repl = `\c`
-		case '\r':
-			repl = `\d`
-		// Encode HTML specials as hex so the output can be embedded
-		// in HTML attributes without further encoding.
-		case '"':
-			repl = `\22`
-		case '&':
-			repl = `\26`
-		case '\'':
-			repl = `\27`
-		case '(':
-			repl = `\28`
-		case ')':
-			repl = `\29`
-		case '+':
-			repl = `\2b`
-		case '/':
-			repl = `\2f`
-		case ':':
-			repl = `\3a`
-		case ';':
-			repl = `\3b`
-		case '<':
-			repl = `\3c`
-		case '>':
-			repl = `\3e`
-		case '\\':
-			repl = `\\`
-		case '{':
-			repl = `\7b`
-		case '}':
-			repl = `\7d`
+		switch {
+		case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "":
+			repl = cssReplacementTable[r]
 		default:
 			continue
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + utf8.RuneLen(r)
+		written = i + w
 		if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) {
 			b.WriteByte(' ')
 		}
@@ -218,6 +182,30 @@ func cssEscaper(args ...interface{}) string {
 	return b.String()
 }
 
+var cssReplacementTable = []string{
+	0:    `\0`,
+	'\t': `\9`,
+	'\n': `\a`,
+	'\f': `\c`,
+	'\r': `\d`,
+	// Encode HTML specials as hex so the output can be embedded
+	// in HTML attributes without further encoding.
+	'"':  `\22`,
+	'&':  `\26`,
+	'\'': `\27`,
+	'(':  `\28`,
+	')':  `\29`,
+	'+':  `\2b`,
+	'/':  `\2f`,
+	':':  `\3a`,
+	';':  `\3b`,
+	'<':  `\3c`,
+	'>':  `\3e`,
+	'\\': `\\`,
+	'{':  `\7b`,
+	'}':  `\7d`,
+}
+
 var expressionBytes = []byte("expression")
 var mozBindingBytes = []byte("mozbinding")
 
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index ee01fb12ab..a9529446dd 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -297,9 +297,9 @@ var redundantFuncs = map[string]map[string]bool{
 // unless it is redundant with the last command.
 func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {
 	if n := len(cmds); n != 0 {
-		last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode)
-		next, _ := cmd.Args[0].(*parse.IdentifierNode)
-		if ok && redundantFuncs[last.Ident][next.Ident] {
+		last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode)
+		next, okNext := cmd.Args[0].(*parse.IdentifierNode)
+		if okLast && okNext && redundantFuncs[last.Ident][next.Ident] {
 			return cmds
 		}
 	}
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index 9c9502a617..6729ebf4a7 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -1547,6 +1547,16 @@ func TestEnsurePipelineContains(t *testing.T) {
 			"($).X | urlquery | html | print",
 			[]string{"urlquery", "html"},
 		},
+		{
+			"{{.X | print 2 | .f 3}}",
+			".X | print 2 | .f 3 | urlquery | html",
+			[]string{"urlquery", "html"},
+		},
+		{
+			"{{.X | html | print 2 | .f 3}}",
+			".X | urlquery | html | print 2 | .f 3",
+			[]string{"urlquery", "html"},
+		},
 	}
 	for i, test := range tests {
 		tmpl := template.Must(template.New("test").Parse(test.input))
diff --git a/src/html/template/html.go b/src/html/template/html.go
index 9c069efd1d..de4aa4abb2 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -138,21 +138,24 @@ var htmlNospaceNormReplacementTable = []string{
 // and when badRunes is true, certain bad runes are allowed through unescaped.
 func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
 	written, b := 0, new(bytes.Buffer)
-	for i, r := range s {
+	r, w := rune(0), 0
+	for i := 0; i < len(s); i += w {
+		// Cannot use 'for range s' because we need to preserve the width
+		// of the runes in the input. If we see a decoding error, the input
+		// width will not be utf8.Runelen(r) and we will overrun the buffer.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		if int(r) < len(replacementTable) {
 			if repl := replacementTable[r]; len(repl) != 0 {
 				b.WriteString(s[written:i])
 				b.WriteString(repl)
-				// Valid as long as replacementTable doesn't
-				// include anything above 0x7f.
-				written = i + utf8.RuneLen(r)
+				written = i + w
 			}
 		} else if badRunes {
 			// No-op.
 			// IE does not allow these ranges in unquoted attrs.
 		} else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff {
 			fmt.Fprintf(b, "%s&#x%x;", s[written:i], r)
-			written = i + utf8.RuneLen(r)
+			written = i + w
 		}
 	}
 	if written == 0 {
diff --git a/src/html/template/html_test.go b/src/html/template/html_test.go
index b9b9703875..f04ee04c27 100644
--- a/src/html/template/html_test.go
+++ b/src/html/template/html_test.go
@@ -19,7 +19,8 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		"`abcdefghijklmno" +
 		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E")
+		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" +
+		"erroneous\x960") // keep at the end
 
 	want := ("�\x01\x02\x03\x04\x05\x06\x07" +
 		"\x08	

\x0E\x0F" +
@@ -31,14 +32,16 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		``abcdefghijklmno` +
 		`pqrstuvwxyz{|}~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff﷬\U0001D11E")
+		"\u00A0\u0100\u2028\u2029\ufeff﷬\U0001D11E" +
+		"erroneous�0") // keep at the end
 
 	got := htmlNospaceEscaper(input)
 	if got != want {
 		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
 
-	got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1)
+	r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd")
+	got, want = html.UnescapeString(got), r.Replace(input)
 	if want != got {
 		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
diff --git a/src/html/template/js.go b/src/html/template/js.go
index 999a61ed07..f6d166b311 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -246,8 +246,10 @@ func jsRegexpEscaper(args ...interface{}) string {
 // `\u2029`.
 func replace(s string, replacementTable []string) string {
 	var b bytes.Buffer
-	written := 0
-	for i, r := range s {
+	r, w, written := rune(0), 0, 0
+	for i := 0; i < len(s); i += w {
+		// See comment in htmlEscaper.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		var repl string
 		switch {
 		case int(r) < len(replacementTable) && replacementTable[r] != "":
@@ -261,7 +263,7 @@ func replace(s string, replacementTable []string) string {
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + utf8.RuneLen(r)
+		written = i + w
 	}
 	if written == 0 {
 		return s
diff --git a/src/internal/mime/header.go b/src/internal/mime/header.go
deleted file mode 100644
index 9bc3e5e576..0000000000
--- a/src/internal/mime/header.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2015 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 mime
-
-import (
-	"bytes"
-	"encoding/base64"
-	"errors"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"strconv"
-	"strings"
-	"unicode"
-)
-
-// EncodeWord encodes a string into an RFC 2047 encoded-word.
-func EncodeWord(s string) string {
-	// UTF-8 "Q" encoding
-	b := bytes.NewBufferString("=?utf-8?q?")
-	for i := 0; i < len(s); i++ {
-		switch c := s[i]; {
-		case c == ' ':
-			b.WriteByte('_')
-		case isVchar(c) && c != '=' && c != '?' && c != '_':
-			b.WriteByte(c)
-		default:
-			fmt.Fprintf(b, "=%02X", c)
-		}
-	}
-	b.WriteString("?=")
-	return b.String()
-}
-
-// DecodeWord decodes an RFC 2047 encoded-word.
-func DecodeWord(s string) (string, error) {
-	fields := strings.Split(s, "?")
-	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
-		return "", errors.New("address not RFC 2047 encoded")
-	}
-	charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
-	if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" {
-		return "", fmt.Errorf("charset not supported: %q", charset)
-	}
-
-	in := bytes.NewBufferString(fields[3])
-	var r io.Reader
-	switch enc {
-	case "b":
-		r = base64.NewDecoder(base64.StdEncoding, in)
-	case "q":
-		r = qDecoder{r: in}
-	default:
-		return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
-	}
-
-	dec, err := ioutil.ReadAll(r)
-	if err != nil {
-		return "", err
-	}
-
-	switch charset {
-	case "us-ascii":
-		b := new(bytes.Buffer)
-		for _, c := range dec {
-			if c >= 0x80 {
-				b.WriteRune(unicode.ReplacementChar)
-			} else {
-				b.WriteRune(rune(c))
-			}
-		}
-		return b.String(), nil
-	case "iso-8859-1":
-		b := new(bytes.Buffer)
-		for _, c := range dec {
-			b.WriteRune(rune(c))
-		}
-		return b.String(), nil
-	case "utf-8":
-		return string(dec), nil
-	}
-	panic("unreachable")
-}
-
-type qDecoder struct {
-	r       io.Reader
-	scratch [2]byte
-}
-
-func (qd qDecoder) Read(p []byte) (n int, err error) {
-	// This method writes at most one byte into p.
-	if len(p) == 0 {
-		return 0, nil
-	}
-	if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
-		return 0, err
-	}
-	switch c := qd.scratch[0]; {
-	case c == '=':
-		if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
-			return 0, err
-		}
-		x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64)
-		if err != nil {
-			return 0, fmt.Errorf("mime: invalid RFC 2047 encoding: %q", qd.scratch[:2])
-		}
-		p[0] = byte(x)
-	case c == '_':
-		p[0] = ' '
-	default:
-		p[0] = c
-	}
-	return 1, nil
-}
-
-// isVchar returns true if c is an RFC 5322 VCHAR character.
-func isVchar(c byte) bool {
-	// Visible (printing) characters.
-	return '!' <= c && c <= '~'
-}
diff --git a/src/internal/syscall/unix/socket.go b/src/internal/syscall/unix/socket.go
new file mode 100644
index 0000000000..d7a9b9cb1d
--- /dev/null
+++ b/src/internal/syscall/unix/socket.go
@@ -0,0 +1,39 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package unix
+
+// Getsockname copies the binary encoding of the current address for s
+// into addr.
+func Getsockname(s int, addr []byte) error {
+	return getsockname(s, addr)
+}
+
+// Getpeername copies the binary encoding of the peer address for s
+// into addr.
+func Getpeername(s int, addr []byte) error {
+	return getpeername(s, addr)
+}
+
+var emptyPayload uintptr
+
+// Recvfrom receives a message from s, copying the message into b.
+// The socket address addr must be large enough for storing the source
+// address of the message.
+// Flags must be operation control flags or 0.
+// It retunrs the number of bytes copied into b.
+func Recvfrom(s int, b []byte, flags int, addr []byte) (int, error) {
+	return recvfrom(s, b, flags, addr)
+}
+
+// Sendto sends a message to the socket address addr, copying the
+// message from b.
+// The socket address addr must be suitable for s.
+// Flags must be operation control flags or 0.
+// It retunrs the number of bytes copied from b.
+func Sendto(s int, b []byte, flags int, addr []byte) (int, error) {
+	return sendto(s, b, flags, addr)
+}
diff --git a/src/internal/syscall/unix/socket_linux_386.go b/src/internal/syscall/unix/socket_linux_386.go
new file mode 100644
index 0000000000..47105e0b1d
--- /dev/null
+++ b/src/internal/syscall/unix/socket_linux_386.go
@@ -0,0 +1,67 @@
+// Copyright 2015 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 unix
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+const (
+	sysGETSOCKNAME = 0x6
+	sysGETPEERNAME = 0x7
+	sysSENDTO      = 0xb
+	sysRECVFROM    = 0xc
+)
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
+
+func getsockname(s int, addr []byte) error {
+	l := uint32(len(addr))
+	_, errno := rawsocketcall(sysGETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&l)), 0, 0, 0)
+	if errno != 0 {
+		return error(errno)
+	}
+	return nil
+}
+
+func getpeername(s int, addr []byte) error {
+	l := uint32(len(addr))
+	_, errno := rawsocketcall(sysGETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&l)), 0, 0, 0)
+	if errno != 0 {
+		return error(errno)
+	}
+	return nil
+}
+
+func recvfrom(s int, b []byte, flags int, from []byte) (int, error) {
+	var p unsafe.Pointer
+	if len(b) > 0 {
+		p = unsafe.Pointer(&b[0])
+	} else {
+		p = unsafe.Pointer(&emptyPayload)
+	}
+	l := uint32(len(from))
+	n, errno := socketcall(sysRECVFROM, uintptr(s), uintptr(p), uintptr(len(b)), uintptr(flags), uintptr(unsafe.Pointer(&from[0])), uintptr(unsafe.Pointer(&l)))
+	if errno != 0 {
+		return int(n), error(errno)
+	}
+	return int(n), nil
+}
+
+func sendto(s int, b []byte, flags int, to []byte) (int, error) {
+	var p unsafe.Pointer
+	if len(b) > 0 {
+		p = unsafe.Pointer(&b[0])
+	} else {
+		p = unsafe.Pointer(&emptyPayload)
+	}
+	n, errno := socketcall(sysSENDTO, uintptr(s), uintptr(p), uintptr(len(b)), uintptr(flags), uintptr(unsafe.Pointer(&to[0])), uintptr(len(to)))
+	if errno != 0 {
+		return int(n), error(errno)
+	}
+	return int(n), nil
+}
diff --git a/src/internal/syscall/unix/socket_linux_386.s b/src/internal/syscall/unix/socket_linux_386.s
new file mode 100644
index 0000000000..48e2094db5
--- /dev/null
+++ b/src/internal/syscall/unix/socket_linux_386.s
@@ -0,0 +1,11 @@
+// Copyright 2015 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.
+
+#include "textflag.h"
+
+TEXT	·socketcall(SB),NOSPLIT,$0-36
+	JMP	syscall·socketcall(SB)
+
+TEXT	·rawsocketcall(SB),NOSPLIT,$0-36
+	JMP	syscall·socketcall(SB)
diff --git a/src/internal/syscall/unix/socket_stub.go b/src/internal/syscall/unix/socket_stub.go
new file mode 100644
index 0000000000..1c89ed1820
--- /dev/null
+++ b/src/internal/syscall/unix/socket_stub.go
@@ -0,0 +1,25 @@
+// Copyright 2015 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.
+
+// +build nacl solaris
+
+package unix
+
+import "syscall"
+
+func getsockname(s int, addr []byte) error {
+	return syscall.EOPNOTSUPP
+}
+
+func getpeername(s int, addr []byte) error {
+	return syscall.EOPNOTSUPP
+}
+
+func recvfrom(s int, b []byte, flags int, from []byte) (int, error) {
+	return 0, syscall.EOPNOTSUPP
+}
+
+func sendto(s int, b []byte, flags int, to []byte) (int, error) {
+	return 0, syscall.EOPNOTSUPP
+}
diff --git a/src/internal/syscall/unix/socket_unix.go b/src/internal/syscall/unix/socket_unix.go
new file mode 100644
index 0000000000..a769bb38b6
--- /dev/null
+++ b/src/internal/syscall/unix/socket_unix.go
@@ -0,0 +1,59 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux,!386 netbsd openbsd
+
+package unix
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+func getsockname(s int, addr []byte) error {
+	l := uint32(len(addr))
+	_, _, errno := syscall.RawSyscall(syscall.SYS_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&l)))
+	if errno != 0 {
+		return error(errno)
+	}
+	return nil
+}
+
+func getpeername(s int, addr []byte) error {
+	l := uint32(len(addr))
+	_, _, errno := syscall.RawSyscall(syscall.SYS_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&l)))
+	if errno != 0 {
+		return error(errno)
+	}
+	return nil
+}
+
+func recvfrom(s int, b []byte, flags int, from []byte) (int, error) {
+	var p unsafe.Pointer
+	if len(b) > 0 {
+		p = unsafe.Pointer(&b[0])
+	} else {
+		p = unsafe.Pointer(&emptyPayload)
+	}
+	l := uint32(len(from))
+	n, _, errno := syscall.Syscall6(syscall.SYS_RECVFROM, uintptr(s), uintptr(p), uintptr(len(b)), uintptr(flags), uintptr(unsafe.Pointer(&from[0])), uintptr(unsafe.Pointer(&l)))
+	if errno != 0 {
+		return int(n), error(errno)
+	}
+	return int(n), nil
+}
+
+func sendto(s int, b []byte, flags int, to []byte) (int, error) {
+	var p unsafe.Pointer
+	if len(b) > 0 {
+		p = unsafe.Pointer(&b[0])
+	} else {
+		p = unsafe.Pointer(&emptyPayload)
+	}
+	n, _, errno := syscall.Syscall6(syscall.SYS_SENDTO, uintptr(s), uintptr(p), uintptr(len(b)), uintptr(flags), uintptr(unsafe.Pointer(&to[0])), uintptr(len(to)))
+	if errno != 0 {
+		return int(n), error(errno)
+	}
+	return int(n), nil
+}
diff --git a/src/internal/syscall/windows/registry/export_test.go b/src/internal/syscall/windows/registry/export_test.go
new file mode 100644
index 0000000000..8badf6fdcf
--- /dev/null
+++ b/src/internal/syscall/windows/registry/export_test.go
@@ -0,0 +1,11 @@
+// Copyright 2015 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.
+
+// +build windows
+
+package registry
+
+func (k Key) SetValue(name string, valtype uint32, data []byte) error {
+	return k.setValue(name, valtype, data)
+}
diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go
index 5f75febd27..07eccb23d8 100644
--- a/src/internal/syscall/windows/registry/registry_test.go
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -611,3 +611,68 @@ func TestExpandString(t *testing.T) {
 		t.Errorf("want %q string expanded, got %q", want, got)
 	}
 }
+
+func TestInvalidValues(t *testing.T) {
+	softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer softwareK.Close()
+
+	testKName := randKeyName("TestInvalidValues_")
+
+	k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	if exist {
+		t.Fatalf("key %q already exists", testKName)
+	}
+
+	defer registry.DeleteKey(softwareK, testKName)
+
+	var tests = []struct {
+		Type uint32
+		Name string
+		Data []byte
+	}{
+		{registry.DWORD, "Dword1", nil},
+		{registry.DWORD, "Dword2", []byte{1, 2, 3}},
+		{registry.QWORD, "Qword1", nil},
+		{registry.QWORD, "Qword2", []byte{1, 2, 3}},
+		{registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}},
+		{registry.MULTI_SZ, "MultiString1", nil},
+		{registry.MULTI_SZ, "MultiString2", []byte{0}},
+		{registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}},
+		{registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}},
+		{registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}},
+	}
+
+	for _, test := range tests {
+		err := k.SetValue(test.Name, test.Type, test.Data)
+		if err != nil {
+			t.Fatalf("SetValue for %q failed: %v", test.Name, err)
+		}
+	}
+
+	for _, test := range tests {
+		switch test.Type {
+		case registry.DWORD, registry.QWORD:
+			value, valType, err := k.GetIntegerValue(test.Name)
+			if err == nil {
+				t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+			}
+		case registry.MULTI_SZ:
+			value, valType, err := k.GetStringsValue(test.Name)
+			if err == nil {
+				if len(value) != 0 {
+					t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+				}
+			}
+		default:
+			t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+		}
+	}
+}
diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go
index 1c1771d30e..bb45a23643 100644
--- a/src/internal/syscall/windows/registry/value.go
+++ b/src/internal/syscall/windows/registry/value.go
@@ -130,7 +130,7 @@ func ExpandString(value string) (string, error) {
 			return "", err
 		}
 		if n <= uint32(len(r)) {
-			u := (*[1 << 10]uint16)(unsafe.Pointer(&r[0]))[:]
+			u := (*[1 << 15]uint16)(unsafe.Pointer(&r[0]))[:]
 			return syscall.UTF16ToString(u), nil
 		}
 		r = make([]uint16, n)
@@ -150,9 +150,17 @@ func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err err
 	if typ != MULTI_SZ {
 		return nil, typ, ErrUnexpectedType
 	}
-	val = make([]string, 0, 5)
+	if len(data) == 0 {
+		return nil, typ, nil
+	}
 	p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
-	p = p[:len(p)-1] // remove terminating nil
+	if len(p) == 0 {
+		return nil, typ, nil
+	}
+	if p[len(p)-1] == 0 {
+		p = p[:len(p)-1] // remove terminating null
+	}
+	val = make([]string, 0, 5)
 	from := 0
 	for i, c := range p {
 		if c == 0 {
@@ -175,8 +183,14 @@ func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error
 	}
 	switch typ {
 	case DWORD:
+		if len(data) != 4 {
+			return 0, typ, errors.New("DWORD value is not 4 bytes long")
+		}
 		return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
 	case QWORD:
+		if len(data) != 8 {
+			return 0, typ, errors.New("QWORD value is not 8 bytes long")
+		}
 		return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
 	default:
 		return 0, typ, ErrUnexpectedType
diff --git a/src/math/big/arith.go b/src/math/big/arith.go
index 1ff6349d9d..d7ea8381e7 100644
--- a/src/math/big/arith.go
+++ b/src/math/big/arith.go
@@ -107,11 +107,26 @@ func log2(x Word) int {
 	return bitLen(x) - 1
 }
 
-// Number of leading zeros in x.
-func leadingZeros(x Word) uint {
+// nlz returns the number of leading zeros in x.
+func nlz(x Word) uint {
 	return uint(_W - bitLen(x))
 }
 
+// nlz64 returns the number of leading zeros in x.
+func nlz64(x uint64) uint {
+	switch _W {
+	case 32:
+		w := x >> 32
+		if w == 0 {
+			return 32 + nlz(Word(x))
+		}
+		return nlz(Word(w))
+	case 64:
+		return nlz(Word(x))
+	}
+	panic("unreachable")
+}
+
 // q = (u1<<_W + u0 - r)/y
 // Adapted from Warren, Hacker's Delight, p. 152.
 func divWW_g(u1, u0, v Word) (q, r Word) {
@@ -119,7 +134,7 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 		return 1<<_W - 1, 1<<_W - 1
 	}
 
-	s := leadingZeros(v)
+	s := nlz(v)
 	v <<= s
 
 	vn1 := v >> _W2
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index d2d5187a48..b69a2c616a 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -351,6 +351,34 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 	MOVQ z_len+8(FP), R11
 	MOVQ $0, BX		// i = 0
 	MOVQ $0, CX		// c = 0
+	MOVQ R11, R12
+	ANDQ $-2, R12
+	CMPQ R11, $2
+	JAE A6
+	JMP E6
+
+A6:
+	MOVQ (R8)(BX*8), AX
+	MULQ R9
+	ADDQ (R10)(BX*8), AX
+	ADCQ $0, DX
+	ADDQ CX, AX
+	ADCQ $0, DX
+	MOVQ DX, CX
+	MOVQ AX, (R10)(BX*8)
+
+	MOVQ (8)(R8)(BX*8), AX
+	MULQ R9
+	ADDQ (8)(R10)(BX*8), AX
+	ADCQ $0, DX
+	ADDQ CX, AX
+	ADCQ $0, DX
+	MOVQ DX, CX
+	MOVQ AX, (8)(R10)(BX*8)
+
+	ADDQ $2, BX
+	CMPQ BX, R12
+	JL A6
 	JMP E6
 
 L6:	MOVQ (R8)(BX*8), AX
diff --git a/src/math/big/bits_test.go b/src/math/big/bits_test.go
index 3ce24222d7..14ecab5909 100644
--- a/src/math/big/bits_test.go
+++ b/src/math/big/bits_test.go
@@ -203,18 +203,18 @@ func TestFromBits(t *testing.T) {
 	}{
 		// all different bit numbers
 		{nil, "0"},
-		{Bits{0}, "0x.8p1"},
-		{Bits{1}, "0x.8p2"},
-		{Bits{-1}, "0x.8p0"},
-		{Bits{63}, "0x.8p64"},
-		{Bits{33, -30}, "0x.8000000000000001p34"},
-		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"},
+		{Bits{0}, "0x.8p+1"},
+		{Bits{1}, "0x.8p+2"},
+		{Bits{-1}, "0x.8p+0"},
+		{Bits{63}, "0x.8p+64"},
+		{Bits{33, -30}, "0x.8000000000000001p+34"},
+		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
 
 		// multiple equal bit numbers
-		{Bits{0, 0}, "0x.8p2"},
-		{Bits{0, 0, 0, 0}, "0x.8p3"},
-		{Bits{0, 1, 0}, "0x.8p3"},
-		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
+		{Bits{0, 0}, "0x.8p+2"},
+		{Bits{0, 0, 0, 0}, "0x.8p+3"},
+		{Bits{0, 1, 0}, "0x.8p+3"},
+		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
 	} {
 		f := test.bits.Float()
 		if got := f.Format('p', 0); got != test.want {
diff --git a/src/math/big/decimal.go b/src/math/big/decimal.go
index 3d024dce68..2595e5f8c1 100644
--- a/src/math/big/decimal.go
+++ b/src/math/big/decimal.go
@@ -19,12 +19,14 @@
 
 package big
 
-// A decimal represents a floating-point number in decimal representation.
-// The value of a decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
-// with the most-significant mantissa digit at index 0.
+// A decimal represents an unsigned floating-point number in decimal representation.
+// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// with the most-significant mantissa digit at index 0. For the zero decimal, the
+// mantissa length and exponent are 0.
+// The zero value for decimal represents a ready-to-use 0.0.
 type decimal struct {
 	mant []byte // mantissa ASCII digits, big-endian
-	exp  int    // exponent, valid if len(mant) > 0
+	exp  int    // exponent
 }
 
 // Maximum shift amount that can be done in one pass without overflow.
@@ -46,6 +48,7 @@ func (x *decimal) init(m nat, shift int) {
 	// special case 0
 	if len(m) == 0 {
 		x.mant = x.mant[:0]
+		x.exp = 0
 		return
 	}
 
@@ -255,4 +258,7 @@ func trim(x *decimal) {
 		i--
 	}
 	x.mant = x.mant[:i]
+	if i == 0 {
+		x.exp = 0
+	}
 }
diff --git a/src/math/big/float.go b/src/math/big/float.go
index d46c046e67..1563528797 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -525,25 +525,6 @@ func (z *Float) round(sbit uint) {
 	return
 }
 
-// nlz returns the number of leading zero bits in x.
-func nlz(x Word) uint {
-	return _W - uint(bitLen(x))
-}
-
-func nlz64(x uint64) uint {
-	// TODO(gri) this can be done more nicely
-	if _W == 32 {
-		if x>>32 == 0 {
-			return 32 + nlz(Word(x))
-		}
-		return nlz(Word(x >> 32))
-	}
-	if _W == 64 {
-		return nlz(Word(x))
-	}
-	panic("unreachable")
-}
-
 func (z *Float) setBits64(neg bool, x uint64) *Float {
 	if z.prec == 0 {
 		z.prec = 64
@@ -732,25 +713,44 @@ func (z *Float) Copy(x *Float) *Float {
 	return z
 }
 
-func high32(x nat) uint32 {
-	// TODO(gri) This can be done more efficiently on 32bit platforms.
-	return uint32(high64(x) >> 32)
-}
-
-func high64(x nat) uint64 {
-	i := len(x)
-	if i == 0 {
+// msb32 returns the 32 most significant bits of x.
+func msb32(x nat) uint32 {
+	i := len(x) - 1
+	if i < 0 {
 		return 0
 	}
-	// i > 0
-	v := uint64(x[i-1])
-	if _W == 32 {
-		v <<= 32
-		if i > 1 {
-			v |= uint64(x[i-2])
-		}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
 	}
-	return v
+	switch _W {
+	case 32:
+		return uint32(x[i])
+	case 64:
+		return uint32(x[i] >> 32)
+	}
+	panic("unreachable")
+}
+
+// msb64 returns the 64 most significant bits of x.
+func msb64(x nat) uint64 {
+	i := len(x) - 1
+	if i < 0 {
+		return 0
+	}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
+	}
+	switch _W {
+	case 32:
+		v := uint64(x[i]) << 32
+		if i > 0 {
+			v |= uint64(x[i-1])
+		}
+		return v
+	case 64:
+		return uint64(x[i])
+	}
+	panic("unreachable")
 }
 
 // Uint64 returns the unsigned integer resulting from truncating x
@@ -776,7 +776,7 @@ func (x *Float) Uint64() (uint64, Accuracy) {
 		// 1 <= x < Inf
 		if x.exp <= 64 {
 			// u = trunc(x) fits into a uint64
-			u := high64(x.mant) >> (64 - uint32(x.exp))
+			u := msb64(x.mant) >> (64 - uint32(x.exp))
 			if x.MinPrec() <= 64 {
 				return u, Exact
 			}
@@ -821,7 +821,7 @@ func (x *Float) Int64() (int64, Accuracy) {
 		// 1 <= |x| < +Inf
 		if x.exp <= 63 {
 			// i = trunc(x) fits into an int64 (excluding math.MinInt64)
-			i := int64(high64(x.mant) >> (64 - uint32(x.exp)))
+			i := int64(msb64(x.mant) >> (64 - uint32(x.exp)))
 			if x.neg {
 				i = -i
 			}
@@ -853,9 +853,6 @@ func (x *Float) Int64() (int64, Accuracy) {
 	panic("unreachable")
 }
 
-// TODO(gri) Float32 and Float64 are very similar internally but for the
-// floatxx parameters and some conversions. Should factor out shared code.
-
 // Float32 returns the float32 value nearest to x. If x is too small to be
 // represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result
 // is (0, Below) or (-0, Above), respectively, depending on the sign of x.
@@ -880,64 +877,71 @@ func (x *Float) Float32() (float32, Accuracy) {
 			emax  = bias              //   127  largest unbiased exponent (normal)
 		)
 
-		// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
-		// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
-		// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
-		// corresponding Float exponent.
-		// (see also implementation of math.Ldexp for similar code)
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
 
-		if x.exp < dmin+1 {
-			// underflow
-			if x.neg {
-				var z float32
-				return -z, Above
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
 			}
-			return 0.0, Below
 		}
-		// x.exp >= dmin+1
 
+		// round
 		var r Float
-		r.prec = mbits + 1 // +1 for implicit msb
-		if x.exp < emin+1 {
-			// denormal number - round to fewer bits
-			r.prec = uint32(x.exp - dmin)
-		}
+		r.prec = uint32(p)
 		r.Set(x)
+		e = r.exp - 1
 
 		// Rounding may have caused r to overflow to ±Inf
 		// (rounding never causes underflows to 0).
 		if r.form == inf {
-			r.exp = emax + 2 // cause overflow below
+			e = emax + 1 // cause overflow below
 		}
 
-		if r.exp > emax+1 {
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
 			// overflow
 			if x.neg {
 				return float32(math.Inf(-1)), Below
 			}
 			return float32(math.Inf(+1)), Above
 		}
-		// dmin+1 <= r.exp <= emax+1
+		// e <= emax
 
-		var s uint32
-		if r.neg {
-			s = 1 << (fbits - 1)
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint32
+		if x.neg {
+			sign = 1 << (fbits - 1)
 		}
 
-		m := high32(r.mant) >> ebits & (1<> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = msb32(r.mant) >> ebits & (1<= dmin+1
 
+		// round
 		var r Float
-		r.prec = mbits + 1 // +1 for implicit msb
-		if x.exp < emin+1 {
-			// denormal number - round to fewer bits
-			r.prec = uint32(x.exp - dmin)
-		}
+		r.prec = uint32(p)
 		r.Set(x)
+		e = r.exp - 1
 
 		// Rounding may have caused r to overflow to ±Inf
 		// (rounding never causes underflows to 0).
 		if r.form == inf {
-			r.exp = emax + 2 // cause overflow below
+			e = emax + 1 // cause overflow below
 		}
 
-		if r.exp > emax+1 {
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
 			// overflow
 			if x.neg {
 				return math.Inf(-1), Below
 			}
 			return math.Inf(+1), Above
 		}
-		// dmin+1 <= r.exp <= emax+1
+		// e <= emax
 
-		var s uint64
-		if r.neg {
-			s = 1 << (fbits - 1)
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint64
+		if x.neg {
+			sign = 1 << (fbits - 1)
 		}
 
-		m := high64(r.mant) >> ebits & (1<> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = msb64(r.mant) >> ebits & (1< x.prec:
-		m = nat(nil).shr(m, uint(w-x.prec))
-	}
-
-	buf = append(buf, m.decimalString()...)
-	buf = append(buf, 'p')
-	e := int64(x.exp) - int64(x.prec)
-	if e >= 0 {
-		buf = append(buf, '+')
-	}
-	return strconv.AppendInt(buf, e, 10)
-}
-
-// pstring appends the string of x in the format ["-"] "0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
-// ad returns the extended buffer.
-// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
-func (x *Float) pstring(buf []byte) []byte {
-	if x.neg {
-		buf = append(buf, '-')
-	}
-	if x.form == zero {
-		return append(buf, '0')
-	}
-
-	if debugFloat && x.form != finite {
-		panic("non-finite float")
-	}
-	// x != 0
-
-	// remove trailing 0 words early
-	// (no need to convert to hex 0's and trim later)
-	m := x.mant
-	i := 0
-	for i < len(m) && m[i] == 0 {
-		i++
-	}
-	m = m[i:]
-
-	buf = append(buf, "0x."...)
-	buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
-	buf = append(buf, 'p')
-	return strconv.AppendInt(buf, int64(x.exp), 10)
-}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index 96c01eed81..9fc2b89fb9 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -125,12 +125,16 @@ func TestFloat64Format(t *testing.T) {
 		{1, 'f', 0, "1"},
 		{-1, 'f', 0, "-1"},
 
+		{0.001, 'e', 0, "1e-03"},
+		{0.459, 'e', 0, "5e-01"},
 		{1.459, 'e', 0, "1e+00"},
 		{2.459, 'e', 1, "2.5e+00"},
 		{3.459, 'e', 2, "3.46e+00"},
 		{4.459, 'e', 3, "4.459e+00"},
 		{5.459, 'e', 4, "5.4590e+00"},
 
+		{0.001, 'f', 0, "0"},
+		{0.459, 'f', 0, "0"},
 		{1.459, 'f', 0, "1"},
 		{2.459, 'f', 1, "2.5"},
 		{3.459, 'f', 2, "3.46"},
@@ -145,8 +149,8 @@ func TestFloat64Format(t *testing.T) {
 
 		{0, 'p', 0, "0"},
 		{math.Copysign(0, -1), 'p', 0, "-0"},
-		{1024.0, 'p', 0, "0x.8p11"},
-		{-1024.0, 'p', 0, "-0x.8p11"},
+		{1024.0, 'p', 0, "0x.8p+11"},
+		{-1024.0, 'p', 0, "-0x.8p+11"},
 
 		// all test cases below from strconv/ftoa_test.go
 		{1, 'e', 5, "1.00000e+00"},
@@ -331,8 +335,8 @@ func TestFloatFormat(t *testing.T) {
 		{"3e40", 100, 'g', 40, "3e+40"},
 
 		// make sure "stupid" exponents don't stall the machine
-		{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap3321929"},
-		{"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p1538481529"},
+		{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
+		{"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"},
 		{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
 		{"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
 
@@ -352,20 +356,21 @@ func TestFloatFormat(t *testing.T) {
 		{"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
 		{"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
 
-		{"3", 350, 'p', 0, "0x.cp2"},
-		{"03", 350, 'p', 0, "0x.cp2"},
-		{"3.", 350, 'p', 0, "0x.cp2"},
-		{"3.0", 350, 'p', 0, "0x.cp2"},
-		{"3.00", 350, 'p', 0, "0x.cp2"},
-		{"3.000", 350, 'p', 0, "0x.cp2"},
+		{"3", 350, 'p', 0, "0x.cp+2"},
+		{"03", 350, 'p', 0, "0x.cp+2"},
+		{"3.", 350, 'p', 0, "0x.cp+2"},
+		{"3.0", 350, 'p', 0, "0x.cp+2"},
+		{"3.00", 350, 'p', 0, "0x.cp+2"},
+		{"3.000", 350, 'p', 0, "0x.cp+2"},
 
 		{"0", 64, 'p', 0, "0"},
 		{"-0", 64, 'p', 0, "-0"},
-		{"1024.0", 64, 'p', 0, "0x.8p11"},
-		{"-1024.0", 64, 'p', 0, "-0x.8p11"},
+		{"1024.0", 64, 'p', 0, "0x.8p+11"},
+		{"-1024.0", 64, 'p', 0, "-0x.8p+11"},
 
 		// unsupported format
 		{"3.14", 64, 'x', 0, "%x"},
+		{"-3.14", 64, 'x', 0, "%x"},
 	} {
 		f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
 		if err != nil {
diff --git a/src/math/big/floatexample_test.go b/src/math/big/floatexample_test.go
index 7db10238bc..d9d39ed365 100644
--- a/src/math/big/floatexample_test.go
+++ b/src/math/big/floatexample_test.go
@@ -21,9 +21,9 @@ func ExampleFloat_Add() {
 	fmt.Printf("y = %s (%s, prec = %d, acc = %s)\n", &y, y.Format('p', 0), y.Prec(), y.Acc())
 	fmt.Printf("z = %s (%s, prec = %d, acc = %s)\n", &z, z.Format('p', 0), z.Prec(), z.Acc())
 	// Output:
-	// x = 1000 (0x.fap10, prec = 64, acc = Exact)
-	// y = 2.718281828 (0x.adf85458248cd8p2, prec = 53, acc = Exact)
-	// z = 1002.718282 (0x.faadf854p10, prec = 32, acc = Below)
+	// x = 1000 (0x.fap+10, prec = 64, acc = Exact)
+	// y = 2.718281828 (0x.adf85458248cd8p+2, prec = 53, acc = Exact)
+	// z = 1002.718282 (0x.faadf854p+10, prec = 32, acc = Below)
 }
 
 func Example_Shift() {
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
index 0a9edfd7b2..4c3e743d6c 100644
--- a/src/math/big/ftoa.go
+++ b/src/math/big/ftoa.go
@@ -2,34 +2,87 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements the 'e', 'f', 'g' floating-point formats.
-// It is closely following the corresponding implementation in
-// strconv/ftoa.go, but modified and simplified for big.Float.
-
-// Algorithm:
-//   1) convert Float to multiprecision decimal
-//   2) round to desired precision
-//   3) read digits out and format
+// This file implements Float-to-string conversion functions.
+// It is closely following the corresponding implementation
+// in strconv/ftoa.go, but modified and simplified for Float.
 
 package big
 
-import "strconv"
+import (
+	"strconv"
+	"strings"
+)
 
-// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
+// Format converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'f'	-ddddd.dddd, no exponent
+//	'g'	like 'e' for large exponents, like 'f' otherwise
+//	'G'	like 'E' for large exponents, like 'f' otherwise
+//	'b'	-ddddddp±dd, binary exponent
+//	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//	'b'	decimal integer mantissa using x.Prec() bits, or -0
+//	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// The precision prec controls the number of digits (excluding the exponent)
+// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
+// it is the number of digits after the decimal point. For 'g' and 'G' it is
+// the total number of digits. A negative precision selects the smallest
+// number of digits necessary such that ParseFloat will return f exactly.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Float.Format does not accept negative precisions.
+// BUG(gri) The Float.Format signature conflicts with Format(f fmt.State, c rune).
+//          (https://github.com/golang/go/issues/10938)
+func (x *Float) Format(format byte, prec int) string {
+	const extra = 10 // TODO(gri) determine a good/better value here
+	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+}
 
-// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
-func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
-	if debugFloat && f.IsInf() {
-		panic("non-finite float")
+// String formats x like x.Format('g', 10).
+func (x *Float) String() string {
+	return x.Format('g', 10)
+}
+
+// Append appends to buf the string form of the floating-point number x,
+// as generated by x.Format, and returns the extended buffer.
+func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
+	// sign
+	if x.neg {
+		buf = append(buf, '-')
 	}
 
+	// Inf
+	if x.form == inf {
+		if !x.neg {
+			buf = append(buf, '+')
+		}
+		return append(buf, "Inf"...)
+	}
+
+	// pick off easy formats
+	switch fmt {
+	case 'b':
+		return x.fmtB(buf)
+	case 'p':
+		return x.fmtP(buf)
+	}
+
+	// Algorithm:
+	//   1) convert Float to multiprecision decimal
+	//   2) round to desired precision
+	//   3) read digits out and format
+
 	// 1) convert Float to multiprecision decimal
-	var mant nat
-	if f.form == finite {
-		mant = f.mant
+	var d decimal // == 0.0
+	if x.form == finite {
+		d.init(x.mant, int(x.exp)-x.mant.bitLen())
 	}
-	var d decimal
-	d.init(mant, int(f.exp)-f.mant.bitLen())
 
 	// 2) round to desired precision
 	shortest := false
@@ -67,9 +120,9 @@ func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
 	// 3) read digits out and format
 	switch fmt {
 	case 'e', 'E':
-		return fmtE(buf, fmt, prec, f.neg, d)
+		return fmtE(buf, fmt, prec, d)
 	case 'f':
-		return fmtF(buf, prec, f.neg, d)
+		return fmtF(buf, prec, d)
 	case 'g', 'G':
 		// trim trailing fractional zeros in %e format
 		eprec := prec
@@ -88,25 +141,23 @@ func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
 			if prec > len(d.mant) {
 				prec = len(d.mant)
 			}
-			return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
+			return fmtE(buf, fmt+'e'-'g', prec-1, d)
 		}
 		if prec > d.exp {
 			prec = len(d.mant)
 		}
-		return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
+		return fmtF(buf, max(prec-d.exp, 0), d)
 	}
 
 	// unknown format
+	if x.neg {
+		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
+	}
 	return append(buf, '%', fmt)
 }
 
-// %e: -d.ddddde±dd
-func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
-	// sign
-	if neg {
-		buf = append(buf, '-')
-	}
-
+// %e: d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
 	// first digit
 	ch := byte('0')
 	if len(d.mant) > 0 {
@@ -149,13 +200,8 @@ func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
 	return strconv.AppendInt(buf, exp, 10)
 }
 
-// %f: -ddddddd.ddddd
-func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
-	// sign
-	if neg {
-		buf = append(buf, '-')
-	}
-
+// %f: ddddddd.ddddd
+func fmtF(buf []byte, prec int, d decimal) []byte {
 	// integer, padded with zeros as needed
 	if d.exp > 0 {
 		m := min(len(d.mant), d.exp)
@@ -182,6 +228,73 @@ func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
 	return buf
 }
 
+// fmtB appends the string of x in the format mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or 0" if x is zero,
+// and returns the extended buffer.
+// The mantissa is normalized such that is uses x.Prec() bits in binary
+// representation.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtB(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// adjust mantissa to use exactly x.prec bits
+	m := x.mant
+	switch w := uint32(len(x.mant)) * _W; {
+	case w < x.prec:
+		m = nat(nil).shl(m, uint(x.prec-w))
+	case w > x.prec:
+		m = nat(nil).shr(m, uint(w-x.prec))
+	}
+
+	buf = append(buf, m.decimalString()...)
+	buf = append(buf, 'p')
+	e := int64(x.exp) - int64(x.prec)
+	if e >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, e, 10)
+}
+
+// fmtP appends the string of x in the format 0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
+// ad returns the extended buffer.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtP(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// remove trailing 0 words early
+	// (no need to convert to hex 0's and trim later)
+	m := x.mant
+	i := 0
+	for i < len(m) && m[i] == 0 {
+		i++
+	}
+	m = m[i:]
+
+	buf = append(buf, "0x."...)
+	buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
+	buf = append(buf, 'p')
+	if x.exp >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, int64(x.exp), 10)
+}
+
 func min(x, y int) int {
 	if x < y {
 		return x
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 7157a5487b..6545bc17ed 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -216,6 +216,34 @@ func basicMul(z, x, y nat) {
 	}
 }
 
+// montgomery computes x*y*2^(-n*_W) mod m,
+// assuming k = -1/m mod 2^_W.
+// z is used for storing the result which is returned;
+// z must not alias x, y or m.
+func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
+	var c1, c2 Word
+	z = z.make(n)
+	z.clear()
+	for i := 0; i < n; i++ {
+		d := y[i]
+		c1 += addMulVVW(z, x, d)
+		t := z[0] * k
+		c2 = addMulVVW(z, m, t)
+
+		copy(z, z[1:])
+		z[n-1] = c1 + c2
+		if z[n-1] < c1 {
+			c1 = 1
+		} else {
+			c1 = 0
+		}
+	}
+	if c1 != 0 {
+		subVV(z, z, m)
+	}
+	return z
+}
+
 // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
 // Factored out for readability - do not use outside karatsuba.
 func karatsubaAdd(z, x nat, n int) {
@@ -544,7 +572,7 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 	u.clear() // TODO(gri) no need to clear if we allocated a new u
 
 	// D1.
-	shift := leadingZeros(v[n-1])
+	shift := nlz(v[n-1])
 	if shift > 0 {
 		// do not modify v, it may be used by another goroutine simultaneously
 		v1 := make(nat, n)
@@ -905,13 +933,16 @@ func (z nat) expNN(x, y, m nat) nat {
 	// 4-bit, windowed exponentiation. This involves precomputing 14 values
 	// (x^2...x^15) but then reduces the number of multiply-reduces by a
 	// third. Even for a 32-bit exponent, this reduces the number of
-	// operations.
+	// operations. Uses Montgomery method for odd moduli.
 	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+		if m[0]&1 == 1 {
+			return z.expNNMontgomery(x, y, m)
+		}
 		return z.expNNWindowed(x, y, m)
 	}
 
 	v := y[len(y)-1] // v > 0 because y is normalized and y > 0
-	shift := leadingZeros(v) + 1
+	shift := nlz(v) + 1
 	v <<= shift
 	var q nat
 
@@ -1029,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 	return z.norm()
 }
 
+// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
+// Uses Montgomery representation.
+func (z nat) expNNMontgomery(x, y, m nat) nat {
+	var zz, one, rr, RR nat
+
+	numWords := len(m)
+
+	// We want the lengths of x and m to be equal.
+	if len(x) > numWords {
+		_, rr = rr.div(rr, x, m)
+	} else if len(x) < numWords {
+		rr = rr.make(numWords)
+		rr.clear()
+		for i := range x {
+			rr[i] = x[i]
+		}
+	} else {
+		rr = x
+	}
+	x = rr
+
+	// Ideally the precomputations would be performed outside, and reused
+	// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+	// Iteration for Multiplicative Inverses Modulo Prime Powers".
+	k0 := 2 - m[0]
+	t := m[0] - 1
+	for i := 1; i < _W; i <<= 1 {
+		t *= t
+		k0 *= (t + 1)
+	}
+	k0 = -k0
+
+	// RR = 2ˆ(2*_W*len(m)) mod m
+	RR = RR.setWord(1)
+	zz = zz.shl(RR, uint(2*numWords*_W))
+	_, RR = RR.div(RR, zz, m)
+	if len(RR) < numWords {
+		zz = zz.make(numWords)
+		copy(zz, RR)
+		RR = zz
+	}
+	// one = 1, with equal length to that of m
+	one = one.make(numWords)
+	one.clear()
+	one[0] = 1
+
+	const n = 4
+	// powers[i] contains x^i
+	var powers [1 << n]nat
+	powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
+	powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
+	for i := 2; i < 1<= 0; i-- {
+		yi := y[i]
+		for j := 0; j < _W; j += n {
+			if i != len(y)-1 || j != 0 {
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+			}
+			zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
+			z, zz = zz, z
+			yi <<= n
+		}
+	}
+	// convert to regular number
+	zz = zz.montgomery(z, one, m, k0, numWords)
+	return zz.norm()
+}
+
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
 // If it returns true, n is prime with probability 1 - 1/4^reps.
 // If it returns false, n is not prime.
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index b25a89f731..7ac3cb8a84 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -205,11 +205,11 @@ func BenchmarkMul(b *testing.B) {
 	}
 }
 
-func TestLeadingZeros(t *testing.T) {
+func TestNLZ(t *testing.T) {
 	var x Word = _B >> 1
 	for i := 0; i <= _W; i++ {
-		if int(leadingZeros(x)) != i {
-			t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
+		if int(nlz(x)) != i {
+			t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
 		}
 		x >>= 1
 	}
@@ -332,6 +332,67 @@ func TestTrailingZeroBits(t *testing.T) {
 	}
 }
 
+var montgomeryTests = []struct {
+	x, y, m      string
+	k0           uint64
+	out32, out64 string
+}{
+	{
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
+		0x0000000000000000,
+		"0xffffffffffffffffffffffffffffffffffffffffff",
+		"0xffffffffffffffffffffffffffffffffff",
+	},
+	{
+		"0x0000000080000000",
+		"0x00000000ffffffff",
+		"0x0000000010000001",
+		0xff0000000fffffff,
+		"0x0000000088000000",
+		"0x0000000007800001",
+	},
+	{
+		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
+		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
+	},
+	{
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
+		"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
+	},
+}
+
+func TestMontgomery(t *testing.T) {
+	for i, test := range montgomeryTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		m := natFromString(test.m)
+
+		var out nat
+		if _W == 32 {
+			out = natFromString(test.out32)
+		} else {
+			out = natFromString(test.out64)
+		}
+
+		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
+		z := nat(nil).montgomery(x, y, m, k0, len(m))
+		z = z.norm()
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
 var expNNTests = []struct {
 	x, y, m string
 	out     string
diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go
index ab0dc49b41..c61494f8eb 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -8,6 +8,8 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"os"
+	"runtime"
 	"testing"
 )
 
@@ -322,10 +324,17 @@ func TestExpTables(t *testing.T) {
 	}
 }
 
-// For issue 6721, the problem came after 7533753 calls, so check 10e6.
 func TestFloat32(t *testing.T) {
+	// For issue 6721, the problem came after 7533753 calls, so check 10e6.
+	num := int(10e6)
+	// But ARM5 floating point emulation is slow (Issue 10749), so
+	// do less for that builder:
+	if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" {
+		num /= 100 // 1.72 seconds instead of 172 seconds
+	}
+
 	r := New(NewSource(1))
-	for ct := 0; ct < 10e6; ct++ {
+	for ct := 0; ct < num; ct++ {
 		f := r.Float32()
 		if f >= 1 {
 			t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go
new file mode 100644
index 0000000000..9796f506dc
--- /dev/null
+++ b/src/mime/encodedword.go
@@ -0,0 +1,329 @@
+// Copyright 2015 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 mime
+
+import (
+	"bytes"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"io"
+	"strings"
+	"sync"
+	"unicode"
+	"unicode/utf8"
+)
+
+// A WordEncoder is a RFC 2047 encoded-word encoder.
+type WordEncoder byte
+
+const (
+	// BEncoding represents Base64 encoding scheme as defined by RFC 2045.
+	BEncoding = WordEncoder('b')
+	// QEncoding represents the Q-encoding scheme as defined by RFC 2047.
+	QEncoding = WordEncoder('q')
+)
+
+var (
+	errInvalidWord = errors.New("mime: invalid RFC 2047 encoded-word")
+)
+
+// Encode returns the encoded-word form of s. If s is ASCII without special
+// characters, it is returned unchanged. The provided charset is the IANA
+// charset name of s. It is case insensitive.
+func (e WordEncoder) Encode(charset, s string) string {
+	if !needsEncoding(s) {
+		return s
+	}
+	return e.encodeWord(charset, s)
+}
+
+func needsEncoding(s string) bool {
+	for _, b := range s {
+		if (b < ' ' || b > '~') && b != '\t' {
+			return true
+		}
+	}
+	return false
+}
+
+// encodeWord encodes a string into an encoded-word.
+func (e WordEncoder) encodeWord(charset, s string) string {
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	buf.WriteString("=?")
+	buf.WriteString(charset)
+	buf.WriteByte('?')
+	buf.WriteByte(byte(e))
+	buf.WriteByte('?')
+
+	if e == BEncoding {
+		w := base64.NewEncoder(base64.StdEncoding, buf)
+		io.WriteString(w, s)
+		w.Close()
+	} else {
+		enc := make([]byte, 3)
+		for i := 0; i < len(s); i++ {
+			b := s[i]
+			switch {
+			case b == ' ':
+				buf.WriteByte('_')
+			case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
+				buf.WriteByte(b)
+			default:
+				enc[0] = '='
+				enc[1] = upperhex[b>>4]
+				enc[2] = upperhex[b&0x0f]
+				buf.Write(enc)
+			}
+		}
+	}
+	buf.WriteString("?=")
+	return buf.String()
+}
+
+const upperhex = "0123456789ABCDEF"
+
+// A WordDecoder decodes MIME headers containing RFC 2047 encoded-words.
+type WordDecoder struct {
+	// CharsetReader, if non-nil, defines a function to generate
+	// charset-conversion readers, converting from the provided
+	// charset into UTF-8.
+	// Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets
+	// are handled by default.
+	// One of the the CharsetReader's result values must be non-nil.
+	CharsetReader func(charset string, input io.Reader) (io.Reader, error)
+}
+
+// Decode decodes an encoded-word. If word is not a valid RFC 2047 encoded-word,
+// word is returned unchanged.
+func (d *WordDecoder) Decode(word string) (string, error) {
+	fields := strings.Split(word, "?") // TODO: remove allocation?
+	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 {
+		return "", errInvalidWord
+	}
+
+	content, err := decode(fields[2][0], fields[3])
+	if err != nil {
+		return "", err
+	}
+
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	if err := d.convert(buf, fields[1], content); err != nil {
+		return "", err
+	}
+
+	return buf.String(), nil
+}
+
+// DecodeHeader decodes all encoded-words of the given string. It returns an
+// error if and only if CharsetReader of d returns an error.
+func (d *WordDecoder) DecodeHeader(header string) (string, error) {
+	// If there is no encoded-word, returns before creating a buffer.
+	i := strings.Index(header, "=?")
+	if i == -1 {
+		return header, nil
+	}
+
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	buf.WriteString(header[:i])
+	header = header[i:]
+
+	betweenWords := false
+	for {
+		start := strings.Index(header, "=?")
+		if start == -1 {
+			break
+		}
+		cur := start + len("=?")
+
+		i := strings.Index(header[cur:], "?")
+		if i == -1 {
+			break
+		}
+		charset := header[cur : cur+i]
+		cur += i + len("?")
+
+		if len(header) < cur+len("Q??=") {
+			break
+		}
+		encoding := header[cur]
+		cur++
+
+		if header[cur] != '?' {
+			break
+		}
+		cur++
+
+		j := strings.Index(header[cur:], "?=")
+		if j == -1 {
+			break
+		}
+		text := header[cur : cur+j]
+		end := cur + j + len("?=")
+
+		content, err := decode(encoding, text)
+		if err != nil {
+			betweenWords = false
+			buf.WriteString(header[:start+2])
+			header = header[start+2:]
+			continue
+		}
+
+		// Write characters before the encoded-word. White-space and newline
+		// characters separating two encoded-words must be deleted.
+		if start > 0 && (!betweenWords || hasNonWhitespace(header[:start])) {
+			buf.WriteString(header[:start])
+		}
+
+		if err := d.convert(buf, charset, content); err != nil {
+			return "", err
+		}
+
+		header = header[end:]
+		betweenWords = true
+	}
+
+	if len(header) > 0 {
+		buf.WriteString(header)
+	}
+
+	return buf.String(), nil
+}
+
+func decode(encoding byte, text string) ([]byte, error) {
+	switch encoding {
+	case 'B', 'b':
+		return base64.StdEncoding.DecodeString(text)
+	case 'Q', 'q':
+		return qDecode(text)
+	default:
+		return nil, errInvalidWord
+	}
+}
+
+func (d *WordDecoder) convert(buf *bytes.Buffer, charset string, content []byte) error {
+	switch {
+	case strings.EqualFold("utf-8", charset):
+		buf.Write(content)
+	case strings.EqualFold("iso-8859-1", charset):
+		for _, c := range content {
+			buf.WriteRune(rune(c))
+		}
+	case strings.EqualFold("us-ascii", charset):
+		for _, c := range content {
+			if c >= utf8.RuneSelf {
+				buf.WriteRune(unicode.ReplacementChar)
+			} else {
+				buf.WriteByte(c)
+			}
+		}
+	default:
+		if d.CharsetReader == nil {
+			return fmt.Errorf("mime: unhandled charset %q", charset)
+		}
+		r, err := d.CharsetReader(strings.ToLower(charset), bytes.NewReader(content))
+		if err != nil {
+			return err
+		}
+		if _, err = buf.ReadFrom(r); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// hasNonWhitespace reports whether s (assumed to be ASCII) contains at least
+// one byte of non-whitespace.
+func hasNonWhitespace(s string) bool {
+	for _, b := range s {
+		switch b {
+		// Encoded-words can only be separated by linear white spaces which does
+		// not include vertical tabs (\v).
+		case ' ', '\t', '\n', '\r':
+		default:
+			return true
+		}
+	}
+	return false
+}
+
+// qDecode decodes a Q encoded string.
+func qDecode(s string) ([]byte, error) {
+	dec := make([]byte, len(s))
+	n := 0
+	for i := 0; i < len(s); i++ {
+		switch c := s[i]; {
+		case c == '_':
+			dec[n] = ' '
+		case c == '=':
+			if i+2 >= len(s) {
+				return nil, errInvalidWord
+			}
+			b, err := readHexByte(s[i+1], s[i+2])
+			if err != nil {
+				return nil, err
+			}
+			dec[n] = b
+			i += 2
+		case (c <= '~' && c >= ' ') || c == '\n' || c == '\r' || c == '\t':
+			dec[n] = c
+		default:
+			return nil, errInvalidWord
+		}
+		n++
+	}
+
+	return dec[:n], nil
+}
+
+// readHexByte returns the byte from its quoted-printable representation.
+func readHexByte(a, b byte) (byte, error) {
+	var hb, lb byte
+	var err error
+	if hb, err = fromHex(a); err != nil {
+		return 0, err
+	}
+	if lb, err = fromHex(b); err != nil {
+		return 0, err
+	}
+	return hb<<4 | lb, nil
+}
+
+func fromHex(b byte) (byte, error) {
+	switch {
+	case b >= '0' && b <= '9':
+		return b - '0', nil
+	case b >= 'A' && b <= 'F':
+		return b - 'A' + 10, nil
+	// Accept badly encoded bytes.
+	case b >= 'a' && b <= 'f':
+		return b - 'a' + 10, nil
+	}
+	return 0, fmt.Errorf("mime: invalid hex byte %#02x", b)
+}
+
+var bufPool = sync.Pool{
+	New: func() interface{} {
+		return new(bytes.Buffer)
+	},
+}
+
+func getBuffer() *bytes.Buffer {
+	return bufPool.Get().(*bytes.Buffer)
+}
+
+func putBuffer(buf *bytes.Buffer) {
+	if buf.Len() > 1024 {
+		return
+	}
+	buf.Reset()
+	bufPool.Put(buf)
+}
diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go
new file mode 100644
index 0000000000..02236ea521
--- /dev/null
+++ b/src/mime/encodedword_test.go
@@ -0,0 +1,241 @@
+// Copyright 2015 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 mime
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+)
+
+func ExampleEncodeWord() {
+	fmt.Println(QEncoding.Encode("utf-8", "¡Hola, señor!"))
+	fmt.Println(QEncoding.Encode("utf-8", "Hello!"))
+	fmt.Println(BEncoding.Encode("UTF-8", "¡Hola, señor!"))
+	fmt.Println(QEncoding.Encode("ISO-8859-1", "Caf\xE9"))
+	// Output:
+	// =?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=
+	// Hello!
+	// =?UTF-8?b?wqFIb2xhLCBzZcOxb3Ih?=
+	// =?ISO-8859-1?q?Caf=E9?=
+}
+
+func ExampleDecodeWord() {
+	dec := new(WordDecoder)
+	header, err := dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+	// Output: ¡Hola, señor!
+}
+
+func ExampleDecodeHeader() {
+	dec := new(WordDecoder)
+	header, err := dec.DecodeHeader("=?utf-8?q?=C3=89ric?= , =?utf-8?q?Ana=C3=AFs?= ")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+
+	header, err = dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+	// Output:
+	// Éric , Anaïs 
+	// ¡Hola, señor!
+}
+
+func TestEncodeWord(t *testing.T) {
+	utf8, iso88591 := "utf-8", "iso-8859-1"
+	tests := []struct {
+		enc      WordEncoder
+		charset  string
+		src, exp string
+	}{
+		{QEncoding, utf8, "François-Jérôme", "=?utf-8?q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?="},
+		{BEncoding, utf8, "Café", "=?utf-8?b?Q2Fmw6k=?="},
+		{QEncoding, iso88591, "La Seleção", "=?iso-8859-1?q?La_Sele=C3=A7=C3=A3o?="},
+		{QEncoding, utf8, "", ""},
+		{QEncoding, utf8, "A", "A"},
+		{QEncoding, iso88591, "a", "a"},
+		{QEncoding, utf8, "123 456", "123 456"},
+		{QEncoding, utf8, "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~"},
+	}
+
+	for _, test := range tests {
+		if s := test.enc.Encode(test.charset, test.src); s != test.exp {
+			t.Errorf("Encode(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestDecodeWord(t *testing.T) {
+	tests := []struct {
+		src, exp string
+		hasErr   bool
+	}{
+		{"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!", false},
+		{"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme", false},
+		{"=?UTF-8?q?ascii?=", "ascii", false},
+		{"=?utf-8?B?QW5kcsOp?=", "André", false},
+		{"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont", false},
+		{"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" `, false},
+		{"=?UTF-8?A?Test?=", "", true},
+		{"=?UTF-8?Q?A=B?=", "", true},
+		{"=?UTF-8?Q?=A?=", "", true},
+		{"=?UTF-8?A?A?=", "", true},
+	}
+
+	for _, test := range tests {
+		dec := new(WordDecoder)
+		s, err := dec.Decode(test.src)
+		if test.hasErr && err == nil {
+			t.Errorf("Decode(%q) should return an error", test.src)
+			continue
+		}
+		if !test.hasErr && err != nil {
+			t.Errorf("Decode(%q): %v", test.src, err)
+			continue
+		}
+		if s != test.exp {
+			t.Errorf("Decode(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestDecodeHeader(t *testing.T) {
+	tests := []struct {
+		src, exp string
+	}{
+		{"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!"},
+		{"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme"},
+		{"=?UTF-8?q?ascii?=", "ascii"},
+		{"=?utf-8?B?QW5kcsOp?=", "André"},
+		{"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont"},
+		{"Jean", "Jean"},
+		{"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" `},
+		{"=?UTF-8?A?Test?=", "=?UTF-8?A?Test?="},
+		{"=?UTF-8?Q?A=B?=", "=?UTF-8?Q?A=B?="},
+		{"=?UTF-8?Q?=A?=", "=?UTF-8?Q?=A?="},
+		{"=?UTF-8?A?A?=", "=?UTF-8?A?A?="},
+		// Incomplete words
+		{"=?", "=?"},
+		{"=?UTF-8?", "=?UTF-8?"},
+		{"=?UTF-8?=", "=?UTF-8?="},
+		{"=?UTF-8?Q", "=?UTF-8?Q"},
+		{"=?UTF-8?Q?", "=?UTF-8?Q?"},
+		{"=?UTF-8?Q?=", "=?UTF-8?Q?="},
+		{"=?UTF-8?Q?A", "=?UTF-8?Q?A"},
+		{"=?UTF-8?Q?A?", "=?UTF-8?Q?A?"},
+		// Tests from RFC 2047
+		{"=?ISO-8859-1?Q?a?=", "a"},
+		{"=?ISO-8859-1?Q?a?= b", "a b"},
+		{"=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a?=  =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a?= \r\n\t =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a_b?=", "a b"},
+	}
+
+	for _, test := range tests {
+		dec := new(WordDecoder)
+		s, err := dec.DecodeHeader(test.src)
+		if err != nil {
+			t.Errorf("DecodeHeader(%q): %v", test.src, err)
+		}
+		if s != test.exp {
+			t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestCharsetDecoder(t *testing.T) {
+	tests := []struct {
+		src      string
+		want     string
+		charsets []string
+		content  []string
+	}{
+		{"=?utf-8?b?Q2Fmw6k=?=", "Café", nil, nil},
+		{"=?ISO-8859-1?Q?caf=E9?=", "café", nil, nil},
+		{"=?US-ASCII?Q?foo_bar?=", "foo bar", nil, nil},
+		{"=?utf-8?Q?=?=", "=?utf-8?Q?=?=", nil, nil},
+		{"=?utf-8?Q?=A?=", "=?utf-8?Q?=A?=", nil, nil},
+		{
+			"=?ISO-8859-15?Q?f=F5=F6?=  =?windows-1252?Q?b=E0r?=",
+			"f\xf5\xf6b\xe0r",
+			[]string{"iso-8859-15", "windows-1252"},
+			[]string{"f\xf5\xf6", "b\xe0r"},
+		},
+	}
+
+	for _, test := range tests {
+		i := 0
+		dec := &WordDecoder{
+			CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+				if charset != test.charsets[i] {
+					t.Errorf("DecodeHeader(%q), got charset %q, want %q", test.src, charset, test.charsets[i])
+				}
+				content, err := ioutil.ReadAll(input)
+				if err != nil {
+					t.Errorf("DecodeHeader(%q), error in reader: %v", test.src, err)
+				}
+				got := string(content)
+				if got != test.content[i] {
+					t.Errorf("DecodeHeader(%q), got content %q, want %q", test.src, got, test.content[i])
+				}
+				i++
+
+				return strings.NewReader(got), nil
+			},
+		}
+		got, err := dec.DecodeHeader(test.src)
+		if err != nil {
+			t.Errorf("DecodeHeader(%q): %v", test.src, err)
+		}
+		if got != test.want {
+			t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, got, test.want)
+		}
+	}
+}
+
+func TestCharsetDecoderError(t *testing.T) {
+	dec := &WordDecoder{
+		CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+			return nil, errors.New("Test error")
+		},
+	}
+
+	if _, err := dec.DecodeHeader("=?charset?Q?foo?="); err == nil {
+		t.Error("DecodeHeader should return an error")
+	}
+}
+
+func BenchmarkQEncodeWord(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		QEncoding.Encode("UTF-8", "¡Hola, señor!")
+	}
+}
+
+func BenchmarkQDecodeWord(b *testing.B) {
+	dec := new(WordDecoder)
+
+	for i := 0; i < b.N; i++ {
+		dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	}
+}
+
+func BenchmarkQDecodeHeader(b *testing.B) {
+	dec := new(WordDecoder)
+
+	for i := 0; i < b.N; i++ {
+		dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	}
+}
diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go
index 55ea86a458..4d5ab23fd3 100644
--- a/src/net/cgo_unix_test.go
+++ b/src/net/cgo_unix_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo,!netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 5a4411f5c7..fab515f5c2 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -214,95 +214,106 @@ func convertRR_AAAA(records []dnsRR) []IP {
 	return addrs
 }
 
+// cfg is used for the storage and reparsing of /etc/resolv.conf
 var cfg struct {
-	ch        chan struct{}
+	// ch is used as a semaphore that only allows one lookup at a time to
+	// recheck resolv.conf.  It acts as guard for lastChecked and modTime.
+	ch          chan struct{}
+	lastChecked time.Time // last time resolv.conf was checked
+	modTime     time.Time // time of resolv.conf modification
+
 	mu        sync.RWMutex // protects dnsConfig
-	dnsConfig *dnsConfig
+	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
 }
 
 var onceLoadConfig sync.Once
 
-// Assume dns config file is /etc/resolv.conf here
-func loadDefaultConfig() {
-	loadConfig("/etc/resolv.conf", 5*time.Second, nil)
-}
-
-func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
-	var mtime time.Time
-	cfg.ch = make(chan struct{}, 1)
-	if fi, err := os.Stat(resolvConfPath); err == nil {
-		mtime = fi.ModTime()
+func initCfg() {
+	// Set dnsConfig, modTime, and lastChecked so we don't parse
+	// resolv.conf twice the first time.
+	cfg.dnsConfig = systemConf().resolv
+	if cfg.dnsConfig == nil {
+		cfg.dnsConfig = dnsReadConfig("/etc/resolv.conf")
 	}
 
-	cfg.dnsConfig = dnsReadConfig(resolvConfPath)
+	if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
+		cfg.modTime = fi.ModTime()
+	}
+	cfg.lastChecked = time.Now()
 
-	go func() {
-		for {
-			time.Sleep(reloadTime)
-			select {
-			case qresp := <-quit:
-				qresp <- struct{}{}
-				return
-			case <-cfg.ch:
-			}
+	// Prepare ch so that only one loadConfig may run at once
+	cfg.ch = make(chan struct{}, 1)
+	cfg.ch <- struct{}{}
+}
 
-			// In case of error, we keep the previous config
-			fi, err := os.Stat(resolvConfPath)
-			if err != nil {
-				continue
-			}
-			// If the resolv.conf mtime didn't change, do not reload
-			m := fi.ModTime()
-			if m.Equal(mtime) {
-				continue
-			}
-			mtime = m
-			// In case of error, we keep the previous config
-			if ncfg := dnsReadConfig(resolvConfPath); ncfg.err == nil {
-				cfg.mu.Lock()
-				cfg.dnsConfig = ncfg
-				cfg.mu.Unlock()
-			}
+func loadConfig(resolvConfPath string) {
+	onceLoadConfig.Do(initCfg)
+
+	// ensure only one loadConfig at a time checks /etc/resolv.conf
+	select {
+	case <-cfg.ch:
+		defer func() { cfg.ch <- struct{}{} }()
+	default:
+		return
+	}
+
+	now := time.Now()
+	if cfg.lastChecked.After(now.Add(-5 * time.Second)) {
+		return
+	}
+	cfg.lastChecked = now
+
+	if fi, err := os.Stat(resolvConfPath); err == nil {
+		if fi.ModTime().Equal(cfg.modTime) {
+			return
 		}
-	}()
+		cfg.modTime = fi.ModTime()
+	} else {
+		// If modTime wasn't set prior, assume nothing has changed.
+		if cfg.modTime.IsZero() {
+			return
+		}
+		cfg.modTime = time.Time{}
+	}
+
+	ncfg := dnsReadConfig(resolvConfPath)
+	cfg.mu.Lock()
+	cfg.dnsConfig = ncfg
+	cfg.mu.Unlock()
 }
 
 func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 	if !isDomainName(name) {
 		return name, nil, &DNSError{Err: "invalid domain name", Name: name}
 	}
-	onceLoadConfig.Do(loadDefaultConfig)
-
-	select {
-	case cfg.ch <- struct{}{}:
-	default:
-	}
 
+	loadConfig("/etc/resolv.conf")
 	cfg.mu.RLock()
-	defer cfg.mu.RUnlock()
+	resolv := cfg.dnsConfig
+	cfg.mu.RUnlock()
 
 	// If name is rooted (trailing dot) or has enough dots,
 	// try it by itself first.
 	rooted := len(name) > 0 && name[len(name)-1] == '.'
-	if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
+	if rooted || count(name, '.') >= resolv.ndots {
 		rname := name
 		if !rooted {
 			rname += "."
 		}
 		// Can try as ordinary name.
-		cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+		cname, rrs, err = tryOneName(resolv, rname, qtype)
 		if rooted || err == nil {
 			return
 		}
 	}
 
 	// Otherwise, try suffixes.
-	for i := 0; i < len(cfg.dnsConfig.search); i++ {
-		rname := name + "." + cfg.dnsConfig.search[i]
+	for _, suffix := range resolv.search {
+		rname := name + "." + suffix
 		if rname[len(rname)-1] != '.' {
 			rname += "."
 		}
-		cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+		cname, rrs, err = tryOneName(resolv, rname, qtype)
 		if err == nil {
 			return
 		}
@@ -310,8 +321,8 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 
 	// Last ditch effort: try unsuffixed only if we haven't already,
 	// that is, name is not rooted and has less than ndots dots.
-	if count(name, '.') < cfg.dnsConfig.ndots {
-		cname, rrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
+	if count(name, '.') < resolv.ndots {
+		cname, rrs, err = tryOneName(resolv, name+".", qtype)
 		if err == nil {
 			return
 		}
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 1b88e7762b..06c9ad3134 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -94,10 +94,8 @@ func TestSpecialDomainName(t *testing.T) {
 
 type resolvConfTest struct {
 	*testing.T
-	dir     string
-	path    string
-	started bool
-	quitc   chan chan struct{}
+	dir  string
+	path string
 }
 
 func newResolvConfTest(t *testing.T) *resolvConfTest {
@@ -106,24 +104,15 @@ func newResolvConfTest(t *testing.T) *resolvConfTest {
 		t.Fatal(err)
 	}
 
-	// Disable the default loadConfig
-	onceLoadConfig.Do(func() {})
-
 	r := &resolvConfTest{
-		T:     t,
-		dir:   dir,
-		path:  path.Join(dir, "resolv.conf"),
-		quitc: make(chan chan struct{}),
+		T:    t,
+		dir:  dir,
+		path: path.Join(dir, "resolv.conf"),
 	}
 
 	return r
 }
 
-func (r *resolvConfTest) Start() {
-	loadConfig(r.path, 100*time.Millisecond, r.quitc)
-	r.started = true
-}
-
 func (r *resolvConfTest) SetConf(s string) {
 	// Make sure the file mtime will be different once we're done here,
 	// even on systems with coarse (1s) mtime resolution.
@@ -138,12 +127,8 @@ func (r *resolvConfTest) SetConf(s string) {
 		r.Fatalf("failed to write temp file: %v", err)
 	}
 	f.Close()
-
-	if r.started {
-		cfg.ch <- struct{}{} // fill buffer
-		cfg.ch <- struct{}{} // wait for reload to begin
-		cfg.ch <- struct{}{} // wait for reload to complete
-	}
+	cfg.lastChecked = time.Time{}
+	loadConfig(r.path)
 }
 
 func (r *resolvConfTest) WantServers(want []string) {
@@ -155,9 +140,6 @@ func (r *resolvConfTest) WantServers(want []string) {
 }
 
 func (r *resolvConfTest) Close() {
-	resp := make(chan struct{})
-	r.quitc <- resp
-	<-resp
 	if err := os.RemoveAll(r.dir); err != nil {
 		r.Logf("failed to remove temp dir %s: %v", r.dir, err)
 	}
@@ -171,7 +153,6 @@ func TestReloadResolvConfFail(t *testing.T) {
 	r := newResolvConfTest(t)
 	defer r.Close()
 
-	r.Start()
 	r.SetConf("nameserver 8.8.8.8")
 
 	if _, err := goLookupIP("golang.org"); err != nil {
@@ -200,7 +181,6 @@ func TestReloadResolvConfChange(t *testing.T) {
 	r := newResolvConfTest(t)
 	defer r.Close()
 
-	r.Start()
 	r.SetConf("nameserver 8.8.8.8")
 
 	if _, err := goLookupIP("golang.org"); err != nil {
@@ -227,7 +207,7 @@ func TestReloadResolvConfChange(t *testing.T) {
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
@@ -235,7 +215,7 @@ func BenchmarkGoLookupIP(b *testing.B) {
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		goLookupIP("some.nonexistent")
@@ -243,16 +223,16 @@ func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
-
-	onceLoadConfig.Do(loadDefaultConfig)
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	// This looks ugly but it's safe as long as benchmarks are run
 	// sequentially in package testing.
+	<-cfg.ch // keep config from being reloaded upon lookup
 	orig := cfg.dnsConfig
 	cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
 	cfg.dnsConfig = orig
+	cfg.ch <- struct{}{}
 }
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index cc660c9d42..be07dc6a16 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -68,7 +68,7 @@ func TestDNSName(t *testing.T) {
 }
 
 func BenchmarkDNSName(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	benchmarks := append(dnsNameTests, []dnsNameTest{
 		{strings.Repeat("a", 63), true},
diff --git a/src/net/error_test.go b/src/net/error_test.go
index c65d3f9d8a..772e0c7f5f 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -521,7 +521,7 @@ third:
 func TestFileError(t *testing.T) {
 	switch runtime.GOOS {
 	case "windows":
-		t.Skip("not supported on %s", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	f, err := ioutil.TempFile("", "go-nettest")
diff --git a/src/net/external_test.go b/src/net/external_test.go
index 20611ff420..d5ff2be20a 100644
--- a/src/net/external_test.go
+++ b/src/net/external_test.go
@@ -15,33 +15,23 @@ func TestResolveGoogle(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
-	if !supportsIPv4 && !supportsIPv6 {
-		t.Skip("ipv4 and ipv6 are not supported")
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
 	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
 		addr, err := ResolveTCPAddr(network, "www.google.com:http")
 		if err != nil {
-			switch {
-			case network == "tcp" && !supportsIPv4:
-				fallthrough
-			case network == "tcp4" && !supportsIPv4:
-				t.Logf("skipping test; ipv4 is not supported: %v", err)
-			case network == "tcp6" && !supportsIPv6:
-				t.Logf("skipping test; ipv6 is not supported: %v", err)
-			default:
-				t.Error(err)
-			}
+			t.Error(err)
 			continue
 		}
-
 		switch {
 		case network == "tcp" && addr.IP.To4() == nil:
 			fallthrough
 		case network == "tcp4" && addr.IP.To4() == nil:
-			t.Errorf("got %v; want an ipv4 address on %s", addr, network)
+			t.Errorf("got %v; want an IPv4 address on %s", addr, network)
 		case network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil):
-			t.Errorf("got %v; want an ipv6 address on %s", addr, network)
+			t.Errorf("got %v; want an IPv6 address on %s", addr, network)
 		}
 	}
 }
@@ -73,8 +63,8 @@ func TestDialGoogle(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
-	if !supportsIPv4 && !supportsIPv6 {
-		t.Skip("ipv4 and ipv6 are not supported")
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
 	var err error
@@ -84,25 +74,6 @@ func TestDialGoogle(t *testing.T) {
 	}
 	for _, tt := range dialGoogleTests {
 		for _, network := range tt.networks {
-			switch {
-			case network == "tcp4" && !supportsIPv4:
-				t.Log("skipping test; ipv4 is not supported")
-				continue
-			case network == "tcp4" && !*testIPv4:
-				fallthrough
-			case tt.unreachableNetwork == "tcp6" && !*testIPv4:
-				t.Log("disabled; use -ipv4 to enable")
-				continue
-			case network == "tcp6" && !supportsIPv6:
-				t.Log("skipping test; ipv6 is not supported")
-				continue
-			case network == "tcp6" && !*testIPv6:
-				fallthrough
-			case tt.unreachableNetwork == "tcp4" && !*testIPv6:
-				t.Log("disabled; use -ipv6 to enable")
-				continue
-			}
-
 			disableSocketConnect(tt.unreachableNetwork)
 			for _, addr := range tt.addrs {
 				if err := fetchGoogle(tt.dial, network, addr); err != nil {
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 64e94fecf8..827045b13d 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"internal/syscall/unix"
 	"io"
 	"os"
 	"runtime"
@@ -225,7 +226,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 		return 0, err
 	}
 	for {
-		n, err = syscall.Read(int(fd.sysfd), p)
+		n, err = syscall.Read(fd.sysfd, p)
 		if err != nil {
 			n = 0
 			if err == syscall.EAGAIN {
@@ -270,6 +271,33 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 	return
 }
 
+func (fd *netFD) recvFrom(b []byte, flags int, from []byte) (n int, err error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.PrepareRead(); err != nil {
+		return 0, err
+	}
+	for {
+		n, err = unix.Recvfrom(fd.sysfd, b, flags, from)
+		if err != nil {
+			n = 0
+			if err == syscall.EAGAIN {
+				if err = fd.pd.WaitRead(); err == nil {
+					continue
+				}
+			}
+		}
+		err = fd.eofError(n, err)
+		break
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("recvfrom", err)
+	}
+	return
+}
+
 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
 	if err := fd.readLock(); err != nil {
 		return 0, 0, 0, nil, err
@@ -307,7 +335,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 	}
 	for {
 		var n int
-		n, err = syscall.Write(int(fd.sysfd), p[nn:])
+		n, err = syscall.Write(fd.sysfd, p[nn:])
 		if n > 0 {
 			nn += n
 		}
@@ -359,6 +387,29 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	return
 }
 
+func (fd *netFD) sendTo(b []byte, flags int, to []byte) (n int, err error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.PrepareWrite(); err != nil {
+		return 0, err
+	}
+	for {
+		n, err = unix.Sendto(fd.sysfd, b, flags, to)
+		if err == syscall.EAGAIN {
+			if err = fd.pd.WaitWrite(); err == nil {
+				continue
+			}
+		}
+		break
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("sendto", err)
+	}
+	return
+}
+
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
 	if err := fd.writeLock(); err != nil {
 		return 0, 0, err
diff --git a/src/net/file.go b/src/net/file.go
index 1aad477400..1d0686c9fc 100644
--- a/src/net/file.go
+++ b/src/net/file.go
@@ -46,3 +46,47 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
 	}
 	return
 }
+
+// A SocketAddr is used with SocketConn or SocketPacketConn to
+// implement a user-configured socket address.
+// The net package does not provide any implementations of SocketAddr;
+// the caller of SocketConn or SocketPacketConn is expected to provide
+// one.
+type SocketAddr interface {
+	// Addr takes a platform-specific socket address and returns
+	// a net.Addr. The result may be nil when the syscall package,
+	// system call or underlying protocol does not support the
+	// socket address.
+	Addr([]byte) Addr
+
+	// Raw takes a net.Addr and returns a platform-specific socket
+	// address. The result may be nil when the syscall package,
+	// system call or underlying protocol does not support the
+	// socket address.
+	Raw(Addr) []byte
+}
+
+// SocketConn returns a copy of the network connection corresponding
+// to the open file f and user-defined socket address sa.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func SocketConn(f *os.File, sa SocketAddr) (c Conn, err error) {
+	c, err = socketConn(f, sa)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
+
+// SocketPacketConn returns a copy of the packet network connection
+// corresponding to the open file f and user-defined socket address
+// sa.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func SocketPacketConn(f *os.File, sa SocketAddr) (c PacketConn, err error) {
+	c, err = socketPacketConn(f, sa)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
diff --git a/src/net/file_bsd_test.go b/src/net/file_bsd_test.go
new file mode 100644
index 0000000000..ffe3c612b4
--- /dev/null
+++ b/src/net/file_bsd_test.go
@@ -0,0 +1,95 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package net
+
+import (
+	"os"
+	"runtime"
+	"strings"
+	"sync"
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+type routeAddr struct{}
+
+func (a *routeAddr) Network() string { return "route" }
+func (a *routeAddr) String() string  { return "" }
+
+func (a *routeAddr) Addr(rsa []byte) Addr { return &routeAddr{} }
+func (a *routeAddr) Raw(addr Addr) []byte { return nil }
+
+func TestSocketConn(t *testing.T) {
+	var freebsd32o64 bool
+	if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" {
+		archs, _ := syscall.Sysctl("kern.supported_archs")
+		for _, s := range strings.Split(archs, " ") {
+			if strings.TrimSpace(s) == "amd64" {
+				freebsd32o64 = true
+				break
+			}
+		}
+	}
+
+	s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+	if err != nil {
+		t.Fatal(err)
+	}
+	f := os.NewFile(uintptr(s), "route")
+	c, err := SocketConn(f, &routeAddr{})
+	f.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	const N = 3
+	var wg sync.WaitGroup
+	wg.Add(2 * N)
+	for i := 0; i < N; i++ {
+		go func(i int) {
+			defer wg.Done()
+			l := syscall.SizeofRtMsghdr + syscall.SizeofSockaddrInet4
+			if freebsd32o64 {
+				l += syscall.SizeofRtMetrics // see syscall/route_freebsd_32bit.go
+			}
+			b := make([]byte, l)
+			h := (*syscall.RtMsghdr)(unsafe.Pointer(&b[0]))
+			h.Msglen = uint16(len(b))
+			h.Version = syscall.RTM_VERSION
+			h.Type = syscall.RTM_GET
+			h.Addrs = syscall.RTA_DST
+			h.Pid = int32(os.Getpid())
+			h.Seq = int32(i)
+			p := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&b[syscall.SizeofRtMsghdr]))
+			p.Len = syscall.SizeofSockaddrInet4
+			p.Family = syscall.AF_INET
+			p.Addr = [4]byte{127, 0, 0, 1}
+			if _, err := c.Write(b); err != nil {
+				t.Error(err)
+				return
+			}
+		}(i + 1)
+	}
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			b := make([]byte, os.Getpagesize())
+			n, err := c.Read(b)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			if _, err := syscall.ParseRoutingMessage(b[:n]); err != nil {
+				t.Error(err)
+				return
+			}
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/net/file_linux_test.go b/src/net/file_linux_test.go
new file mode 100644
index 0000000000..e04fea38f6
--- /dev/null
+++ b/src/net/file_linux_test.go
@@ -0,0 +1,98 @@
+// Copyright 2015 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 net
+
+import (
+	"fmt"
+	"os"
+	"sync"
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+type netlinkAddr struct {
+	PID    uint32
+	Groups uint32
+}
+
+func (a *netlinkAddr) Network() string { return "netlink" }
+func (a *netlinkAddr) String() string  { return fmt.Sprintf("%x:%x", a.PID, a.Groups) }
+
+func (a *netlinkAddr) Addr(rsa []byte) Addr {
+	if len(rsa) < syscall.SizeofSockaddrNetlink {
+		return nil
+	}
+	var addr netlinkAddr
+	b := (*[unsafe.Sizeof(addr)]byte)(unsafe.Pointer(&addr))
+	copy(b[0:4], rsa[4:8])
+	copy(b[4:8], rsa[8:12])
+	return &addr
+}
+
+func (a *netlinkAddr) Raw(addr Addr) []byte {
+	if addr, ok := addr.(*netlinkAddr); ok {
+		rsa := &syscall.RawSockaddrNetlink{Family: syscall.AF_NETLINK, Pid: addr.PID, Groups: addr.Groups}
+		return (*[unsafe.Sizeof(*rsa)]byte)(unsafe.Pointer(rsa))[:]
+	}
+	return nil
+}
+
+func TestSocketPacketConn(t *testing.T) {
+	s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	lsa := syscall.SockaddrNetlink{Family: syscall.AF_NETLINK}
+	if err := syscall.Bind(s, &lsa); err != nil {
+		syscall.Close(s)
+		t.Fatal(err)
+	}
+	f := os.NewFile(uintptr(s), "netlink")
+	c, err := SocketPacketConn(f, &netlinkAddr{})
+	f.Close()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	const N = 3
+	var wg sync.WaitGroup
+	wg.Add(2 * N)
+	dst := &netlinkAddr{PID: 0}
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			l := syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg
+			b := make([]byte, l)
+			*(*uint32)(unsafe.Pointer(&b[0:4][0])) = uint32(l)
+			*(*uint16)(unsafe.Pointer(&b[4:6][0])) = uint16(syscall.RTM_GETLINK)
+			*(*uint16)(unsafe.Pointer(&b[6:8][0])) = uint16(syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST)
+			*(*uint32)(unsafe.Pointer(&b[8:12][0])) = uint32(1)
+			*(*uint32)(unsafe.Pointer(&b[12:16][0])) = uint32(0)
+			b[16] = byte(syscall.AF_UNSPEC)
+			if _, err := c.WriteTo(b, dst); err != nil {
+				t.Error(err)
+				return
+			}
+		}()
+	}
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			b := make([]byte, os.Getpagesize())
+			n, _, err := c.ReadFrom(b)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			if _, err := syscall.ParseNetlinkMessage(b[:n]); err != nil {
+				t.Error(err)
+				return
+			}
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go
index 892775a024..efe416f690 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -135,3 +135,11 @@ func fileListener(f *os.File) (Listener, error) {
 func filePacketConn(f *os.File) (PacketConn, error) {
 	return nil, syscall.EPLAN9
 }
+
+func socketConn(f *os.File, sa SocketAddr) (Conn, error) {
+	return nil, syscall.EPLAN9
+}
+
+func socketPacketConn(f *os.File, sa SocketAddr) (PacketConn, error) {
+	return nil, syscall.EPLAN9
+}
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 0f7460c757..41ca78b437 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -11,6 +11,8 @@ import (
 	"syscall"
 )
 
-func fileConn(f *os.File) (Conn, error)             { return nil, syscall.ENOPROTOOPT }
-func fileListener(f *os.File) (Listener, error)     { return nil, syscall.ENOPROTOOPT }
-func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
+func fileConn(f *os.File) (Conn, error)                              { return nil, syscall.ENOPROTOOPT }
+func fileListener(f *os.File) (Listener, error)                      { return nil, syscall.ENOPROTOOPT }
+func filePacketConn(f *os.File) (PacketConn, error)                  { return nil, syscall.ENOPROTOOPT }
+func socketConn(f *os.File, sa SocketAddr) (Conn, error)             { return nil, syscall.ENOPROTOOPT }
+func socketPacketConn(f *os.File, sa SocketAddr) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 147ca1ed95..df884d1603 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -7,76 +7,81 @@
 package net
 
 import (
+	"internal/syscall/unix"
 	"os"
 	"syscall"
 )
 
-func newFileFD(f *os.File) (*netFD, error) {
-	fd, err := dupCloseOnExec(int(f.Fd()))
+func dupSocket(f *os.File) (int, error) {
+	s, err := dupCloseOnExec(int(f.Fd()))
+	if err != nil {
+		return -1, err
+	}
+	if err := syscall.SetNonblock(s, true); err != nil {
+		closeFunc(s)
+		return -1, os.NewSyscallError("setnonblock", err)
+	}
+	return s, nil
+}
+
+func newFileFD(f *os.File, sa SocketAddr) (*netFD, error) {
+	s, err := dupSocket(f)
 	if err != nil {
 		return nil, err
 	}
-
-	if err = syscall.SetNonblock(fd, true); err != nil {
-		closeFunc(fd)
-		return nil, os.NewSyscallError("setnonblock", err)
+	var laddr, raddr Addr
+	var fd *netFD
+	if sa != nil {
+		lsa := make([]byte, syscall.SizeofSockaddrAny)
+		if err := unix.Getsockname(s, lsa); err != nil {
+			lsa = nil
+		}
+		rsa := make([]byte, syscall.SizeofSockaddrAny)
+		if err := unix.Getpeername(s, rsa); err != nil {
+			rsa = nil
+		}
+		laddr = sa.Addr(lsa)
+		raddr = sa.Addr(rsa)
+		fd, err = newFD(s, -1, -1, laddr.Network())
+	} else {
+		family := syscall.AF_UNSPEC
+		sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
+		if err != nil {
+			closeFunc(s)
+			return nil, os.NewSyscallError("getsockopt", err)
+		}
+		lsa, _ := syscall.Getsockname(s)
+		rsa, _ := syscall.Getpeername(s)
+		switch lsa.(type) {
+		case *syscall.SockaddrInet4:
+			family = syscall.AF_INET
+		case *syscall.SockaddrInet6:
+			family = syscall.AF_INET6
+		case *syscall.SockaddrUnix:
+			family = syscall.AF_UNIX
+		default:
+			closeFunc(s)
+			return nil, syscall.EPROTONOSUPPORT
+		}
+		fd, err = newFD(s, family, sotype, "")
+		laddr = fd.addrFunc()(lsa)
+		raddr = fd.addrFunc()(rsa)
+		fd.net = laddr.Network()
 	}
-
-	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
-		closeFunc(fd)
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-
-	family := syscall.AF_UNSPEC
-	toAddr := sockaddrToTCP
-	lsa, _ := syscall.Getsockname(fd)
-	switch lsa.(type) {
-	case *syscall.SockaddrInet4:
-		family = syscall.AF_INET
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUDP
-		} else if sotype == syscall.SOCK_RAW {
-			toAddr = sockaddrToIP
-		}
-	case *syscall.SockaddrInet6:
-		family = syscall.AF_INET6
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUDP
-		} else if sotype == syscall.SOCK_RAW {
-			toAddr = sockaddrToIP
-		}
-	case *syscall.SockaddrUnix:
-		family = syscall.AF_UNIX
-		toAddr = sockaddrToUnix
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUnixgram
-		} else if sotype == syscall.SOCK_SEQPACKET {
-			toAddr = sockaddrToUnixpacket
-		}
-	default:
-		closeFunc(fd)
-		return nil, syscall.EPROTONOSUPPORT
-	}
-	laddr := toAddr(lsa)
-	rsa, _ := syscall.Getpeername(fd)
-	raddr := toAddr(rsa)
-
-	netfd, err := newFD(fd, family, sotype, laddr.Network())
-	if err != nil {
-		closeFunc(fd)
+		closeFunc(s)
 		return nil, err
 	}
-	if err := netfd.init(); err != nil {
-		netfd.Close()
+	if err := fd.init(); err != nil {
+		fd.Close()
 		return nil, err
 	}
-	netfd.setAddr(laddr, raddr)
-	return netfd, nil
+	fd.setAddr(laddr, raddr)
+	return fd, nil
 }
 
 func fileConn(f *os.File) (Conn, error) {
-	fd, err := newFileFD(f)
+	fd, err := newFileFD(f, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -95,7 +100,7 @@ func fileConn(f *os.File) (Conn, error) {
 }
 
 func fileListener(f *os.File) (Listener, error) {
-	fd, err := newFileFD(f)
+	fd, err := newFileFD(f, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -110,7 +115,7 @@ func fileListener(f *os.File) (Listener, error) {
 }
 
 func filePacketConn(f *os.File) (PacketConn, error) {
-	fd, err := newFileFD(f)
+	fd, err := newFileFD(f, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -125,3 +130,55 @@ func filePacketConn(f *os.File) (PacketConn, error) {
 	fd.Close()
 	return nil, syscall.EINVAL
 }
+
+func socketConn(f *os.File, sa SocketAddr) (Conn, error) {
+	fd, err := newFileFD(f, sa)
+	if err != nil {
+		return nil, err
+	}
+	return &socketFile{conn: conn{fd}, SocketAddr: sa}, nil
+}
+
+func socketPacketConn(f *os.File, sa SocketAddr) (PacketConn, error) {
+	fd, err := newFileFD(f, sa)
+	if err != nil {
+		return nil, err
+	}
+	return &socketFile{conn: conn{fd}, SocketAddr: sa}, nil
+}
+
+var (
+	_ Conn       = &socketFile{}
+	_ PacketConn = &socketFile{}
+)
+
+// A socketFile is a placeholder that holds a user-specified socket
+// descriptor and a profile of socket address encoding.
+// It implements both Conn and PacketConn interfaces.
+type socketFile struct {
+	conn
+	SocketAddr
+}
+
+func (c *socketFile) ReadFrom(b []byte) (int, Addr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	from := make([]byte, syscall.SizeofSockaddrAny)
+	n, err := c.fd.recvFrom(b, 0, from)
+	if err != nil {
+		return n, nil, &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, c.SocketAddr.Addr(from), nil
+}
+
+func (c *socketFile) WriteTo(b []byte, addr Addr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	n, err := c.fd.sendTo(b, 0, c.SocketAddr.Raw(addr))
+	if err != nil {
+		return n, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, nil
+}
diff --git a/src/net/file_windows.go b/src/net/file_windows.go
index 241fa17617..1ed72d5bd4 100644
--- a/src/net/file_windows.go
+++ b/src/net/file_windows.go
@@ -23,3 +23,13 @@ func filePacketConn(f *os.File) (PacketConn, error) {
 	// TODO: Implement this
 	return nil, syscall.EWINDOWS
 }
+
+func socketConn(f *os.File, sa SocketAddr) (Conn, error) {
+	// TODO: Implement this
+	return nil, syscall.EWINDOWS
+}
+
+func socketPacketConn(f *os.File, sa SocketAddr) (PacketConn, error) {
+	// TODO: Implement this
+	return nil, syscall.EWINDOWS
+}
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index dc499a90b6..b1d8799fa5 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -927,7 +927,14 @@ func TestClientTimeout_Headers(t *testing.T) {
 		<-donec
 	}))
 	defer ts.Close()
-	defer close(donec)
+	// Note that we use a channel send here and not a close.
+	// The race detector doesn't know that we're waiting for a timeout
+	// and thinks that the waitgroup inside httptest.Server is added to concurrently
+	// with us closing it. If we timed out immediately, we could close the testserver
+	// before we entered the handler. We're not timing out immediately and there's
+	// no way we would be done before we entered the handler, but the race detector
+	// doesn't know this, so synchronize explicitly.
+	defer func() { donec <- true }()
 
 	c := &Client{Timeout: 500 * time.Millisecond}
 
diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
index 9294deb3e5..6d7c69874d 100644
--- a/src/net/http/internal/chunked.go
+++ b/src/net/http/internal/chunked.go
@@ -173,8 +173,12 @@ func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
 		err = io.ErrShortWrite
 		return
 	}
-	_, err = io.WriteString(cw.Wire, "\r\n")
-
+	if _, err = io.WriteString(cw.Wire, "\r\n"); err != nil {
+		return
+	}
+	if bw, ok := cw.Wire.(*FlushAfterChunkWriter); ok {
+		err = bw.Flush()
+	}
 	return
 }
 
@@ -183,6 +187,15 @@ func (cw *chunkedWriter) Close() error {
 	return err
 }
 
+// FlushAfterChunkWriter signals from the caller of NewChunkedWriter
+// that each chunk should be followed by a flush. It is used by the
+// http.Transport code to keep the buffering behavior for headers and
+// trailers, but flush out chunks aggressively in the middle for
+// request bodies which may be generated slowly. See Issue 6574.
+type FlushAfterChunkWriter struct {
+	*bufio.Writer
+}
+
 func parseHexUint(v []byte) (n uint64, err error) {
 	for _, b := range v {
 		n <<= 4
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 5640344345..289d53dec0 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -43,6 +43,7 @@ type transferWriter struct {
 	Close            bool
 	TransferEncoding []string
 	Trailer          Header
+	IsResponse       bool
 }
 
 func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -89,6 +90,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 			}
 		}
 	case *Response:
+		t.IsResponse = true
 		if rr.Request != nil {
 			t.Method = rr.Request.Method
 		}
@@ -206,6 +208,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 	// Write body
 	if t.Body != nil {
 		if chunked(t.TransferEncoding) {
+			if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
+				w = &internal.FlushAfterChunkWriter{bw}
+			}
 			cw := internal.NewChunkedWriter(w)
 			_, err = io.Copy(cw, t.Body)
 			if err == nil {
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index ace58896b8..ca1a3ab407 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -23,6 +23,7 @@ import (
 	"net/http/httptest"
 	"net/url"
 	"os"
+	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -2447,6 +2448,104 @@ func TestTransportDialCancelRace(t *testing.T) {
 	}
 }
 
+// logWritesConn is a net.Conn that logs each Write call to writes
+// and then proxies to w.
+// It proxies Read calls to a reader it receives from rch.
+type logWritesConn struct {
+	net.Conn // nil. crash on use.
+
+	w io.Writer
+
+	rch <-chan io.Reader
+	r   io.Reader // nil until received by rch
+
+	mu     sync.Mutex
+	writes []string
+}
+
+func (c *logWritesConn) Write(p []byte) (n int, err error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	c.writes = append(c.writes, string(p))
+	return c.w.Write(p)
+}
+
+func (c *logWritesConn) Read(p []byte) (n int, err error) {
+	if c.r == nil {
+		c.r = <-c.rch
+	}
+	return c.r.Read(p)
+}
+
+func (c *logWritesConn) Close() error { return nil }
+
+// Issue 6574
+func TestTransportFlushesBodyChunks(t *testing.T) {
+	defer afterTest(t)
+	resBody := make(chan io.Reader, 1)
+	connr, connw := io.Pipe() // connection pipe pair
+	lw := &logWritesConn{
+		rch: resBody,
+		w:   connw,
+	}
+	tr := &Transport{
+		Dial: func(network, addr string) (net.Conn, error) {
+			return lw, nil
+		},
+	}
+	bodyr, bodyw := io.Pipe() // body pipe pair
+	go func() {
+		defer bodyw.Close()
+		for i := 0; i < 3; i++ {
+			fmt.Fprintf(bodyw, "num%d\n", i)
+		}
+	}()
+	resc := make(chan *Response)
+	go func() {
+		req, _ := NewRequest("POST", "http://localhost:8080", bodyr)
+		req.Header.Set("User-Agent", "x") // known value for test
+		res, err := tr.RoundTrip(req)
+		if err != nil {
+			t.Error("RoundTrip: %v", err)
+			close(resc)
+			return
+		}
+		resc <- res
+
+	}()
+	// Fully consume the request before checking the Write log vs. want.
+	req, err := ReadRequest(bufio.NewReader(connr))
+	if err != nil {
+		t.Fatal(err)
+	}
+	io.Copy(ioutil.Discard, req.Body)
+
+	// Unblock the transport's roundTrip goroutine.
+	resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
+	res, ok := <-resc
+	if !ok {
+		return
+	}
+	defer res.Body.Close()
+
+	want := []string{
+		// Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content.
+		// That explains the initial "num0" being split into "n" and "um0".
+		// The first byte is included with the request headers Write. Perhaps in the future
+		// we will want to flush the headers out early if the first byte of the request body is
+		// taking a long time to arrive. But not yet.
+		"POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" +
+			"1\r\nn\r\n",
+		"4\r\num0\n\r\n",
+		"5\r\nnum1\n\r\n",
+		"5\r\nnum2\n\r\n",
+		"0\r\n\r\n",
+	}
+	if !reflect.DeepEqual(lw.writes, want) {
+		t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want)
+	}
+}
+
 func wantBody(res *http.Response, err error, want string) error {
 	if err != nil {
 		return err
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 0e5c2e3ddf..567d18de44 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -229,7 +229,7 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
 }
 
 func BenchmarkInterfaces(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		if _, err := Interfaces(); err != nil {
@@ -239,7 +239,7 @@ func BenchmarkInterfaces(b *testing.B) {
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -253,7 +253,7 @@ func BenchmarkInterfaceByIndex(b *testing.B) {
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -267,7 +267,7 @@ func BenchmarkInterfaceByName(b *testing.B) {
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceAddrs(); err != nil {
@@ -277,7 +277,7 @@ func BenchmarkInterfaceAddrs(b *testing.B) {
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -291,7 +291,7 @@ func BenchmarkInterfacesAndAddrs(b *testing.B) {
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go
index 3ae1c6be3c..60e581f463 100644
--- a/src/net/internal/socktest/main_test.go
+++ b/src/net/internal/socktest/main_test.go
@@ -9,6 +9,7 @@ package socktest_test
 import (
 	"net/internal/socktest"
 	"os"
+	"sync"
 	"syscall"
 	"testing"
 )
@@ -27,6 +28,21 @@ func TestMain(m *testing.M) {
 	os.Exit(st)
 }
 
+func TestSwitch(t *testing.T) {
+	const N = 10
+	var wg sync.WaitGroup
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} {
+				socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+			}
+		}()
+	}
+	wg.Wait()
+}
+
 func TestSocket(t *testing.T) {
 	for _, f := range []socktest.Filter{
 		func(st *socktest.Status) (socktest.AfterFilter, error) { return nil, nil },
diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go
index 5e558a2de3..4e38c7a85f 100644
--- a/src/net/internal/socktest/switch.go
+++ b/src/net/internal/socktest/switch.go
@@ -10,12 +10,6 @@ import (
 	"sync"
 )
 
-func switchInit(sw *Switch) {
-	sw.fltab = make(map[FilterType]Filter)
-	sw.sotab = make(Sockets)
-	sw.stats = make(stats)
-}
-
 // A Switch represents a callpath point switch for socket system
 // calls.
 type Switch struct {
@@ -29,6 +23,12 @@ type Switch struct {
 	stats stats
 }
 
+func (sw *Switch) init() {
+	sw.fltab = make(map[FilterType]Filter)
+	sw.sotab = make(Sockets)
+	sw.stats = make(stats)
+}
+
 // Stats returns a list of per-cookie socket statistics.
 func (sw *Switch) Stats() []Stat {
 	var st []Stat
@@ -162,7 +162,7 @@ func (f AfterFilter) apply(st *Status) error {
 
 // Set deploys the socket system call filter f for the filter type t.
 func (sw *Switch) Set(t FilterType, f Filter) {
-	sw.once.Do(func() { switchInit(sw) })
+	sw.once.Do(sw.init)
 	sw.fmu.Lock()
 	sw.fltab[t] = f
 	sw.fmu.Unlock()
diff --git a/src/net/internal/socktest/switch_unix.go b/src/net/internal/socktest/switch_unix.go
index 2b89276fa1..14c0c228a2 100644
--- a/src/net/internal/socktest/switch_unix.go
+++ b/src/net/internal/socktest/switch_unix.go
@@ -22,7 +22,7 @@ func (sw *Switch) sockso(s int) *Status {
 // addLocked returns a new Status without locking.
 // sw.smu must be held before call.
 func (sw *Switch) addLocked(s, family, sotype, proto int) *Status {
-	sw.once.Do(func() { switchInit(sw) })
+	sw.once.Do(sw.init)
 	so := Status{Cookie: cookie(family, sotype, proto)}
 	sw.sotab[s] = so
 	return &so
diff --git a/src/net/internal/socktest/switch_windows.go b/src/net/internal/socktest/switch_windows.go
index 3cee49ba0b..4f1d597a27 100644
--- a/src/net/internal/socktest/switch_windows.go
+++ b/src/net/internal/socktest/switch_windows.go
@@ -22,7 +22,7 @@ func (sw *Switch) sockso(s syscall.Handle) *Status {
 // addLocked returns a new Status without locking.
 // sw.smu must be held before call.
 func (sw *Switch) addLocked(s syscall.Handle, family, sotype, proto int) *Status {
-	sw.once.Do(func() { switchInit(sw) })
+	sw.once.Do(sw.init)
 	so := Status{Cookie: cookie(family, sotype, proto)}
 	sw.sotab[s] = so
 	return &so
diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go
index 4089f8cea2..f983e266f1 100644
--- a/src/net/internal/socktest/sys_unix.go
+++ b/src/net/internal/socktest/sys_unix.go
@@ -10,6 +10,8 @@ import "syscall"
 
 // Socket wraps syscall.Socket.
 func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
+	sw.once.Do(sw.init)
+
 	so := &Status{Cookie: cookie(family, sotype, proto)}
 	sw.fmu.RLock()
 	f, _ := sw.fltab[FilterSocket]
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
index 907e01b5a2..07af0e7046 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -8,6 +8,8 @@ import "syscall"
 
 // Socket wraps syscall.Socket.
 func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) {
+	sw.once.Do(sw.init)
+
 	so := &Status{Cookie: cookie(family, sotype, proto)}
 	sw.fmu.RLock()
 	f, _ := sw.fltab[FilterSocket]
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 24f67cac97..b1939cd08f 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -53,7 +53,7 @@ func TestParseIP(t *testing.T) {
 }
 
 func BenchmarkParseIP(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range parseIPTests {
@@ -110,7 +110,7 @@ func TestIPString(t *testing.T) {
 }
 
 func BenchmarkIPString(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipStringTests {
@@ -162,7 +162,7 @@ func TestIPMaskString(t *testing.T) {
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipMaskStringTests {
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index 56b9872fd1..83eaf855b4 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -9,10 +9,18 @@
 package net
 
 import (
+	"runtime"
 	"syscall"
 	"time"
 )
 
+// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
+// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
+// connections. This is due to the fact that IPv4 traffic will not be
+// routed to an IPv6 socket - two separate sockets are required if
+// both address families are to be supported.
+// See inet6(4) for details.
+
 func probeIPv4Stack() bool {
 	s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 	switch err {
@@ -41,13 +49,28 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
 		laddr TCPAddr
 		value int
-		ok    bool
 	}{
 		// IPv6 communication capability
 		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
 		// IPv6 IPv4-mapped address communication capability
 		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
+	var supps [2]bool
+	switch runtime.GOOS {
+	case "dragonfly", "openbsd":
+		// Some released versions of DragonFly BSD pretend to
+		// accept IPV6_V6ONLY=0 successfully, but the state
+		// still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
+		// stops preteding, but the transition period would
+		// cause unpredictable behavior and we need to avoid
+		// it.
+		//
+		// OpenBSD also doesn't support IPV6_V6ONLY=0 but it
+		// never pretends to accept IPV6_V6OLY=0. It always
+		// returns an error and we don't need to probe the
+		// capability.
+		probes = probes[:1]
+	}
 
 	for i := range probes {
 		s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
@@ -63,10 +86,10 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		if err := syscall.Bind(s, sa); err != nil {
 			continue
 		}
-		probes[i].ok = true
+		supps[i] = true
 	}
 
-	return probes[0].ok, probes[1].ok
+	return supps[0], supps[1]
 }
 
 // favoriteAddrFamily returns the appropriate address family to
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
index 8f43c846d9..89d4d7e0de 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -218,8 +218,6 @@ var dualStackTCPListenerTests = []struct {
 // listening address and same port.
 func TestDualStackTCPListener(t *testing.T) {
 	switch runtime.GOOS {
-	case "dragonfly":
-		t.Skip("not supported on DragonFly, see golang.org/issue/10729")
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
@@ -233,7 +231,7 @@ func TestDualStackTCPListener(t *testing.T) {
 			continue
 		}
 
-		if runtime.GOOS == "openbsd" && differentWildcardAddr(tt.address1, tt.address2) {
+		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
 			tt.xerr = nil
 		}
 		var firstErr, secondErr error
@@ -320,7 +318,7 @@ func TestDualStackUDPListener(t *testing.T) {
 			continue
 		}
 
-		if runtime.GOOS == "openbsd" && differentWildcardAddr(tt.address1, tt.address2) {
+		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
 			tt.xerr = nil
 		}
 		var firstErr, secondErr error
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 1f36184d55..064bc0b9f1 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -23,17 +23,34 @@ func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr,
 	}
 }
 
+// The Lookup APIs use various sources such as local database, DNS or
+// mDNS, and may use platform-dependent DNS stub resolver if possible.
+// The APIs accept any of forms for a query; host name in various
+// encodings, UTF-8 encoded net name, domain name, FQDN or absolute
+// FQDN, but the result would be one of the forms and it depends on
+// the circumstances.
+
 var lookupGoogleSRVTests = []struct {
 	service, proto, name string
 	cname, target        string
 }{
 	{
 		"xmpp-server", "tcp", "google.com",
-		".google.com", ".google.com",
+		"google.com", "google.com",
 	},
 	{
-		"", "", "_xmpp-server._tcp.google.com", // non-standard back door
-		".google.com", ".google.com",
+		"xmpp-server", "tcp", "google.com.",
+		"google.com", "google.com",
+	},
+
+	// non-standard back door
+	{
+		"", "", "_xmpp-server._tcp.google.com",
+		"google.com", "google.com",
+	},
+	{
+		"", "", "_xmpp-server._tcp.google.com.",
+		"google.com", "google.com",
 	},
 }
 
@@ -41,6 +58,9 @@ func TestLookupGoogleSRV(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
 	for _, tt := range lookupGoogleSRVTests {
 		cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
@@ -50,88 +70,126 @@ func TestLookupGoogleSRV(t *testing.T) {
 		if len(srvs) == 0 {
 			t.Error("got no record")
 		}
-		if !strings.Contains(cname, tt.cname) {
-			t.Errorf("got %q; want %q", cname, tt.cname)
+		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+			t.Errorf("got %s; want %s", cname, tt.cname)
 		}
 		for _, srv := range srvs {
-			if !strings.Contains(srv.Target, tt.target) {
-				t.Errorf("got %v; want a record containing %q", srv, tt.target)
+			if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") {
+				t.Errorf("got %v; want a record containing %s", srv, tt.target)
 			}
 		}
 	}
 }
 
+var lookupGmailMXTests = []struct {
+	name, host string
+}{
+	{"gmail.com", "google.com"},
+	{"gmail.com.", "google.com"},
+}
+
 func TestLookupGmailMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	mxs, err := LookupMX("gmail.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(mxs) == 0 {
-		t.Error("got no record")
-	}
-	for _, mx := range mxs {
-		if !strings.Contains(mx.Host, ".google.com") {
-			t.Errorf("got %v; want a record containing .google.com.", mx)
+	for _, tt := range lookupGmailMXTests {
+		mxs, err := LookupMX(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(mxs) == 0 {
+			t.Error("got no record")
+		}
+		for _, mx := range mxs {
+			if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") {
+				t.Errorf("got %v; want a record containing %s", mx, tt.host)
+			}
 		}
 	}
 }
 
+var lookupGmailNSTests = []struct {
+	name, host string
+}{
+	{"gmail.com", "google.com"},
+	{"gmail.com.", "google.com"},
+}
+
 func TestLookupGmailNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	nss, err := LookupNS("gmail.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(nss) == 0 {
-		t.Error("got no record")
-	}
-	for _, ns := range nss {
-		if !strings.Contains(ns.Host, ".google.com") {
-			t.Errorf("got %v; want a record containing .google.com.", ns)
+	for _, tt := range lookupGmailNSTests {
+		nss, err := LookupNS(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(nss) == 0 {
+			t.Error("got no record")
+		}
+		for _, ns := range nss {
+			if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") {
+				t.Errorf("got %v; want a record containing %s", ns, tt.host)
+			}
 		}
 	}
 }
 
+var lookupGmailTXTTests = []struct {
+	name, txt, host string
+}{
+	{"gmail.com", "spf", "google.com"},
+	{"gmail.com.", "spf", "google.com"},
+}
+
 func TestLookupGmailTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	txts, err := LookupTXT("gmail.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(txts) == 0 {
-		t.Error("got no record")
-	}
-	for _, txt := range txts {
-		if !strings.Contains(txt, "spf") {
-			t.Errorf("got %q; want a spf record", txt)
+	for _, tt := range lookupGmailTXTTests {
+		txts, err := LookupTXT(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(txts) == 0 {
+			t.Error("got no record")
+		}
+		for _, txt := range txts {
+			if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
+				t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
+			}
 		}
 	}
 }
 
 var lookupGooglePublicDNSAddrs = []struct {
-	addr string
-	name string
+	addr, name string
 }{
-	{"8.8.8.8", ".google.com."},
-	{"8.8.4.4", ".google.com."},
-	{"2001:4860:4860::8888", ".google.com."},
-	{"2001:4860:4860::8844", ".google.com."},
+	{"8.8.8.8", ".google.com"},
+	{"8.8.4.4", ".google.com"},
+	{"2001:4860:4860::8888", ".google.com"},
+	{"2001:4860:4860::8844", ".google.com"},
 }
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
 
 	for _, tt := range lookupGooglePublicDNSAddrs {
 		names, err := LookupAddr(tt.addr)
@@ -142,61 +200,97 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
 			t.Error("got no record")
 		}
 		for _, name := range names {
-			if !strings.HasSuffix(name, tt.name) {
-				t.Errorf("got %q; want a record containing %q", name, tt.name)
+			if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") {
+				t.Errorf("got %s; want a record containing %s", name, tt.name)
 			}
 		}
 	}
 }
 
+var lookupIANACNAMETests = []struct {
+	name, cname string
+}{
+	{"www.iana.org", "icann.org"},
+	{"www.iana.org.", "icann.org"},
+}
+
 func TestLookupIANACNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	cname, err := LookupCNAME("www.iana.org")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !strings.HasSuffix(cname, ".icann.org.") {
-		t.Errorf("got %q; want a record containing .icann.org.", cname)
+	for _, tt := range lookupIANACNAMETests {
+		cname, err := LookupCNAME(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+			t.Errorf("got %s; want a record containing %s", cname, tt.cname)
+		}
 	}
 }
 
+var lookupGoogleHostTests = []struct {
+	name string
+}{
+	{"google.com"},
+	{"google.com."},
+}
+
 func TestLookupGoogleHost(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	addrs, err := LookupHost("google.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(addrs) == 0 {
-		t.Error("got no record")
-	}
-	for _, addr := range addrs {
-		if ParseIP(addr) == nil {
-			t.Errorf("got %q; want a literal ip address", addr)
+	for _, tt := range lookupGoogleHostTests {
+		addrs, err := LookupHost(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(addrs) == 0 {
+			t.Error("got no record")
+		}
+		for _, addr := range addrs {
+			if ParseIP(addr) == nil {
+				t.Errorf("got %q; want a literal IP address", addr)
+			}
 		}
 	}
 }
 
+var lookupGoogleIPTests = []struct {
+	name string
+}{
+	{"google.com"},
+	{"google.com."},
+}
+
 func TestLookupGoogleIP(t *testing.T) {
 	if testing.Short() || !*testExternal {
 		t.Skip("avoid external network")
 	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
+	}
 
-	ips, err := LookupIP("google.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(ips) == 0 {
-		t.Error("got no record")
-	}
-	for _, ip := range ips {
-		if ip.To4() == nil && ip.To16() == nil {
-			t.Errorf("got %v; want an ip address", ip)
+	for _, tt := range lookupGoogleIPTests {
+		ips, err := LookupIP(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(ips) == 0 {
+			t.Error("got no record")
+		}
+		for _, ip := range ips {
+			if ip.To4() == nil && ip.To16() == nil {
+				t.Errorf("got %v; want an IP address", ip)
+			}
 		}
 	}
 }
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index f3f698cf23..04cbfd3e8b 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -20,9 +20,9 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
-	"internal/mime"
 	"io"
 	"log"
+	"mime"
 	"net/textproto"
 	"strings"
 	"time"
@@ -138,12 +138,30 @@ type Address struct {
 
 // Parses a single RFC 5322 address, e.g. "Barry Gibbs "
 func ParseAddress(address string) (*Address, error) {
-	return newAddrParser(address).parseAddress()
+	return (&addrParser{s: address}).parseAddress()
 }
 
 // ParseAddressList parses the given string as a list of addresses.
 func ParseAddressList(list string) ([]*Address, error) {
-	return newAddrParser(list).parseAddressList()
+	return (&addrParser{s: list}).parseAddressList()
+}
+
+// An AddressParser is an RFC 5322 address parser.
+type AddressParser struct {
+	// WordDecoder optionally specifies a decoder for RFC 2047 encoded-words.
+	WordDecoder *mime.WordDecoder
+}
+
+// Parse parses a single RFC 5322 address of the
+// form "Gogh Fir " or "foo@example.com".
+func (p *AddressParser) Parse(address string) (*Address, error) {
+	return (&addrParser{s: address, dec: p.WordDecoder}).parseAddress()
+}
+
+// ParseList parses the given string as a list of comma-separated addresses
+// of the form "Gogh Fir " or "foo@example.com".
+func (p *AddressParser) ParseList(list string) ([]*Address, error) {
+	return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList()
 }
 
 // String formats the address as a valid RFC 5322 address.
@@ -177,14 +195,12 @@ func (a *Address) String() string {
 		return b.String()
 	}
 
-	return mime.EncodeWord(a.Name) + " " + s
+	return mime.QEncoding.Encode("utf-8", a.Name) + " " + s
 }
 
-type addrParser []byte
-
-func newAddrParser(s string) *addrParser {
-	p := addrParser(s)
-	return &p
+type addrParser struct {
+	s   string
+	dec *mime.WordDecoder // may be nil
 }
 
 func (p *addrParser) parseAddressList() ([]*Address, error) {
@@ -210,7 +226,7 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
 
 // parseAddress parses a single RFC 5322 address at the start of p.
 func (p *addrParser) parseAddress() (addr *Address, err error) {
-	debug.Printf("parseAddress: %q", *p)
+	debug.Printf("parseAddress: %q", p.s)
 	p.skipSpace()
 	if p.empty() {
 		return nil, errors.New("mail: no address")
@@ -229,7 +245,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 		}, err
 	}
 	debug.Printf("parseAddress: not an addr-spec: %v", err)
-	debug.Printf("parseAddress: state is now %q", *p)
+	debug.Printf("parseAddress: state is now %q", p.s)
 
 	// display-name
 	var displayName string
@@ -263,7 +279,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 
 // consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
 func (p *addrParser) consumeAddrSpec() (spec string, err error) {
-	debug.Printf("consumeAddrSpec: %q", *p)
+	debug.Printf("consumeAddrSpec: %q", p.s)
 
 	orig := *p
 	defer func() {
@@ -313,7 +329,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 
 // consumePhrase parses the RFC 5322 phrase at the start of p.
 func (p *addrParser) consumePhrase() (phrase string, err error) {
-	debug.Printf("consumePhrase: [%s]", *p)
+	debug.Printf("consumePhrase: [%s]", p.s)
 	// phrase = 1*word
 	var words []string
 	for {
@@ -333,9 +349,8 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			word, err = p.consumeAtom(true)
 		}
 
-		// RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
-		if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
-			word, err = mime.DecodeWord(word)
+		if err == nil {
+			word, err = p.decodeRFC2047Word(word)
 		}
 
 		if err != nil {
@@ -363,14 +378,14 @@ Loop:
 		if i >= p.len() {
 			return "", errors.New("mail: unclosed quoted-string")
 		}
-		switch c := (*p)[i]; {
+		switch c := p.s[i]; {
 		case c == '"':
 			break Loop
 		case c == '\\':
 			if i+1 == p.len() {
 				return "", errors.New("mail: unclosed quoted-string")
 			}
-			qsb = append(qsb, (*p)[i+1])
+			qsb = append(qsb, p.s[i+1])
 			i += 2
 		case isQtext(c), c == ' ' || c == '\t':
 			// qtext (printable US-ASCII excluding " and \), or
@@ -381,7 +396,7 @@ Loop:
 			return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
 		}
 	}
-	*p = (*p)[i+1:]
+	p.s = p.s[i+1:]
 	return string(qsb), nil
 }
 
@@ -392,9 +407,9 @@ func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
 		return "", errors.New("mail: invalid string")
 	}
 	i := 1
-	for ; i < p.len() && isAtext((*p)[i], dot); i++ {
+	for ; i < p.len() && isAtext(p.s[i], dot); i++ {
 	}
-	atom, *p = string((*p)[:i]), (*p)[i:]
+	atom, p.s = string(p.s[:i]), p.s[i:]
 	return atom, nil
 }
 
@@ -402,17 +417,17 @@ func (p *addrParser) consume(c byte) bool {
 	if p.empty() || p.peek() != c {
 		return false
 	}
-	*p = (*p)[1:]
+	p.s = p.s[1:]
 	return true
 }
 
 // skipSpace skips the leading space and tab characters.
 func (p *addrParser) skipSpace() {
-	*p = bytes.TrimLeft(*p, " \t")
+	p.s = strings.TrimLeft(p.s, " \t")
 }
 
 func (p *addrParser) peek() byte {
-	return (*p)[0]
+	return p.s[0]
 }
 
 func (p *addrParser) empty() bool {
@@ -420,7 +435,37 @@ func (p *addrParser) empty() bool {
 }
 
 func (p *addrParser) len() int {
-	return len(*p)
+	return len(p.s)
+}
+
+func (p *addrParser) decodeRFC2047Word(s string) (string, error) {
+	if p.dec != nil {
+		return p.dec.DecodeHeader(s)
+	}
+
+	dec, err := rfc2047Decoder.Decode(s)
+	if err == nil {
+		return dec, nil
+	}
+
+	if _, ok := err.(charsetError); ok {
+		return s, err
+	}
+
+	// Ignore invalid RFC 2047 encoded-word errors.
+	return s, nil
+}
+
+var rfc2047Decoder = mime.WordDecoder{
+	CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+		return nil, charsetError(charset)
+	},
+}
+
+type charsetError string
+
+func (e charsetError) Error() string {
+	return fmt.Sprintf("charset not supported: %q", string(e))
 }
 
 var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
index 6ba48be04f..43574c6188 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -6,7 +6,9 @@ package mail
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
+	"mime"
 	"reflect"
 	"strings"
 	"testing"
@@ -278,6 +280,175 @@ func TestAddressParsing(t *testing.T) {
 	}
 }
 
+func TestAddressParser(t *testing.T) {
+	tests := []struct {
+		addrsStr string
+		exp      []*Address
+	}{
+		// Bare address
+		{
+			`jdoe@machine.example`,
+			[]*Address{{
+				Address: "jdoe@machine.example",
+			}},
+		},
+		// RFC 5322, Appendix A.1.1
+		{
+			`John Doe `,
+			[]*Address{{
+				Name:    "John Doe",
+				Address: "jdoe@machine.example",
+			}},
+		},
+		// RFC 5322, Appendix A.1.2
+		{
+			`"Joe Q. Public" `,
+			[]*Address{{
+				Name:    "Joe Q. Public",
+				Address: "john.q.public@example.com",
+			}},
+		},
+		{
+			`Mary Smith , jdoe@example.org, Who? `,
+			[]*Address{
+				{
+					Name:    "Mary Smith",
+					Address: "mary@x.test",
+				},
+				{
+					Address: "jdoe@example.org",
+				},
+				{
+					Name:    "Who?",
+					Address: "one@y.test",
+				},
+			},
+		},
+		{
+			`, "Giant; \"Big\" Box" `,
+			[]*Address{
+				{
+					Address: "boss@nil.test",
+				},
+				{
+					Name:    `Giant; "Big" Box`,
+					Address: "sysservices@example.net",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded ISO-8859-1 address.
+		{
+			`=?iso-8859-1?q?J=F6rg_Doe?= `,
+			[]*Address{
+				{
+					Name:    `Jörg Doe`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal.
+		{
+			`=?us-ascii?q?J=6Frg_Doe?= `,
+			[]*Address{
+				{
+					Name:    `Jorg Doe`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded ISO-8859-15 address.
+		{
+			`=?ISO-8859-15?Q?J=F6rg_Doe?= `,
+			[]*Address{
+				{
+					Name:    `Jörg Doe`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// RFC 2047 "B"-encoded windows-1252 address.
+		{
+			`=?windows-1252?q?Andr=E9?= Pirard `,
+			[]*Address{
+				{
+					Name:    `André Pirard`,
+					Address: "PIRARD@vm1.ulg.ac.be",
+				},
+			},
+		},
+		// Custom example of RFC 2047 "B"-encoded ISO-8859-15 address.
+		{
+			`=?ISO-8859-15?B?SvZyZw==?= `,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// Custom example of RFC 2047 "B"-encoded UTF-8 address.
+		{
+			`=?UTF-8?B?SsO2cmc=?= `,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// Custom example with "." in name. For issue 4938
+		{
+			`Asem H. `,
+			[]*Address{
+				{
+					Name:    `Asem H.`,
+					Address: "noreply@example.com",
+				},
+			},
+		},
+	}
+
+	ap := AddressParser{WordDecoder: &mime.WordDecoder{
+		CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+			in, err := ioutil.ReadAll(input)
+			if err != nil {
+				return nil, err
+			}
+
+			switch charset {
+			case "iso-8859-15":
+				in = bytes.Replace(in, []byte("\xf6"), []byte("ö"), -1)
+			case "windows-1252":
+				in = bytes.Replace(in, []byte("\xe9"), []byte("é"), -1)
+			}
+
+			return bytes.NewReader(in), nil
+		},
+	}}
+
+	for _, test := range tests {
+		if len(test.exp) == 1 {
+			addr, err := ap.Parse(test.addrsStr)
+			if err != nil {
+				t.Errorf("Failed parsing (single) %q: %v", test.addrsStr, err)
+				continue
+			}
+			if !reflect.DeepEqual([]*Address{addr}, test.exp) {
+				t.Errorf("Parse (single) of %q: got %+v, want %+v", test.addrsStr, addr, test.exp)
+			}
+		}
+
+		addrs, err := ap.ParseList(test.addrsStr)
+		if err != nil {
+			t.Errorf("Failed parsing (list) %q: %v", test.addrsStr, err)
+			continue
+		}
+		if !reflect.DeepEqual(addrs, test.exp) {
+			t.Errorf("Parse (list) of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
+		}
+	}
+}
+
 func TestAddressFormatting(t *testing.T) {
 	tests := []struct {
 		addr *Address
diff --git a/src/net/main_test.go b/src/net/main_test.go
index a56b9cd5f9..f3f8b1a900 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -30,10 +30,16 @@ var (
 
 	// If external IPv4 connectivity exists, we can try dialing
 	// non-node/interface local scope IPv4 addresses.
+	// On Windows, Lookup APIs may not return IPv4-related
+	// resource records when a node has no external IPv4
+	// connectivity.
 	testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists")
 
 	// If external IPv6 connectivity exists, we can try dialing
 	// non-node/interface local scope IPv6 addresses.
+	// On Windows, Lookup APIs may not return IPv6-related
+	// resource records when a node has no external IPv6
+	// connectivity.
 	testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists")
 )
 
@@ -43,16 +49,26 @@ func TestMain(m *testing.M) {
 
 	st := m.Run()
 
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
-	if !testing.Short() {
-		printLeakedGoroutines()
-		printLeakedSockets()
+	testHookUninstaller.Do(uninstallTestHooks)
+	if testing.Verbose() {
+		printRunningGoroutines()
+		printInflightSockets()
 		printSocketStats()
 	}
 	forceCloseSockets()
 	os.Exit(st)
 }
 
+type ipv6LinkLocalUnicastTest struct {
+	network, address string
+	nameLookup       bool
+}
+
+var (
+	ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest
+	ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest
+)
+
 func setupTestData() {
 	if supportsIPv4 {
 		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
@@ -75,7 +91,8 @@ func setupTestData() {
 		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
 	}
 
-	if ifi := loopbackInterface(); ifi != nil {
+	ifi := loopbackInterface()
+	if ifi != nil {
 		index := fmt.Sprintf("%v", ifi.Index)
 		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
 			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
@@ -90,23 +107,60 @@ func setupTestData() {
 			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
 		}...)
 	}
+
+	addr := ipv6LinkLocalUnicastAddr(ifi)
+	if addr != "" {
+		if runtime.GOOS != "dragonfly" {
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[" + addr + "%" + ifi.Name + "]:0", false},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[" + addr + "%" + ifi.Name + "]:0", false},
+			}...)
+		}
+		ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+			{"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false},
+		}...)
+		ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+			{"udp6", "[" + addr + "%" + ifi.Name + "]:0", false},
+		}...)
+		switch runtime.GOOS {
+		case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[localhost%" + ifi.Name + "]:0", true},
+				{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[localhost%" + ifi.Name + "]:0", true},
+				{"udp6", "[localhost%" + ifi.Name + "]:0", true},
+			}...)
+		case "linux":
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+				{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+				{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			}...)
+		}
+	}
 }
 
-func printLeakedGoroutines() {
-	gss := leakedGoroutines()
+func printRunningGoroutines() {
+	gss := runningGoroutines()
 	if len(gss) == 0 {
 		return
 	}
-	fmt.Fprintf(os.Stderr, "Leaked goroutines:\n")
+	fmt.Fprintf(os.Stderr, "Running goroutines:\n")
 	for _, gs := range gss {
 		fmt.Fprintf(os.Stderr, "%v\n", gs)
 	}
 	fmt.Fprintf(os.Stderr, "\n")
 }
 
-// leakedGoroutines returns a list of remaining goroutines used in
-// test cases.
-func leakedGoroutines() []string {
+// runningGoroutines returns a list of remaining goroutines.
+func runningGoroutines() []string {
 	var gss []string
 	b := make([]byte, 2<<20)
 	b = b[:runtime.Stack(b, true)]
@@ -125,12 +179,12 @@ func leakedGoroutines() []string {
 	return gss
 }
 
-func printLeakedSockets() {
+func printInflightSockets() {
 	sos := sw.Sockets()
 	if len(sos) == 0 {
 		return
 	}
-	fmt.Fprintf(os.Stderr, "Leaked sockets:\n")
+	fmt.Fprintf(os.Stderr, "Inflight sockets:\n")
 	for s, so := range sos {
 		fmt.Fprintf(os.Stderr, "%v: %v\n", s, so)
 	}
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index 62bcfa4022..dd6f4df3b9 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -186,7 +186,7 @@ func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
 	for i := range dss.lns {
 		ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
 		if err != nil {
-			for _, ln := range dss.lns {
+			for _, ln := range dss.lns[:i] {
 				ln.Listener.Close()
 			}
 			return nil, err
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index 21b47964a4..da03e10b36 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -15,16 +15,31 @@ import (
 	"time"
 )
 
+func toErrno(err error) (syscall.Errno, bool) {
+	operr, ok := err.(*OpError)
+	if !ok {
+		return 0, false
+	}
+	syserr, ok := operr.Err.(*os.SyscallError)
+	if !ok {
+		return 0, false
+	}
+	errno, ok := syserr.Err.(syscall.Errno)
+	if !ok {
+		return 0, false
+	}
+	return errno, true
+}
+
+// TestAcceptIgnoreSomeErrors tests that windows TCPListener.AcceptTCP
+// handles broken connections. It verifies that broken connections do
+// not affect future connections.
 func TestAcceptIgnoreSomeErrors(t *testing.T) {
-	recv := func(ln Listener) (string, error) {
+	recv := func(ln Listener, ignoreSomeReadErrors bool) (string, error) {
 		c, err := ln.Accept()
 		if err != nil {
 			// Display windows errno in error message.
-			operr, ok := err.(*OpError)
-			if !ok {
-				return "", err
-			}
-			errno, ok := operr.Err.(syscall.Errno)
+			errno, ok := toErrno(err)
 			if !ok {
 				return "", err
 			}
@@ -34,10 +49,14 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 
 		b := make([]byte, 100)
 		n, err := c.Read(b)
-		if err != nil && err != io.EOF {
-			return "", err
+		if err == nil || err == io.EOF {
+			return string(b[:n]), nil
 		}
-		return string(b[:n]), nil
+		errno, ok := toErrno(err)
+		if ok && ignoreSomeReadErrors && (errno == syscall.ERROR_NETNAME_DELETED || errno == syscall.WSAECONNRESET) {
+			return "", nil
+		}
+		return "", err
 	}
 
 	send := func(addr string, data string) error {
@@ -121,13 +140,13 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}()
 
 	// Receive first or second connection.
-	s, err := recv(ln)
+	s, err := recv(ln, true)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
 	switch s {
 	case "":
-		// First connection data is received, lets get second connection data.
+		// First connection data is received, let's get second connection data.
 	case "abc":
 		// First connection is lost forever, but that is ok.
 		return
@@ -136,7 +155,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}
 
 	// Get second connection data.
-	s, err = recv(ln)
+	s, err = recv(ln, false)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index b700091dc5..d6248520f3 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -14,7 +14,8 @@ import (
 // testableNetwork reports whether network is testable on the current
 // platform configuration.
 func testableNetwork(network string) bool {
-	switch ss := strings.Split(network, ":"); ss[0] {
+	ss := strings.Split(network, ":")
+	switch ss[0] {
 	case "ip+nopriv":
 		switch runtime.GOOS {
 		case "nacl":
@@ -46,6 +47,16 @@ func testableNetwork(network string) bool {
 			return false
 		}
 	}
+	switch ss[0] {
+	case "tcp4", "udp4", "ip4":
+		if !supportsIPv4 {
+			return false
+		}
+	case "tcp6", "udp6", "ip6":
+		if !supportsIPv6 {
+			return false
+		}
+	}
 	return true
 }
 
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 00e4dbf376..1b4a586a7e 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -25,7 +25,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
 		}
 	}
-	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+	if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
 		// is otherwise.  Note that some operating systems
 		// never admit this option.
diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go
index 6229df2869..2191c91fa3 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -58,7 +58,7 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) {
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	const msgLen = 512
 	conns := b.N
@@ -168,7 +168,7 @@ func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
 }
 
 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	// The benchmark creates GOMAXPROCS client/server pairs.
 	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
@@ -367,39 +367,11 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	ifi := loopbackInterface()
-	if ifi == nil {
-		t.Skip("loopback interface not found")
-	}
-	laddr := ipv6LinkLocalUnicastAddr(ifi)
-	if laddr == "" {
-		t.Skip("ipv6 unicast address on loopback not found")
+		t.Skip("IPv6 is not supported")
 	}
 
-	type test struct {
-		net, addr  string
-		nameLookup bool
-	}
-	var tests = []test{
-		{"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
-		{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
-	}
-	switch runtime.GOOS {
-	case "darwin", "freebsd", "openbsd", "netbsd":
-		tests = append(tests, []test{
-			{"tcp", "[localhost%" + ifi.Name + "]:0", true},
-			{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
-		}...)
-	case "linux":
-		tests = append(tests, []test{
-			{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
-			{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
-		}...)
-	}
-	for i, tt := range tests {
-		ln, err := Listen(tt.net, tt.addr)
+	for i, tt := range ipv6LinkLocalUnicastTCPTests {
+		ln, err := Listen(tt.network, tt.address)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
@@ -420,7 +392,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		c, err := Dial(tt.net, ls.Listener.Addr().String())
+		c, err := Dial(tt.network, ls.Listener.Addr().String())
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index 1f43521a9e..51a8e97915 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -13,11 +13,6 @@ import (
 	"time"
 )
 
-// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
-// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic
-// will not be routed to an IPv6 socket - two separate sockets are required
-// if both AFs are to be supported. See inet6(4) on OpenBSD for details.
-
 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index cafa3755f6..9688c21699 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -696,14 +696,18 @@ func TestWriteTimeoutFluctuation(t *testing.T) {
 	}
 	defer c.Close()
 
-	max := time.NewTimer(time.Second)
+	d := time.Second
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		d = 3 * time.Second // see golang.org/issue/10775
+	}
+	max := time.NewTimer(d)
 	defer max.Stop()
 	ch := make(chan error)
 	go timeoutTransmitter(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
 
 	select {
 	case <-max.C:
-		t.Fatal("Write took over 1s; expected 0.1s")
+		t.Fatalf("Write took over %v; expected 0.1s", d)
 	case err := <-ch:
 		if perr := parseWriteError(err); perr != nil {
 			t.Error(perr)
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index 2213468e79..b25f96a3fd 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -238,55 +238,32 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	ifi := loopbackInterface()
-	if ifi == nil {
-		t.Skip("loopback interface not found")
-	}
-	laddr := ipv6LinkLocalUnicastAddr(ifi)
-	if laddr == "" {
-		t.Skip("ipv6 unicast address on loopback not found")
+		t.Skip("IPv6 is not supported")
 	}
 
-	type test struct {
-		net, addr  string
-		nameLookup bool
-	}
-	var tests = []test{
-		{"udp", "[" + laddr + "%" + ifi.Name + "]:0", false},
-		{"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
-	}
-	// The first udp test fails on DragonFly - see issue 7473.
-	if runtime.GOOS == "dragonfly" {
-		tests = tests[1:]
-	}
-	switch runtime.GOOS {
-	case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
-		tests = append(tests, []test{
-			{"udp", "[localhost%" + ifi.Name + "]:0", true},
-			{"udp6", "[localhost%" + ifi.Name + "]:0", true},
-		}...)
-	case "linux":
-		tests = append(tests, []test{
-			{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
-			{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
-		}...)
-	}
-	for _, tt := range tests {
-		c1, err := ListenPacket(tt.net, tt.addr)
+	for i, tt := range ipv6LinkLocalUnicastUDPTests {
+		c1, err := ListenPacket(tt.network, tt.address)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
 			t.Log(err)
 			continue
 		}
-		defer c1.Close()
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		c2, err := Dial(tt.net, c1.LocalAddr().String())
+		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -302,12 +279,12 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 			t.Fatal(err)
 		}
 		b := make([]byte, 32)
-		if _, from, err := c1.ReadFrom(b); err != nil {
+		if _, err := c2.Read(b); err != nil {
 			t.Fatal(err)
-		} else {
-			if ra, ok := from.(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
-				t.Fatalf("got %v; expected a proper address with zone identifier", ra)
-			}
+		}
+
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
 		}
 	}
 }
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 949f666d74..7bbcf6e4cb 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -200,9 +200,16 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on ifi, which specifies the
-// interface to join.  ListenMulticastUDP uses default multicast
-// interface if ifi is nil.
-func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: syscall.EPLAN9}
+// addressed to the group address gaddr on the interface ifi.
+// Network must be "udp", "udp4" or "udp6".
+// ListenMulticastUDP uses the system-assigned multicast interface
+// when ifi is nil, although this is not recommended because the
+// assignment depends on platforms and sometimes it might require
+// routing configuration.
+//
+// ListenMulticastUDP is just for convenience of simple, small
+// applications. There are golang.org/x/net/ipv4 and
+// golang.org/x/net/ipv6 packages for general purpose uses.
+func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: syscall.EPLAN9}
 }
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 2e43068be3..36ada176a1 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -220,32 +220,39 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on ifi, which specifies the
-// interface to join.  ListenMulticastUDP uses default multicast
-// interface if ifi is nil.
-func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	switch net {
+// addressed to the group address gaddr on the interface ifi.
+// Network must be "udp", "udp4" or "udp6".
+// ListenMulticastUDP uses the system-assigned multicast interface
+// when ifi is nil, although this is not recommended because the
+// assignment depends on platforms and sometimes it might require
+// routing configuration.
+//
+// ListenMulticastUDP is just for convenience of simple, small
+// applications. There are golang.org/x/net/ipv4 and
+// golang.org/x/net/ipv6 packages for general purpose uses.
+func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	switch network {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: UnknownNetworkError(network)}
 	}
 	if gaddr == nil || gaddr.IP == nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: errMissingAddress}
 	}
-	fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
+	fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: gaddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
 	}
 	c := newUDPConn(fd)
 	if ip4 := gaddr.IP.To4(); ip4 != nil {
 		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: net, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
+			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
 		}
 	} else {
 		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: net, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
 		}
 	}
 	return c, nil
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 877b2efd84..9a99f742d6 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -4388,18 +4388,16 @@ func TestCallGC(t *testing.T) {
 type funcLayoutTest struct {
 	rcvr, t                  Type
 	size, argsize, retOffset uintptr
-	stack                    []byte
+	stack                    []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
 	gc                       []byte
 }
 
 var funcLayoutTests []funcLayoutTest
 
 func init() {
-	var argAlign = PtrSize
-	var naclExtra []byte
+	var argAlign uintptr = PtrSize
 	if runtime.GOARCH == "amd64p32" {
 		argAlign = 2 * PtrSize
-		naclExtra = append(naclExtra, BitsScalar)
 	}
 	roundup := func(x uintptr, a uintptr) uintptr {
 		return (x + a - 1) / a * a
@@ -4412,17 +4410,15 @@ func init() {
 			6 * PtrSize,
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsPointer, BitsScalar, BitsPointer},
-			[]byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar},
+			[]byte{1, 0, 1},
+			[]byte{1, 0, 1, 0, 1},
 		})
 
-	var r, s []byte
+	var r []byte
 	if PtrSize == 4 {
-		r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
-		s = append([]byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer, BitsScalar}, naclExtra...)
+		r = []byte{0, 0, 0, 1}
 	} else {
-		r = []byte{BitsScalar, BitsScalar, BitsPointer}
-		s = []byte{BitsScalar, BitsScalar, BitsPointer, BitsScalar}
+		r = []byte{0, 0, 1}
 	}
 	funcLayoutTests = append(funcLayoutTests,
 		funcLayoutTest{
@@ -4432,7 +4428,7 @@ func init() {
 			roundup(3*4, PtrSize) + PtrSize + 2,
 			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			r,
-			s,
+			r,
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4442,8 +4438,8 @@ func init() {
 			4 * PtrSize,
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
-			[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
+			[]byte{1, 0, 1, 1},
+			[]byte{1, 0, 1, 1},
 		})
 
 	type S struct {
@@ -4457,8 +4453,8 @@ func init() {
 			4 * PtrSize,
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
-			[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
+			[]byte{0, 0, 1, 1},
+			[]byte{0, 0, 1, 1},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4468,8 +4464,8 @@ func init() {
 			roundup(3*PtrSize, argAlign),
 			3 * PtrSize,
 			roundup(3*PtrSize, argAlign),
-			[]byte{BitsPointer, BitsScalar, BitsPointer},
-			append([]byte{BitsPointer, BitsScalar, BitsPointer}, naclExtra...),
+			[]byte{1, 0, 1},
+			[]byte{1, 0, 1},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4480,7 +4476,7 @@ func init() {
 			PtrSize,
 			roundup(PtrSize, argAlign),
 			[]byte{},
-			append([]byte{BitsScalar}, naclExtra...),
+			[]byte{},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4491,7 +4487,7 @@ func init() {
 			0,
 			0,
 			[]byte{},
-			[]byte{BitsScalar},
+			[]byte{},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4501,8 +4497,8 @@ func init() {
 			2 * PtrSize,
 			2 * PtrSize,
 			2 * PtrSize,
-			[]byte{BitsPointer},
-			[]byte{BitsPointer, BitsScalar},
+			[]byte{1},
+			[]byte{1},
 			// Note: this one is tricky, as the receiver is not a pointer.  But we
 			// pass the receiver by reference to the autogenerated pointer-receiver
 			// version of the function.
@@ -4532,3 +4528,139 @@ func TestFuncLayout(t *testing.T) {
 		}
 	}
 }
+
+func verifyGCBits(t *testing.T, typ Type, bits []byte) {
+	heapBits := GCBits(New(typ).Interface())
+	if !bytes.Equal(heapBits, bits) {
+		t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits)
+	}
+}
+
+func TestGCBits(t *testing.T) {
+	verifyGCBits(t, TypeOf((*byte)(nil)), []byte{1})
+
+	// Building blocks for types seen by the compiler (like [2]Xscalar).
+	// The compiler will create the type structures for the derived types,
+	// including their GC metadata.
+	type Xscalar struct{ x uintptr }
+	type Xptr struct{ x *byte }
+	type Xptrscalar struct {
+		*byte
+		uintptr
+	}
+	type Xscalarptr struct {
+		uintptr
+		*byte
+	}
+
+	var Tscalar, Tptr, Tscalarptr, Tptrscalar Type
+	{
+		// Building blocks for types constructed by reflect.
+		// This code is in a separate block so that code below
+		// cannot accidentally refer to these.
+		// The compiler must NOT see types derived from these
+		// (for example, [2]Scalar must NOT appear in the program),
+		// or else reflect will use it instead of having to construct one.
+		// The goal is to test the construction.
+		type Scalar struct{ x uintptr }
+		type Ptr struct{ x *byte }
+		type Ptrscalar struct {
+			*byte
+			uintptr
+		}
+		type Scalarptr struct {
+			uintptr
+			*byte
+		}
+		Tscalar = TypeOf(Scalar{})
+		Tptr = TypeOf(Ptr{})
+		Tscalarptr = TypeOf(Scalarptr{})
+		Tptrscalar = TypeOf(Ptrscalar{})
+	}
+
+	empty := []byte{}
+
+	verifyGCBits(t, TypeOf(Xscalar{}), empty)
+	verifyGCBits(t, Tscalar, empty)
+	verifyGCBits(t, TypeOf(Xptr{}), lit(1))
+	verifyGCBits(t, Tptr, lit(1))
+	verifyGCBits(t, TypeOf(Xscalarptr{}), lit(0, 1))
+	verifyGCBits(t, Tscalarptr, lit(0, 1))
+	verifyGCBits(t, TypeOf(Xptrscalar{}), lit(1))
+	verifyGCBits(t, Tptrscalar, lit(1))
+
+	verifyGCBits(t, TypeOf([0]Xptr{}), empty)
+	verifyGCBits(t, ArrayOf(0, Tptr), empty)
+	verifyGCBits(t, TypeOf([1]Xptrscalar{}), lit(1))
+	verifyGCBits(t, ArrayOf(1, Tptrscalar), lit(1))
+	verifyGCBits(t, TypeOf([2]Xscalar{}), empty)
+	verifyGCBits(t, ArrayOf(2, Tscalar), empty)
+	verifyGCBits(t, TypeOf([100]Xscalar{}), empty)
+	verifyGCBits(t, ArrayOf(100, Tscalar), empty)
+	verifyGCBits(t, TypeOf([2]Xptr{}), lit(1, 1))
+	verifyGCBits(t, ArrayOf(2, Tptr), lit(1, 1))
+	verifyGCBits(t, TypeOf([100]Xptr{}), rep(100, lit(1)))
+	verifyGCBits(t, ArrayOf(100, Tptr), rep(100, lit(1)))
+	verifyGCBits(t, TypeOf([2]Xscalarptr{}), lit(0, 1, 0, 1))
+	verifyGCBits(t, ArrayOf(2, Tscalarptr), lit(0, 1, 0, 1))
+	verifyGCBits(t, TypeOf([100]Xscalarptr{}), rep(100, lit(0, 1)))
+	verifyGCBits(t, ArrayOf(100, Tscalarptr), rep(100, lit(0, 1)))
+	verifyGCBits(t, TypeOf([2]Xptrscalar{}), lit(1, 0, 1))
+	verifyGCBits(t, ArrayOf(2, Tptrscalar), lit(1, 0, 1))
+	verifyGCBits(t, TypeOf([100]Xptrscalar{}), rep(100, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(100, Tptrscalar), rep(100, lit(1, 0)))
+	verifyGCBits(t, TypeOf([1][100]Xptrscalar{}), rep(100, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(1, ArrayOf(100, Tptrscalar)), rep(100, lit(1, 0)))
+	verifyGCBits(t, TypeOf([2][100]Xptrscalar{}), rep(200, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(2, ArrayOf(100, Tptrscalar)), rep(200, lit(1, 0)))
+
+	verifyGCBits(t, TypeOf((chan [100]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1))
+
+	verifyGCBits(t, TypeOf((func([100]Xscalarptr))(nil)), lit(1))
+	verifyGCBits(t, FuncOf([]Type{ArrayOf(100, Tscalarptr)}, nil, false), lit(1))
+
+	verifyGCBits(t, TypeOf((map[[100]Xscalarptr]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, MapOf(ArrayOf(100, Tscalarptr), Tscalar), lit(1))
+
+	verifyGCBits(t, TypeOf((*[100]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, PtrTo(ArrayOf(100, Tscalar)), lit(1))
+
+	verifyGCBits(t, TypeOf(([][100]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, SliceOf(ArrayOf(100, Tscalar)), lit(1))
+
+	hdr := make([]byte, 8/PtrSize)
+	verifyGCBits(t, MapBucketOf(Tscalar, Tptr), join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1)))
+	verifyGCBits(t, MapBucketOf(Tscalarptr, Tptr), join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1)))
+	verifyGCBits(t, MapBucketOf(Tscalar, Tscalar), empty)
+	verifyGCBits(t, MapBucketOf(ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar)), join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1)))
+	verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar)), join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
+	verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar)), join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
+	verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar)), join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1)))
+	verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar)), join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1)))
+}
+
+func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) }
+func join(b ...[]byte) []byte    { return bytes.Join(b, nil) }
+func lit(x ...byte) []byte       { return x }
+
+func TestTypeOfTypeOf(t *testing.T) {
+	// Check that all the type constructors return concrete *rtype implementations.
+	// It's difficult to test directly because the reflect package is only at arm's length.
+	// The easiest thing to do is just call a function that crashes if it doesn't get an *rtype.
+	check := func(name string, typ Type) {
+		if underlying := TypeOf(typ).String(); underlying != "*reflect.rtype" {
+			t.Errorf("%v returned %v, not *reflect.rtype", name, underlying)
+		}
+	}
+
+	type T struct{ int }
+	check("TypeOf", TypeOf(T{}))
+
+	check("ArrayOf", ArrayOf(10, TypeOf(T{})))
+	check("ChanOf", ChanOf(BothDir, TypeOf(T{})))
+	check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false))
+	check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{})))
+	check("PtrTo", PtrTo(TypeOf(T{})))
+	check("SliceOf", SliceOf(TypeOf(T{})))
+}
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index c89e9c1298..a4e2e7e28c 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -4,6 +4,8 @@
 
 package reflect
 
+import "unsafe"
+
 // MakeRO returns a copy of v with the read-only flag set.
 func MakeRO(v Value) Value {
 	v.flag |= flagRO
@@ -18,8 +20,6 @@ func IsRO(v Value) bool {
 var CallGC = &callGC
 
 const PtrSize = ptrSize
-const BitsPointer = bitsPointer
-const BitsScalar = bitsScalar
 
 func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte, gc []byte, ptrs bool) {
 	var ft *rtype
@@ -30,15 +30,15 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr,
 		ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
 	}
 	frametype = ft
-	for i := uint32(0); i < s.n; i += 2 {
-		stack = append(stack, s.data[i/8]>>(i%8)&3)
+	for i := uint32(0); i < s.n; i++ {
+		stack = append(stack, s.data[i/8]>>(i%8)&1)
 	}
 	if ft.kind&kindGCProg != 0 {
 		panic("can't handle gc programs")
 	}
-	gcdata := (*[1000]byte)(ft.gc[0])
-	for i := uintptr(0); i < ft.size/ptrSize; i++ {
-		gc = append(gc, gcdata[i/2]>>(i%2*4+2)&3)
+	gcdata := (*[1000]byte)(unsafe.Pointer(ft.gcdata))
+	for i := uintptr(0); i < ft.ptrdata/ptrSize; i++ {
+		gc = append(gc, gcdata[i/8]>>(i%8)&1)
 	}
 	ptrs = ft.kind&kindNoPointers == 0
 	return
@@ -53,3 +53,11 @@ func TypeLinks() []string {
 	}
 	return r
 }
+
+var GCBits = gcbits
+
+func gcbits(interface{}) []byte // provided by runtime
+
+func MapBucketOf(x, y Type) Type {
+	return bucketOf(x.(*rtype), y.(*rtype))
+}
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 5315bd3971..e55a0d146c 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -247,17 +247,17 @@ const (
 type rtype struct {
 	size          uintptr
 	ptrdata       uintptr
-	hash          uint32            // hash of type; avoids computation in hash tables
-	_             uint8             // unused/padding
-	align         uint8             // alignment of variable with this type
-	fieldAlign    uint8             // alignment of struct field with this type
-	kind          uint8             // enumeration for C
-	alg           *typeAlg          // algorithm table
-	gc            [2]unsafe.Pointer // garbage collection data
-	string        *string           // string form; unnecessary but undeniably useful
-	*uncommonType                   // (relatively) uncommon fields
-	ptrToThis     *rtype            // type for pointer to this type, if used in binary or has methods
-	zero          unsafe.Pointer    // pointer to zero value
+	hash          uint32         // hash of type; avoids computation in hash tables
+	_             uint8          // unused/padding
+	align         uint8          // alignment of variable with this type
+	fieldAlign    uint8          // alignment of struct field with this type
+	kind          uint8          // enumeration for C
+	alg           *typeAlg       // algorithm table
+	gcdata        *byte          // garbage collection data
+	string        *string        // string form; unnecessary but undeniably useful
+	*uncommonType                // (relatively) uncommon fields
+	ptrToThis     *rtype         // type for pointer to this type, if used in binary or has methods
+	zero          unsafe.Pointer // pointer to zero value
 }
 
 // a copy of runtime.typeAlg
@@ -1087,7 +1087,6 @@ func (t *rtype) ptrTo() *rtype {
 
 	p.uncommonType = nil
 	p.ptrToThis = nil
-	p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
 	p.elem = t
 
 	ptrMap.m[t] = p
@@ -1467,7 +1466,6 @@ func ChanOf(dir ChanDir, t Type) Type {
 	ch.elem = typ
 	ch.uncommonType = nil
 	ch.ptrToThis = nil
-	ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
 
 	return cachePut(ckey, &ch.rtype)
 }
@@ -1530,7 +1528,6 @@ func MapOf(key, elem Type) Type {
 	mt.reflexivekey = isReflexive(ktyp)
 	mt.uncommonType = nil
 	mt.ptrToThis = nil
-	mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
 
 	return cachePut(ckey, &mt.rtype)
 }
@@ -1610,10 +1607,9 @@ func FuncOf(in, out []Type, variadic bool) Type {
 	ft.string = &str
 	ft.uncommonType = nil
 	ft.ptrToThis = nil
-	ft.zero = unsafe.Pointer(&make([]byte, ft.size)[0])
 	funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
 
-	return ft
+	return &ft.rtype
 }
 
 // funcStr builds a string representation of a funcType.
@@ -1674,125 +1670,14 @@ func isReflexive(t *rtype) bool {
 	}
 }
 
-// gcProg is a helper type for generatation of GC pointer info.
-type gcProg struct {
-	gc       []byte
-	size     uintptr // size of type in bytes
-	hasPtr   bool
-	lastZero uintptr // largest offset of a zero-byte field
-}
-
-func (gc *gcProg) append(v byte) {
-	gc.align(unsafe.Sizeof(uintptr(0)))
-	gc.appendWord(v)
-}
-
-// Appends t's type info to the current program.
-func (gc *gcProg) appendProg(t *rtype) {
-	gc.align(uintptr(t.align))
-	if !t.pointers() {
-		gc.size += t.size
-		if t.size == 0 {
-			gc.lastZero = gc.size
-		}
-		return
-	}
-	switch t.Kind() {
-	default:
-		panic("reflect: non-pointer type marked as having pointers")
-	case Ptr, UnsafePointer, Chan, Func, Map:
-		gc.appendWord(bitsPointer)
-	case Slice:
-		gc.appendWord(bitsPointer)
-		gc.appendWord(bitsScalar)
-		gc.appendWord(bitsScalar)
-	case String:
-		gc.appendWord(bitsPointer)
-		gc.appendWord(bitsScalar)
-	case Array:
-		c := t.Len()
-		e := t.Elem().common()
-		for i := 0; i < c; i++ {
-			gc.appendProg(e)
-		}
-	case Interface:
-		gc.appendWord(bitsPointer)
-		gc.appendWord(bitsPointer)
-	case Struct:
-		oldsize := gc.size
-		c := t.NumField()
-		for i := 0; i < c; i++ {
-			gc.appendProg(t.Field(i).Type.common())
-		}
-		if gc.size > oldsize+t.size {
-			panic("reflect: struct components are larger than the struct itself")
-		}
-		gc.size = oldsize + t.size
-	}
-}
-
-func (gc *gcProg) appendWord(v byte) {
-	ptrsize := unsafe.Sizeof(uintptr(0))
-	if gc.size%ptrsize != 0 {
-		panic("reflect: unaligned GC program")
-	}
-	nptr := gc.size / ptrsize
-	for uintptr(len(gc.gc)) < nptr/2+1 {
-		gc.gc = append(gc.gc, 0x44) // BitsScalar
-	}
-	gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2))
-	gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2)
-	gc.size += ptrsize
-	if v == bitsPointer {
-		gc.hasPtr = true
-	}
-}
-
-func (gc *gcProg) finalize() (unsafe.Pointer, bool) {
-	if gc.size == 0 {
-		return nil, false
-	}
-	if gc.lastZero == gc.size {
-		gc.size++
-	}
-	ptrsize := unsafe.Sizeof(uintptr(0))
-	gc.align(ptrsize)
-	nptr := gc.size / ptrsize
-	for uintptr(len(gc.gc)) < nptr/2+1 {
-		gc.gc = append(gc.gc, 0x44) // BitsScalar
-	}
-	// If number of words is odd, repeat the mask twice.
-	// Compiler does the same.
-	if nptr%2 != 0 {
-		for i := uintptr(0); i < nptr; i++ {
-			gc.appendWord(extractGCWord(gc.gc, i))
-		}
-	}
-	return unsafe.Pointer(&gc.gc[0]), gc.hasPtr
-}
-
-func extractGCWord(gc []byte, i uintptr) byte {
-	return (gc[i/2] >> ((i%2)*4 + 2)) & 3
-}
-
-func (gc *gcProg) align(a uintptr) {
-	gc.size = align(gc.size, a)
-}
-
-// These constants must stay in sync with ../runtime/mbitmap.go.
-const (
-	bitsScalar  = 1
-	bitsPointer = 2
-)
-
 // Make sure these routines stay in sync with ../../runtime/hashmap.go!
 // These types exist only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in string
 // for possible debugging use.
 const (
-	bucketSize = 8
-	maxKeySize = 128
-	maxValSize = 128
+	bucketSize uintptr = 8
+	maxKeySize uintptr = 128
+	maxValSize uintptr = 128
 )
 
 func bucketOf(ktyp, etyp *rtype) *rtype {
@@ -1809,33 +1694,70 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 	if etyp.size > maxValSize {
 		etyp = PtrTo(etyp).(*rtype)
 	}
-	ptrsize := unsafe.Sizeof(uintptr(0))
 
-	var gc gcProg
-	// topbits
-	for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ {
-		gc.append(bitsScalar)
+	// Prepare GC data if any.
+	// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes,
+	// or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap.
+	// Normally the enforced limit on pointer maps is 16 bytes,
+	// but larger ones are acceptable, 33 bytes isn't too too big,
+	// and it's easier to generate a pointer bitmap than a GC program.
+	// Note that since the key and value are known to be <= 128 bytes,
+	// they're guaranteed to have bitmaps instead of GC programs.
+	var gcdata *byte
+	var ptrdata uintptr
+	if kind != kindNoPointers {
+		nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize
+		mask := make([]byte, (nptr+7)/8)
+		base := bucketSize / ptrSize
+
+		if ktyp.kind&kindNoPointers == 0 {
+			if ktyp.kind&kindGCProg != 0 {
+				panic("reflect: unexpected GC program in MapOf")
+			}
+			kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata))
+			for i := uintptr(0); i < ktyp.size/ptrSize; i++ {
+				if (kmask[i/8]>>(i%8))&1 != 0 {
+					for j := uintptr(0); j < bucketSize; j++ {
+						word := base + j*ktyp.size/ptrSize + i
+						mask[word/8] |= 1 << (word % 8)
+					}
+				}
+			}
+		}
+		base += bucketSize * ktyp.size / ptrSize
+
+		if etyp.kind&kindNoPointers == 0 {
+			if etyp.kind&kindGCProg != 0 {
+				panic("reflect: unexpected GC program in MapOf")
+			}
+			emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata))
+			for i := uintptr(0); i < etyp.size/ptrSize; i++ {
+				if (emask[i/8]>>(i%8))&1 != 0 {
+					for j := uintptr(0); j < bucketSize; j++ {
+						word := base + j*etyp.size/ptrSize + i
+						mask[word/8] |= 1 << (word % 8)
+					}
+				}
+			}
+		}
+		base += bucketSize * etyp.size / ptrSize
+
+		word := base
+		mask[word/8] |= 1 << (word % 8)
+		gcdata = &mask[0]
+		ptrdata = (word + 1) * ptrSize
 	}
-	// keys
-	for i := 0; i < bucketSize; i++ {
-		gc.appendProg(ktyp)
-	}
-	// values
-	for i := 0; i < bucketSize; i++ {
-		gc.appendProg(etyp)
-	}
-	// overflow
-	gc.append(bitsPointer)
-	ptrdata := gc.size
+
+	size := bucketSize*(1+ktyp.size+etyp.size) + ptrSize
 	if runtime.GOARCH == "amd64p32" {
-		gc.append(bitsScalar)
+		size += ptrSize
 	}
 
 	b := new(rtype)
-	b.size = gc.size
+	b.size = size
 	b.ptrdata = ptrdata
 	b.kind = kind
-	b.gc[0], _ = gc.finalize()
+	b.gcdata = gcdata
 	s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
 	b.string = &s
 	return b
@@ -1871,7 +1793,6 @@ func SliceOf(t Type) Type {
 	slice.elem = typ
 	slice.uncommonType = nil
 	slice.ptrToThis = nil
-	slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
 
 	return cachePut(ckey, &slice.rtype)
 }
@@ -1927,26 +1848,86 @@ func ArrayOf(count int, elem Type) Type {
 	array.fieldAlign = typ.fieldAlign
 	array.uncommonType = nil
 	array.ptrToThis = nil
-	if array.size > 0 {
-		zero := make([]byte, array.size)
-		array.zero = unsafe.Pointer(&zero[0])
-	}
 	array.len = uintptr(count)
 	array.slice = slice.(*rtype)
 
-	var gc gcProg
-	// TODO(sbinet): count could be possibly very large.
-	// use insArray directives from ../runtime/mbitmap.go.
-	for i := 0; i < count; i++ {
-		gc.appendProg(typ)
-	}
-
-	var hasPtr bool
-	array.gc[0], hasPtr = gc.finalize()
-	if !hasPtr {
+	array.kind &^= kindNoPointers
+	switch {
+	case typ.kind&kindNoPointers != 0 || array.size == 0:
+		// No pointers.
 		array.kind |= kindNoPointers
-	} else {
-		array.kind &^= kindNoPointers
+		array.gcdata = nil
+		array.ptrdata = 0
+
+	case count == 1:
+		// In memory, 1-element array looks just like the element.
+		array.kind |= typ.kind & kindGCProg
+		array.gcdata = typ.gcdata
+		array.ptrdata = typ.ptrdata
+
+	case typ.kind&kindGCProg == 0 && array.size <= 16*8*ptrSize:
+		// Element is small with pointer mask; array is still small.
+		// Create direct pointer mask by turning each 1 bit in elem
+		// into count 1 bits in larger mask.
+		mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
+		elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
+		elemWords := typ.size / ptrSize
+		for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ {
+			if (elemMask[j/8]>>(j%8))&1 != 0 {
+				for i := uintptr(0); i < array.len; i++ {
+					k := i*elemWords + j
+					mask[k/8] |= 1 << (k % 8)
+				}
+			}
+		}
+		array.gcdata = &mask[0]
+
+	default:
+		// Create program that emits one element
+		// and then repeats to make the array.
+		prog := []byte{0, 0, 0, 0} // will be length of prog
+		elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
+		elemPtrs := typ.ptrdata / ptrSize
+		if typ.kind&kindGCProg == 0 {
+			// Element is small with pointer mask; use as literal bits.
+			mask := elemGC
+			// Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes).
+			var n uintptr
+			for n = elemPtrs; n > 120; n -= 120 {
+				prog = append(prog, 120)
+				prog = append(prog, mask[:15]...)
+				mask = mask[15:]
+			}
+			prog = append(prog, byte(n))
+			prog = append(prog, mask[:(n+7)/8]...)
+		} else {
+			// Element has GC program; emit one element.
+			elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1]
+			prog = append(prog, elemProg...)
+		}
+		// Pad from ptrdata to size.
+		elemWords := typ.size / ptrSize
+		if elemPtrs < elemWords {
+			// Emit literal 0 bit, then repeat as needed.
+			prog = append(prog, 0x01, 0x00)
+			if elemPtrs+1 < elemWords {
+				prog = append(prog, 0x81)
+				prog = appendVarint(prog, elemWords-elemPtrs-1)
+			}
+		}
+		// Repeat count-1 times.
+		if elemWords < 0x80 {
+			prog = append(prog, byte(elemWords|0x80))
+		} else {
+			prog = append(prog, 0x80)
+			prog = appendVarint(prog, elemWords)
+		}
+		prog = appendVarint(prog, uintptr(count)-1)
+		prog = append(prog, 0)
+		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
+		array.kind |= kindGCProg
+		array.gcdata = &prog[0]
+		array.ptrdata = array.size // overestimate but ok; must match program
 	}
 
 	etyp := typ.common()
@@ -1990,6 +1971,14 @@ func ArrayOf(count int, elem Type) Type {
 	return cachePut(ckey, &array.rtype)
 }
 
+func appendVarint(x []byte, v uintptr) []byte {
+	for ; v >= 0x80; v >>= 7 {
+		x = append(x, byte(v|0x80))
+	}
+	x = append(x, byte(v))
+	return x
+}
+
 // toType converts from a *rtype to a Type that can be returned
 // to the client of package reflect. In gc, the only concern is that
 // a nil *rtype must be replaced by a nil Type, but in gccgo this
@@ -2026,7 +2015,7 @@ var layoutCache struct {
 // The returned type exists only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in
 // the name for possible debugging use.
-func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector, framePool *sync.Pool) {
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
 	if t.Kind() != Func {
 		panic("reflect: funcLayout of non-func type")
 	}
@@ -2049,53 +2038,47 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	tt := (*funcType)(unsafe.Pointer(t))
 
 	// compute gc program & stack bitmap for arguments
-	stack = new(bitVector)
-	var gc gcProg
+	ptrmap := new(bitVector)
 	var offset uintptr
 	if rcvr != nil {
 		// Reflect uses the "interface" calling convention for
 		// methods, where receivers take one word of argument
 		// space no matter how big they actually are.
-		if ifaceIndir(rcvr) {
-			// we pass a pointer to the receiver.
-			gc.append(bitsPointer)
-			stack.append2(bitsPointer)
-		} else if rcvr.pointers() {
-			// rcvr is a one-word pointer object.  Its gc program
-			// is just what we need here.
-			gc.append(bitsPointer)
-			stack.append2(bitsPointer)
-		} else {
-			gc.append(bitsScalar)
-			stack.append2(bitsScalar)
+		if ifaceIndir(rcvr) || rcvr.pointers() {
+			ptrmap.append(1)
 		}
 		offset += ptrSize
 	}
 	for _, arg := range tt.in {
-		gc.appendProg(arg)
-		addTypeBits(stack, &offset, arg)
+		offset += -offset & uintptr(arg.align-1)
+		addTypeBits(ptrmap, offset, arg)
+		offset += arg.size
 	}
-	argSize = gc.size
+	argN := ptrmap.n
+	argSize = offset
 	if runtime.GOARCH == "amd64p32" {
-		gc.align(8)
+		offset += -offset & (8 - 1)
 	}
-	gc.align(ptrSize)
-	retOffset = gc.size
+	offset += -offset & (ptrSize - 1)
+	retOffset = offset
 	for _, res := range tt.out {
-		gc.appendProg(res)
-		// stack map does not need result bits
+		offset += -offset & uintptr(res.align-1)
+		addTypeBits(ptrmap, offset, res)
+		offset += res.size
 	}
-	gc.align(ptrSize)
+	offset += -offset & (ptrSize - 1)
 
 	// build dummy rtype holding gc program
 	x := new(rtype)
-	x.size = gc.size
-	x.ptrdata = gc.size // over-approximation
-	var hasPtr bool
-	x.gc[0], hasPtr = gc.finalize()
-	if !hasPtr {
+	x.size = offset
+	x.ptrdata = uintptr(ptrmap.n) * ptrSize
+	if ptrmap.n > 0 {
+		x.gcdata = &ptrmap.data[0]
+	} else {
 		x.kind |= kindNoPointers
 	}
+	ptrmap.n = argN
+
 	var s string
 	if rcvr != nil {
 		s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
@@ -2115,11 +2098,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 		t:         x,
 		argSize:   argSize,
 		retOffset: retOffset,
-		stack:     stack,
+		stack:     ptrmap,
 		framePool: framePool,
 	}
 	layoutCache.Unlock()
-	return x, argSize, retOffset, stack, framePool
+	return x, argSize, retOffset, ptrmap, framePool
 }
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
@@ -2133,56 +2116,49 @@ type bitVector struct {
 	data []byte
 }
 
-// append a bit pair to the bitmap.
-func (bv *bitVector) append2(bits uint8) {
-	// assume bv.n is a multiple of 2, since append2 is the only operation.
+// append a bit to the bitmap.
+func (bv *bitVector) append(bit uint8) {
 	if bv.n%8 == 0 {
 		bv.data = append(bv.data, 0)
 	}
-	bv.data[bv.n/8] |= bits << (bv.n % 8)
-	bv.n += 2
+	bv.data[bv.n/8] |= bit << (bv.n % 8)
+	bv.n++
 }
 
-func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
-	*offset = align(*offset, uintptr(t.align))
-	if !t.pointers() {
-		*offset += t.size
+func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
+	if t.kind&kindNoPointers != 0 {
 		return
 	}
 
 	switch Kind(t.kind & kindMask) {
 	case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
 		// 1 pointer at start of representation
-		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
-			bv.append2(bitsScalar)
+		for bv.n < uint32(offset/uintptr(ptrSize)) {
+			bv.append(0)
 		}
-		bv.append2(bitsPointer)
+		bv.append(1)
 
 	case Interface:
 		// 2 pointers
-		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
-			bv.append2(bitsScalar)
+		for bv.n < uint32(offset/uintptr(ptrSize)) {
+			bv.append(0)
 		}
-		bv.append2(bitsPointer)
-		bv.append2(bitsPointer)
+		bv.append(1)
+		bv.append(1)
 
 	case Array:
 		// repeat inner type
 		tt := (*arrayType)(unsafe.Pointer(t))
 		for i := 0; i < int(tt.len); i++ {
-			addTypeBits(bv, offset, tt.elem)
+			addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem)
 		}
 
 	case Struct:
 		// apply fields
 		tt := (*structType)(unsafe.Pointer(t))
-		start := *offset
 		for i := range tt.fields {
 			f := &tt.fields[i]
-			off := start + f.offset
-			addTypeBits(bv, &off, f.typ)
+			addTypeBits(bv, offset+f.offset, f.typ)
 		}
 	}
-
-	*offset += t.size
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index fb9e85a8cf..91c38c9ffc 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -10,7 +10,7 @@ import (
 	"unsafe"
 )
 
-const ptrSize = unsafe.Sizeof((*byte)(nil))
+const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
 const cannotSet = "cannot set value obtained from unexported struct field"
 
 // Value is the reflection interface to a Go value.
diff --git a/src/run.bash b/src/run.bash
index 6fc864dc0e..f35ec78982 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -35,4 +35,4 @@ if ulimit -T &> /dev/null; then
 	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
 fi
 
-exec go tool dist test $@
+exec go tool dist test "$@"
diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go
index b024d7a51f..d41696a6d6 100644
--- a/src/runtime/arch1_386.go
+++ b/src/runtime/arch1_386.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '8'
-	_BigEndian        = 0
-	_CacheLineSize    = 64
-	_RuntimeGogoBytes = 64
-	_PhysPageSize     = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl
-	_PCQuantum        = 1
-	_Int64Align       = 4
-	hugePageSize      = 1 << 21
+	thechar        = '8'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl
+	_PCQuantum     = 1
+	_Int64Align    = 4
+	hugePageSize   = 1 << 21
 )
diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go
index 932b2b7c55..15f4cc65fe 100644
--- a/src/runtime/arch1_amd64.go
+++ b/src/runtime/arch1_amd64.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '6'
-	_BigEndian        = 0
-	_CacheLineSize    = 64
-	_RuntimeGogoBytes = 80 + (goos_solaris)*16
-	_PhysPageSize     = 4096
-	_PCQuantum        = 1
-	_Int64Align       = 8
-	hugePageSize      = 1 << 21
+	thechar        = '6'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 4096
+	_PCQuantum     = 1
+	_Int64Align    = 8
+	hugePageSize   = 1 << 21
 )
diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go
index 79421e848a..3c5456f933 100644
--- a/src/runtime/arch1_amd64p32.go
+++ b/src/runtime/arch1_amd64p32.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '6'
-	_BigEndian        = 0
-	_CacheLineSize    = 64
-	_RuntimeGogoBytes = 64
-	_PhysPageSize     = 65536*goos_nacl + 4096*(1-goos_nacl)
-	_PCQuantum        = 1
-	_Int64Align       = 8
-	hugePageSize      = 1 << 21
+	thechar        = '6'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536*goos_nacl + 4096*(1-goos_nacl)
+	_PCQuantum     = 1
+	_Int64Align    = 8
+	hugePageSize   = 1 << 21
 )
diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go
index c3fe4f0cb3..0ec2093881 100644
--- a/src/runtime/arch1_arm.go
+++ b/src/runtime/arch1_arm.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '5'
-	_BigEndian        = 0
-	_CacheLineSize    = 32
-	_RuntimeGogoBytes = 60
-	_PhysPageSize     = 65536*goos_nacl + 4096*(1-goos_nacl)
-	_PCQuantum        = 4
-	_Int64Align       = 4
-	hugePageSize      = 0
+	thechar        = '5'
+	_BigEndian     = 0
+	_CacheLineSize = 32
+	_PhysPageSize  = 65536*goos_nacl + 4096*(1-goos_nacl)
+	_PCQuantum     = 4
+	_Int64Align    = 4
+	hugePageSize   = 0
 )
diff --git a/src/runtime/arch1_arm64.go b/src/runtime/arch1_arm64.go
index 549a635ca4..1a3165c8b7 100644
--- a/src/runtime/arch1_arm64.go
+++ b/src/runtime/arch1_arm64.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '7'
-	_BigEndian        = 0
-	_CacheLineSize    = 32
-	_RuntimeGogoBytes = 64
-	_PhysPageSize     = 4096*(1-goos_darwin) + 16384*goos_darwin
-	_PCQuantum        = 4
-	_Int64Align       = 8
-	hugePageSize      = 0
+	thechar        = '7'
+	_BigEndian     = 0
+	_CacheLineSize = 32
+	_PhysPageSize  = 4096*(1-goos_darwin) + 16384*goos_darwin
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
 )
diff --git a/src/runtime/arch1_ppc64.go b/src/runtime/arch1_ppc64.go
index ee453c09f2..de6dd91401 100644
--- a/src/runtime/arch1_ppc64.go
+++ b/src/runtime/arch1_ppc64.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '9'
-	_BigEndian        = 1
-	_CacheLineSize    = 64
-	_RuntimeGogoBytes = 72
-	_PhysPageSize     = 65536
-	_PCQuantum        = 4
-	_Int64Align       = 8
-	hugePageSize      = 0
+	thechar        = '9'
+	_BigEndian     = 1
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
 )
diff --git a/src/runtime/arch1_ppc64le.go b/src/runtime/arch1_ppc64le.go
index aa028a10f3..9a55c71101 100644
--- a/src/runtime/arch1_ppc64le.go
+++ b/src/runtime/arch1_ppc64le.go
@@ -5,12 +5,11 @@
 package runtime
 
 const (
-	thechar           = '9'
-	_BigEndian        = 0
-	_CacheLineSize    = 64
-	_RuntimeGogoBytes = 72
-	_PhysPageSize     = 65536
-	_PCQuantum        = 4
-	_Int64Align       = 8
-	hugePageSize      = 0
+	thechar        = '9'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
 )
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 36353d108f..0f9aeb8f37 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -1693,8 +1693,10 @@ TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
 	RET
 
 // This is called from .init_array and follows the platform, not Go, ABI.
-TEXT runtime·addmoduledata(SB),NOSPLIT,$0-8
+TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
+	PUSHQ	R15 // The access to global variables below implicitly uses R15, which is callee-save
 	MOVQ	runtime·lastmoduledatap(SB), AX
 	MOVQ	DI, moduledata_next(AX)
 	MOVQ	DI, runtime·lastmoduledatap(SB)
+	POPQ	R15
 	RET
diff --git a/src/runtime/atomic_pointer.go b/src/runtime/atomic_pointer.go
index 50a30242d9..f84afe0362 100644
--- a/src/runtime/atomic_pointer.go
+++ b/src/runtime/atomic_pointer.go
@@ -20,18 +20,12 @@ import "unsafe"
 func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
 	atomicstorep1(noescape(ptr), new)
 	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(ptr)))
-	}
 }
 
 //go:nosplit
 func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
 	old := xchgp1(noescape(ptr), new)
 	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(ptr)))
-	}
 	return old
 }
 
@@ -41,9 +35,6 @@ func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
 		return false
 	}
 	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(unsafe.Pointer(ptr))))
-	}
 	return true
 }
 
@@ -60,9 +51,6 @@ func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) {
 	sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
 	atomicstorep1(noescape(unsafe.Pointer(ptr)), new)
 	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(unsafe.Pointer(ptr))))
-	}
 }
 
 //go:linkname sync_atomic_SwapUintptr sync/atomic.SwapUintptr
@@ -73,9 +61,6 @@ func sync_atomic_SwapUintptr(ptr *uintptr, new uintptr) uintptr
 func sync_atomic_SwapPointer(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
 	old := unsafe.Pointer(sync_atomic_SwapUintptr((*uintptr)(noescape(ptr)), uintptr(new)))
 	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(ptr)))
-	}
 	return old
 }
 
@@ -89,8 +74,5 @@ func sync_atomic_CompareAndSwapPointer(ptr *unsafe.Pointer, old, new unsafe.Poin
 		return false
 	}
 	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
-	if mheap_.shadow_enabled {
-		writebarrierptr_noshadow((*uintptr)(noescape(unsafe.Pointer(ptr))))
-	}
 	return true
 }
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index 3ecaac10bc..9aec3b03e0 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -22,17 +22,12 @@ func GOMAXPROCS(n int) int {
 		return ret
 	}
 
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.preemptoff = "GOMAXPROCS"
-	systemstack(stoptheworld)
+	stopTheWorld("GOMAXPROCS")
 
-	// newprocs will be processed by starttheworld
+	// newprocs will be processed by startTheWorld
 	newprocs = int32(n)
 
-	gp.m.preemptoff = ""
-	semrelease(&worldsema)
-	systemstack(starttheworld)
+	startTheWorld()
 	return ret
 }
 
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index e0c8b17bd3..3fddcc868f 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -76,24 +76,17 @@ func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
 }
 
 func GCMask(x interface{}) (ret []byte) {
-	e := (*eface)(unsafe.Pointer(&x))
-	s := (*slice)(unsafe.Pointer(&ret))
 	systemstack(func() {
-		var len uintptr
-		var a *byte
-		getgcmask(e.data, e._type, &a, &len)
-		s.array = unsafe.Pointer(a)
-		s.len = int(len)
-		s.cap = s.len
+		ret = getgcmask(x)
 	})
 	return
 }
 
 func RunSchedLocalQueueTest() {
-	systemstack(testSchedLocalQueue)
+	testSchedLocalQueue()
 }
 func RunSchedLocalQueueStealTest() {
-	systemstack(testSchedLocalQueueSteal)
+	testSchedLocalQueueSteal()
 }
 
 var StringHash = stringHash
@@ -106,11 +99,6 @@ var MemclrBytes = memclrBytes
 
 var HashLoad = &hashLoad
 
-// For testing.
-func GogoBytes() int32 {
-	return _RuntimeGogoBytes
-}
-
 // entry point for testing
 func GostringW(w []uint16) (s string) {
 	systemstack(func() {
@@ -133,3 +121,34 @@ func Envs() []string     { return envs }
 func SetEnvs(e []string) { envs = e }
 
 var BigEndian = _BigEndian
+
+// For benchmarking.
+
+func BenchSetType(n int, x interface{}) {
+	e := *(*eface)(unsafe.Pointer(&x))
+	t := e._type
+	var size uintptr
+	var p unsafe.Pointer
+	switch t.kind & kindMask {
+	case _KindPtr:
+		t = (*ptrtype)(unsafe.Pointer(t)).elem
+		size = t.size
+		p = e.data
+	case _KindSlice:
+		slice := *(*struct {
+			ptr      unsafe.Pointer
+			len, cap uintptr
+		})(e.data)
+		t = (*slicetype)(unsafe.Pointer(t)).elem
+		size = t.size * slice.len
+		p = slice.ptr
+	}
+	allocSize := roundupsize(size)
+	systemstack(func() {
+		for i := 0; i < n; i++ {
+			heapBitsSetType(uintptr(p), allocSize, size, t)
+		}
+	})
+}
+
+const PtrSize = ptrSize
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 540d7b5124..476c3c5ae3 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -58,18 +58,6 @@ a comma-separated list of name=val pairs. Supported names are:
 
 	scavenge: scavenge=1 enables debugging mode of heap scavenger.
 
-	wbshadow: setting wbshadow=1 enables a shadow copy of the heap
-	used to detect missing write barriers at the next write to a
-	given location. If a bug can be detected in this mode it is
-	typically easy to understand, since the crash says quite
-	clearly what kind of word has missed a write barrier.
-	Setting wbshadow=2 checks the shadow copy during garbage
-	collection as well. Bugs detected at garbage collection can be
-	difficult to understand, because there is no context for what
-	the found word means. Typically you have to reproduce the
-	problem with allocfreetrace=1 in order to understand the type
-	of the badly updated word.
-
 	gccheckmark: setting gccheckmark=1 enables verification of the
 	garbage collector's concurrent mark phase by performing a
 	second mark pass while the world is stopped.  If the second
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 6abec4cca7..e3e0c3a583 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -6,6 +6,7 @@ package runtime_test
 
 import (
 	"os"
+	"reflect"
 	"runtime"
 	"runtime/debug"
 	"testing"
@@ -197,45 +198,166 @@ func TestHugeGCInfo(t *testing.T) {
 	}
 }
 
-func BenchmarkSetTypeNoPtr1(b *testing.B) {
-	type NoPtr1 struct {
-		p uintptr
-	}
-	var p *NoPtr1
-	for i := 0; i < b.N; i++ {
-		p = &NoPtr1{}
-	}
-	_ = p
+func BenchmarkSetTypePtr(b *testing.B) {
+	benchSetType(b, new(*byte))
 }
-func BenchmarkSetTypeNoPtr2(b *testing.B) {
-	type NoPtr2 struct {
-		p, q uintptr
-	}
-	var p *NoPtr2
-	for i := 0; i < b.N; i++ {
-		p = &NoPtr2{}
-	}
-	_ = p
+
+func BenchmarkSetTypePtr8(b *testing.B) {
+	benchSetType(b, new([8]*byte))
 }
-func BenchmarkSetTypePtr1(b *testing.B) {
-	type Ptr1 struct {
-		p *byte
-	}
-	var p *Ptr1
-	for i := 0; i < b.N; i++ {
-		p = &Ptr1{}
-	}
-	_ = p
+
+func BenchmarkSetTypePtr16(b *testing.B) {
+	benchSetType(b, new([16]*byte))
 }
-func BenchmarkSetTypePtr2(b *testing.B) {
-	type Ptr2 struct {
-		p, q *byte
+
+func BenchmarkSetTypePtr32(b *testing.B) {
+	benchSetType(b, new([32]*byte))
+}
+
+func BenchmarkSetTypePtr64(b *testing.B) {
+	benchSetType(b, new([64]*byte))
+}
+
+func BenchmarkSetTypePtr126(b *testing.B) {
+	benchSetType(b, new([126]*byte))
+}
+
+func BenchmarkSetTypePtr128(b *testing.B) {
+	benchSetType(b, new([128]*byte))
+}
+
+func BenchmarkSetTypePtrSlice(b *testing.B) {
+	benchSetType(b, make([]*byte, 1<<10))
+}
+
+type Node1 struct {
+	Value       [1]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode1(b *testing.B) {
+	benchSetType(b, new(Node1))
+}
+
+func BenchmarkSetTypeNode1Slice(b *testing.B) {
+	benchSetType(b, make([]Node1, 32))
+}
+
+type Node8 struct {
+	Value       [8]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode8(b *testing.B) {
+	benchSetType(b, new(Node8))
+}
+
+func BenchmarkSetTypeNode8Slice(b *testing.B) {
+	benchSetType(b, make([]Node8, 32))
+}
+
+type Node64 struct {
+	Value       [64]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode64(b *testing.B) {
+	benchSetType(b, new(Node64))
+}
+
+func BenchmarkSetTypeNode64Slice(b *testing.B) {
+	benchSetType(b, make([]Node64, 32))
+}
+
+type Node64Dead struct {
+	Left, Right *byte
+	Value       [64]uintptr
+}
+
+func BenchmarkSetTypeNode64Dead(b *testing.B) {
+	benchSetType(b, new(Node64Dead))
+}
+
+func BenchmarkSetTypeNode64DeadSlice(b *testing.B) {
+	benchSetType(b, make([]Node64Dead, 32))
+}
+
+type Node124 struct {
+	Value       [124]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode124(b *testing.B) {
+	benchSetType(b, new(Node124))
+}
+
+func BenchmarkSetTypeNode124Slice(b *testing.B) {
+	benchSetType(b, make([]Node124, 32))
+}
+
+type Node126 struct {
+	Value       [126]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode126(b *testing.B) {
+	benchSetType(b, new(Node126))
+}
+
+func BenchmarkSetTypeNode126Slice(b *testing.B) {
+	benchSetType(b, make([]Node126, 32))
+}
+
+type Node128 struct {
+	Value       [128]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode128(b *testing.B) {
+	benchSetType(b, new(Node128))
+}
+
+func BenchmarkSetTypeNode128Slice(b *testing.B) {
+	benchSetType(b, make([]Node128, 32))
+}
+
+type Node130 struct {
+	Value       [130]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode130(b *testing.B) {
+	benchSetType(b, new(Node130))
+}
+
+func BenchmarkSetTypeNode130Slice(b *testing.B) {
+	benchSetType(b, make([]Node130, 32))
+}
+
+type Node1024 struct {
+	Value       [1024]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode1024(b *testing.B) {
+	benchSetType(b, new(Node1024))
+}
+
+func BenchmarkSetTypeNode1024Slice(b *testing.B) {
+	benchSetType(b, make([]Node1024, 32))
+}
+
+func benchSetType(b *testing.B, x interface{}) {
+	v := reflect.ValueOf(x)
+	t := v.Type()
+	switch t.Kind() {
+	case reflect.Ptr:
+		b.SetBytes(int64(t.Elem().Size()))
+	case reflect.Slice:
+		b.SetBytes(int64(t.Elem().Size()) * int64(v.Len()))
 	}
-	var p *Ptr2
-	for i := 0; i < b.N; i++ {
-		p = &Ptr2{}
-	}
-	_ = p
+	b.ResetTimer()
+	runtime.BenchSetType(b.N, x)
 }
 
 func BenchmarkAllocation(b *testing.B) {
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index 66b0353f08..f330bf2430 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -10,8 +10,14 @@ import (
 	"testing"
 )
 
+const (
+	typeScalar  = 0
+	typePointer = 1
+)
+
 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
 func TestGCInfo(t *testing.T) {
+	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
 	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
 	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
 	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
@@ -20,6 +26,7 @@ func TestGCInfo(t *testing.T) {
 	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
 	verifyGCInfo(t, "bss iface", &bssIface, infoIface)
 
+	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
 	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
 	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
 	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
@@ -28,6 +35,7 @@ func TestGCInfo(t *testing.T) {
 	verifyGCInfo(t, "data eface", &dataEface, infoEface)
 	verifyGCInfo(t, "data iface", &dataIface, infoIface)
 
+	verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr)
 	verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
 	verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
 	verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
@@ -37,38 +45,43 @@ func TestGCInfo(t *testing.T) {
 	verifyGCInfo(t, "stack iface", new(Iface), infoIface)
 
 	for i := 0; i < 10; i++ {
-		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), infoScalarPtr)
-		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), infoPtrScalar)
-		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), infoBigStruct())
-		verifyGCInfo(t, "heap string", escape(new(string)), infoString)
-		verifyGCInfo(t, "heap eface", escape(new(interface{})), infoEface)
-		verifyGCInfo(t, "heap iface", escape(new(Iface)), infoIface)
+		verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr)))
+		verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
+		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
+		verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
+		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), trimDead(infoPtrScalar))
+		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), trimDead(infoBigStruct()))
+		verifyGCInfo(t, "heap string", escape(new(string)), trimDead(infoString))
+		verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
+		verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
 	}
-
 }
 
 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
 	mask := runtime.GCMask(p)
-	if len(mask) > len(mask0) {
-		mask0 = append(mask0, typeDead)
-		mask = mask[:len(mask0)]
-	}
 	if bytes.Compare(mask, mask0) != 0 {
 		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
 		return
 	}
 }
 
-func nonStackInfo(mask []byte) []byte {
-	// typeDead is replaced with typeScalar everywhere except stacks.
-	mask1 := make([]byte, len(mask))
-	for i, v := range mask {
-		if v == typeDead {
-			v = typeScalar
-		}
-		mask1[i] = v
+func padDead(mask []byte) []byte {
+	// Because the dead bit isn't encoded until the third word,
+	// and because on 32-bit systems a one-word allocation
+	// uses a two-word block, the pointer info for a one-word
+	// object needs to be expanded to include an extra scalar
+	// on 32-bit systems to match the heap bitmap.
+	if runtime.PtrSize == 4 && len(mask) == 1 {
+		return []byte{mask[0], 0}
 	}
-	return mask1
+	return mask
+}
+
+func trimDead(mask []byte) []byte {
+	for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
+		mask = mask[:len(mask)-1]
+	}
+	return mask
 }
 
 var gcinfoSink interface{}
@@ -78,18 +91,13 @@ func escape(p interface{}) interface{} {
 	return p
 }
 
-const (
-	typeDead = iota
-	typeScalar
-	typePointer
-)
+var infoPtr = []byte{typePointer}
 
-const (
-	BitsString = iota // unused
-	BitsSlice         // unused
-	BitsIface
-	BitsEface
-)
+type Ptr struct {
+	*byte
+}
+
+var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
 
 type ScalarPtr struct {
 	q int
@@ -102,6 +110,8 @@ type ScalarPtr struct {
 
 var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
 
+var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
+
 type PtrScalar struct {
 	q *int
 	w int
@@ -166,6 +176,7 @@ func (IfaceImpl) f() {
 
 var (
 	// BSS
+	bssPtr       Ptr
 	bssScalarPtr ScalarPtr
 	bssPtrScalar PtrScalar
 	bssBigStruct BigStruct
@@ -175,6 +186,7 @@ var (
 	bssIface     Iface
 
 	// DATA
+	dataPtr                   = Ptr{new(byte)}
 	dataScalarPtr             = ScalarPtr{q: 1}
 	dataPtrScalar             = PtrScalar{w: 1}
 	dataBigStruct             = BigStruct{w: 1}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 9ca33992bb..b199330a1e 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -233,6 +233,9 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 		throw("need padding in bucket (value)")
 	}
 
+	// make sure zero of element type is available.
+	mapzero(t.elem)
+
 	// find size parameter which will hold the requested # of elements
 	B := uint8(0)
 	for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<2GB zero on 32-bit machine
+				throw("map element too large")
+			}
+		}
+		zerobuf.p = (*byte)(persistentalloc(zerobuf.size, 64, &memstats.other_sys))
+	}
+	atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(zerobuf.p))
+	unlock(&zerobuf.lock)
+}
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index e18aa79164..c0fff3f1ce 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -15,20 +15,13 @@ import "unsafe"
 
 //go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump
 func runtime_debug_WriteHeapDump(fd uintptr) {
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.preemptoff = "write heap dump"
-	systemstack(stoptheworld)
+	stopTheWorld("write heap dump")
 
 	systemstack(func() {
 		writeheapdump_m(fd)
 	})
 
-	gp.m.preemptoff = ""
-	gp.m.locks++
-	semrelease(&worldsema)
-	systemstack(starttheworld)
-	gp.m.locks--
+	startTheWorld()
 }
 
 const (
@@ -730,14 +723,13 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector {
 	i := uintptr(0)
 	hbits := heapBitsForAddr(p)
 	for ; i < nptr; i++ {
-		bits := hbits.typeBits()
-		if bits == typeDead {
+		if i >= 2 && !hbits.isMarked() {
 			break // end of object
 		}
-		hbits = hbits.next()
-		if bits == typePointer {
+		if hbits.isPointer() {
 			tmpbuf[i/8] |= 1 << (i % 8)
 		}
+		hbits = hbits.next()
 	}
 	return bitvector{int32(i), &tmpbuf[0]}
 }
diff --git a/src/runtime/lfstack_test.go b/src/runtime/lfstack_test.go
index 68f221d6ef..4da4d88619 100644
--- a/src/runtime/lfstack_test.go
+++ b/src/runtime/lfstack_test.go
@@ -24,8 +24,12 @@ func toMyNode(node *LFNode) *MyNode {
 	return (*MyNode)(unsafe.Pointer(node))
 }
 
+var global interface{}
+
 func TestLFStack(t *testing.T) {
 	stack := new(uint64)
+	global = stack // force heap allocation
+
 	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
 	var nodes []*MyNode
 
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 1619ccb9f4..2d7e55643f 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -424,9 +424,6 @@ func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer {
 		if raceenabled {
 			racemapshadow((unsafe.Pointer)(p), n)
 		}
-		if mheap_.shadow_enabled {
-			sysMap(unsafe.Pointer(p+mheap_.shadow_heap), n, h.shadow_reserved, &memstats.other_sys)
-		}
 
 		if uintptr(p)&(_PageSize-1) != 0 {
 			throw("misrounded allocation in MHeap_SysAlloc")
@@ -512,6 +509,9 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 	if mp.mallocing != 0 {
 		throw("malloc deadlock")
 	}
+	if mp.gsignal == getg() {
+		throw("malloc during signal")
+	}
 	mp.mallocing = 1
 
 	shouldhelpgc := false
@@ -669,10 +669,6 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 		})
 	}
 
-	if mheap_.shadow_enabled {
-		clearshadow(uintptr(x), size)
-	}
-
 	if raceenabled {
 		racemalloc(x, size)
 	}
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index eb5881707b..53a0a00ae7 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -10,12 +10,6 @@
 // implementation, markwb, and the various wrappers called by the
 // compiler to implement pointer assignment, slice assignment,
 // typed memmove, and so on.
-//
-// To check for missed write barriers, the GODEBUG=wbshadow debugging
-// mode allocates a second copy of the heap. Write barrier-based pointer
-// updates make changes to both the real heap and the shadow, and both
-// the pointer updates and the GC look for inconsistencies between the two,
-// indicating pointer writes that bypassed the barrier.
 
 package runtime
 
@@ -66,7 +60,7 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) {
 	default:
 		throw("gcphasework in bad gcphase")
 
-	case _GCoff, _GCquiesce, _GCstw, _GCsweep, _GCscan:
+	case _GCoff, _GCstw, _GCsweep, _GCscan:
 		// ok
 
 	case _GCmark, _GCmarktermination:
@@ -107,43 +101,19 @@ func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
 // but if we do that, Go inserts a write barrier on *dst = src.
 //go:nosplit
 func writebarrierptr(dst *uintptr, src uintptr) {
+	*dst = src
 	if !writeBarrierEnabled {
-		*dst = src
 		return
 	}
-
 	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
-		systemstack(func() { throw("bad pointer in write barrier") })
+		systemstack(func() {
+			print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
+			throw("bad pointer in write barrier")
+		})
 	}
-
-	if mheap_.shadow_enabled {
-		writebarrierptr_shadow(dst, src)
-	}
-
-	*dst = src
 	writebarrierptr_nostore1(dst, src)
 }
 
-//go:nosplit
-func writebarrierptr_shadow(dst *uintptr, src uintptr) {
-	systemstack(func() {
-		addr := uintptr(unsafe.Pointer(dst))
-		shadow := shadowptr(addr)
-		if shadow == nil {
-			return
-		}
-		// There is a race here but only if the program is using
-		// racy writes instead of sync/atomic. In that case we
-		// don't mind crashing.
-		if *shadow != *dst && *shadow != noShadow && istrackedptr(*dst) {
-			mheap_.shadow_enabled = false
-			print("runtime: write barrier dst=", dst, " old=", hex(*dst), " shadow=", shadow, " old=", hex(*shadow), " new=", hex(src), "\n")
-			throw("missed write barrier")
-		}
-		*shadow = src
-	})
-}
-
 // Like writebarrierptr, but the store has already been applied.
 // Do not reapply.
 //go:nosplit
@@ -151,44 +121,12 @@ func writebarrierptr_nostore(dst *uintptr, src uintptr) {
 	if !writeBarrierEnabled {
 		return
 	}
-
 	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
 		systemstack(func() { throw("bad pointer in write barrier") })
 	}
-
-	// Apply changes to shadow.
-	// Since *dst has been overwritten already, we cannot check
-	// whether there were any missed updates, but writebarrierptr_nostore
-	// is only rarely used.
-	if mheap_.shadow_enabled {
-		systemstack(func() {
-			addr := uintptr(unsafe.Pointer(dst))
-			shadow := shadowptr(addr)
-			if shadow == nil {
-				return
-			}
-			*shadow = src
-		})
-	}
-
 	writebarrierptr_nostore1(dst, src)
 }
 
-// writebarrierptr_noshadow records that the value in *dst
-// has been written to using an atomic operation and the shadow
-// has not been updated. (In general if dst must be manipulated
-// atomically we cannot get the right bits for use in the shadow.)
-//go:nosplit
-func writebarrierptr_noshadow(dst *uintptr) {
-	addr := uintptr(unsafe.Pointer(dst))
-	shadow := shadowptr(addr)
-	if shadow == nil {
-		return
-	}
-
-	*shadow = noShadow
-}
-
 //go:nosplit
 func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
 	writebarrierptr(&dst[0], src[0])
@@ -217,37 +155,11 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
 // typedmemmove copies a value of type t to dst from src.
 //go:nosplit
 func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
-	if !writeBarrierEnabled || (typ.kind&kindNoPointers) != 0 {
-		memmove(dst, src, typ.size)
+	memmove(dst, src, typ.size)
+	if typ.kind&kindNoPointers != 0 {
 		return
 	}
-
-	systemstack(func() {
-		mask := typeBitmapInHeapBitmapFormat(typ)
-		nptr := typ.size / ptrSize
-		for i := uintptr(0); i < nptr; i += 2 {
-			bits := mask[i/2]
-			if (bits>>2)&typeMask == typePointer {
-				writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
-			} else {
-				*(*uintptr)(dst) = *(*uintptr)(src)
-			}
-			// TODO(rsc): The noescape calls should be unnecessary.
-			dst = add(noescape(dst), ptrSize)
-			src = add(noescape(src), ptrSize)
-			if i+1 == nptr {
-				break
-			}
-			bits >>= 4
-			if (bits>>2)&typeMask == typePointer {
-				writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
-			} else {
-				*(*uintptr)(dst) = *(*uintptr)(src)
-			}
-			dst = add(noescape(dst), ptrSize)
-			src = add(noescape(src), ptrSize)
-		}
-	})
+	heapBitsBulkBarrier(uintptr(dst), typ.size)
 }
 
 //go:linkname reflect_typedmemmove reflect.typedmemmove
@@ -259,38 +171,16 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
 // dst and src point off bytes into the value and only copies size bytes.
 //go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
 func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
-	if !writeBarrierEnabled || (typ.kind&kindNoPointers) != 0 || size < ptrSize {
-		memmove(dst, src, size)
+	memmove(dst, src, size)
+	if !writeBarrierEnabled || typ.kind&kindNoPointers != 0 || size < ptrSize || !inheap(uintptr(dst)) {
 		return
 	}
 
-	if off&(ptrSize-1) != 0 {
-		frag := -off & (ptrSize - 1)
-		// frag < size, because size >= ptrSize, checked above.
-		memmove(dst, src, frag)
+	if frag := -off & (ptrSize - 1); frag != 0 {
+		dst = add(dst, frag)
 		size -= frag
-		dst = add(noescape(dst), frag)
-		src = add(noescape(src), frag)
-		off += frag
-	}
-
-	mask := typeBitmapInHeapBitmapFormat(typ)
-	nptr := (off + size) / ptrSize
-	for i := uintptr(off / ptrSize); i < nptr; i++ {
-		bits := mask[i/2] >> ((i & 1) << 2)
-		if (bits>>2)&typeMask == typePointer {
-			writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
-		} else {
-			*(*uintptr)(dst) = *(*uintptr)(src)
-		}
-		// TODO(rsc): The noescape calls should be unnecessary.
-		dst = add(noescape(dst), ptrSize)
-		src = add(noescape(src), ptrSize)
-	}
-	size &= ptrSize - 1
-	if size > 0 {
-		memmove(dst, src, size)
 	}
+	heapBitsBulkBarrier(uintptr(dst), size&^(ptrSize-1))
 }
 
 // callwritebarrier is invoked at the end of reflectcall, to execute
@@ -302,29 +192,16 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size
 // not to be preempted before the write barriers have been run.
 //go:nosplit
 func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
-	if !writeBarrierEnabled || typ == nil || (typ.kind&kindNoPointers) != 0 || framesize-retoffset < ptrSize {
+	if !writeBarrierEnabled || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < ptrSize || !inheap(uintptr(frame)) {
 		return
 	}
-
-	systemstack(func() {
-		mask := typeBitmapInHeapBitmapFormat(typ)
-		// retoffset is known to be pointer-aligned (at least).
-		// TODO(rsc): The noescape call should be unnecessary.
-		dst := add(noescape(frame), retoffset)
-		nptr := framesize / ptrSize
-		for i := uintptr(retoffset / ptrSize); i < nptr; i++ {
-			bits := mask[i/2] >> ((i & 1) << 2)
-			if (bits>>2)&typeMask == typePointer {
-				writebarrierptr_nostore((*uintptr)(dst), *(*uintptr)(dst))
-			}
-			// TODO(rsc): The noescape call should be unnecessary.
-			dst = add(noescape(dst), ptrSize)
-		}
-	})
+	heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
 }
 
 //go:nosplit
 func typedslicecopy(typ *_type, dst, src slice) int {
+	// TODO(rsc): If typedslicecopy becomes faster than calling
+	// typedmemmove repeatedly, consider using during func growslice.
 	n := dst.len
 	if n > src.len {
 		n = src.len
@@ -342,6 +219,10 @@ func typedslicecopy(typ *_type, dst, src slice) int {
 		racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
 	}
 
+	// Note: No point in checking typ.kind&kindNoPointers here:
+	// compiler only emits calls to typedslicecopy for types with pointers,
+	// and growslice and reflect_typedslicecopy check for pointers
+	// before calling typedslicecopy.
 	if !writeBarrierEnabled {
 		memmove(dstp, srcp, uintptr(n)*typ.size)
 		return n
@@ -382,134 +263,13 @@ func typedslicecopy(typ *_type, dst, src slice) int {
 
 //go:linkname reflect_typedslicecopy reflect.typedslicecopy
 func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
+	if elemType.kind&kindNoPointers != 0 {
+		n := dst.len
+		if n > src.len {
+			n = src.len
+		}
+		memmove(dst.array, src.array, uintptr(n)*elemType.size)
+		return n
+	}
 	return typedslicecopy(elemType, dst, src)
 }
-
-// Shadow heap for detecting missed write barriers.
-
-// noShadow is stored in as the shadow pointer to mark that there is no
-// shadow word recorded. It matches any actual pointer word.
-// noShadow is used when it is impossible to know the right word
-// to store in the shadow heap, such as when the real heap word
-// is being manipulated atomically.
-const noShadow uintptr = 1
-
-func wbshadowinit() {
-	// Initialize write barrier shadow heap if we were asked for it
-	// and we have enough address space (not on 32-bit).
-	if debug.wbshadow == 0 {
-		return
-	}
-	if ptrSize != 8 {
-		print("runtime: GODEBUG=wbshadow=1 disabled on 32-bit system\n")
-		return
-	}
-
-	var reserved bool
-	p1 := sysReserveHigh(mheap_.arena_end-mheap_.arena_start, &reserved)
-	if p1 == nil {
-		throw("cannot map shadow heap")
-	}
-	mheap_.shadow_heap = uintptr(p1) - mheap_.arena_start
-	sysMap(p1, mheap_.arena_used-mheap_.arena_start, reserved, &memstats.other_sys)
-	memmove(p1, unsafe.Pointer(mheap_.arena_start), mheap_.arena_used-mheap_.arena_start)
-
-	mheap_.shadow_reserved = reserved
-
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		start := ^uintptr(0)
-		end := uintptr(0)
-		if start > datap.noptrdata {
-			start = datap.noptrdata
-		}
-		if start > datap.data {
-			start = datap.data
-		}
-		if start > datap.noptrbss {
-			start = datap.noptrbss
-		}
-		if start > datap.bss {
-			start = datap.bss
-		}
-		if end < datap.enoptrdata {
-			end = datap.enoptrdata
-		}
-		if end < datap.edata {
-			end = datap.edata
-		}
-		if end < datap.enoptrbss {
-			end = datap.enoptrbss
-		}
-		if end < datap.ebss {
-			end = datap.ebss
-		}
-		start &^= _PhysPageSize - 1
-		end = round(end, _PhysPageSize)
-		datap.data_start = start
-		datap.data_end = end
-		reserved = false
-		p1 = sysReserveHigh(end-start, &reserved)
-		if p1 == nil {
-			throw("cannot map shadow data")
-		}
-		datap.shadow_data = uintptr(p1) - start
-		sysMap(p1, end-start, reserved, &memstats.other_sys)
-		memmove(p1, unsafe.Pointer(start), end-start)
-	}
-
-	mheap_.shadow_enabled = true
-	writeBarrierEnabled = true
-}
-
-// shadowptr returns a pointer to the shadow value for addr.
-//go:nosplit
-func shadowptr(addr uintptr) *uintptr {
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		if datap.data_start <= addr && addr < datap.data_end {
-			return (*uintptr)(unsafe.Pointer(addr + datap.shadow_data))
-		}
-	}
-	if inheap(addr) {
-		return (*uintptr)(unsafe.Pointer(addr + mheap_.shadow_heap))
-	}
-	return nil
-}
-
-// istrackedptr reports whether the pointer value p requires a write barrier
-// when stored into the heap.
-func istrackedptr(p uintptr) bool {
-	return inheap(p)
-}
-
-// checkwbshadow checks that p matches its shadow word.
-// The garbage collector calls checkwbshadow for each pointer during the checkmark phase.
-// It is only called when mheap_.shadow_enabled is true.
-func checkwbshadow(p *uintptr) {
-	addr := uintptr(unsafe.Pointer(p))
-	shadow := shadowptr(addr)
-	if shadow == nil {
-		return
-	}
-	// There is no race on the accesses here, because the world is stopped,
-	// but there may be racy writes that lead to the shadow and the
-	// heap being inconsistent. If so, we will detect that here as a
-	// missed write barrier and crash. We don't mind.
-	// Code should use sync/atomic instead of racy pointer writes.
-	if *shadow != *p && *shadow != noShadow && istrackedptr(*p) {
-		mheap_.shadow_enabled = false
-		print("runtime: checkwritebarrier p=", p, " *p=", hex(*p), " shadow=", shadow, " *shadow=", hex(*shadow), "\n")
-		throw("missed write barrier")
-	}
-}
-
-// clearshadow clears the shadow copy associated with the n bytes of memory at addr.
-func clearshadow(addr, n uintptr) {
-	if !mheap_.shadow_enabled {
-		return
-	}
-	p := shadowptr(addr)
-	if p == nil || n <= ptrSize {
-		return
-	}
-	memclr(unsafe.Pointer(p), n)
-}
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index f0c7520e38..b20908fb49 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -6,48 +6,40 @@
 //
 // Stack, data, and bss bitmaps
 //
-// Not handled in this file, but worth mentioning: stack frames and global data
-// in the data and bss sections are described by 1-bit bitmaps in which 0 means
-// scalar or uninitialized or dead and 1 means pointer to visit during GC.
-//
-// Comparing this 1-bit form with the 2-bit form described below, 0 represents
-// both the 2-bit 00 and 01, while 1 represents the 2-bit 10.
-// Therefore conversions between the two (until the 2-bit form is gone)
-// can be done by x>>1 for 2-bit to 1-bit and x+1 for 1-bit to 2-bit.
-//
-// Type bitmaps
-//
-// Types that aren't too large
-// record information about the layout of their memory words using a type bitmap.
-// The bitmap holds two bits for each pointer-sized word. The two-bit values are:
-//
-// 	00 - typeDead: not a pointer, and no pointers in the rest of the object
-//	01 - typeScalar: not a pointer
-//	10 - typePointer: a pointer that GC should trace
-//	11 - unused
-//
-// typeDead only appears in type bitmaps in Go type descriptors
-// and in type bitmaps embedded in the heap bitmap (see below).
+// Stack frames and global variables in the data and bss sections are described
+// by 1-bit bitmaps in which 0 means uninteresting and 1 means live pointer
+// to be visited during GC. The bits in each byte are consumed starting with
+// the low bit: 1<<0, 1<<1, and so on.
 //
 // Heap bitmap
 //
 // The allocated heap comes from a subset of the memory in the range [start, used),
 // where start == mheap_.arena_start and used == mheap_.arena_used.
-// The heap bitmap comprises 4 bits for each pointer-sized word in that range,
+// The heap bitmap comprises 2 bits for each pointer-sized word in that range,
 // stored in bytes indexed backward in memory from start.
-// That is, the byte at address start-1 holds the 4-bit entries for the two words
-// start, start+ptrSize, the byte at start-2 holds the entries for start+2*ptrSize,
-// start+3*ptrSize, and so on.
-// In the byte holding the entries for addresses p and p+ptrSize, the low 4 bits
-// describe p and the high 4 bits describe p+ptrSize.
+// That is, the byte at address start-1 holds the 2-bit entries for the four words
+// start through start+3*ptrSize, the byte at start-2 holds the entries for
+// start+4*ptrSize through start+7*ptrSize, and so on.
 //
-// The 4 bits for each word are:
-//	0001 - not used
-//	0010 - bitMarked: this object has been marked by GC
-//	tt00 - word type bits, as in a type bitmap.
+// In each 2-bit entry, the lower bit holds the same information as in the 1-bit
+// bitmaps: 0 means uninteresting and 1 means live pointer to be visited during GC.
+// The meaning of the high bit depends on the position of the word being described
+// in its allocated object. In the first word, the high bit is the GC ``marked'' bit.
+// In the second word, the high bit is the GC ``checkmarked'' bit (see below).
+// In the third and later words, the high bit indicates that the object is still
+// being described. In these words, if a bit pair with a high bit 0 is encountered,
+// the low bit can also be assumed to be 0, and the object description is over.
+// This 00 is called the ``dead'' encoding: it signals that the rest of the words
+// in the object are uninteresting to the garbage collector.
 //
-// The code makes use of the fact that the zero value for a heap bitmap nibble
-// has no boundary bit set, no marked bit set, and type bits == typeDead.
+// The 2-bit entries are split when written into the byte, so that the top half
+// of the byte contains 4 mark bits and the bottom half contains 4 pointer bits.
+// This form allows a copy from the 1-bit to the 4-bit form to keep the
+// pointer bits contiguous, instead of having to space them out.
+//
+// The code makes use of the fact that the zero value for a heap bitmap
+// has no live pointer bit set and is (depending on position), not marked,
+// not checkmarked, and is the dead encoding.
 // These properties must be preserved when modifying the encoding.
 //
 // Checkmarks
@@ -57,55 +49,71 @@
 // collector implementation. As a sanity check, the GC has a 'checkmark'
 // mode that retraverses the object graph with the world stopped, to make
 // sure that everything that should be marked is marked.
-// In checkmark mode, in the heap bitmap, the type bits for the first word
-// of an object are redefined:
+// In checkmark mode, in the heap bitmap, the high bit of the 2-bit entry
+// for the second word of the object holds the checkmark bit.
+// When not in checkmark mode, this bit is set to 1.
 //
-//	00 - typeScalarCheckmarked // typeScalar, checkmarked
-//	01 - typeScalar // typeScalar, not checkmarked
-//	10 - typePointer // typePointer, not checkmarked
-//	11 - typePointerCheckmarked // typePointer, checkmarked
-//
-// That is, typeDead is redefined to be typeScalar + a checkmark, and the
-// previously unused 11 pattern is redefined to be typePointer + a checkmark.
-// To prepare for this mode, we must move any typeDead in the first word of
-// a multiword object to the second word.
+// The smallest possible allocation is 8 bytes. On a 32-bit machine, that
+// means every allocated object has two words, so there is room for the
+// checkmark bit. On a 64-bit machine, however, the 8-byte allocation is
+// just one word, so the second bit pair is not available for encoding the
+// checkmark. However, because non-pointer allocations are combined
+// into larger 16-byte (maxTinySize) allocations, a plain 8-byte allocation
+// must be a pointer, so the type bit in the first word is not actually needed.
+// It is still used in general, except in checkmark the type bit is repurposed
+// as the checkmark bit and then reinitialized (to 1) as the type bit when
+// finished.
 
 package runtime
 
 import "unsafe"
 
 const (
-	typeDead               = 0
-	typeScalarCheckmarked  = 0
-	typeScalar             = 1
-	typePointer            = 2
-	typePointerCheckmarked = 3
+	bitPointer = 1 << 0
+	bitMarked  = 1 << 4
 
-	typeBitsWidth = 2 // # of type bits per pointer-sized word
-	typeMask      = 1<> h.shift
 }
 
 // isMarked reports whether the heap bits have the marked bit set.
+// h must describe the initial word of the object.
 func (h heapBits) isMarked() bool {
 	return *h.bitp&(bitMarked<> (h.shift + typeShift)) & typeMask
+// isPointer reports whether the heap bits describe a pointer word.
+// h must describe the initial word of the object.
+func (h heapBits) isPointer() bool {
+	return (*h.bitp>>h.shift)&bitPointer != 0
+}
+
+// hasPointers reports whether the given object has any pointers.
+// It must be told how large the object at h is, so that it does not read too
+// far into the bitmap.
+// h must describe the initial word of the object.
+func (h heapBits) hasPointers(size uintptr) bool {
+	if size == ptrSize { // 1-word objects are always pointers
+		return true
+	}
+	// Otherwise, at least a 2-word object, and at least 2-word aligned,
+	// so h.shift is either 0 or 4, so we know we can get the bits for the
+	// first two words out of *h.bitp.
+	// If either of the first two words is a pointer, not pointer free.
+	b := uint32(*h.bitp >> h.shift)
+	if b&(bitPointer|bitPointer<>h.shift)&bitPointer != 0
+	}
+	// All multiword objects are 2-word aligned,
+	// so we know that the initial word's 2-bit pair
+	// and the second word's 2-bit pair are in the
+	// same heap bitmap byte, *h.bitp.
+	return (*h.bitp>>(heapBitsShift+h.shift))&bitMarked != 0
 }
 
 // setCheckmarked sets the checkmarked bit.
-func (h heapBits) setCheckmarked() {
-	typ := h.typeBits()
-	if typ == typeScalar {
-		// Clear low type bit to turn 01 into 00.
-		atomicand8(h.bitp, ^((1 << typeShift) << h.shift))
-	} else if typ == typePointer {
-		// Set low type bit to turn 10 into 11.
-		atomicor8(h.bitp, (1<>typeShift)&typeMask == typeDead {
-				x += (typeScalar - typeDead) << typeShift
-			}
-			if (x>>(4+typeShift))&typeMask == typeDead {
-				x += (typeScalar - typeDead) << (4 + typeShift)
-			}
-			*bitp = uint8(x)
-			bitp = subtractb(bitp, 1)
+		for i := uintptr(0); i < n; i += 4 {
+			*bitp &^= bitPointerAll
+			bitp = subtract1(bitp)
 		}
 		return
 	}
-
-	// Update bottom nibble for first word of each object.
-	// If the bottom nibble says typeDead, change to typeScalar
-	// and clear top nibble to mark as typeDead.
-	bitp := h.bitp
-	step := size / heapBitmapScale
 	for i := uintptr(0); i < n; i++ {
-		x := *bitp
-		if (x>>typeShift)&typeMask == typeDead {
-			x += (typeScalar - typeDead) << typeShift
-			x &= 0x0f // clear top nibble to typeDead
-		}
-		bitp = subtractb(bitp, step)
+		*h.bitp &^= bitMarked << (heapBitsShift + h.shift)
+		h = h.forward(size / ptrSize)
 	}
 }
 
-// clearCheckmarkSpan removes all the checkmarks from a span.
-// If it finds a multiword object starting with typeScalar typeDead,
-// it rewrites the heap bits to the simpler typeDead typeDead.
+// clearCheckmarkSpan undoes all the checkmarking in a span.
+// The actual checkmark bits are ignored, so the only work to do
+// is to fix the pointer bits. (Pointer bits are ignored by scanobject
+// but consulted by typedmemmove.)
 func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
-	if size == ptrSize {
+	// The ptrSize == 8 is a compile-time constant false on 32-bit and eliminates this code entirely.
+	if ptrSize == 8 && size == ptrSize {
+		// Checkmark bit is type bit, bottom bit of every 2-bit entry.
 		// Only possible on 64-bit system, since minimum size is 8.
-		// Must update both top and bottom nibble of each byte.
-		// typeScalarCheckmarked can be left as typeDead,
-		// but we want to change typeScalar back to typeDead.
+		// Must clear type bit (checkmark bit) of every word.
+		// The type bit is the lower of every two-bit pair.
 		bitp := h.bitp
-		for i := uintptr(0); i < n; i += 2 {
-			x := int(*bitp)
-			switch typ := (x >> typeShift) & typeMask; typ {
-			case typeScalar:
-				x += (typeDead - typeScalar) << typeShift
-			case typePointerCheckmarked:
-				x += (typePointer - typePointerCheckmarked) << typeShift
-			}
-
-			switch typ := (x >> (4 + typeShift)) & typeMask; typ {
-			case typeScalar:
-				x += (typeDead - typeScalar) << (4 + typeShift)
-			case typePointerCheckmarked:
-				x += (typePointer - typePointerCheckmarked) << (4 + typeShift)
-			}
-
-			*bitp = uint8(x)
-			bitp = subtractb(bitp, 1)
+		for i := uintptr(0); i < n; i += 4 {
+			*bitp |= bitPointerAll
+			bitp = subtract1(bitp)
 		}
-		return
-	}
-
-	// Update bottom nibble for first word of each object.
-	// If the bottom nibble says typeScalarCheckmarked and the top is not typeDead,
-	// change to typeScalar. Otherwise leave, since typeScalarCheckmarked == typeDead.
-	// If the bottom nibble says typePointerCheckmarked, change to typePointer.
-	bitp := h.bitp
-	step := size / heapBitmapScale
-	for i := uintptr(0); i < n; i++ {
-		x := int(*bitp)
-		switch typ := (x >> typeShift) & typeMask; {
-		case typ == typeScalarCheckmarked && (x>>(4+typeShift))&typeMask != typeDead:
-			x += (typeScalar - typeScalarCheckmarked) << typeShift
-		case typ == typePointerCheckmarked:
-			x += (typePointer - typePointerCheckmarked) << typeShift
-		}
-
-		*bitp = uint8(x)
-		bitp = subtractb(bitp, step)
 	}
 }
 
@@ -393,348 +457,1046 @@ func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
 // bits for the first two words (or one for single-word objects) to typeDead
 // and then calls f(p), where p is the object's base address.
 // f is expected to add the object to a free list.
+// For non-free objects, heapBitsSweepSpan turns off the marked bit.
 func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) {
 	h := heapBitsForSpan(base)
-	if size == ptrSize {
-		// Only possible on 64-bit system, since minimum size is 8.
-		// Must read and update both top and bottom nibble of each byte.
+	switch {
+	default:
+		throw("heapBitsSweepSpan")
+	case ptrSize == 8 && size == ptrSize:
+		// Consider mark bits in all four 2-bit entries of each bitmap byte.
 		bitp := h.bitp
-		for i := uintptr(0); i < n; i += 2 {
-			x := int(*bitp)
+		for i := uintptr(0); i < n; i += 4 {
+			x := uint32(*bitp)
+			// Note that unlike the other size cases, we leave the pointer bits set here.
+			// These are initialized during initSpan when the span is created and left
+			// in place the whole time the span is used for pointer-sized objects.
+			// That lets heapBitsSetType avoid an atomic update to set the pointer bit
+			// during allocation.
 			if x&bitMarked != 0 {
 				x &^= bitMarked
 			} else {
-				x &^= typeMask << typeShift
 				f(base + i*ptrSize)
 			}
-			if x&(bitMarked<<4) != 0 {
-				x &^= bitMarked << 4
+			if x&(bitMarked< 2*ptrSize {
+					x = 0
+				}
+			}
+			*bitp = uint8(x)
+			if i+1 >= n {
+				break
+			}
+			bitp = subtractb(bitp, step)
+			x = uint32(*bitp)
+			if x&(bitMarked<<(2*heapBitsShift)) != 0 {
+				x &^= bitMarked << (2 * heapBitsShift)
+			} else {
+				x &^= (bitMarked|bitPointer)<<(2*heapBitsShift) | (bitMarked|bitPointer)<<(3*heapBitsShift)
+				f(base + (i+1)*size)
+				if size > 2*ptrSize {
+					*subtract1(bitp) = 0
+				}
+			}
+			*bitp = uint8(x)
+			bitp = subtractb(bitp, step+1)
 		}
-		*bitp = uint8(x)
-		bitp = subtractb(bitp, step)
 	}
 }
 
-// TODO(rsc): Clean up the next two functions.
-
 // heapBitsSetType records that the new allocation [x, x+size)
 // holds in [x, x+dataSize) one or more values of type typ.
 // (The number of values is given by dataSize / typ.size.)
 // If dataSize < size, the fragment [x+dataSize, x+size) is
 // recorded as non-pointer data.
+// It is known that the type has pointers somewhere;
+// malloc does not call heapBitsSetType when there are no pointers,
+// because all free objects are marked as noscan during
+// heapBitsSweepSpan.
+// There can only be one allocation from a given span active at a time,
+// so this code is not racing with other instances of itself,
+// and we don't allocate from a span until it has been swept,
+// so this code is not racing with heapBitsSweepSpan.
+// It is, however, racing with the concurrent GC mark phase,
+// which can be setting the mark bit in the leading 2-bit entry
+// of an allocated block. The block we are modifying is not quite
+// allocated yet, so the GC marker is not racing with updates to x's bits,
+// but if the start or end of x shares a bitmap byte with an adjacent
+// object, the GC marker is racing with updates to those object's mark bits.
 func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
-	// From here till marked label marking the object as allocated
-	// and storing type info in the GC bitmap.
-	h := heapBitsForAddr(x)
+	const doubleCheck = false // slow but helpful; enable to test modifications to this code
 
-	var ti, te uintptr
-	var ptrmask *uint8
-	if size == ptrSize {
+	// dataSize is always size rounded up to the next malloc size class,
+	// except in the case of allocating a defer block, in which case
+	// size is sizeof(_defer{}) (at least 6 words) and dataSize may be
+	// arbitrarily larger.
+	//
+	// The checks for size == ptrSize and size == 2*ptrSize can therefore
+	// assume that dataSize == size without checking it explicitly.
+
+	if ptrSize == 8 && size == ptrSize {
 		// It's one word and it has pointers, it must be a pointer.
-		// The bitmap byte is shared with the one-word object
-		// next to it, and concurrent GC might be marking that
-		// object, so we must use an atomic update.
-		atomicor8(h.bitp, typePointer<<(typeShift+h.shift))
+		// In general we'd need an atomic update here if the
+		// concurrent GC were marking objects in this span,
+		// because each bitmap byte describes 3 other objects
+		// in addition to the one being allocated.
+		// However, since all allocated one-word objects are pointers
+		// (non-pointers are aggregated into tinySize allocations),
+		// initSpan sets the pointer bits for us. Nothing to do here.
+		if doubleCheck {
+			h := heapBitsForAddr(x)
+			if !h.isPointer() {
+				throw("heapBitsSetType: pointer bit missing")
+			}
+		}
 		return
 	}
-	if typ.kind&kindGCProg != 0 {
-		nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
-		masksize := nptr
-		if masksize%2 != 0 {
-			masksize *= 2 // repeated
-		}
-		const typeBitsPerByte = 8 / typeBitsWidth
-		masksize = masksize * typeBitsPerByte / 8 // 4 bits per word
-		masksize++                                // unroll flag in the beginning
-		if masksize > maxGCMask && typ.gc[1] != 0 {
-			// write barriers have not been updated to deal with this case yet.
-			throw("maxGCMask too small for now")
-			// If the mask is too large, unroll the program directly
-			// into the GC bitmap. It's 7 times slower than copying
-			// from the pre-unrolled mask, but saves 1/16 of type size
-			// memory for the mask.
-			systemstack(func() {
-				unrollgcproginplace_m(unsafe.Pointer(x), typ, size, dataSize)
-			})
-			return
-		}
-		ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
-		// Check whether the program is already unrolled
-		// by checking if the unroll flag byte is set
-		maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
-		if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
-			systemstack(func() {
-				unrollgcprog_m(typ)
-			})
-		}
-		ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
-	} else {
-		ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
-	}
+
+	h := heapBitsForAddr(x)
+	ptrmask := typ.gcdata // start of 1-bit pointer mask (or GC program, handled below)
+
+	// Heap bitmap bits for 2-word object are only 4 bits,
+	// so also shared with objects next to it; use atomic updates.
+	// This is called out as a special case primarily for 32-bit systems,
+	// so that on 32-bit systems the code below can assume all objects
+	// are 4-word aligned (because they're all 16-byte aligned).
 	if size == 2*ptrSize {
-		// h.shift is 0 for all sizes > ptrSize.
-		*h.bitp = *ptrmask
-		return
-	}
-	te = uintptr(typ.size) / ptrSize
-	// If the type occupies odd number of words, its mask is repeated.
-	if te%2 == 0 {
-		te /= 2
-	}
-	// Copy pointer bitmask into the bitmap.
-	// TODO(rlh): add comment addressing the following concerns:
-	// If size > 2*ptrSize, is x guaranteed to be at least 2*ptrSize-aligned?
-	// And if type occupies and odd number of words, why are we only going through half
-	// of ptrmask and why don't we have to shift everything by 4 on odd iterations?
-
-	for i := uintptr(0); i < dataSize; i += 2 * ptrSize {
-		v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
-		ti++
-		if ti == te {
-			ti = 0
-		}
-		if i+ptrSize == dataSize {
-			v &^= typeMask << (4 + typeShift)
-		}
-
-		*h.bitp = v
-		h.bitp = subtractb(h.bitp, 1)
-	}
-	if dataSize%(2*ptrSize) == 0 && dataSize < size {
-		// Mark the word after last object's word as typeDead.
-		*h.bitp = 0
-	}
-}
-
-// typeBitmapInHeapBitmapFormat returns a bitmap holding
-// the type bits for the type typ, but expanded into heap bitmap format
-// to make it easier to copy them into the heap bitmap.
-// TODO(rsc): Change clients to use the type bitmap format instead,
-// which can be stored more densely (especially if we drop to 1 bit per pointer).
-//
-// To make it easier to replicate the bits when filling out the heap
-// bitmap for an array of typ, if typ holds an odd number of words
-// (meaning the heap bitmap would stop halfway through a byte),
-// typeBitmapInHeapBitmapFormat returns the bitmap for two instances
-// of typ in a row.
-// TODO(rsc): Remove doubling.
-func typeBitmapInHeapBitmapFormat(typ *_type) []uint8 {
-	var ptrmask *uint8
-	nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
-	if typ.kind&kindGCProg != 0 {
-		masksize := nptr
-		if masksize%2 != 0 {
-			masksize *= 2 // repeated
-		}
-		const typeBitsPerByte = 8 / typeBitsWidth
-		masksize = masksize * typeBitsPerByte / 8 // 4 bits per word
-		masksize++                                // unroll flag in the beginning
-		if masksize > maxGCMask && typ.gc[1] != 0 {
-			// write barriers have not been updated to deal with this case yet.
-			throw("maxGCMask too small for now")
-		}
-		ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
-		// Check whether the program is already unrolled
-		// by checking if the unroll flag byte is set
-		maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
-		if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
-			systemstack(func() {
-				unrollgcprog_m(typ)
-			})
-		}
-		ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
-	} else {
-		ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
-	}
-	return (*[1 << 30]byte)(unsafe.Pointer(ptrmask))[:(nptr+1)/2]
-}
-
-// GC type info programs
-//
-// TODO(rsc): Clean up and enable.
-
-const (
-	// GC type info programs.
-	// The programs allow to store type info required for GC in a compact form.
-	// Most importantly arrays take O(1) space instead of O(n).
-	// The program grammar is:
-	//
-	// Program = {Block} "insEnd"
-	// Block = Data | Array
-	// Data = "insData" DataSize DataBlock
-	// DataSize = int // size of the DataBlock in bit pairs, 1 byte
-	// DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes
-	// Array = "insArray" ArrayLen Block "insArrayEnd"
-	// ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch)
-	//
-	// Each instruction (insData, insArray, etc) is 1 byte.
-	// For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; }
-	// the program looks as:
-	//
-	// insData 3 (typePointer typeScalar typeScalar)
-	//	insArray 20 insData 2 (typeScalar typePointer) insArrayEnd insEnd
-	//
-	// Total size of the program is 17 bytes (13 bytes on 32-bits).
-	// The corresponding GC mask would take 43 bytes (it would be repeated
-	// because the type has odd number of words).
-	insData = 1 + iota
-	insArray
-	insArrayEnd
-	insEnd
-
-	// 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
-	maxGCMask = 65536 // TODO(rsc): change back to 64
-)
-
-// Recursively unrolls GC program in prog.
-// mask is where to store the result.
-// If inplace is true, store the result not in mask but in the heap bitmap for mask.
-// ppos is a pointer to position in mask, in bits.
-// sparse says to generate 4-bits per word mask for heap (1-bit for data/bss otherwise).
-//go:nowritebarrier
-func unrollgcprog1(maskp *byte, prog *byte, ppos *uintptr, inplace, sparse bool) *byte {
-	pos := *ppos
-	mask := (*[1 << 30]byte)(unsafe.Pointer(maskp))
-	for {
-		switch *prog {
-		default:
-			throw("unrollgcprog: unknown instruction")
-
-		case insData:
-			prog = addb(prog, 1)
-			siz := int(*prog)
-			prog = addb(prog, 1)
-			p := (*[1 << 30]byte)(unsafe.Pointer(prog))
-			for i := 0; i < siz; i++ {
-				const typeBitsPerByte = 8 / typeBitsWidth
-				v := p[i/typeBitsPerByte]
-				v >>= (uint(i) % typeBitsPerByte) * typeBitsWidth
-				v &= typeMask
-				if inplace {
-					// Store directly into GC bitmap.
-					h := heapBitsForAddr(uintptr(unsafe.Pointer(&mask[pos])))
-					if h.shift == 0 {
-						*h.bitp = v << typeShift
-					} else {
-						*h.bitp |= v << (4 + typeShift)
-					}
-					pos += ptrSize
-				} else if sparse {
-					// 4-bits per word, type bits in high bits
-					v <<= (pos % 8) + typeShift
-					mask[pos/8] |= v
-					pos += heapBitsWidth
+		if typ.size == ptrSize {
+			// We're allocating a block big enough to hold two pointers.
+			// On 64-bit, that means the actual object must be two pointers,
+			// or else we'd have used the one-pointer-sized block.
+			// On 32-bit, however, this is the 8-byte block, the smallest one.
+			// So it could be that we're allocating one pointer and this was
+			// just the smallest block available. Distinguish by checking dataSize.
+			// (In general the number of instances of typ being allocated is
+			// dataSize/typ.size.)
+			if ptrSize == 4 && dataSize == ptrSize {
+				// 1 pointer.
+				if gcphase == _GCoff {
+					*h.bitp |= bitPointer << h.shift
 				} else {
-					// 1 bit per word, for data/bss bitmap
-					v >>= 1 // convert typePointer to 1, others to 0
-					mask[pos/8] |= v << (pos % 8)
-					pos++
+					atomicor8(h.bitp, bitPointer<= nw {
+			goto Phase3
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+		nb -= 4
+
+	case ptrSize == 8 && h.shift == 2:
+		// Ptrmask and heap bitmap are misaligned.
+		// The bits for the first two words are in a byte shared with another object
+		// and must be updated atomically.
+		// NOTE(rsc): The atomic here may not be necessary.
+		// We took care of 1-word and 2-word objects above,
+		// so this is at least a 6-word object, so our start bits
+		// are shared only with the type bits of another object,
+		// not with its mark bit. Since there is only one allocation
+		// from a given span at a time, we should be able to set
+		// these bits non-atomically. Not worth the risk right now.
+		hb = (b & 3) << (2 * heapBitsShift)
+		b >>= 2
+		nb -= 2
+		// Note: no bitMarker in hb because the first two words don't get markers from us.
+		if gcphase == _GCoff {
+			*hbitp |= uint8(hb)
+		} else {
+			atomicor8(hbitp, uint8(hb))
+		}
+		hbitp = subtract1(hbitp)
+		if w += 2; w >= nw {
+			// We know that there is more data, because we handled 2-word objects above.
+			// This must be at least a 6-word object. If we're out of pointer words,
+			// mark no scan in next bitmap byte and finish.
+			hb = 0
+			w += 4
+			goto Phase3
+		}
+	}
+
+	// Phase 2: Full bytes in bitmap, up to but not including write to last byte (full or partial) in bitmap.
+	// The loop computes the bits for that last write but does not execute the write;
+	// it leaves the bits in hb for processing by phase 3.
+	// To avoid repeated adjustment of nb, we subtract out the 4 bits we're going to
+	// use in the first half of the loop right now, and then we only adjust nb explicitly
+	// if the 8 bits used by each iteration isn't balanced by 8 bits loaded mid-loop.
+	nb -= 4
+	for {
+		// Emit bitmap byte.
+		// b has at least nb+4 bits, with one exception:
+		// if w+4 >= nw, then b has only nw-w bits,
+		// but we'll stop at the break and then truncate
+		// appropriately in Phase 3.
+		hb = b & bitPointerAll
+		hb |= bitMarkedAll
+		if w += 4; w >= nw {
+			break
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+
+		// Load more bits. b has nb right now.
+		if p != endp {
+			// Fast path: keep reading from ptrmask.
+			// nb unmodified: we just loaded 8 bits,
+			// and the next iteration will consume 8 bits,
+			// leaving us with the same nb the next time we're here.
+			b |= uintptr(*p) << nb
+			p = add1(p)
+		} else if p == nil {
+			// Almost as fast path: track bit count and refill from pbits.
+			// For short repetitions.
+			if nb < 8 {
+				b |= pbits << nb
+				nb += endnb
+			}
+			nb -= 8 // for next iteration
+		} else {
+			// Slow path: reached end of ptrmask.
+			// Process final partial byte and rewind to start.
+			b |= uintptr(*p) << nb
+			nb += endnb
+			if nb < 8 {
+				b |= uintptr(*ptrmask) << nb
+				p = add1(ptrmask)
+			} else {
+				nb -= 8
+				p = ptrmask
+			}
+		}
+
+		// Emit bitmap byte.
+		hb = b & bitPointerAll
+		hb |= bitMarkedAll
+		if w += 4; w >= nw {
+			break
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+	}
+
+Phase3:
+	// Phase 3: Write last byte or partial byte and zero the rest of the bitmap entries.
+	if w > nw {
+		// Counting the 4 entries in hb not yet written to memory,
+		// there are more entries than possible pointer slots.
+		// Discard the excess entries (can't be more than 3).
+		mask := uintptr(1)<<(4-(w-nw)) - 1
+		hb &= mask | mask<<4 // apply mask to both pointer bits and mark bits
+	}
+
+	// Change nw from counting possibly-pointer words to total words in allocation.
+	nw = size / ptrSize
+
+	// Write whole bitmap bytes.
+	// The first is hb, the rest are zero.
+	if w <= nw {
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		hb = 0 // for possible final half-byte below
+		for w += 4; w <= nw; w += 4 {
+			*hbitp = 0
+			hbitp = subtract1(hbitp)
+		}
+	}
+
+	// Write final partial bitmap byte if any.
+	// We know w > nw, or else we'd still be in the loop above.
+	// It can be bigger only due to the 4 entries in hb that it counts.
+	// If w == nw+4 then there's nothing left to do: we wrote all nw entries
+	// and can discard the 4 sitting in hb.
+	// But if w == nw+2, we need to write first two in hb.
+	// The byte is shared with the next object so we may need an atomic.
+	if w == nw+2 {
+		if gcphase == _GCoff {
+			*hbitp = *hbitp&^(bitPointer|bitMarked|(bitPointer|bitMarked)<> h.shift) & (bitPointer | bitMarked)
+			if i >= totalptr {
+				want = 0 // deadmarker
+				if typ.kind&kindGCProg != 0 && i < (totalptr+3)/4*4 {
+					want = bitMarked
+				}
+			} else {
+				if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 {
+					want |= bitPointer
+				}
+				if i >= 2 {
+					want |= bitMarked
+				} else {
+					have &^= bitMarked
+				}
+			}
+			if have != want {
+				println("mismatch writing bits for", *typ._string, "x", dataSize/typ.size)
+				print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
+				print("kindGCProg=", typ.kind&kindGCProg != 0, "\n")
+				print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
+				h0 := heapBitsForAddr(x)
+				print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n")
+				print("current bits h.bitp=", h.bitp, " h.shift=", h.shift, " *h.bitp=", hex(*h.bitp), "\n")
+				print("ptrmask=", ptrmask, " p=", p, " endp=", endp, " endnb=", endnb, " pbits=", hex(pbits), " b=", hex(b), " nb=", nb, "\n")
+				println("at word", i, "offset", i*ptrSize, "have", have, "want", want)
+				if typ.kind&kindGCProg != 0 {
+					println("GC program:")
+					dumpGCProg(addb(typ.gcdata, 4))
+				}
+				throw("bad heapBitsSetType")
+			}
+			h = h.next()
+		}
+		if ptrmask == debugPtrmask.data {
+			unlock(&debugPtrmask.lock)
 		}
 	}
 }
 
-// Unrolls GC program prog for data/bss, returns dense GC mask.
-func unrollglobgcprog(prog *byte, size uintptr) bitvector {
-	masksize := round(round(size, ptrSize)/ptrSize, 8) / 8
-	mask := (*[1 << 30]byte)(persistentalloc(masksize+1, 0, &memstats.gc_sys))
-	mask[masksize] = 0xa1
-	pos := uintptr(0)
-	prog = unrollgcprog1(&mask[0], prog, &pos, false, false)
-	if pos != size/ptrSize {
-		print("unrollglobgcprog: bad program size, got ", pos, ", expect ", size/ptrSize, "\n")
-		throw("unrollglobgcprog: bad program size")
-	}
-	if *prog != insEnd {
-		throw("unrollglobgcprog: program does not end with insEnd")
-	}
-	if mask[masksize] != 0xa1 {
-		throw("unrollglobgcprog: overflow")
-	}
-	return bitvector{int32(masksize * 8), &mask[0]}
+var debugPtrmask struct {
+	lock mutex
+	data *byte
 }
 
-func unrollgcproginplace_m(v unsafe.Pointer, typ *_type, size, size0 uintptr) {
-	// TODO(rsc): Explain why these non-atomic updates are okay.
-	pos := uintptr(0)
-	prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
-	for pos != size0 {
-		unrollgcprog1((*byte)(v), prog, &pos, true, true)
+// heapBitsSetTypeGCProg implements heapBitsSetType using a GC program.
+// progSize is the size of the memory described by the program.
+// elemSize is the size of the element that the GC program describes (a prefix of).
+// dataSize is the total size of the intended data, a multiple of elemSize.
+// allocSize is the total size of the allocated memory.
+//
+// GC programs are only used for large allocations.
+// heapBitsSetType requires that allocSize is a multiple of 4 words,
+// so that the relevant bitmap bytes are not shared with surrounding
+// objects and need not be accessed with atomic instructions.
+func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) {
+	if ptrSize == 8 && allocSize%(4*ptrSize) != 0 {
+		// Alignment will be wrong.
+		throw("heapBitsSetTypeGCProg: small allocation")
 	}
+	var totalBits uintptr
+	if elemSize == dataSize {
+		totalBits = runGCProg(prog, nil, h.bitp, 2)
+		if totalBits*ptrSize != progSize {
+			println("runtime: heapBitsSetTypeGCProg: total bits", totalBits, "but progSize", progSize)
+			throw("heapBitsSetTypeGCProg: unexpected bit count")
+		}
+	} else {
+		count := dataSize / elemSize
 
-	// Mark first word as bitAllocated.
-	// Mark word after last as typeDead.
-	if size0 < size {
-		h := heapBitsForAddr(uintptr(v) + size0)
-		*h.bitp &^= typeMask << typeShift
+		// Piece together program trailer to run after prog that does:
+		//	literal(0)
+		//	repeat(1, elemSize-progSize-1) // zeros to fill element size
+		//	repeat(elemSize, count-1) // repeat that element for count
+		// This zero-pads the data remaining in the first element and then
+		// repeats that first element to fill the array.
+		var trailer [40]byte // 3 varints (max 10 each) + some bytes
+		i := 0
+		if n := elemSize/ptrSize - progSize/ptrSize; n > 0 {
+			// literal(0)
+			trailer[i] = 0x01
+			i++
+			trailer[i] = 0
+			i++
+			if n > 1 {
+				// repeat(1, n-1)
+				trailer[i] = 0x81
+				i++
+				n--
+				for ; n >= 0x80; n >>= 7 {
+					trailer[i] = byte(n | 0x80)
+					i++
+				}
+				trailer[i] = byte(n)
+				i++
+			}
+		}
+		// repeat(elemSize/ptrSize, count-1)
+		trailer[i] = 0x80
+		i++
+		n := elemSize / ptrSize
+		for ; n >= 0x80; n >>= 7 {
+			trailer[i] = byte(n | 0x80)
+			i++
+		}
+		trailer[i] = byte(n)
+		i++
+		n = count
+		for ; n >= 0x80; n >>= 7 {
+			trailer[i] = byte(n | 0x80)
+			i++
+		}
+		trailer[i] = byte(n)
+		i++
+		trailer[i] = 0
+		i++
+
+		runGCProg(prog, &trailer[0], h.bitp, 2)
+
+		// Even though we filled in the full array just now,
+		// record that we only filled in up to the ptrdata of the
+		// last element. This will cause the code below to
+		// memclr the dead section of the final array element,
+		// so that scanobject can stop early in the final element.
+		totalBits = (elemSize*(count-1) + progSize) / ptrSize
 	}
+	endProg := unsafe.Pointer(subtractb(h.bitp, (totalBits+3)/4))
+	endAlloc := unsafe.Pointer(subtractb(h.bitp, allocSize/heapBitmapScale))
+	memclr(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc))
 }
 
-var unroll mutex
-
-// Unrolls GC program in typ.gc[1] into typ.gc[0]
-//go:nowritebarrier
-func unrollgcprog_m(typ *_type) {
-	lock(&unroll)
-	mask := (*byte)(unsafe.Pointer(uintptr(typ.gc[0])))
-	if *mask == 0 {
-		pos := uintptr(8) // skip the unroll flag
-		prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
-		prog = unrollgcprog1(mask, prog, &pos, false, true)
-		if *prog != insEnd {
-			throw("unrollgcprog: program does not end with insEnd")
-		}
-		if typ.size/ptrSize%2 != 0 {
-			// repeat the program
-			prog := (*byte)(unsafe.Pointer(uintptr(typ.gc[1])))
-			unrollgcprog1(mask, prog, &pos, false, true)
-		}
-
-		// atomic way to say mask[0] = 1
-		atomicor8(mask, 1)
+// progToPointerMask returns the 1-bit pointer mask output by the GC program prog.
+// size the size of the region described by prog, in bytes.
+// The resulting bitvector will have no more than size/ptrSize bits.
+func progToPointerMask(prog *byte, size uintptr) bitvector {
+	n := (size/ptrSize + 7) / 8
+	x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1]
+	x[len(x)-1] = 0xa1 // overflow check sentinel
+	n = runGCProg(prog, nil, &x[0], 1)
+	if x[len(x)-1] != 0xa1 {
+		throw("progToPointerMask: overflow")
+	}
+	return bitvector{int32(n), &x[0]}
+}
+
+// Packed GC pointer bitmaps, aka GC programs.
+//
+// For large types containing arrays, the type information has a
+// natural repetition that can be encoded to save space in the
+// binary and in the memory representation of the type information.
+//
+// The encoding is a simple Lempel-Ziv style bytecode machine
+// with the following instructions:
+//
+//	00000000: stop
+//	0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes
+//	10000000 n c: repeat the previous n bits c times; n, c are varints
+//	1nnnnnnn c: repeat the previous n bits c times; c is a varint
+
+// runGCProg executes the GC program prog, and then trailer if non-nil,
+// writing to dst with entries of the given size.
+// If size == 1, dst is a 1-bit pointer mask laid out moving forward from dst.
+// If size == 2, dst is the 2-bit heap bitmap, and writes move backward
+// starting at dst (because the heap bitmap does). In this case, the caller guarantees
+// that only whole bytes in dst need to be written.
+//
+// runGCProg returns the number of 1- or 2-bit entries written to memory.
+func runGCProg(prog, trailer, dst *byte, size int) uintptr {
+	dstStart := dst
+
+	// Bits waiting to be written to memory.
+	var bits uintptr
+	var nbits uintptr
+
+	p := prog
+Run:
+	for {
+		// Flush accumulated full bytes.
+		// The rest of the loop assumes that nbits <= 7.
+		for ; nbits >= 8; nbits -= 8 {
+			if size == 1 {
+				*dst = uint8(bits)
+				dst = add1(dst)
+				bits >>= 8
+			} else {
+				v := bits&bitPointerAll | bitMarkedAll
+				*dst = uint8(v)
+				dst = subtract1(dst)
+				bits >>= 4
+				v = bits&bitPointerAll | bitMarkedAll
+				*dst = uint8(v)
+				dst = subtract1(dst)
+				bits >>= 4
+			}
+		}
+
+		// Process one instruction.
+		inst := uintptr(*p)
+		p = add1(p)
+		n := inst & 0x7F
+		if inst&0x80 == 0 {
+			// Literal bits; n == 0 means end of program.
+			if n == 0 {
+				// Program is over; continue in trailer if present.
+				if trailer != nil {
+					//println("trailer")
+					p = trailer
+					trailer = nil
+					continue
+				}
+				//println("done")
+				break Run
+			}
+			//println("lit", n, dst)
+			nbyte := n / 8
+			for i := uintptr(0); i < nbyte; i++ {
+				bits |= uintptr(*p) << nbits
+				p = add1(p)
+				if size == 1 {
+					*dst = uint8(bits)
+					dst = add1(dst)
+					bits >>= 8
+				} else {
+					v := bits&0xf | bitMarkedAll
+					*dst = uint8(v)
+					dst = subtract1(dst)
+					bits >>= 4
+					v = bits&0xf | bitMarkedAll
+					*dst = uint8(v)
+					dst = subtract1(dst)
+					bits >>= 4
+				}
+			}
+			if n %= 8; n > 0 {
+				bits |= uintptr(*p) << nbits
+				p = add1(p)
+				nbits += n
+			}
+			continue Run
+		}
+
+		// Repeat. If n == 0, it is encoded in a varint in the next bytes.
+		if n == 0 {
+			for off := uint(0); ; off += 7 {
+				x := uintptr(*p)
+				p = add1(p)
+				n |= (x & 0x7F) << off
+				if x&0x80 == 0 {
+					break
+				}
+			}
+		}
+
+		// Count is encoded in a varint in the next bytes.
+		c := uintptr(0)
+		for off := uint(0); ; off += 7 {
+			x := uintptr(*p)
+			p = add1(p)
+			c |= (x & 0x7F) << off
+			if x&0x80 == 0 {
+				break
+			}
+		}
+		c *= n // now total number of bits to copy
+
+		// If the number of bits being repeated is small, load them
+		// into a register and use that register for the entire loop
+		// instead of repeatedly reading from memory.
+		// Handling fewer than 8 bits here makes the general loop simpler.
+		// The cutoff is ptrSize*8 - 7 to guarantee that when we add
+		// the pattern to a bit buffer holding at most 7 bits (a partial byte)
+		// it will not overflow.
+		src := dst
+		const maxBits = ptrSize*8 - 7
+		if n <= maxBits {
+			// Start with bits in output buffer.
+			pattern := bits
+			npattern := nbits
+
+			// If we need more bits, fetch them from memory.
+			if size == 1 {
+				src = subtract1(src)
+				for npattern < n {
+					pattern <<= 8
+					pattern |= uintptr(*src)
+					src = subtract1(src)
+					npattern += 8
+				}
+			} else {
+				src = add1(src)
+				for npattern < n {
+					pattern <<= 4
+					pattern |= uintptr(*src) & 0xf
+					src = add1(src)
+					npattern += 4
+				}
+			}
+
+			// We started with the whole bit output buffer,
+			// and then we loaded bits from whole bytes.
+			// Either way, we might now have too many instead of too few.
+			// Discard the extra.
+			if npattern > n {
+				pattern >>= npattern - n
+				npattern = n
+			}
+
+			// Replicate pattern to at most maxBits.
+			if npattern == 1 {
+				// One bit being repeated.
+				// If the bit is 1, make the pattern all 1s.
+				// If the bit is 0, the pattern is already all 0s,
+				// but we can claim that the number of bits
+				// in the word is equal to the number we need (c),
+				// because right shift of bits will zero fill.
+				if pattern == 1 {
+					pattern = 1<8 bits, there will be full bytes to flush
+			// on each iteration.
+			for ; c >= npattern; c -= npattern {
+				bits |= pattern << nbits
+				nbits += npattern
+				if size == 1 {
+					for nbits >= 8 {
+						*dst = uint8(bits)
+						dst = add1(dst)
+						bits >>= 8
+						nbits -= 8
+					}
+				} else {
+					for nbits >= 4 {
+						*dst = uint8(bits&0xf | bitMarkedAll)
+						dst = subtract1(dst)
+						bits >>= 4
+						nbits -= 4
+					}
+				}
+			}
+
+			// Add final fragment to bit buffer.
+			if c > 0 {
+				pattern &= 1< nbits because n > maxBits and nbits <= 7
+		if size == 1 {
+			// Leading src fragment.
+			src = subtractb(src, (off+7)/8)
+			if frag := off & 7; frag != 0 {
+				bits |= uintptr(*src) >> (8 - frag) << nbits
+				src = add1(src)
+				nbits += frag
+				c -= frag
+			}
+			// Main loop: load one byte, write another.
+			// The bits are rotating through the bit buffer.
+			for i := c / 8; i > 0; i-- {
+				bits |= uintptr(*src) << nbits
+				src = add1(src)
+				*dst = uint8(bits)
+				dst = add1(dst)
+				bits >>= 8
+			}
+			// Final src fragment.
+			if c %= 8; c > 0 {
+				bits |= (uintptr(*src) & (1<> (4 - frag) << nbits
+				src = subtract1(src)
+				nbits += frag
+				c -= frag
+			}
+			// Main loop: load one byte, write another.
+			// The bits are rotating through the bit buffer.
+			for i := c / 4; i > 0; i-- {
+				bits |= (uintptr(*src) & 0xf) << nbits
+				src = subtract1(src)
+				*dst = uint8(bits&0xf | bitMarkedAll)
+				dst = subtract1(dst)
+				bits >>= 4
+			}
+			// Final src fragment.
+			if c %= 4; c > 0 {
+				bits |= (uintptr(*src) & (1< 0; nbits -= 8 {
+			*dst = uint8(bits)
+			dst = add1(dst)
+			bits >>= 8
+		}
+	} else {
+		totalBits = (uintptr(unsafe.Pointer(dstStart))-uintptr(unsafe.Pointer(dst)))*4 + nbits
+		nbits += -nbits & 3
+		for ; nbits > 0; nbits -= 4 {
+			v := bits&0xf | bitMarkedAll
+			*dst = uint8(v)
+			dst = subtract1(dst)
+			bits >>= 4
+		}
+		// Clear the mark bits in the first two entries.
+		// They are the actual mark and checkmark bits,
+		// not non-dead markers. It simplified the code
+		// above to set the marker in every bit written and
+		// then clear these two as a special case at the end.
+		*dstStart &^= bitMarked | bitMarked< nptr && ret[len(ret)-1] == 0 {
+		ret = ret[:len(ret)-1]
+	}
+	return ret
+}
 
-	// data
+// Returns GC type info for object p for testing.
+func getgcmask(ep interface{}) (mask []byte) {
+	e := *(*eface)(unsafe.Pointer(&ep))
+	p := e.data
+	t := e._type
+	// data or bss
 	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		// data
 		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
+			bitmap := datap.gcdatamask.bytedata
 			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
-			*len = n / ptrSize
-			*mask = &make([]byte, *len)[0]
+			mask = make([]byte, n/ptrSize)
 			for i := uintptr(0); i < n; i += ptrSize {
 				off := (uintptr(p) + i - datap.data) / ptrSize
-				bits := (*addb(datap.gcdatamask.bytedata, off/8) >> (off % 8)) & 1
-				bits += 1 // convert 1-bit to 2-bit
-				*addb(*mask, i/ptrSize) = bits
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
 			}
 			return
 		}
 
 		// bss
 		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
+			bitmap := datap.gcbssmask.bytedata
 			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
-			*len = n / ptrSize
-			*mask = &make([]byte, *len)[0]
+			mask = make([]byte, n/ptrSize)
 			for i := uintptr(0); i < n; i += ptrSize {
 				off := (uintptr(p) + i - datap.bss) / ptrSize
-				bits := (*addb(datap.gcbssmask.bytedata, off/8) >> (off % 8)) & 1
-				bits += 1 // convert 1-bit to 2-bit
-				*addb(*mask, i/ptrSize) = bits
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
 			}
 			return
 		}
@@ -787,47 +1559,58 @@ func getgcmask(p unsafe.Pointer, t *_type, mask **byte, len *uintptr) {
 	var n uintptr
 	var base uintptr
 	if mlookup(uintptr(p), &base, &n, nil) != 0 {
-		*len = n / ptrSize
-		*mask = &make([]byte, *len)[0]
+		mask = make([]byte, n/ptrSize)
 		for i := uintptr(0); i < n; i += ptrSize {
-			bits := heapBitsForAddr(base + i).typeBits()
-			*addb(*mask, i/ptrSize) = bits
+			hbits := heapBitsForAddr(base + i)
+			if hbits.isPointer() {
+				mask[i/ptrSize] = 1
+			}
+			if i >= 2*ptrSize && !hbits.isMarked() {
+				mask = mask[:i/ptrSize]
+				break
+			}
 		}
 		return
 	}
 
 	// stack
-	var frame stkframe
-	frame.sp = uintptr(p)
-	_g_ := getg()
-	gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
-	if frame.fn != nil {
-		f := frame.fn
-		targetpc := frame.continpc
-		if targetpc == 0 {
-			return
-		}
-		if targetpc != f.entry {
-			targetpc--
-		}
-		pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
-		if pcdata == -1 {
-			return
-		}
-		stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
-		if stkmap == nil || stkmap.n <= 0 {
-			return
-		}
-		bv := stackmapdata(stkmap, pcdata)
-		size := uintptr(bv.n) * ptrSize
-		n := (*ptrtype)(unsafe.Pointer(t)).elem.size
-		*len = n / ptrSize
-		*mask = &make([]byte, *len)[0]
-		for i := uintptr(0); i < n; i += ptrSize {
-			off := (uintptr(p) + i - frame.varp + size) / ptrSize
-			bits := (*addb(bv.bytedata, off/8) >> (off % 8)) & 1
-			bits += 1 // convert 1-bit to 2-bit
-			*addb(*mask, i/ptrSize) = bits
+	if _g_ := getg(); _g_.m.curg.stack.lo <= uintptr(p) && uintptr(p) < _g_.m.curg.stack.hi {
+		var frame stkframe
+		frame.sp = uintptr(p)
+		_g_ := getg()
+		gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
+		if frame.fn != nil {
+			f := frame.fn
+			targetpc := frame.continpc
+			if targetpc == 0 {
+				return
+			}
+			if targetpc != f.entry {
+				targetpc--
+			}
+			pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+			if pcdata == -1 {
+				return
+			}
+			stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+			if stkmap == nil || stkmap.n <= 0 {
+				return
+			}
+			bv := stackmapdata(stkmap, pcdata)
+			size := uintptr(bv.n) * ptrSize
+			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+			mask = make([]byte, n/ptrSize)
+			for i := uintptr(0); i < n; i += ptrSize {
+				bitmap := bv.bytedata
+				off := (uintptr(p) + i - frame.varp + size) / ptrSize
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
+			}
 		}
+		return
 	}
+
+	// otherwise, not something the GC knows about.
+	// possibly read-only data, like malloc(0).
+	// must not have pointers
+	return
 }
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 9bd36d1a5e..db5b2dcd36 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -127,13 +127,22 @@ const (
 	_RootCount       = 5
 )
 
-// heapminimum is the minimum number of bytes in the heap.
-// This cleans up the corner case of where we have a very small live set but a lot
-// of allocations and collecting every GOGC * live set is expensive.
-// heapminimum is adjust by multiplying it by GOGC/100. In
-// the special case of GOGC==0 this will set heapminimum to 0 resulting
-// collecting at every allocation even when the heap size is small.
-var heapminimum = uint64(4 << 20)
+// heapminimum is the minimum heap size at which to trigger GC.
+// For small heaps, this overrides the usual GOGC*live set rule.
+//
+// When there is a very small live set but a lot of allocation, simply
+// collecting when the heap reaches GOGC*live results in many GC
+// cycles and high total per-GC overhead. This minimum amortizes this
+// per-GC overhead while keeping the heap reasonably small.
+//
+// During initialization this is set to 4MB*GOGC/100. In the case of
+// GOGC==0, this will set heapminimum to 0, resulting in constant
+// collection even when the heap size is small, which is useful for
+// debugging.
+var heapminimum uint64 = defaultHeapMinimum
+
+// defaultHeapMinimum is the value of heapminimum for GOGC==100.
+const defaultHeapMinimum = 4 << 20
 
 // Initialized from $GOGC.  GOGC=off means no GC.
 var gcpercent int32
@@ -146,8 +155,8 @@ func gcinit() {
 	work.markfor = parforalloc(_MaxGcproc)
 	_ = setGCPercent(readgogc())
 	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		datap.gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data)
-		datap.gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss)
+		datap.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data)
+		datap.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss)
 	}
 	memstats.next_gc = heapminimum
 }
@@ -180,7 +189,7 @@ func setGCPercent(in int32) (out int32) {
 		in = -1
 	}
 	gcpercent = in
-	heapminimum = heapminimum * uint64(gcpercent) / 100
+	heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100
 	unlock(&mheap_.lock)
 	return out
 }
@@ -197,7 +206,6 @@ var gcBlackenEnabled uint32
 
 const (
 	_GCoff             = iota // GC not running, write barrier disabled
-	_GCquiesce                // unused state
 	_GCstw                    // unused state
 	_GCscan                   // GC collecting roots into workbufs, write barrier disabled
 	_GCmark                   // GC marking from workbufs, write barrier ENABLED
@@ -208,7 +216,7 @@ const (
 //go:nosplit
 func setGCPhase(x uint32) {
 	atomicstore(&gcphase, x)
-	writeBarrierEnabled = gcphase == _GCmark || gcphase == _GCmarktermination || mheap_.shadow_enabled
+	writeBarrierEnabled = gcphase == _GCmark || gcphase == _GCmarktermination
 }
 
 // gcMarkWorkerMode represents the mode that a concurrent mark worker
@@ -699,11 +707,11 @@ const (
 func startGC(mode int) {
 	// The gc is turned off (via enablegc) until the bootstrap has completed.
 	// Also, malloc gets called in the guts of a number of libraries that might be
-	// holding locks. To avoid deadlocks during stoptheworld, don't bother
+	// holding locks. To avoid deadlocks during stop-the-world, don't bother
 	// trying to run gc while holding a lock. The next mallocgc without a lock
 	// will do the gc instead.
 	mp := acquirem()
-	if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
+	if gp := getg(); gp == mp.g0 || mp.locks > 1 || mp.preemptoff != "" || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
 		releasem(mp)
 		return
 	}
@@ -797,7 +805,7 @@ func gc(mode int) {
 		traceGCStart()
 	}
 
-	systemstack(stoptheworld)
+	systemstack(stopTheWorldWithSema)
 	systemstack(finishsweep_m) // finish sweep before we start concurrent scan.
 	// clearpools before we start the GC. If we wait they memory will not be
 	// reclaimed until the next GC cycle.
@@ -814,7 +822,7 @@ func gc(mode int) {
 			setGCPhase(_GCscan)
 
 			// Concurrent scan.
-			starttheworld()
+			startTheWorldWithSema()
 			if debug.gctrace > 0 {
 				tScan = nanotime()
 			}
@@ -858,7 +866,7 @@ func gc(mode int) {
 		if debug.gctrace > 0 {
 			tMarkTerm = nanotime()
 		}
-		systemstack(stoptheworld)
+		systemstack(stopTheWorldWithSema)
 		// The gcphase is _GCmark, it will transition to _GCmarktermination
 		// below. The important thing is that the wb remains active until
 		// all marking is complete. This includes writes made by the GC.
@@ -952,13 +960,12 @@ func gc(mode int) {
 	// all done
 	mp.preemptoff = ""
 
-	semrelease(&worldsema)
-
 	if gcphase != _GCoff {
 		throw("gc done but gcphase != _GCoff")
 	}
 
-	systemstack(starttheworld)
+	systemstack(startTheWorldWithSema)
+	semrelease(&worldsema)
 
 	releasem(mp)
 	mp = nil
@@ -1160,6 +1167,18 @@ func gcBgMarkDone() {
 	}
 }
 
+// gcMarkWorkAvailable determines if mark work is readily available.
+// It is used by the scheduler to decide if this p run a mark work.
+func gcMarkWorkAvailable(p *p) bool {
+	if !p.gcw.empty() {
+		return true
+	}
+	if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 {
+		return true // global work available
+	}
+	return false
+}
+
 // gcFlushGCWork disposes the gcWork caches of all Ps. The world must
 // be stopped.
 //go:nowritebarrier
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 9d78ddecae..62fa33895b 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -261,7 +261,7 @@ func gcphasework(gp *g) {
 	switch gcphase {
 	default:
 		throw("gcphasework in bad gcphase")
-	case _GCoff, _GCquiesce, _GCstw, _GCsweep:
+	case _GCoff, _GCstw, _GCsweep:
 		// No work.
 	case _GCscan:
 		// scan the stack, mark the objects, put pointers in work buffers
@@ -557,9 +557,6 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
 				// Same work as in scanobject; see comments there.
 				obj := *(*uintptr)(unsafe.Pointer(b + i))
 				if obj != 0 && arena_start <= obj && obj < arena_used {
-					if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
-						checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
-					}
 					if obj, hbits, span := heapBitsForObject(obj); obj != 0 {
 						greyobject(obj, b, i, hbits, span, gcw)
 					}
@@ -597,32 +594,25 @@ func scanobject(b uintptr, gcw *gcWork) {
 			// Avoid needless hbits.next() on last iteration.
 			hbits = hbits.next()
 		}
-		bits := uintptr(hbits.typeBits())
-		if bits == typeDead {
+		// During checkmarking, 1-word objects store the checkmark
+		// in the type bit for the one word. The only one-word objects
+		// are pointers, or else they'd be merged with other non-pointer
+		// data into larger allocations.
+		bits := hbits.bits()
+		if i >= 2*ptrSize && bits&bitMarked == 0 {
 			break // no more pointers in this object
 		}
-
-		if bits <= typeScalar { // typeScalar, typeDead, typeScalarMarked
-			continue
+		if bits&bitPointer == 0 {
+			continue // not a pointer
 		}
 
-		if bits&typePointer != typePointer {
-			print("gc useCheckmark=", useCheckmark, " b=", hex(b), "\n")
-			throw("unexpected garbage collection bits")
-		}
-
-		// Work here is duplicated in scanblock.
+		// Work here is duplicated in scanblock and above.
 		// If you make changes here, make changes there too.
-
 		obj := *(*uintptr)(unsafe.Pointer(b + i))
 
 		// At this point we have extracted the next potential pointer.
-		// Check if it points into heap.
-		if obj != 0 && arena_start <= obj && obj < arena_used {
-			if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && useCheckmark {
-				checkwbshadow((*uintptr)(unsafe.Pointer(b + i)))
-			}
-
+		// Check if it points into heap and not back at the current object.
+		if obj != 0 && arena_start <= obj && obj < arena_used && obj-b >= n {
 			// Mark the object.
 			if obj, hbits, span := heapBitsForObject(obj); obj != 0 {
 				greyobject(obj, b, i, hbits, span, gcw)
@@ -673,11 +663,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 
 			throw("checkmark found unmarked object")
 		}
-		if hbits.isCheckmarked() {
+		if hbits.isCheckmarked(span.elemsize) {
 			return
 		}
-		hbits.setCheckmarked()
-		if !hbits.isCheckmarked() {
+		hbits.setCheckmarked(span.elemsize)
+		if !hbits.isCheckmarked(span.elemsize) {
 			throw("setCheckmarked and isCheckmarked disagree")
 		}
 	} else {
@@ -685,12 +675,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 		if hbits.isMarked() {
 			return
 		}
-
 		hbits.setMarked()
 
 		// If this is a noscan object, fast-track it to black
 		// instead of greying it.
-		if hbits.typeBits() == typeDead {
+		if !hbits.hasPointers(span.elemsize) {
 			gcw.bytesMarked += uint64(span.elemsize)
 			return
 		}
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index 9c32ae8880..b7feb847b4 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -7,7 +7,7 @@ package runtime
 import "unsafe"
 
 const (
-	_Debugwbufs  = true    // if true check wbufs consistency
+	_Debugwbufs  = false   // if true check wbufs consistency
 	_WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion.
 )
 
@@ -182,6 +182,13 @@ func (w *gcWork) balance() {
 	}
 }
 
+// empty returns true if w has no mark work available.
+//go:nowritebarrier
+func (w *gcWork) empty() bool {
+	wbuf := w.wbuf
+	return wbuf == 0 || wbuf.ptr().nobj == 0
+}
+
 // Internally, the GC work pool is kept in arrays in work buffers.
 // The gcWork interface caches a work buffer until full (or empty) to
 // avoid contending on the global work buffer lists.
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 10878ee5cf..04fa050bc5 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -28,6 +28,15 @@ type mheap struct {
 	spans        **mspan
 	spans_mapped uintptr
 
+	// Proportional sweep
+	pagesSwept        uint64  // pages swept this cycle; updated atomically
+	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
+
+	// Malloc stats.
+	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
+	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
+	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
+
 	// range of addresses we might see in the heap
 	bitmap         uintptr
 	bitmap_mapped  uintptr
@@ -36,14 +45,6 @@ type mheap struct {
 	arena_end      uintptr
 	arena_reserved bool
 
-	// write barrier shadow heap.
-	// 64-bit systems only, enabled by GODEBUG=wbshadow=1.
-	// See also shadow_data, data_start, data_end fields on moduledata in
-	// symtab.go.
-	shadow_enabled  bool    // shadow should be updated and checked
-	shadow_reserved bool    // shadow memory is reserved
-	shadow_heap     uintptr // heap-addr + shadow_heap = shadow heap addr
-
 	// central free lists for small size classes.
 	// the padding makes sure that the MCentrals are
 	// spaced CacheLineSize bytes apart, so that each MCentral.lock
@@ -58,15 +59,6 @@ type mheap struct {
 	specialfinalizeralloc fixalloc // allocator for specialfinalizer*
 	specialprofilealloc   fixalloc // allocator for specialprofile*
 	speciallock           mutex    // lock for sepcial record allocators.
-
-	// Proportional sweep
-	pagesSwept        uint64  // pages swept this cycle; updated atomically
-	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
-
-	// Malloc stats.
-	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
-	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
-	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
 }
 
 var mheap_ mheap
@@ -176,7 +168,9 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
 
 // inheap reports whether b is a pointer into a (potentially dead) heap object.
 // It returns false for pointers into stack spans.
+// Non-preemptible because it is used by write barriers.
 //go:nowritebarrier
+//go:nosplit
 func inheap(b uintptr) bool {
 	if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used {
 		return false
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index 4544344780..a618bd5e81 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -521,9 +521,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 	n = NumGoroutine()
 	if n <= len(p) {
 		gp := getg()
-		semacquire(&worldsema, false)
-		gp.m.preemptoff = "profile"
-		systemstack(stoptheworld)
+		stopTheWorld("profile")
 
 		n = NumGoroutine()
 		if n <= len(p) {
@@ -544,9 +542,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 			}
 		}
 
-		gp.m.preemptoff = ""
-		semrelease(&worldsema)
-		systemstack(starttheworld)
+		startTheWorld()
 	}
 
 	return n, ok
@@ -565,10 +561,7 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
 // into buf after the trace for the current goroutine.
 func Stack(buf []byte, all bool) int {
 	if all {
-		semacquire(&worldsema, false)
-		gp := getg()
-		gp.m.preemptoff = "stack trace"
-		systemstack(stoptheworld)
+		stopTheWorld("stack trace")
 	}
 
 	n := 0
@@ -590,10 +583,7 @@ func Stack(buf []byte, all bool) int {
 	}
 
 	if all {
-		gp := getg()
-		gp.m.preemptoff = ""
-		semrelease(&worldsema)
-		systemstack(starttheworld)
+		startTheWorld()
 	}
 	return n
 }
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index c8e5249156..3eff7f6b3e 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -153,24 +153,13 @@ func init() {
 
 // ReadMemStats populates m with memory allocator statistics.
 func ReadMemStats(m *MemStats) {
-	// Have to acquire worldsema to stop the world,
-	// because stoptheworld can only be used by
-	// one goroutine at a time, and there might be
-	// a pending garbage collection already calling it.
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.preemptoff = "read mem stats"
-	systemstack(stoptheworld)
+	stopTheWorld("read mem stats")
 
 	systemstack(func() {
 		readmemstats_m(m)
 	})
 
-	gp.m.preemptoff = ""
-	gp.m.locks++
-	semrelease(&worldsema)
-	systemstack(starttheworld)
-	gp.m.locks--
+	startTheWorld()
 }
 
 func readmemstats_m(stats *MemStats) {
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
index 10cf460f7f..1b74e3e653 100644
--- a/src/runtime/os1_darwin.go
+++ b/src/runtime/os1_darwin.go
@@ -8,7 +8,6 @@ import "unsafe"
 
 //extern SigTabTT runtime·sigtab[];
 
-var sigset_none = uint32(0)
 var sigset_all = ^uint32(0)
 
 func unimplemented(name string) {
@@ -126,17 +125,36 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
 	// Initialize signal handling.
 	_g_ := getg()
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask &^= 1 << (uint32(i) - 1)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
 	signalstack(nil, 0)
 }
 
@@ -447,6 +465,6 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+func updatesigmask(m sigmask) {
+	sigprocmask(_SIG_SETMASK, &m[0], nil)
 }
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
index a590aea39b..eb42b54e2b 100644
--- a/src/runtime/os1_dragonfly.go
+++ b/src/runtime/os1_dragonfly.go
@@ -12,7 +12,6 @@ const (
 	_HW_NCPU = 3
 )
 
-var sigset_none = sigset{}
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
 func getncpu() int32 {
@@ -120,6 +119,14 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(nil, smask)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -130,11 +137,22 @@ func minit() {
 
 	// Initialize signal handling
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(&sigset_none, nil)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(&nmask, nil)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(smask, nil)
 	signalstack(nil, 0)
 }
 
@@ -215,6 +233,8 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(&sigset_none, nil)
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(&mask, nil)
 }
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
index 8719a49286..f7f34bd386 100644
--- a/src/runtime/os1_freebsd.go
+++ b/src/runtime/os1_freebsd.go
@@ -12,7 +12,6 @@ const (
 	_HW_NCPU = 3
 )
 
-var sigset_none = sigset{}
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
 func getncpu() int32 {
@@ -119,6 +118,14 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(nil, smask)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -132,11 +139,22 @@ func minit() {
 
 	// Initialize signal handling.
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(&sigset_none, nil)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(&nmask, nil)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(smask, nil)
 	signalstack(nil, 0)
 }
 
@@ -217,6 +235,8 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(&sigset_none, nil)
+func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(&mask, nil)
 }
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
index e4b18c79b3..02f98d7c5f 100644
--- a/src/runtime/os1_linux.go
+++ b/src/runtime/os1_linux.go
@@ -6,7 +6,6 @@ package runtime
 
 import "unsafe"
 
-var sigset_none sigset
 var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
 
 // Linux futex.
@@ -190,17 +189,36 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
 	// Initialize signal handling.
 	_g_ := getg()
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
 	signalstack(nil, 0)
 }
 
@@ -304,6 +322,8 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	rtsigprocmask(_SIG_SETMASK, &sigset_none, nil, int32(unsafe.Sizeof(sigset_none)))
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask[:], m[:])
+	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
 }
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
index dbb5dec2fd..66e60f8b12 100644
--- a/src/runtime/os1_nacl.go
+++ b/src/runtime/os1_nacl.go
@@ -15,6 +15,9 @@ func mpreinit(mp *m) {
 
 func sigtramp()
 
+func msigsave(mp *m) {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
index 8df74b5593..3fb05989e7 100644
--- a/src/runtime/os1_netbsd.go
+++ b/src/runtime/os1_netbsd.go
@@ -17,7 +17,6 @@ const (
 	_CLOCK_MONOTONIC = 3
 )
 
-var sigset_none = sigset{}
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
 // From NetBSD's 
@@ -139,6 +138,14 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -147,11 +154,23 @@ func minit() {
 
 	// Initialize signal handling
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+
 	signalstack(nil, 0)
 }
 
@@ -206,6 +225,8 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
 }
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
index 95729a56df..5ccf642468 100644
--- a/src/runtime/os1_openbsd.go
+++ b/src/runtime/os1_openbsd.go
@@ -148,6 +148,14 @@ func mpreinit(mp *m) {
 	mp.gsignal.m = mp
 }
 
+func msigsave(mp *m) {
+	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	*smask = sigprocmask(_SIG_BLOCK, 0)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -158,11 +166,22 @@ func minit() {
 
 	// Initialize signal handling
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(_SIG_SETMASK, sigset_none)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask &^= 1 << (uint32(i) - 1)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, nmask)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask)
 	signalstack(nil, 0)
 }
 
@@ -217,6 +236,6 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(_SIG_SETMASK, sigset_none)
+func updatesigmask(m sigmask) {
+	sigprocmask(_SIG_SETMASK, m[0])
 }
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
index c026218241..bda7057f44 100644
--- a/src/runtime/os1_plan9.go
+++ b/src/runtime/os1_plan9.go
@@ -18,6 +18,9 @@ func mpreinit(mp *m) {
 	mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan))
 }
 
+func msigsave(mp *m) {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -177,7 +180,7 @@ func exit(e int) {
 	} else {
 		// build error string
 		var tmp [32]byte
-		status = []byte(gostringnocopy(&itoa(tmp[:len(tmp)-1], uint64(e))[0]))
+		status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
 	}
 	goexitsall(&status[0])
 	exits(&status[0])
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
index 5719b320f5..bc472d0de9 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -292,6 +292,9 @@ func newosproc(mp *m, stk unsafe.Pointer) {
 func mpreinit(mp *m) {
 }
 
+func msigsave(mp *m) {
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 69ac5b4970..e4fe92de41 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -114,7 +114,6 @@ var (
 	libc_write libcFunc
 )
 
-var sigset_none = sigset{}
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
 func getncpu() int32 {
@@ -190,6 +189,14 @@ func mpreinit(mp *m) {
 
 func miniterrno()
 
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
 // Called to initialize a new m (including the bootstrap m).
 // Called on the new thread, can not allocate memory.
 func minit() {
@@ -197,11 +204,23 @@ func minit() {
 	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
 	// Initialize signal handling
 	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
 }
 
 // Called from dropm to undo the effect of an minit.
 func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+
 	signalstack(nil, 0)
 }
 
@@ -278,8 +297,10 @@ func signalstack(p *byte, n int32) {
 	sigaltstack(&st, nil)
 }
 
-func unblocksignals() {
-	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__sigbits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
 }
 
 //go:nosplit
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 0e4086c7ef..47563f450e 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -188,16 +188,6 @@ func newdefer(siz int32) *_defer {
 		d = (*_defer)(mallocgc(total, deferType, 0))
 	}
 	d.siz = siz
-	if mheap_.shadow_enabled {
-		// This memory will be written directly, with no write barrier,
-		// and then scanned like stacks during collection.
-		// Unlike real stacks, it is from heap spans, so mark the
-		// shadow as explicitly unusable.
-		p := deferArgs(d)
-		for i := uintptr(0); i+ptrSize <= uintptr(siz); i += ptrSize {
-			writebarrierptr_noshadow((*uintptr)(add(p, i)))
-		}
-	}
 	gp := mp.curg
 	d.link = gp._defer
 	gp._defer = d
@@ -214,12 +204,6 @@ func freedefer(d *_defer) {
 	if d.fn != nil {
 		freedeferfn()
 	}
-	if mheap_.shadow_enabled {
-		// Undo the marking in newdefer.
-		systemstack(func() {
-			clearshadow(uintptr(deferArgs(d)), uintptr(d.siz))
-		})
-	}
 	sc := deferclass(uintptr(d.siz))
 	if sc < uintptr(len(p{}.deferpool)) {
 		mp := acquirem()
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index b3d0ae9b64..4290edb7be 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -442,35 +442,33 @@ func writeHeap(w io.Writer, debug int) error {
 
 	// Print memstats information too.
 	// Pprof will ignore, but useful for people
-	if debug > 0 {
-		s := new(runtime.MemStats)
-		runtime.ReadMemStats(s)
-		fmt.Fprintf(w, "\n# runtime.MemStats\n")
-		fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
-		fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
-		fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
-		fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
-		fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
-		fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
+	s := new(runtime.MemStats)
+	runtime.ReadMemStats(s)
+	fmt.Fprintf(w, "\n# runtime.MemStats\n")
+	fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
+	fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
+	fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
+	fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
+	fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
+	fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
 
-		fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
-		fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
-		fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
-		fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
-		fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
-		fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
+	fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
+	fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
+	fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
+	fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
+	fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
+	fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
 
-		fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
-		fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
-		fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
-		fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+	fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+	fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+	fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+	fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
 
-		fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
-		fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
-		fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
-		fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
-		fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
-	}
+	fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+	fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+	fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+	fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
+	fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
 
 	if tw != nil {
 		tw.Flush()
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index f725fc890b..805b96e627 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -203,7 +203,7 @@ func acquireSudog() *sudog {
 	// acquireSudog, acquireSudog calls new(sudog),
 	// new calls malloc, malloc can call the garbage collector,
 	// and the garbage collector calls the semaphore implementation
-	// in stoptheworld.
+	// in stopTheWorld.
 	// Break the cycle by doing acquirem/releasem around new(sudog).
 	// The acquirem/releasem increments m.locks during new(sudog),
 	// which keeps the garbage collector from being invoked.
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 00535da77d..c070f7d773 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -59,7 +59,6 @@ func schedinit() {
 	goargs()
 	goenvs()
 	parsedebugvars()
-	wbshadowinit()
 	gcinit()
 
 	sched.lastpoll = uint64(nanotime())
@@ -212,7 +211,7 @@ func helpgc(nproc int32) {
 // sched.stopwait to in order to request that all Gs permanently stop.
 const freezeStopWait = 0x7fffffff
 
-// Similar to stoptheworld but best-effort and can be called several times.
+// Similar to stopTheWorld but best-effort and can be called several times.
 // There is no reverse operation, used during crashing.
 // This function must not lock any mutexes.
 func freezetheworld() {
@@ -466,94 +465,68 @@ func stopscanstart(gp *g) {
 	}
 }
 
-// Runs on g0 and does the actual work after putting the g back on the run queue.
-func mquiesce(gpmaster *g) {
-	// enqueue the calling goroutine.
-	restartg(gpmaster)
-
-	activeglen := len(allgs)
-	for i := 0; i < activeglen; i++ {
-		gp := allgs[i]
-		if readgstatus(gp) == _Gdead {
-			gp.gcworkdone = true // noop scan.
-		} else {
-			gp.gcworkdone = false
-		}
-		stopscanstart(gp)
-	}
-
-	// Check that the G's gcwork (such as scanning) has been done. If not do it now.
-	// You can end up doing work here if the page trap on a Grunning Goroutine has
-	// not been sprung or in some race situations. For example a runnable goes dead
-	// and is started up again with a gp->gcworkdone set to false.
-	for i := 0; i < activeglen; i++ {
-		gp := allgs[i]
-		for !gp.gcworkdone {
-			status := readgstatus(gp)
-			if status == _Gdead {
-				//do nothing, scan not needed.
-				gp.gcworkdone = true // scan is a noop
-				break
-			}
-			if status == _Grunning && gp.stackguard0 == uintptr(stackPreempt) && notetsleep(&sched.stopnote, 100*1000) { // nanosecond arg
-				noteclear(&sched.stopnote)
-			} else {
-				stopscanstart(gp)
-			}
-		}
-	}
-
-	for i := 0; i < activeglen; i++ {
-		gp := allgs[i]
-		status := readgstatus(gp)
-		if isscanstatus(status) {
-			print("mstopandscang:bottom: post scan bad status gp=", gp, " has status ", hex(status), "\n")
-			dumpgstatus(gp)
-		}
-		if !gp.gcworkdone && status != _Gdead {
-			print("mstopandscang:bottom: post scan gp=", gp, "->gcworkdone still false\n")
-			dumpgstatus(gp)
-		}
-	}
-
-	schedule() // Never returns.
+// stopTheWorld stops all P's from executing goroutines, interrupting
+// all goroutines at GC safe points and records reason as the reason
+// for the stop. On return, only the current goroutine's P is running.
+// stopTheWorld must not be called from a system stack and the caller
+// must not hold worldsema. The caller must call startTheWorld when
+// other P's should resume execution.
+//
+// stopTheWorld is safe for multiple goroutines to call at the
+// same time. Each will execute its own stop, and the stops will
+// be serialized.
+//
+// This is also used by routines that do stack dumps. If the system is
+// in panic or being exited, this may not reliably stop all
+// goroutines.
+func stopTheWorld(reason string) {
+	semacquire(&worldsema, false)
+	getg().m.preemptoff = reason
+	systemstack(stopTheWorldWithSema)
 }
 
-// quiesce moves all the goroutines to a GC safepoint which for now is a at preemption point.
-// If the global gcphase is GCmark quiesce will ensure that all of the goroutine's stacks
-// have been scanned before it returns.
-func quiesce(mastergp *g) {
-	castogscanstatus(mastergp, _Grunning, _Gscanenqueue)
-	// Now move this to the g0 (aka m) stack.
-	// g0 will potentially scan this thread and put mastergp on the runqueue
-	mcall(mquiesce)
+// startTheWorld undoes the effects of stopTheWorld.
+func startTheWorld() {
+	systemstack(startTheWorldWithSema)
+	// worldsema must be held over startTheWorldWithSema to ensure
+	// gomaxprocs cannot change while worldsema is held.
+	semrelease(&worldsema)
+	getg().m.preemptoff = ""
 }
 
-// Holding worldsema grants an M the right to try to stop the world.
-// The procedure is:
-//
-//	semacquire(&worldsema);
-//	m.preemptoff = "reason";
-//	stoptheworld();
-//
-//	... do stuff ...
-//
-//	m.preemptoff = "";
-//	semrelease(&worldsema);
-//	starttheworld();
-//
+// Holding worldsema grants an M the right to try to stop the world
+// and prevents gomaxprocs from changing concurrently.
 var worldsema uint32 = 1
 
-// This is used by the GC as well as the routines that do stack dumps. In the case
-// of GC all the routines can be reliably stopped. This is not always the case
-// when the system is in panic or being exited.
-func stoptheworld() {
+// stopTheWorldWithSema is the core implementation of stopTheWorld.
+// The caller is responsible for acquiring worldsema and disabling
+// preemption first and then should stopTheWorldWithSema on the system
+// stack:
+//
+//	semacquire(&worldsema, false)
+//	m.preemptoff = "reason"
+//	systemstack(stopTheWorldWithSema)
+//
+// When finished, the caller must either call startTheWorld or undo
+// these three operations separately:
+//
+//	m.preemptoff = ""
+//	systemstack(startTheWorldWithSema)
+//	semrelease(&worldsema)
+//
+// It is allowed to acquire worldsema once and then execute multiple
+// startTheWorldWithSema/stopTheWorldWithSema pairs.
+// Other P's are able to execute between successive calls to
+// startTheWorldWithSema and stopTheWorldWithSema.
+// Holding worldsema causes any other goroutines invoking
+// stopTheWorld to block.
+func stopTheWorldWithSema() {
 	_g_ := getg()
 
 	// If we hold a lock, then we won't be able to stop another M
 	// that is blocked trying to acquire the lock.
 	if _g_.m.locks > 0 {
-		throw("stoptheworld: holding locks")
+		throw("stopTheWorld: holding locks")
 	}
 
 	lock(&sched.lock)
@@ -600,12 +573,12 @@ func stoptheworld() {
 		}
 	}
 	if sched.stopwait != 0 {
-		throw("stoptheworld: not stopped")
+		throw("stopTheWorld: not stopped")
 	}
 	for i := 0; i < int(gomaxprocs); i++ {
 		p := allp[i]
 		if p.status != _Pgcstop {
-			throw("stoptheworld: not stopped")
+			throw("stopTheWorld: not stopped")
 		}
 	}
 }
@@ -615,7 +588,7 @@ func mhelpgc() {
 	_g_.m.helpgc = -1
 }
 
-func starttheworld() {
+func startTheWorldWithSema() {
 	_g_ := getg()
 
 	_g_.m.locks++        // disable preemption because it can be holding p in a local var
@@ -644,7 +617,7 @@ func starttheworld() {
 			mp := p.m.ptr()
 			p.m = 0
 			if mp.nextp != 0 {
-				throw("starttheworld: inconsistent mp->nextp")
+				throw("startTheWorld: inconsistent mp->nextp")
 			}
 			mp.nextp.set(p)
 			notewakeup(&mp.park)
@@ -754,10 +727,10 @@ func forEachP(fn func(*p)) {
 	_p_ := getg().m.p.ptr()
 
 	lock(&sched.lock)
-	if sched.stopwait != 0 {
-		throw("forEachP: sched.stopwait != 0")
+	if sched.safePointWait != 0 {
+		throw("forEachP: sched.safePointWait != 0")
 	}
-	sched.stopwait = gomaxprocs - 1
+	sched.safePointWait = gomaxprocs - 1
 	sched.safePointFn = fn
 
 	// Ask all Ps to run the safe point function.
@@ -777,11 +750,11 @@ func forEachP(fn func(*p)) {
 	for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
 		if cas(&p.runSafePointFn, 1, 0) {
 			fn(p)
-			sched.stopwait--
+			sched.safePointWait--
 		}
 	}
 
-	wait := sched.stopwait > 0
+	wait := sched.safePointWait > 0
 	unlock(&sched.lock)
 
 	// Run fn for the current P.
@@ -807,15 +780,15 @@ func forEachP(fn func(*p)) {
 		for {
 			// Wait for 100us, then try to re-preempt in
 			// case of any races.
-			if notetsleep(&sched.stopnote, 100*1000) {
-				noteclear(&sched.stopnote)
+			if notetsleep(&sched.safePointNote, 100*1000) {
+				noteclear(&sched.safePointNote)
 				break
 			}
 			preemptall()
 		}
 	}
-	if sched.stopwait != 0 {
-		throw("forEachP: not stopped")
+	if sched.safePointWait != 0 {
+		throw("forEachP: not done")
 	}
 	for i := 0; i < int(gomaxprocs); i++ {
 		p := allp[i]
@@ -851,9 +824,9 @@ func runSafePointFn() {
 	}
 	sched.safePointFn(p)
 	lock(&sched.lock)
-	sched.stopwait--
-	if sched.stopwait == 0 {
-		notewakeup(&sched.stopnote)
+	sched.safePointWait--
+	if sched.safePointWait == 0 {
+		notewakeup(&sched.safePointNote)
 	}
 	unlock(&sched.lock)
 }
@@ -971,6 +944,7 @@ func needm(x byte) {
 	_g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024
 	_g_.stackguard0 = _g_.stack.lo + _StackGuard
 
+	msigsave(mp)
 	// Initialize this thread to use the m.
 	asminit()
 	minit()
@@ -1098,6 +1072,7 @@ func unlockextra(mp *m) {
 func newm(fn func(), _p_ *p) {
 	mp := allocm(_p_, fn)
 	mp.nextp.set(_p_)
+	msigsave(mp)
 	if iscgo {
 		var ts cgothreadstart
 		if _cgo_thread_start == nil {
@@ -1226,9 +1201,9 @@ func handoffp(_p_ *p) {
 	}
 	if _p_.runSafePointFn != 0 && cas(&_p_.runSafePointFn, 1, 0) {
 		sched.safePointFn(_p_)
-		sched.stopwait--
-		if sched.stopwait == 0 {
-			notewakeup(&sched.stopnote)
+		sched.safePointWait--
+		if sched.safePointWait == 0 {
+			notewakeup(&sched.safePointNote)
 		}
 	}
 	if sched.runqsize != 0 {
@@ -1305,7 +1280,7 @@ func startlockedm(gp *g) {
 	stopm()
 }
 
-// Stops the current m for stoptheworld.
+// Stops the current m for stopTheWorld.
 // Returns when the world is restarted.
 func gcstopm() {
 	_g_ := getg()
@@ -1421,7 +1396,7 @@ top:
 		xadd(&sched.nmspinning, 1)
 	}
 	// random steal from other P's
-	for i := 0; i < int(2*gomaxprocs); i++ {
+	for i := 0; i < int(4*gomaxprocs); i++ {
 		if sched.gcwaiting != 0 {
 			goto top
 		}
@@ -1430,18 +1405,20 @@ top:
 		if _p_ == _g_.m.p.ptr() {
 			gp, _ = runqget(_p_)
 		} else {
-			gp = runqsteal(_g_.m.p.ptr(), _p_)
+			stealRunNextG := i > 2*int(gomaxprocs) // first look for ready queues with more than 1 g
+			gp = runqsteal(_g_.m.p.ptr(), _p_, stealRunNextG)
 		}
 		if gp != nil {
 			return gp, false
 		}
 	}
+
 stop:
 
-	// We have nothing to do. If we're in the GC mark phaseand can
+	// We have nothing to do. If we're in the GC mark phase and can
 	// safely scan and blacken objects, run idle-time marking
 	// rather than give up the P.
-	if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil {
+	if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil && gcMarkWorkAvailable(_p_) {
 		_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
 		gp := _p_.gcBgMarkWorker
 		casgstatus(gp, _Gwaiting, _Grunnable)
@@ -2484,11 +2461,9 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	mp.mallocing++
 
 	// Define that a "user g" is a user-created goroutine, and a "system g"
-	// is one that is m->g0 or m->gsignal. We've only made sure that we
-	// can unwind user g's, so exclude the system g's.
+	// is one that is m->g0 or m->gsignal.
 	//
-	// It is not quite as easy as testing gp == m->curg (the current user g)
-	// because we might be interrupted for profiling halfway through a
+	// We might be interrupted for profiling halfway through a
 	// goroutine switch. The switch involves updating three (or four) values:
 	// g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
 	// because once it gets updated the new g is running.
@@ -2497,8 +2472,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	// so the update only affects g, SP, and PC. Since PC must be last, there
 	// the possible partial transitions in ordinary execution are (1) g alone is updated,
 	// (2) both g and SP are updated, and (3) SP alone is updated.
-	// If g is updated, we'll see a system g and not look closer.
-	// If SP alone is updated, we can detect the partial transition by checking
+	// If SP or g alone is updated, we can detect the partial transition by checking
 	// whether the SP is within g's stack bounds. (We could also require that SP
 	// be changed only after g, but the stack bounds check is needed by other
 	// cases, so there is no need to impose an additional requirement.)
@@ -2527,15 +2501,11 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	// disabled, so a profiling signal cannot arrive then anyway.
 	//
 	// Third, the common case: it may be that the switch updates g, SP, and PC
-	// separately, as in gogo.
-	//
-	// Because gogo is the only instance, we check whether the PC lies
-	// within that function, and if so, not ask for a traceback. This approach
-	// requires knowing the size of the gogo function, which we
-	// record in arch_*.h and check in runtime_test.go.
+	// separately. If the PC is within any of the functions that does this,
+	// we don't ask for a traceback. C.F. the function setsSP for more about this.
 	//
 	// There is another apparently viable approach, recorded here in case
-	// the "PC within gogo" check turns out not to be usable.
+	// the "PC within setsSP function" check turns out not to be usable.
 	// It would be possible to delay the update of either g or SP until immediately
 	// before the PC update instruction. Then, because of the stack bounds check,
 	// the only problematic interrupt point is just before that PC update instruction,
@@ -2556,28 +2526,23 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	// transition. We simply require that g and SP match and that the PC is not
 	// in gogo.
 	traceback := true
-	gogo := funcPC(gogo)
-	if gp == nil || gp != mp.curg ||
-		sp < gp.stack.lo || gp.stack.hi < sp ||
-		(gogo <= pc && pc < gogo+_RuntimeGogoBytes) {
+	if gp == nil || sp < gp.stack.lo || gp.stack.hi < sp || setsSP(pc) {
 		traceback = false
 	}
-
 	var stk [maxCPUProfStack]uintptr
 	n := 0
-	if traceback {
-		n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap)
+	if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
+		// Cgo, we can't unwind and symbolize arbitrary C code,
+		// so instead collect Go stack that leads to the cgo call.
+		// This is especially important on windows, since all syscalls are cgo calls.
+		n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0)
+	} else if traceback {
+		n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
 	}
 	if !traceback || n <= 0 {
 		// Normal traceback is impossible or has failed.
 		// See if it falls into several common cases.
 		n = 0
-		if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
-			// Cgo, we can't unwind and symbolize arbitrary C code,
-			// so instead collect Go stack that leads to the cgo call.
-			// This is especially important on windows, since all syscalls are cgo calls.
-			n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0)
-		}
 		if GOOS == "windows" && n == 0 && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
 			// Libcall, i.e. runtime syscall on windows.
 			// Collect Go stack that leads to the call.
@@ -2612,6 +2577,30 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	mp.mallocing--
 }
 
+// Reports whether a function will set the SP
+// to an absolute value. Important that
+// we don't traceback when these are at the bottom
+// of the stack since we can't be sure that we will
+// find the caller.
+//
+// If the function is not on the bottom of the stack
+// we assume that it will have set it up so that traceback will be consistent,
+// either by being a traceback terminating function
+// or putting one on the stack at the right offset.
+func setsSP(pc uintptr) bool {
+	f := findfunc(pc)
+	if f == nil {
+		// couldn't find the function for this PC,
+		// so assume the worst and stop traceback
+		return true
+	}
+	switch f.entry {
+	case gogoPC, systemstackPC, mcallPC, morestackPC:
+		return true
+	}
+	return false
+}
+
 // Arrange to call fn with a traceback hz times a second.
 func setcpuprofilerate_m(hz int32) {
 	// Force sane arguments.
@@ -3447,23 +3436,34 @@ func runqget(_p_ *p) (gp *g, inheritTime bool) {
 	}
 }
 
-// Grabs a batch of goroutines from local runnable queue.
-// batch array must be of size len(p->runq)/2. Returns number of grabbed goroutines.
+// Grabs a batch of goroutines from _p_'s runnable queue into batch.
+// Batch is a ring buffer starting at batchHead.
+// Returns number of grabbed goroutines.
 // Can be executed by any P.
-func runqgrab(_p_ *p, batch []*g) uint32 {
+func runqgrab(_p_ *p, batch *[256]*g, batchHead uint32, stealRunNextG bool) uint32 {
 	for {
 		h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
 		t := atomicload(&_p_.runqtail) // load-acquire, synchronize with the producer
 		n := t - h
 		n = n - n/2
 		if n == 0 {
-			// Try to steal from _p_.runnext.
-			if next := _p_.runnext; next != 0 {
-				if !_p_.runnext.cas(next, 0) {
-					continue
+			if stealRunNextG {
+				// Try to steal from _p_.runnext.
+				if next := _p_.runnext; next != 0 {
+					// Sleep to ensure that _p_ isn't about to run the g we
+					// are about to steal.
+					// The important use case here is when the g running on _p_
+					// ready()s another g and then almost immediately blocks.
+					// Instead of stealing runnext in this window, back off
+					// to give _p_ a chance to schedule runnext. This will avoid
+					// thrashing gs between different Ps.
+					usleep(100)
+					if !_p_.runnext.cas(next, 0) {
+						continue
+					}
+					batch[batchHead%uint32(len(batch))] = next.ptr()
+					return 1
 				}
-				batch[0] = next.ptr()
-				return 1
 			}
 			return 0
 		}
@@ -3471,7 +3471,8 @@ func runqgrab(_p_ *p, batch []*g) uint32 {
 			continue
 		}
 		for i := uint32(0); i < n; i++ {
-			batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))]
+			g := _p_.runq[(h+i)%uint32(len(_p_.runq))]
+			batch[(batchHead+i)%uint32(len(batch))] = g
 		}
 		if cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
 			return n
@@ -3482,26 +3483,21 @@ func runqgrab(_p_ *p, batch []*g) uint32 {
 // Steal half of elements from local runnable queue of p2
 // and put onto local runnable queue of p.
 // Returns one of the stolen elements (or nil if failed).
-func runqsteal(_p_, p2 *p) *g {
-	var batch [len(_p_.runq) / 2]*g
-
-	n := runqgrab(p2, batch[:])
+func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
+	t := _p_.runqtail
+	n := runqgrab(p2, &_p_.runq, t, stealRunNextG)
 	if n == 0 {
 		return nil
 	}
 	n--
-	gp := batch[n]
+	gp := _p_.runq[(t+n)%uint32(len(_p_.runq))]
 	if n == 0 {
 		return gp
 	}
 	h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
-	t := _p_.runqtail
 	if t-h+n >= uint32(len(_p_.runq)) {
 		throw("runqsteal: runq overflow")
 	}
-	for i := uint32(0); i < n; i++ {
-		_p_.runq[(t+i)%uint32(len(_p_.runq))] = batch[i]
-	}
 	atomicstore(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
 	return gp
 }
@@ -3528,20 +3524,16 @@ func testSchedLocalQueue() {
 	}
 }
 
-var pSink *p
-
 func testSchedLocalQueueSteal() {
 	p1 := new(p)
 	p2 := new(p)
-	pSink = p1 // Force to heap, too large to allocate on system stack ("G0 stack")
-	pSink = p2 // Force to heap, too large to allocate on system stack ("G0 stack")
 	gs := make([]g, len(p1.runq))
 	for i := 0; i < len(p1.runq); i++ {
 		for j := 0; j < i; j++ {
 			gs[j].sig = 0
 			runqput(p1, &gs[j], false)
 		}
-		gp := runqsteal(p2, p1)
+		gp := runqsteal(p2, p1, true)
 		s := 0
 		if gp != nil {
 			s++
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 4c5712d32f..4471ee5afb 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -7,6 +7,7 @@ package runtime_test
 import (
 	"math"
 	"runtime"
+	"runtime/debug"
 	"sync"
 	"sync/atomic"
 	"syscall"
@@ -104,8 +105,8 @@ func TestGoroutineParallelism(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
 	// If runtime triggers a forced GC during this test then it will deadlock,
 	// since the goroutines can't be stopped/preempted.
-	// So give this test as much time as possible.
-	runtime.GC()
+	// Disable GC for this test (see issue #10958).
+	defer debug.SetGCPercent(debug.SetGCPercent(-1))
 	for try := 0; try < N; try++ {
 		done := make(chan bool)
 		x := uint32(0)
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index fe7d38a39c..f4014b2e05 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -59,7 +59,7 @@ func TestGdbPython(t *testing.T) {
 
 	cmd := exec.Command("go", "build", "-o", "a.exe")
 	cmd.Dir = dir
-	out, err := cmd.CombinedOutput()
+	out, err := testEnv(cmd).CombinedOutput()
 	if err != nil {
 		t.Fatalf("building source %v\n%s", err, out)
 	}
@@ -85,7 +85,7 @@ func TestGdbPython(t *testing.T) {
 	// stack frames on RISC architectures.
 	canBackTrace := false
 	switch runtime.GOARCH {
-	case "amd64", "386":
+	case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64":
 		canBackTrace = true
 		args = append(args,
 			"-ex", "echo BEGIN goroutine 2 bt\n",
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index ac539b9a9d..3ee5d5d29d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -266,6 +266,7 @@ type m struct {
 	// Fields not known to debuggers.
 	procid        uint64     // for debuggers, but offset not hard-coded
 	gsignal       *g         // signal-handling g
+	sigmask       [4]uintptr // storage for saved signal mask
 	tls           [4]uintptr // thread-local storage (for x86 extern register)
 	mstartfn      func()
 	curg          *g       // current running goroutine
@@ -441,7 +442,9 @@ type schedt struct {
 
 	// safepointFn should be called on each P at the next GC
 	// safepoint if p.runSafePointFn is set.
-	safePointFn func(*p)
+	safePointFn   func(*p)
+	safePointWait int32
+	safePointNote note
 
 	profilehz int32 // cpu profiling rate
 
@@ -467,15 +470,16 @@ type sigtabtt struct {
 }
 
 const (
-	_SigNotify   = 1 << 0 // let signal.Notify have signal, even if from kernel
-	_SigKill     = 1 << 1 // if signal.Notify doesn't take it, exit quietly
-	_SigThrow    = 1 << 2 // if signal.Notify doesn't take it, exit loudly
-	_SigPanic    = 1 << 3 // if the signal is from the kernel, panic
-	_SigDefault  = 1 << 4 // if the signal isn't explicitly requested, don't monitor it
-	_SigHandling = 1 << 5 // our signal handler is registered
-	_SigIgnored  = 1 << 6 // the signal was ignored before we registered for it
-	_SigGoExit   = 1 << 7 // cause all runtime procs to exit (only used on Plan 9).
-	_SigSetStack = 1 << 8 // add SA_ONSTACK to libc handler
+	_SigNotify   = 1 << iota // let signal.Notify have signal, even if from kernel
+	_SigKill                 // if signal.Notify doesn't take it, exit quietly
+	_SigThrow                // if signal.Notify doesn't take it, exit loudly
+	_SigPanic                // if the signal is from the kernel, panic
+	_SigDefault              // if the signal isn't explicitly requested, don't monitor it
+	_SigHandling             // our signal handler is registered
+	_SigIgnored              // the signal was ignored before we registered for it
+	_SigGoExit               // cause all runtime procs to exit (only used on Plan 9).
+	_SigSetStack             // add SA_ONSTACK to libc handler
+	_SigUnblock              // unblocked in minit
 )
 
 // Layout of in-memory per-function information prepared by linker
@@ -594,8 +598,9 @@ type stkframe struct {
 }
 
 const (
-	_TraceRuntimeFrames = 1 << 0 // include frames for internal runtime functions.
-	_TraceTrap          = 1 << 1 // the initial PC, SP are from a trap, not a return PC from a call
+	_TraceRuntimeFrames = 1 << iota // include frames for internal runtime functions.
+	_TraceTrap                      // the initial PC, SP are from a trap, not a return PC from a call
+	_TraceJumpStack                 // if traceback is on a systemstack, resume trace at g that called into it
 )
 
 const (
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index d4cccbf084..f65562ab91 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -6,13 +6,8 @@ package runtime_test
 
 import (
 	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
 	. "runtime"
 	"runtime/debug"
-	"strconv"
-	"strings"
 	"testing"
 	"unsafe"
 )
@@ -88,53 +83,6 @@ func BenchmarkDeferMany(b *testing.B) {
 	}
 }
 
-// The profiling signal handler needs to know whether it is executing runtime.gogo.
-// The constant RuntimeGogoBytes in arch_*.h gives the size of the function;
-// we don't have a way to obtain it from the linker (perhaps someday).
-// Test that the constant matches the size determined by 'go tool nm -S'.
-// The value reported will include the padding between runtime.gogo and the
-// next function in memory. That's fine.
-func TestRuntimeGogoBytes(t *testing.T) {
-	switch GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", GOOS)
-	case "darwin":
-		switch GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on %s/%s, no fork", GOOS, GOARCH)
-		}
-	}
-
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	out, err := exec.Command("go", "build", "-o", dir+"/hello", "../../test/helloworld.go").CombinedOutput()
-	if err != nil {
-		t.Fatalf("building hello world: %v\n%s", err, out)
-	}
-
-	out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
-	if err != nil {
-		t.Fatalf("go tool nm: %v\n%s", err, out)
-	}
-
-	for _, line := range strings.Split(string(out), "\n") {
-		f := strings.Fields(line)
-		if len(f) == 4 && f[3] == "runtime.gogo" {
-			size, _ := strconv.Atoi(f[1])
-			if GogoBytes() != int32(size) {
-				t.Fatalf("RuntimeGogoBytes = %d, should be %d", GogoBytes(), size)
-			}
-			return
-		}
-	}
-
-	t.Fatalf("go tool nm did not report size for runtime.gogo")
-}
-
 // golang.org/issue/7063
 func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
 	SetCPUProfileRate(0)
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
index 7577d43a64..d3e9dac097 100644
--- a/src/runtime/signal1_unix.go
+++ b/src/runtime/signal1_unix.go
@@ -19,6 +19,19 @@ const (
 // Signal forwarding is currently available only on Linux.
 var fwdSig [_NSIG]uintptr
 
+// sigmask represents a general signal mask compatible with the GOOS
+// specific sigset types: the signal numbered x is represented by bit x-1
+// to match the representation expected by sigprocmask.
+type sigmask [(_NSIG + 31) / 32]uint32
+
+// channels for synchronizing signal mask updates with the signal mask
+// thread
+var (
+	disableSigChan  chan uint32
+	enableSigChan   chan uint32
+	maskUpdatedChan chan struct{}
+)
+
 func initsig() {
 	// _NSIG is the number of signals on this operating system.
 	// sigtable should describe what to do for all the possible signals.
@@ -61,12 +74,17 @@ func sigenable(sig uint32) {
 	}
 
 	t := &sigtable[sig]
-	if t.flags&_SigNotify != 0 && t.flags&_SigHandling == 0 {
-		t.flags |= _SigHandling
-		if getsig(int32(sig)) == _SIG_IGN {
-			t.flags |= _SigIgnored
+	if t.flags&_SigNotify != 0 {
+		ensureSigM()
+		enableSigChan <- sig
+		<-maskUpdatedChan
+		if t.flags&_SigHandling == 0 {
+			t.flags |= _SigHandling
+			if getsig(int32(sig)) == _SIG_IGN {
+				t.flags |= _SigIgnored
+			}
+			setsig(int32(sig), funcPC(sighandler), true)
 		}
-		setsig(int32(sig), funcPC(sighandler), true)
 	}
 }
 
@@ -76,12 +94,17 @@ func sigdisable(sig uint32) {
 	}
 
 	t := &sigtable[sig]
-	if t.flags&_SigNotify != 0 && t.flags&_SigHandling != 0 {
-		t.flags &^= _SigHandling
-		if t.flags&_SigIgnored != 0 {
-			setsig(int32(sig), _SIG_IGN, true)
-		} else {
-			setsig(int32(sig), _SIG_DFL, true)
+	if t.flags&_SigNotify != 0 {
+		ensureSigM()
+		disableSigChan <- sig
+		<-maskUpdatedChan
+		if t.flags&_SigHandling != 0 {
+			t.flags &^= _SigHandling
+			if t.flags&_SigIgnored != 0 {
+				setsig(int32(sig), _SIG_IGN, true)
+			} else {
+				setsig(int32(sig), _SIG_DFL, true)
+			}
 		}
 	}
 }
@@ -130,7 +153,52 @@ func crash() {
 		}
 	}
 
-	unblocksignals()
+	updatesigmask(sigmask{})
 	setsig(_SIGABRT, _SIG_DFL, false)
 	raise(_SIGABRT)
 }
+
+// createSigM starts one global, sleeping thread to make sure at least one thread
+// is available to catch signals enabled for os/signal.
+func ensureSigM() {
+	if maskUpdatedChan != nil {
+		return
+	}
+	maskUpdatedChan = make(chan struct{})
+	disableSigChan = make(chan uint32)
+	enableSigChan = make(chan uint32)
+	go func() {
+		// Signal masks are per-thread, so make sure this goroutine stays on one
+		// thread.
+		LockOSThread()
+		defer UnlockOSThread()
+		// The sigBlocked mask contains the signals not active for os/signal,
+		// initially all signals except the essential. When signal.Notify()/Stop is called,
+		// sigenable/sigdisable in turn notify this thread to update its signal
+		// mask accordingly.
+		var sigBlocked sigmask
+		for i := range sigBlocked {
+			sigBlocked[i] = ^uint32(0)
+		}
+		for i := range sigtable {
+			if sigtable[i].flags&_SigUnblock != 0 {
+				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+			}
+		}
+		updatesigmask(sigBlocked)
+		for {
+			select {
+			case sig := <-enableSigChan:
+				if b := sig - 1; b >= 0 {
+					sigBlocked[b/32] &^= (1 << (b & 31))
+				}
+			case sig := <-disableSigChan:
+				if b := sig - 1; b >= 0 {
+					sigBlocked[b/32] |= (1 << (b & 31))
+				}
+			}
+			updatesigmask(sigBlocked)
+			maskUpdatedChan <- struct{}{}
+		}
+	}()
+}
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
index 32ecce0d7d..6cd18653d5 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -16,14 +16,14 @@ var sigtable = [...]sigTabT{
 	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
 	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
 	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
-	/* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
-	/* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
 	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
 	/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
-	/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/* 9 */ {0, "SIGKILL: kill"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
 	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
 	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
@@ -32,14 +32,14 @@ var sigtable = [...]sigTabT{
 	/* 17 */ {0, "SIGSTOP: stop"},
 	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
 	/* 19 */ {0, "SIGCONT: continue after stop"},
-	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
 	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
 	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
 	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
 	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
 	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
 	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
-	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
 	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
 	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
 	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go
index f8250b9fa1..2f25b59663 100644
--- a/src/runtime/signal_linux.go
+++ b/src/runtime/signal_linux.go
@@ -16,20 +16,20 @@ var sigtable = [...]sigTabT{
 	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
 	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
 	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
-	/* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
-	/* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
 	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
-	/* 7 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/* 7 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/* 9 */ {0, "SIGKILL: kill"},
 	/* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
 	/* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
 	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
 	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
-	/* 16 */ {_SigThrow, "SIGSTKFLT: stack fault"},
-	/* 17 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 16 */ {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"},
+	/* 17 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
 	/* 18 */ {0, "SIGCONT: continue"},
 	/* 19 */ {0, "SIGSTOP: stop, unblockable"},
 	/* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{
 	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
 	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
 	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
-	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
 	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
 	/* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
 	/* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go
index 78afc59efa..d93a450d98 100644
--- a/src/runtime/signal_netbsd.go
+++ b/src/runtime/signal_netbsd.go
@@ -14,14 +14,14 @@ var sigtable = [...]sigTabT{
 	/*  1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
 	/*  2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
 	/*  3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
-	/*  4 */ {_SigThrow, "SIGILL: illegal instruction"},
-	/*  5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/*  4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/*  5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
 	/*  6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
 	/*  7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
-	/*  8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/*  8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/*  9 */ {0, "SIGKILL: kill"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
 	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
 	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
@@ -30,14 +30,14 @@ var sigtable = [...]sigTabT{
 	/* 17 */ {0, "SIGSTOP: stop"},
 	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
 	/* 19 */ {0, "SIGCONT: continue after stop"},
-	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
 	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
 	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
 	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
 	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
 	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
 	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
-	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
 	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
 	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
 	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
diff --git a/src/runtime/signal_solaris.go b/src/runtime/signal_solaris.go
index 2986c5aabc..d8ac676846 100644
--- a/src/runtime/signal_solaris.go
+++ b/src/runtime/signal_solaris.go
@@ -14,21 +14,21 @@ var sigtable = [...]sigTabT{
 	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: hangup"},
 	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt (rubout)"},
 	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit (ASCII FS)"},
-	/* 4 */ {_SigThrow, "SIGILL: illegal instruction (not reset when caught)"},
-	/* 5 */ {_SigThrow, "SIGTRAP: trace trap (not reset when caught)"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction (not reset when caught)"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap (not reset when caught)"},
 	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: used by abort, replace SIGIOT in the future"},
 	/* 7 */ {_SigThrow, "SIGEMT: EMT instruction"},
-	/* 8 */ {_SigPanic, "SIGFPE: floating point exception"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating point exception"},
 	/* 9 */ {0, "SIGKILL: kill (cannot be caught or ignored)"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
 	/* 12 */ {_SigThrow, "SIGSYS: bad argument to system call"},
 	/* 13 */ {_SigNotify, "SIGPIPE: write on a pipe with no one to read it"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
 	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: software termination signal from kill"},
 	/* 16 */ {_SigNotify, "SIGUSR1: user defined signal 1"},
 	/* 17 */ {_SigNotify, "SIGUSR2: user defined signal 2"},
-	/* 18 */ {_SigNotify, "SIGCHLD: child status change alias (POSIX)"},
+	/* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status change alias (POSIX)"},
 	/* 19 */ {_SigNotify, "SIGPWR: power-fail restart"},
 	/* 20 */ {_SigNotify, "SIGWINCH: window size change"},
 	/* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
@@ -39,7 +39,7 @@ var sigtable = [...]sigTabT{
 	/* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"},
 	/* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background tty write attempted"},
 	/* 28 */ {_SigNotify, "SIGVTALRM: virtual timer expired"},
-	/* 29 */ {_SigNotify, "SIGPROF: profiling timer expired"},
+	/* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling timer expired"},
 	/* 30 */ {_SigNotify, "SIGXCPU: exceeded cpu limit"},
 	/* 31 */ {_SigNotify, "SIGXFSZ: exceeded file size limit"},
 	/* 32 */ {_SigNotify, "SIGWAITING: reserved signal no longer used by"},
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
index da8a1c5801..b2fce53534 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -131,7 +131,9 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
 
 	print("PC=", hex(r.ip()), "\n")
 	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
-		print("signal arrived during cgo execution\n")
+		if iscgo {
+			print("signal arrived during external code execution\n")
+		}
 		gp = _g_.m.lockedg
 	}
 	print("\n")
diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go
index 38f0a57b90..f000fabd1a 100644
--- a/src/runtime/sigqueue_plan9.go
+++ b/src/runtime/sigqueue_plan9.go
@@ -17,21 +17,29 @@ var sig struct {
 	sleeping bool
 }
 
+type noteData struct {
+	s [_ERRMAX]byte
+	n int // n bytes of s are valid
+}
+
 type noteQueue struct {
 	lock mutex
-	data [qsize]*byte
+	data [qsize]noteData
 	ri   int
 	wi   int
 	full bool
 }
 
+// It is not allowed to allocate memory in the signal handler.
 func (q *noteQueue) push(item *byte) bool {
 	lock(&q.lock)
 	if q.full {
 		unlock(&q.lock)
 		return false
 	}
-	q.data[q.wi] = item
+	s := gostringnocopy(item)
+	copy(q.data[q.wi].s[:], s)
+	q.data[q.wi].n = len(s)
 	q.wi++
 	if q.wi == qsize {
 		q.wi = 0
@@ -43,14 +51,15 @@ func (q *noteQueue) push(item *byte) bool {
 	return true
 }
 
-func (q *noteQueue) pop() *byte {
+func (q *noteQueue) pop() string {
 	lock(&q.lock)
 	q.full = false
 	if q.ri == q.wi {
 		unlock(&q.lock)
-		return nil
+		return ""
 	}
-	item := q.data[q.ri]
+	note := &q.data[q.ri]
+	item := string(note.s[:note.n])
 	q.ri++
 	if q.ri == qsize {
 		q.ri = 0
@@ -86,8 +95,8 @@ func sendNote(s *byte) bool {
 func signal_recv() string {
 	for {
 		note := sig.q.pop()
-		if note != nil {
-			return gostring(note)
+		if note != "" {
+			return note
 		}
 
 		lock(&sig.lock)
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 5ccc6592bf..79b611839d 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -84,10 +84,13 @@ func growslice(t *slicetype, old slice, n int) slice {
 		memclr(add(p, lenmem), capmem-lenmem)
 	} else {
 		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory.
-		// TODO(rsc): Use memmove when !writeBarrierEnabled.
 		p = newarray(et, uintptr(newcap))
-		for i := 0; i < old.len; i++ {
-			typedmemmove(et, add(p, uintptr(i)*et.size), add(old.array, uintptr(i)*et.size))
+		if !writeBarrierEnabled {
+			memmove(p, old.array, lenmem)
+		} else {
+			for i := uintptr(0); i < lenmem; i += et.size {
+				typedmemmove(et, add(p, i), add(old.array, i))
+			}
 		}
 	}
 
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index f74694b7e9..27427af955 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -352,6 +352,12 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
 	}
 }
 
+// Information from the compiler about the layout of stack frames.
+type bitvector struct {
+	n        int32 // # of bits
+	bytedata *uint8
+}
+
 type gobitvector struct {
 	n        uintptr
 	bytedata []uint8
@@ -381,20 +387,20 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
 			print("        ", add(scanp, i*ptrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*ptrSize))), " # ", i, " ", bv.bytedata[i/4], "\n")
 		}
 		if ptrbit(&bv, i) == 1 {
-			p := *(*unsafe.Pointer)(add(scanp, i*ptrSize))
-			up := uintptr(p)
-			if f != nil && 0 < up && up < _PageSize && debug.invalidptr != 0 || up == poisonStack {
+			pp := (*uintptr)(add(scanp, i*ptrSize))
+			p := *pp
+			if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 || p == poisonStack {
 				// Looks like a junk value in a pointer slot.
 				// Live analysis wrong?
 				getg().m.traceback = 2
-				print("runtime: bad pointer in frame ", funcname(f), " at ", add(scanp, i*ptrSize), ": ", p, "\n")
+				print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
 				throw("invalid stack pointer")
 			}
-			if minp <= up && up < maxp {
+			if minp <= p && p < maxp {
 				if stackDebug >= 3 {
 					print("adjust ptr ", p, " ", funcname(f), "\n")
 				}
-				*(*unsafe.Pointer)(add(scanp, i*ptrSize)) = unsafe.Pointer(up + delta)
+				*pp = p + delta
 			}
 		}
 	}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 25f5bf46fb..687f067cb9 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -32,6 +32,8 @@ const (
 // moduledata records information about the layout of the executable
 // image. It is written by the linker. Any changes here must be
 // matched changes to the code in cmd/internal/ld/symtab.go:symtab.
+// moduledata is stored in read-only memory; none of the pointers here
+// are visible to the garbage collector.
 type moduledata struct {
 	pclntable    []byte
 	ftab         []functab
@@ -48,18 +50,24 @@ type moduledata struct {
 
 	typelinks []*_type
 
+	modulename   string
+	modulehashes []modulehash
+
 	gcdatamask, gcbssmask bitvector
 
-	// write barrier shadow data
-	// 64-bit systems only, enabled by GODEBUG=wbshadow=1.
-	// See also the shadow_* fields on mheap in mheap.go.
-	shadow_data uintptr // data-addr + shadow_data = shadow data addr
-	data_start  uintptr // start of shadowed data addresses
-	data_end    uintptr // end of shadowed data addresses
-
 	next *moduledata
 }
 
+// For each shared library a module links against, the linker creates an entry in the
+// moduledata.modulehashes slice containing the name of the module, the abi hash seen
+// at link time and a pointer to the runtime abi hash. These are checked in
+// moduledataverify1 below.
+type modulehash struct {
+	modulename   string
+	linktimehash string
+	runtimehash  *string
+}
+
 var firstmoduledata moduledata  // linker symbol
 var lastmoduledatap *moduledata // linker symbol
 
@@ -124,6 +132,13 @@ func moduledataverify1(datap *moduledata) {
 		datap.maxpc != datap.ftab[nftab].entry {
 		throw("minpc or maxpc invalid")
 	}
+
+	for _, modulehash := range datap.modulehashes {
+		if modulehash.linktimehash != *modulehash.runtimehash {
+			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
+			throw("abi mismatch")
+		}
+	}
 }
 
 // FuncForPC returns a *Func describing the function that contains the
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 3b7501b9b4..6da7baddc5 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -132,10 +132,7 @@ type traceBuf struct {
 func StartTrace() error {
 	// Stop the world, so that we can take a consistent snapshot
 	// of all goroutines at the beginning of the trace.
-	semacquire(&worldsema, false)
-	_g_ := getg()
-	_g_.m.preemptoff = "start tracing"
-	systemstack(stoptheworld)
+	stopTheWorld("start tracing")
 
 	// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
 	// Exitsyscall could check trace.enabled long before and then suddenly wake up
@@ -146,9 +143,7 @@ func StartTrace() error {
 
 	if trace.enabled || trace.shutdown {
 		unlock(&trace.bufLock)
-		_g_.m.preemptoff = ""
-		semrelease(&worldsema)
-		systemstack(starttheworld)
+		startTheWorld()
 		return errorString("tracing is already enabled")
 	}
 
@@ -175,9 +170,7 @@ func StartTrace() error {
 
 	unlock(&trace.bufLock)
 
-	_g_.m.preemptoff = ""
-	semrelease(&worldsema)
-	systemstack(starttheworld)
+	startTheWorld()
 	return nil
 }
 
@@ -186,19 +179,14 @@ func StartTrace() error {
 func StopTrace() {
 	// Stop the world so that we can collect the trace buffers from all p's below,
 	// and also to avoid races with traceEvent.
-	semacquire(&worldsema, false)
-	_g_ := getg()
-	_g_.m.preemptoff = "stop tracing"
-	systemstack(stoptheworld)
+	stopTheWorld("stop tracing")
 
 	// See the comment in StartTrace.
 	lock(&trace.bufLock)
 
 	if !trace.enabled {
 		unlock(&trace.bufLock)
-		_g_.m.preemptoff = ""
-		semrelease(&worldsema)
-		systemstack(starttheworld)
+		startTheWorld()
 		return
 	}
 
@@ -236,9 +224,7 @@ func StopTrace() {
 
 	unlock(&trace.bufLock)
 
-	_g_.m.preemptoff = ""
-	semrelease(&worldsema)
-	systemstack(starttheworld)
+	startTheWorld()
 
 	// The world is started but we've set trace.shutdown, so new tracing can't start.
 	// Wait for the trace reader to flush pending buffers and stop.
@@ -428,9 +414,9 @@ func traceEvent(ev byte, skip int, args ...uint64) {
 
 	// The caller checked that trace.enabled == true, but trace.enabled might have been
 	// turned off between the check and now. Check again. traceLockBuffer did mp.locks++,
-	// StopTrace does stoptheworld, and stoptheworld waits for mp.locks to go back to zero,
+	// StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero,
 	// so if we see trace.enabled == true now, we know it's true for the rest of the function.
-	// Exitsyscall can run even during stoptheworld. The race with StartTrace/StopTrace
+	// Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace
 	// during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer.
 	if !trace.enabled {
 		traceReleaseBuffer(pid)
@@ -733,7 +719,7 @@ func traceProcStart() {
 }
 
 func traceProcStop(pp *p) {
-	// Sysmon and stoptheworld can stop Ps blocked in syscalls,
+	// Sysmon and stopTheWorld can stop Ps blocked in syscalls,
 	// to handle this we temporary employ the P.
 	mp := acquirem()
 	oldp := mp.p
@@ -807,7 +793,7 @@ func traceGoSysExit(ts int64) {
 }
 
 func traceGoSysBlock(pp *p) {
-	// Sysmon and stoptheworld can declare syscalls running on remote Ps as blocked,
+	// Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked,
 	// to handle this we temporary employ the P.
 	mp := acquirem()
 	oldp := mp.p
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 9f34e37ea4..5ed601e6f3 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -46,6 +46,9 @@ var (
 	timerprocPC          uintptr
 	gcBgMarkWorkerPC     uintptr
 	systemstack_switchPC uintptr
+	systemstackPC        uintptr
+
+	gogoPC uintptr
 
 	externalthreadhandlerp uintptr // initialized elsewhere
 )
@@ -69,6 +72,10 @@ func tracebackinit() {
 	timerprocPC = funcPC(timerproc)
 	gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
 	systemstack_switchPC = funcPC(systemstack_switch)
+	systemstackPC = funcPC(systemstack)
+
+	// used by sigprof handler
+	gogoPC = funcPC(gogo)
 }
 
 // Traceback over the deferred function calls.
@@ -194,7 +201,14 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		// Found an actual function.
 		// Derive frame pointer and link register.
 		if frame.fp == 0 {
-			frame.fp = frame.sp + uintptr(funcspdelta(f, frame.pc))
+			// We want to jump over the systemstack switch. If we're running on the
+			// g0, this systemstack is at the top of the stack.
+			// if we're not on g0 or there's a no curg, then this is a regular call.
+			sp := frame.sp
+			if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
+				sp = gp.m.curg.sched.sp
+			}
+			frame.fp = sp + uintptr(funcspdelta(f, frame.pc))
 			if !usesLR {
 				// On x86, call instruction pushes return PC before entering new function.
 				frame.fp += regSize
@@ -455,7 +469,7 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) {
 				throw("reflect mismatch")
 			}
 			bv := (*bitvector)(unsafe.Pointer(fn[1]))
-			frame.arglen = uintptr(bv.n / 2 * ptrSize)
+			frame.arglen = uintptr(bv.n * ptrSize)
 			frame.argmap = bv
 		}
 	}
@@ -517,9 +531,10 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
 func callers(skip int, pcbuf []uintptr) int {
 	sp := getcallersp(unsafe.Pointer(&skip))
 	pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
+	gp := getg()
 	var n int
 	systemstack(func() {
-		n = gentraceback(pc, sp, 0, getg(), skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
+		n = gentraceback(pc, sp, 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
 	})
 	return n
 }
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 48df2a4382..45bdac8b91 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -20,17 +20,10 @@ type _type struct {
 	fieldalign uint8
 	kind       uint8
 	alg        *typeAlg
-	// gc stores type info required for garbage collector.
-	// If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap
-	// (no indirection), 4 bits per word.
-	// If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated
-	// read-only GC program; and gc[0] points to BSS space for sparse GC bitmap.
-	// For huge types (>maxGCMask), runtime unrolls the program directly into
-	// GC bitmap and gc[0] is not used. For moderately-sized types, runtime
-	// unrolls the program into gc[0] space on first use. The first byte of gc[0]
-	// (gc[0][0]) contains 'unroll' flag saying whether the program is already
-	// unrolled into gc[0] or not.
-	gc      [2]uintptr
+	// gcdata stores the GC type data for the garbage collector.
+	// If the KindGCProg bit is set in kind, gcdata is a GC program.
+	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
+	gcdata  *byte
 	_string *string
 	x       *uncommontype
 	ptrto   *_type
diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go
index d59c78e493..468c37fafb 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -223,9 +223,8 @@ func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec i
 	return append(dst, '%', fmt)
 }
 
-// Round d (= mant * 2^exp) to the shortest number of digits
-// that will let the original floating point value be precisely
-// reconstructed.  Size is original floating point size (64 or 32).
+// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely reconstructed.
 func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
 	// If mantissa is zero, the number is zero; stop now.
 	if mant == 0 {
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index ced2ca862d..3aa30c7364 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -132,26 +132,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Parent death signal
-	if sys.Pdeathsig != 0 {
-		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
-		if err1 != 0 {
-			goto childerror
-		}
-
-		// Signal self if parent is already dead. This might cause a
-		// duplicate signal in rare cases, but it won't matter when
-		// using SIGKILL.
-		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
-		if r1 != ppid {
-			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
-			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
-			if err1 != 0 {
-				goto childerror
-			}
-		}
-	}
-
 	// Enable tracing if requested.
 	if sys.Ptrace {
 		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
@@ -232,6 +212,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
+	// Parent death signal
+	if sys.Pdeathsig != 0 {
+		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+
+		// Signal self if parent is already dead. This might cause a
+		// duplicate signal in rare cases, but it won't matter when
+		// using SIGKILL.
+		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
+		if r1 != ppid {
+			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+			if err1 != 0 {
+				goto childerror
+			}
+		}
+	}
+
 	// Pass 1: look for fd[i] < i and move those up above len(fd)
 	// so that pass 2 won't stomp on an fd it needs later.
 	if pipe < nextfd {
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 1b7cd64c8d..85fab4ff3e 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -179,7 +179,7 @@ linux_amd64)
 linux_arm)
 	mkerrors="$mkerrors"
 	mksyscall="./mksyscall.pl -l32 -arm"
-	mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
+	mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl -"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 linux_arm64)
@@ -285,7 +285,7 @@ esac
 		syscall_goos="syscall_bsd.go $syscall_goos"
  		;;
  	esac
-	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
+	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
 	if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
 	if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
 	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index d25527bbf9..438de6e5d8 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -87,7 +87,9 @@ includes_FreeBSD='
 includes_Linux='
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
+#ifndef __LP64__
 #define _FILE_OFFSET_BITS 64
+#endif
 #define _GNU_SOURCE
 
 #include 
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index 7a8add8bab..b6fbcb599b 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -28,7 +28,8 @@ sub fmt {
 }
 
 my $prev;
-while(<>){
+open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
+while(){
 	if(/^#define __NR_syscalls\s+/) {
 		# ignore redefinitions of __NR_syscalls
 	}
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 05d4044635..4f88d517e4 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -852,7 +852,6 @@ func Getpgrp() (pid int) {
 //sysnb	Gettid() (tid int)
 //sys	Getxattr(path string, attr string, dest []byte) (sz int, err error)
 //sys	InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
-//sysnb	InotifyInit() (fd int, err error)
 //sysnb	InotifyInit1(flags int) (fd int, err error)
 //sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
 //sysnb	Kill(pid int, sig Signal) (err error)
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 98636a53ad..9ee1c1cd16 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -66,6 +66,7 @@ func Pipe2(p []int, flags int) (err error) {
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index fad9c32580..6fbef21120 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -16,6 +16,7 @@ const _SYS_dup = SYS_DUP2
 //sysnb	Getgid() (gid int)
 //sysnb	Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb	Getuid() (uid int)
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error)
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index f0cc25ebed..218d6b86d4 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -87,6 +87,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
 //sys	Listen(s int, n int) (err error)
 //sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
index 3c4eabca5f..7ca4164544 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -124,11 +124,14 @@ func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint64(length)
 }
 
+func InotifyInit() (fd int, err error) {
+	return InotifyInit1(0)
+}
+
 // TODO(dfc): constants that should be in zsysnum_linux_arm64.go, remove
 // these when the deprecated syscalls that the syscall package relies on
 // are removed.
 const (
-	SYS_INOTIFY_INIT = 1043
 	SYS_GETPGRP      = 1060
 	SYS_UTIMES       = 1037
 	SYS_FUTIMESAT    = 1066
diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go
index 5318c6128c..10489d927f 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -19,6 +19,7 @@ const _SYS_dup = SYS_DUP2
 //sysnb	Getgid() (gid int)
 //sysnb	Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT
 //sysnb	Getuid() (uid int)
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error)
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
new file mode 100644
index 0000000000..40fce6d68c
--- /dev/null
+++ b/src/syscall/syscall_linux_test.go
@@ -0,0 +1,140 @@
+// Copyright 2015 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 syscall_test
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"os/signal"
+	"path/filepath"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestMain(m *testing.M) {
+	if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
+		deathSignalParent()
+	} else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
+		deathSignalChild()
+	}
+
+	os.Exit(m.Run())
+}
+
+func TestLinuxDeathSignal(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("skipping root only test")
+	}
+
+	// Copy the test binary to a location that a non-root user can read/execute
+	// after we drop privileges
+	tempDir, err := ioutil.TempDir("", "TestDeathSignal")
+	if err != nil {
+		t.Fatalf("cannot create temporary directory: %v", err)
+	}
+	defer os.RemoveAll(tempDir)
+	os.Chmod(tempDir, 0755)
+
+	tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
+
+	src, err := os.Open(os.Args[0])
+	if err != nil {
+		t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
+	}
+	defer src.Close()
+
+	dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
+	}
+	if _, err := io.Copy(dst, src); err != nil {
+		t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
+	}
+	err = dst.Close()
+	if err != nil {
+		t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
+	}
+
+	cmd := exec.Command(tmpBinary)
+	cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
+	chldStdin, err := cmd.StdinPipe()
+	if err != nil {
+		t.Fatal("failed to create new stdin pipe: %v", err)
+	}
+	chldStdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal("failed to create new stdout pipe: %v", err)
+	}
+	cmd.Stderr = os.Stderr
+
+	err = cmd.Start()
+	defer cmd.Wait()
+	if err != nil {
+		t.Fatalf("failed to start first child process: %v", err)
+	}
+
+	chldPipe := bufio.NewReader(chldStdout)
+
+	if got, err := chldPipe.ReadString('\n'); got == "start\n" {
+		syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
+
+		go func() {
+			time.Sleep(5 * time.Second)
+			chldStdin.Close()
+		}()
+
+		want := "ok\n"
+		if got, err = chldPipe.ReadString('\n'); got != want {
+			t.Fatalf("expected %q, received %q, %v", want, got, err)
+		}
+	} else {
+		t.Fatalf("did not receive start from child, received %q, %v", got, err)
+	}
+}
+
+func deathSignalParent() {
+	cmd := exec.Command(os.Args[0])
+	cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	attrs := syscall.SysProcAttr{
+		Pdeathsig: syscall.SIGUSR1,
+		// UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
+		// unused on Ubuntu
+		Credential: &syscall.Credential{Uid: 99, Gid: 99},
+	}
+	cmd.SysProcAttr = &attrs
+
+	err := cmd.Start()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "death signal parent error: %v\n")
+		os.Exit(1)
+	}
+	cmd.Wait()
+	os.Exit(0)
+}
+
+func deathSignalChild() {
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGUSR1)
+	go func() {
+		<-c
+		fmt.Println("ok")
+		os.Exit(0)
+	}()
+	fmt.Println("start")
+
+	buf := make([]byte, 32)
+	os.Stdin.Read(buf)
+
+	// We expected to be signaled before stdin closed
+	fmt.Println("not ok")
+	os.Exit(1)
+}
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index 01fc670aba..af92013739 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -60,20 +60,58 @@ func _() {
 
 // TestFcntlFlock tests whether the file locking structure matches
 // the calling convention of each kernel.
+// On some Linux systems, glibc uses another set of values for the
+// commands and translates them to the correct value that the kernel
+// expects just before the actual fcntl syscall. As Go uses raw
+// syscalls directly, it must use the real value, not the glibc value.
+// Thus this test also verifies that the Flock_t structure can be
+// roundtripped with F_SETLK and F_GETLK.
 func TestFcntlFlock(t *testing.T) {
-	name := filepath.Join(os.TempDir(), "TestFcntlFlock")
-	fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
-	if err != nil {
-		t.Fatalf("Open failed: %v", err)
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skip("skipping; no child processes allowed on iOS")
 	}
-	defer syscall.Unlink(name)
-	defer syscall.Close(fd)
 	flock := syscall.Flock_t{
-		Type:  syscall.F_RDLCK,
-		Start: 0, Len: 0, Whence: 1,
+		Type:  syscall.F_WRLCK,
+		Start: 31415, Len: 271828, Whence: 1,
 	}
-	if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
-		t.Fatalf("FcntlFlock failed: %v", err)
+	if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
+		// parent
+		name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+		fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+		if err != nil {
+			t.Fatalf("Open failed: %v", err)
+		}
+		defer syscall.Unlink(name)
+		defer syscall.Close(fd)
+		if err := syscall.Ftruncate(fd, 1<<20); err != nil {
+			t.Fatalf("Ftruncate(1<<20) failed: %v", err)
+		}
+		if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil {
+			t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
+		}
+		cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$")
+		cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
+		cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)}
+		out, err := cmd.CombinedOutput()
+		if len(out) > 0 || err != nil {
+			t.Fatalf("child process: %q, %v", out, err)
+		}
+	} else {
+		// child
+		got := flock
+		// make sure the child lock is conflicting with the parent lock
+		got.Start--
+		got.Len++
+		if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil {
+			t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err)
+		}
+		flock.Pid = int32(syscall.Getppid())
+		// Linux kernel always set Whence to 0
+		flock.Whence = 0
+		if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence {
+			os.Exit(0)
+		}
+		t.Fatalf("FcntlFlock got %v, want %v", got, flock)
 	}
 }
 
@@ -121,7 +159,7 @@ func TestPassFD(t *testing.T) {
 	defer readFile.Close()
 
 	cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
-	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
 	cmd.ExtraFiles = []*os.File{writeFile}
 
 	out, err := cmd.CombinedOutput()
diff --git a/src/syscall/zerrors_darwin_386.go b/src/syscall/zerrors_darwin_386.go
index bb3a1610c0..debadaa9ce 100644
--- a/src/syscall/zerrors_darwin_386.go
+++ b/src/syscall/zerrors_darwin_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go
index 05ab48ee32..d4262ba55a 100644
--- a/src/syscall/zerrors_darwin_amd64.go
+++ b/src/syscall/zerrors_darwin_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_arm.go b/src/syscall/zerrors_darwin_arm.go
index 7e800d4259..a64f3735e2 100644
--- a/src/syscall/zerrors_darwin_arm.go
+++ b/src/syscall/zerrors_darwin_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go
index a3841a277a..98f431c4e7 100644
--- a/src/syscall/zerrors_darwin_arm64.go
+++ b/src/syscall/zerrors_darwin_arm64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build arm64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go
index 59bff751cb..15d300fd2d 100644
--- a/src/syscall/zerrors_dragonfly_amd64.go
+++ b/src/syscall/zerrors_dragonfly_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go
index cd3aa80a9c..bbad05f069 100644
--- a/src/syscall/zerrors_freebsd_386.go
+++ b/src/syscall/zerrors_freebsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go
index 9edce6e2fa..b36125b6d3 100644
--- a/src/syscall/zerrors_freebsd_amd64.go
+++ b/src/syscall/zerrors_freebsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go
index f29dd057b6..0c844f1387 100644
--- a/src/syscall/zerrors_freebsd_arm.go
+++ b/src/syscall/zerrors_freebsd_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go
index 7aa8ff07a7..d433a4f1a4 100644
--- a/src/syscall/zerrors_linux_386.go
+++ b/src/syscall/zerrors_linux_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go
index 94d051d8aa..dd86a3b0a1 100644
--- a/src/syscall/zerrors_linux_amd64.go
+++ b/src/syscall/zerrors_linux_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go
index dcaaef7423..2a9c0f93c1 100644
--- a/src/syscall/zerrors_linux_arm.go
+++ b/src/syscall/zerrors_linux_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go
index f3d708be9c..35d9acefe5 100644
--- a/src/syscall/zerrors_linux_arm64.go
+++ b/src/syscall/zerrors_linux_arm64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go
index 15e0770c18..1c769cdc77 100644
--- a/src/syscall/zerrors_linux_ppc64.go
+++ b/src/syscall/zerrors_linux_ppc64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build ppc64,linux
+
 package syscall
 
 const (
@@ -366,9 +368,9 @@ const (
 	F_SETFD                          = 0x2
 	F_SETFL                          = 0x4
 	F_SETLEASE                       = 0x400
-	F_SETLK                          = 0xd
+	F_SETLK                          = 0x6
 	F_SETLK64                        = 0xd
-	F_SETLKW                         = 0xe
+	F_SETLKW                         = 0x7
 	F_SETLKW64                       = 0xe
 	F_SETOWN                         = 0x8
 	F_SETOWN_EX                      = 0xf
diff --git a/src/syscall/zerrors_linux_ppc64le.go b/src/syscall/zerrors_linux_ppc64le.go
index fdecdf24dd..73727a4197 100644
--- a/src/syscall/zerrors_linux_ppc64le.go
+++ b/src/syscall/zerrors_linux_ppc64le.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build ppc64le,linux
+
 package syscall
 
 const (
@@ -366,9 +368,9 @@ const (
 	F_SETFD                          = 0x2
 	F_SETFL                          = 0x4
 	F_SETLEASE                       = 0x400
-	F_SETLK                          = 0xd
+	F_SETLK                          = 0x6
 	F_SETLK64                        = 0xd
-	F_SETLKW                         = 0xe
+	F_SETLKW                         = 0x7
 	F_SETLKW64                       = 0xe
 	F_SETOWN                         = 0x8
 	F_SETOWN_EX                      = 0xf
diff --git a/src/syscall/zerrors_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go
index 1e3dff7fac..6f32def661 100644
--- a/src/syscall/zerrors_netbsd_386.go
+++ b/src/syscall/zerrors_netbsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go
index 1469d00b78..a6d1701f8c 100644
--- a/src/syscall/zerrors_netbsd_amd64.go
+++ b/src/syscall/zerrors_netbsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go
index 1a88c0d225..7f99279e55 100644
--- a/src/syscall/zerrors_netbsd_arm.go
+++ b/src/syscall/zerrors_netbsd_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -marm _const.go
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go
index 0829834943..540d310e9f 100644
--- a/src/syscall/zerrors_openbsd_386.go
+++ b/src/syscall/zerrors_openbsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go
index e9fa37cdee..ae5b8c955a 100644
--- a/src/syscall/zerrors_openbsd_amd64.go
+++ b/src/syscall/zerrors_openbsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_arm.go b/src/syscall/zerrors_openbsd_arm.go
index 5376fe6e85..c49ebcfd03 100644
--- a/src/syscall/zerrors_openbsd_arm.go
+++ b/src/syscall/zerrors_openbsd_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go
index 3f4cbfd984..62ec81be6b 100644
--- a/src/syscall/zerrors_solaris_amd64.go
+++ b/src/syscall/zerrors_solaris_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,solaris
+
 package syscall
 
 const (
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 0ce383fb3b..23e7b5e420 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,darwin
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 2370630f09..6e63d9a074 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,darwin
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
index c9426ee85a..f996a508f0 100644
--- a/src/syscall/zsyscall_darwin_arm.go
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,darwin
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
index 828b167fea..c260cc7acd 100644
--- a/src/syscall/zsyscall_darwin_arm64.go
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm64,darwin
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 5eef1380ff..88e09d3a14 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,dragonfly
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 7cb21c9b39..30f29e52a9 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,freebsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 3cb87c1a02..93059d1b5b 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,freebsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 340418345b..84096b07a5 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,freebsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index e7cf7452c2..620fba287a 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
@@ -1298,6 +1289,17 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index b23573bc84..16cafbf06e 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_linux.go syscall_linux_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
@@ -1298,6 +1289,17 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index 054cf4005d..9bc3a54f31 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
@@ -1457,6 +1448,17 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Lchown(path string, uid int, gid int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go
index 26a14b7244..2ee58cfc8b 100644
--- a/src/syscall/zsyscall_linux_arm64.go
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_linux.go syscall_linux_arm64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm64,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go
index 326218031e..4f61114d5f 100644
--- a/src/syscall/zsyscall_linux_ppc64.go
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build ppc64,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
@@ -1298,6 +1289,17 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
index 326218031e..4073a0fa34 100644
--- a/src/syscall/zsyscall_linux_ppc64le.go
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build ppc64le,linux
+
 package syscall
 
 import "unsafe"
@@ -615,17 +617,6 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
@@ -1298,6 +1289,17 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index d0ff66c819..bf3f9e3dcd 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,nacl
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go
index 592c8d84a5..3f08da6e77 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64p32,nacl
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go
index 10657ad080..77d46c3d81 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,nacl
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index 5131c25696..e24c3b71cd 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,netbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index 0e26f6869d..7aa75ab12d 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,netbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 4aae1040ad..21f482b40f 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,netbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index f6a19833ec..df7df1e7e4 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,openbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index 93f5fc0085..1d640700f7 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,openbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go
index f59739c1e0..f40fb31c98 100644
--- a/src/syscall/zsyscall_openbsd_arm.go
+++ b/src/syscall/zsyscall_openbsd_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -openbsd -arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,openbsd
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index 06f1f04114..a424e789e3 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,plan9
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index 06f1f04114..d58556b01a 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,plan9
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index be9bc28474..cabab7ece3 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,solaris
+
 package syscall
 
 import "unsafe"
diff --git a/src/syscall/zsysnum_darwin_386.go b/src/syscall/zsysnum_darwin_386.go
index abdef77436..c6f8342841 100644
--- a/src/syscall/zsysnum_darwin_386.go
+++ b/src/syscall/zsysnum_darwin_386.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go
index abdef77436..7189abe3db 100644
--- a/src/syscall/zsysnum_darwin_amd64.go
+++ b/src/syscall/zsysnum_darwin_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_arm.go b/src/syscall/zsysnum_darwin_arm.go
index 1a53f13eff..1d76861204 100644
--- a/src/syscall/zsysnum_darwin_arm.go
+++ b/src/syscall/zsysnum_darwin_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go
index 723b1aa19e..ddf8e83c87 100644
--- a/src/syscall/zsysnum_darwin_arm64.go
+++ b/src/syscall/zsysnum_darwin_arm64.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go
index 4b086b9214..277478d208 100644
--- a/src/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/syscall/zsysnum_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_dragonfly.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go
index dfca558bb5..5e47217957 100644
--- a/src/syscall/zsysnum_freebsd_386.go
+++ b/src/syscall/zsysnum_freebsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go
index dfca558bb5..df8928cc68 100644
--- a/src/syscall/zsysnum_freebsd_amd64.go
+++ b/src/syscall/zsysnum_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go
index dfca558bb5..f670a59179 100644
--- a/src/syscall/zsysnum_freebsd_arm.go
+++ b/src/syscall/zsysnum_freebsd_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go
index c40b5f1ace..c277ed9a25 100644
--- a/src/syscall/zsysnum_linux_386.go
+++ b/src/syscall/zsysnum_linux_386.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_32.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go
index 7cf70a4d86..978a4d3c3d 100644
--- a/src/syscall/zsysnum_linux_amd64.go
+++ b/src/syscall/zsysnum_linux_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_64.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go
index 7068e4e210..5061cbab2b 100644
--- a/src/syscall/zsysnum_linux_arm.go
+++ b/src/syscall/zsysnum_linux_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go
index 4bcf0573e7..d53712c681 100644
--- a/src/syscall/zsysnum_linux_arm64.go
+++ b/src/syscall/zsysnum_linux_arm64.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm-generic/unistd.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_ppc64.go b/src/syscall/zsysnum_linux_ppc64.go
index 0567fd0ea8..82d253a1ab 100644
--- a/src/syscall/zsysnum_linux_ppc64.go
+++ b/src/syscall/zsysnum_linux_ppc64.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm/unistd.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build ppc64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_ppc64le.go b/src/syscall/zsysnum_linux_ppc64le.go
index 52c63e3d3e..3af4e83822 100644
--- a/src/syscall/zsysnum_linux_ppc64le.go
+++ b/src/syscall/zsysnum_linux_ppc64le.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build ppc64le,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go
index c570965237..c8af210082 100644
--- a/src/syscall/zsysnum_netbsd_386.go
+++ b/src/syscall/zsysnum_netbsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go
index c570965237..e342a3ce58 100644
--- a/src/syscall/zsysnum_netbsd_amd64.go
+++ b/src/syscall/zsysnum_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go
index c570965237..1f5b569b8f 100644
--- a/src/syscall/zsysnum_netbsd_arm.go
+++ b/src/syscall/zsysnum_netbsd_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go
index 3b9ac4c941..c19f6de649 100644
--- a/src/syscall/zsysnum_openbsd_386.go
+++ b/src/syscall/zsysnum_openbsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go
index 3b9ac4c941..86e04cd47e 100644
--- a/src/syscall/zsysnum_openbsd_amd64.go
+++ b/src/syscall/zsysnum_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go
index 8457c14732..38b43caba6 100644
--- a/src/syscall/zsysnum_openbsd_arm.go
+++ b/src/syscall/zsysnum_openbsd_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_solaris_amd64.go b/src/syscall/zsysnum_solaris_amd64.go
index 43b3d8b40d..be198f899b 100644
--- a/src/syscall/zsysnum_solaris_amd64.go
+++ b/src/syscall/zsysnum_solaris_amd64.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build amd64,solaris
+
 package syscall
 
 // TODO(aram): remove these before Go 1.3.
diff --git a/src/syscall/ztypes_darwin_386.go b/src/syscall/ztypes_darwin_386.go
index 13724c3cc6..7298d0243d 100644
--- a/src/syscall/ztypes_darwin_386.go
+++ b/src/syscall/ztypes_darwin_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_amd64.go b/src/syscall/ztypes_darwin_amd64.go
index 65b02ae4f5..ec95d51f91 100644
--- a/src/syscall/ztypes_darwin_amd64.go
+++ b/src/syscall/ztypes_darwin_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_arm.go b/src/syscall/ztypes_darwin_arm.go
index ec87f54fb2..91c4470e7c 100644
--- a/src/syscall/ztypes_darwin_arm.go
+++ b/src/syscall/ztypes_darwin_arm.go
@@ -2,6 +2,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build arm,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_arm64.go b/src/syscall/ztypes_darwin_arm64.go
index 65b02ae4f5..1d65cfde9d 100644
--- a/src/syscall/ztypes_darwin_arm64.go
+++ b/src/syscall/ztypes_darwin_arm64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build arm64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_dragonfly_amd64.go b/src/syscall/ztypes_dragonfly_amd64.go
index 954ffd7ab2..00120d0a27 100644
--- a/src/syscall/ztypes_dragonfly_amd64.go
+++ b/src/syscall/ztypes_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_dragonfly.go
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go
index b809eea37a..d972fb6bdf 100644
--- a/src/syscall/ztypes_freebsd_386.go
+++ b/src/syscall/ztypes_freebsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go
index a05908aed1..0a5a10bf7d 100644
--- a/src/syscall/ztypes_freebsd_amd64.go
+++ b/src/syscall/ztypes_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go
index 9303816f91..5d7acd547b 100644
--- a/src/syscall/ztypes_freebsd_arm.go
+++ b/src/syscall/ztypes_freebsd_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -fsigned-char types_freebsd.go
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go
index a887f31427..dd198cb394 100644
--- a/src/syscall/ztypes_linux_386.go
+++ b/src/syscall/ztypes_linux_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build 386,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go
index adf95caee7..a39489e4e5 100644
--- a/src/syscall/ztypes_linux_amd64.go
+++ b/src/syscall/ztypes_linux_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build amd64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go
index 1ae9718945..f446e41be0 100644
--- a/src/syscall/ztypes_linux_arm.go
+++ b/src/syscall/ztypes_linux_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build arm,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go
index 1cb1d435d8..dcb1178dc4 100644
--- a/src/syscall/ztypes_linux_arm64.go
+++ b/src/syscall/ztypes_linux_arm64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -fsigned-char types_linux.go
 
+// +build arm64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go
index fe438364d4..33d1b7f3e5 100644
--- a/src/syscall/ztypes_linux_ppc64.go
+++ b/src/syscall/ztypes_linux_ppc64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build ppc64,linux
+
 package syscall
 
 const (
@@ -549,7 +551,7 @@ type Sysinfo_t struct {
 	Totalhigh uint64
 	Freehigh  uint64
 	Unit      uint32
-	X_f       [0]byte
+	X_f       [0]uint8
 	Pad_cgo_1 [4]byte
 }
 
diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go
index c6b6f1615d..27ca004834 100644
--- a/src/syscall/ztypes_linux_ppc64le.go
+++ b/src/syscall/ztypes_linux_ppc64le.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build ppc64le,linux
+
 package syscall
 
 const (
@@ -549,7 +551,7 @@ type Sysinfo_t struct {
 	Totalhigh uint64
 	Freehigh  uint64
 	Unit      uint32
-	X_f       [0]byte
+	X_f       [0]uint8
 	Pad_cgo_1 [4]byte
 }
 
diff --git a/src/syscall/ztypes_netbsd_386.go b/src/syscall/ztypes_netbsd_386.go
index 6add325a37..1752c6c229 100644
--- a/src/syscall/ztypes_netbsd_386.go
+++ b/src/syscall/ztypes_netbsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_amd64.go b/src/syscall/ztypes_netbsd_amd64.go
index 4451fc1f02..b8d4b0b02a 100644
--- a/src/syscall/ztypes_netbsd_amd64.go
+++ b/src/syscall/ztypes_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_arm.go b/src/syscall/ztypes_netbsd_arm.go
index 4e853eaa23..c21d875a93 100644
--- a/src/syscall/ztypes_netbsd_arm.go
+++ b/src/syscall/ztypes_netbsd_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_386.go b/src/syscall/ztypes_openbsd_386.go
index 2e4d9dd174..0376d3acab 100644
--- a/src/syscall/ztypes_openbsd_386.go
+++ b/src/syscall/ztypes_openbsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_amd64.go b/src/syscall/ztypes_openbsd_amd64.go
index f07bc714e9..bf23626ff2 100644
--- a/src/syscall/ztypes_openbsd_amd64.go
+++ b/src/syscall/ztypes_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_arm.go b/src/syscall/ztypes_openbsd_arm.go
index 5f8fb1262f..e1d8938f0e 100644
--- a/src/syscall/ztypes_openbsd_arm.go
+++ b/src/syscall/ztypes_openbsd_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
+// +build arm,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_solaris_amd64.go b/src/syscall/ztypes_solaris_amd64.go
index 77275a54e3..2471519ade 100644
--- a/src/syscall/ztypes_solaris_amd64.go
+++ b/src/syscall/ztypes_solaris_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_solaris.go
 
+// +build amd64,solaris
+
 package syscall
 
 const (
diff --git a/src/testing/example.go b/src/testing/example.go
index 61339a6465..30baf27030 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -43,7 +43,7 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
 
 func runExample(eg InternalExample) (ok bool) {
 	if *chatty {
-		fmt.Printf("=== RUN: %s\n", eg.Name)
+		fmt.Printf("=== RUN   %s\n", eg.Name)
 	}
 
 	// Capture stdout.
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 280d76a1aa..2a1c45f768 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -44,7 +44,7 @@
 //     }
 //
 // The benchmark function must run the target code b.N times.
-// During benchark execution, b.N is adjusted until the benchmark function lasts
+// During benchmark execution, b.N is adjusted until the benchmark function lasts
 // long enough to be timed reliably.  The output
 //     BenchmarkHello    10000000    282 ns/op
 // means that the loop ran 10000000 times at a speed of 282 ns per loop.
@@ -557,7 +557,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 			}
 			t.self = t
 			if *chatty {
-				fmt.Printf("=== RUN %s\n", t.name)
+				fmt.Printf("=== RUN   %s\n", t.name)
 			}
 			go tRunner(t, &tests[i])
 			out := (<-t.signal).(*T)
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index d3eadfd7e1..eacc0a2245 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -314,7 +314,9 @@ func (s *Scanner) Next() rune {
 	s.tokPos = -1 // don't collect token text
 	s.Line = 0    // invalidate token position
 	ch := s.Peek()
-	s.ch = s.next()
+	if ch != EOF {
+		s.ch = s.next()
+	}
 	return ch
 }
 
@@ -597,6 +599,8 @@ redo:
 		}
 	default:
 		switch ch {
+		case EOF:
+			break
 		case '"':
 			if s.Mode&ScanStrings != 0 {
 				s.scanString('"')
diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go
index aca17b1b27..798bed7e92 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -619,13 +619,12 @@ func TestPos(t *testing.T) {
 
 type countReader int
 
-func (c *countReader) Read([]byte) (int, error) {
-	*c++
-
+func (r *countReader) Read([]byte) (int, error) {
+	*r++
 	return 0, io.EOF
 }
 
-func TestPeekEOFHandling(t *testing.T) {
+func TestNextEOFHandling(t *testing.T) {
 	var r countReader
 
 	// corner case: empty source
@@ -633,15 +632,36 @@ func TestPeekEOFHandling(t *testing.T) {
 
 	tok := s.Next()
 	if tok != EOF {
-		t.Errorf("EOF not reported")
+		t.Error("1) EOF not reported")
 	}
 
 	tok = s.Peek()
 	if tok != EOF {
-		t.Errorf("EOF not reported")
+		t.Error("2) EOF not reported")
 	}
 
-	if r != 2 {
-		t.Errorf("scanner called Read %d times, not twice", r)
+	if r != 1 {
+		t.Errorf("scanner called Read %d times, not once", r)
+	}
+}
+
+func TestScanEOFHandling(t *testing.T) {
+	var r countReader
+
+	// corner case: empty source
+	s := new(Scanner).Init(&r)
+
+	tok := s.Scan()
+	if tok != EOF {
+		t.Error("1) EOF not reported")
+	}
+
+	tok = s.Peek()
+	if tok != EOF {
+		t.Error("2) EOF not reported")
+	}
+
+	if r != 1 {
+		t.Errorf("scanner called Read %d times, not once", r)
 	}
 }
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index e6e1287993..ebafb4b5dc 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -660,7 +660,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
 	case *parse.PipeNode:
 		return s.validateType(s.evalPipeline(dot, arg), typ)
 	case *parse.IdentifierNode:
-		return s.evalFunction(dot, arg, arg, nil, zero)
+		return s.validateType(s.evalFunction(dot, arg, arg, nil, zero), typ)
 	case *parse.ChainNode:
 		return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ)
 	}
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index abce27ff3d..0f1ad62380 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -531,6 +531,8 @@ var execTests = []execTest{
 	{"bug14a", "{{(nil).True}}", "", tVal, false},
 	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
 	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
+	// Didn't call validateType on function results. Issue 10800.
+	{"bug15", "{{valueString returnInt}}", "", tVal, false},
 }
 
 func zeroArgs() string {
@@ -570,6 +572,11 @@ func valueString(v string) string {
 	return "value is ignored"
 }
 
+// returnInt returns an int
+func returnInt() int {
+	return 7
+}
+
 func add(args ...int) int {
 	sum := 0
 	for _, x := range args {
@@ -611,6 +618,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
 		"makemap":     makemap,
 		"mapOfThree":  mapOfThree,
 		"oneArg":      oneArg,
+		"returnInt":   returnInt,
 		"stringer":    stringer,
 		"typeOf":      typeOf,
 		"valueString": valueString,
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index cdd187bda2..ccd0dfc80d 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -92,6 +92,8 @@ func goodFunc(typ reflect.Type) bool {
 // findFunction looks for a function in the template, and global map.
 func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
 	if tmpl != nil && tmpl.common != nil {
+		tmpl.muFuncs.RLock()
+		defer tmpl.muFuncs.RUnlock()
 		if fn := tmpl.execFuncs[name]; fn.IsValid() {
 			return fn, true
 		}
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 8611faad9f..a7c5c8cd2c 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -7,18 +7,20 @@ package template
 import (
 	"fmt"
 	"reflect"
+	"sync"
 	"text/template/parse"
 )
 
 // common holds the information shared by related templates.
 type common struct {
-	tmpl map[string]*Template
+	tmpl   map[string]*Template
+	option option
 	// We use two maps, one for parsing and one for execution.
 	// This separation makes the API cleaner since it doesn't
 	// expose reflection to the client.
+	muFuncs    sync.RWMutex // protects parseFuncs and execFuncs
 	parseFuncs FuncMap
 	execFuncs  map[string]reflect.Value
-	option     option
 }
 
 // Template is the representation of a parsed template. The *parse.Tree
@@ -84,6 +86,8 @@ func (t *Template) Clone() (*Template, error) {
 		tmpl := v.copy(nt.common)
 		nt.tmpl[k] = tmpl
 	}
+	t.muFuncs.RLock()
+	defer t.muFuncs.RUnlock()
 	for k, v := range t.parseFuncs {
 		nt.parseFuncs[k] = v
 	}
@@ -146,6 +150,8 @@ func (t *Template) Delims(left, right string) *Template {
 // value is the template, so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
 	t.init()
+	t.muFuncs.Lock()
+	defer t.muFuncs.Unlock()
 	addValueFuncs(t.execFuncs, funcMap)
 	addFuncs(t.parseFuncs, funcMap)
 	return t
@@ -169,7 +175,9 @@ func (t *Template) Lookup(name string) *Template {
 // can contain text other than space, comments, and template definitions.)
 func (t *Template) Parse(text string) (*Template, error) {
 	t.init()
+	t.muFuncs.RLock()
 	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
+	t.muFuncs.RUnlock()
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/time/export_windows_test.go b/src/time/export_windows_test.go
index 7e689b829f..6fd4509137 100644
--- a/src/time/export_windows_test.go
+++ b/src/time/export_windows_test.go
@@ -8,3 +8,7 @@ func ForceAusForTesting() {
 	ResetLocalOnceForTest()
 	localOnce.Do(initAusTestingZone)
 }
+
+func ToEnglishName(stdname, dstname string) (string, error) {
+	return toEnglishName(stdname, dstname)
+}
diff --git a/src/time/time.go b/src/time/time.go
index 0300e846a4..fbf3f8d3c8 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -966,6 +966,8 @@ func (t *Time) UnmarshalText(data []byte) (err error) {
 // Unix returns the local Time corresponding to the given Unix time,
 // sec seconds and nsec nanoseconds since January 1, 1970 UTC.
 // It is valid to pass nsec outside the range [0, 999999999].
+// Not all sec values have a corresponding time value. Notable such
+// values are -1<<63 and 1<<63-1.
 func Unix(sec int64, nsec int64) Time {
 	if nsec < 0 || nsec >= 1e9 {
 		n := nsec / 1e9
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index 9f987ab302..d04ebec614 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -49,7 +49,7 @@ func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (ma
 // toEnglishName searches the registry for an English name of a time zone
 // whose zone names are stdname and dstname and returns the English name.
 func toEnglishName(stdname, dstname string) (string, error) {
-	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS)
+	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
 	if err != nil {
 		return "", err
 	}
diff --git a/src/time/zoneinfo_windows_test.go b/src/time/zoneinfo_windows_test.go
index 9db81b7cfd..5f1141d3ca 100644
--- a/src/time/zoneinfo_windows_test.go
+++ b/src/time/zoneinfo_windows_test.go
@@ -5,6 +5,7 @@
 package time_test
 
 import (
+	"internal/syscall/windows/registry"
 	"testing"
 	. "time"
 )
@@ -33,3 +34,27 @@ func TestAusZoneAbbr(t *testing.T) {
 	defer ForceUSPacificForTesting()
 	testZoneAbbr(t)
 }
+
+func TestToEnglishName(t *testing.T) {
+	const want = "Central Europe Standard Time"
+	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+want, registry.READ)
+	if err != nil {
+		t.Fatalf("cannot open CEST time zone information from registry: %s", err)
+	}
+	defer k.Close()
+	std, _, err := k.GetStringValue("Std")
+	if err != nil {
+		t.Fatalf("cannot read CEST Std registry key: %s", err)
+	}
+	dlt, _, err := k.GetStringValue("Dlt")
+	if err != nil {
+		t.Fatalf("cannot read CEST Dlt registry key: %s", err)
+	}
+	name, err := ToEnglishName(std, dlt)
+	if err != nil {
+		t.Fatalf("toEnglishName failed: %s", err)
+	}
+	if name != want {
+		t.Fatalf("english name: %q, want: %q", name, want)
+	}
+}
diff --git a/test/bench/shootout/timing.sh b/test/bench/shootout/timing.sh
index a06c326c3e..d8b1486480 100755
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -6,9 +6,8 @@
 set -e
 
 eval $(go tool dist env)
-O=$GOCHAR
-GC="go tool ${O}g"
-LD="go tool ${O}l"
+GC="go tool compile"
+LD="go tool link"
 
 gccm=""
 case "$O" in
@@ -61,11 +60,11 @@ X-test)
 esac
 
 gc() {
-	$GC $1.go; $LD -o $O.$EXE $1.$O
+	$GC $1.go; $LD -o a.$EXE $1.o
 }
 
 gc_B() {
-	$GC -B $1.go; $LD -o $O.$EXE $1.$O
+	$GC -B $1.go; $LD -o a.$EXE $1.o
 }
 
 runonly() {
@@ -115,8 +114,8 @@ fasta() {
 	runonly echo 'fasta -n 25000000'
 	run "gcc $gccm -O2 fasta.c" a.$EXE 25000000
 	run 'gccgo -O2 fasta.go' a.$EXE -n 25000000	#commented out until WriteString is in bufio
-	run 'gc fasta' $O.$EXE -n 25000000
-	run 'gc_B fasta' $O.$EXE -n 25000000
+	run 'gc fasta' a.$EXE -n 25000000
+	run 'gc_B fasta' a.$EXE -n 25000000
 }
 
 revcomp() {
@@ -125,8 +124,8 @@ revcomp() {
 	runonly echo 'reverse-complement < output-of-fasta-25000000'
 	run "gcc $gccm -O2 reverse-complement.c" a.$EXE < x
 	run 'gccgo -O2 reverse-complement.go' a.$EXE < x
-	run 'gc reverse-complement' $O.$EXE < x
-	run 'gc_B reverse-complement' $O.$EXE < x
+	run 'gc reverse-complement' a.$EXE < x
+	run 'gc_B reverse-complement' a.$EXE < x
 	rm x
 }
 
@@ -134,8 +133,8 @@ nbody() {
 	runonly echo 'nbody -n 50000000'
 	run "gcc $gccm -O2 nbody.c -lm" a.$EXE 50000000
 	run 'gccgo -O2 nbody.go' a.$EXE -n 50000000
-	run 'gc nbody' $O.$EXE -n 50000000
-	run 'gc_B nbody' $O.$EXE -n 50000000
+	run 'gc nbody' a.$EXE -n 50000000
+	run 'gc_B nbody' a.$EXE -n 50000000
 }
 
 binarytree() {
@@ -143,8 +142,8 @@ binarytree() {
 	run "gcc $gccm -O2 binary-tree.c -lm" a.$EXE 15
 	run 'gccgo -O2 binary-tree.go' a.$EXE -n 15
 	run 'gccgo -O2 binary-tree-freelist.go' a.$EXE -n 15
-	run 'gc binary-tree' $O.$EXE -n 15
-	run 'gc binary-tree-freelist' $O.$EXE -n 15
+	run 'gc binary-tree' a.$EXE -n 15
+	run 'gc binary-tree-freelist' a.$EXE -n 15
 }
 
 fannkuch() {
@@ -152,9 +151,9 @@ fannkuch() {
 	run "gcc $gccm -O2 fannkuch.c" a.$EXE 12
 	run 'gccgo -O2 fannkuch.go' a.$EXE -n 12
 	run 'gccgo -O2 fannkuch-parallel.go' a.$EXE -n 12
-	run 'gc fannkuch' $O.$EXE -n 12
-	run 'gc fannkuch-parallel' $O.$EXE -n 12
-	run 'gc_B fannkuch' $O.$EXE -n 12
+	run 'gc fannkuch' a.$EXE -n 12
+	run 'gc fannkuch-parallel' a.$EXE -n 12
+	run 'gc_B fannkuch' a.$EXE -n 12
 }
 
 regexdna() {
@@ -166,9 +165,9 @@ regexdna() {
 	fi
 	run 'gccgo -O2 regex-dna.go' a.$EXE  0 {
@@ -192,11 +180,11 @@ func goFiles(dir string) []string {
 type runCmd func(...string) ([]byte, error)
 
 func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
-	return runcmd("go", "tool", gc, "-e", longname)
+	return runcmd("go", "tool", "compile", "-e", longname)
 }
 
 func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err error) {
-	cmd := []string{"go", "tool", gc, "-e", "-D", ".", "-I", "."}
+	cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
 	for _, name := range names {
 		cmd = append(cmd, filepath.Join(dir, name))
 	}
@@ -204,8 +192,8 @@ func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err e
 }
 
 func linkFile(runcmd runCmd, goname string) (err error) {
-	pfile := strings.Replace(goname, ".go", "."+letter, -1)
-	_, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile)
+	pfile := strings.Replace(goname, ".go", ".o", -1)
+	_, err = runcmd("go", "tool", "link", "-w", "-o", "a.exe", "-L", ".", pfile)
 	return
 }
 
@@ -506,7 +494,7 @@ func (t *test) run() {
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "errorcheck":
-		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
+		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, long)
 		out, err := runcmd(cmdline...)
@@ -669,7 +657,7 @@ func (t *test) run() {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
+		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, tfile)
 		out, err = runcmd(cmdline...)
diff --git a/test/sinit_run.go b/test/sinit_run.go
index b0a91ce5b1..c9afd3b777 100644
--- a/test/sinit_run.go
+++ b/test/sinit_run.go
@@ -12,26 +12,19 @@ package main
 import (
 	"bytes"
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 )
 
 func main() {
-	letter, err := build.ArchChar(build.Default.GOARCH)
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-
-	cmd := exec.Command("go", "tool", letter+"g", "-S", "sinit.go")
+	cmd := exec.Command("go", "tool", "compile", "-S", "sinit.go")
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		fmt.Println(string(out))
 		fmt.Println(err)
 		os.Exit(1)
 	}
-	os.Remove("sinit." + letter)
+	os.Remove("sinit.o")
 
 	if bytes.Contains(out, []byte("initdone")) {
 		fmt.Println("sinit generated an init function")
diff --git a/test/sliceopt.go b/test/sliceopt.go
new file mode 100644
index 0000000000..c9d089f7d2
--- /dev/null
+++ b/test/sliceopt.go
@@ -0,0 +1,59 @@
+// errorcheck -0 -d=append,slice
+
+// Copyright 2015 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.
+
+// Check optimization results for append and slicing.
+
+package main
+
+func a1(x []int, y int) []int {
+	x = append(x, y) // ERROR "append: len-only update"
+	return x
+}
+
+func a2(x []int, y int) []int {
+	return append(x, y) // ERROR "append: full update"
+}
+
+func a3(x *[]int, y int) {
+	*x = append(*x, y) // ERROR "append: len-only update"
+}
+
+func s1(x **[]int, xs **string, i, j int) {
+	var z []int
+	z = (**x)[2:]         // ERROR "slice: omit check for 2nd index"
+	z = (**x)[2:len(**x)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
+	z = (**x)[2:cap(**x)] // not yet: "slice: reuse cap" "slice: omit check for 2nd index"
+	z = (**x)[i:i]        // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0"
+	z = (**x)[1:i:i]      // ERROR "slice: reuse 2nd index" "slice: omit check for 2nd index" "slice: result cap == result len"
+	z = (**x)[i:j:0]      // ERROR "slice: omit check for 3rd index"
+	z = (**x)[i:0:j]      // ERROR "slice: omit check for 2nd index"
+	z = (**x)[0:i:j]      // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+	z = (**x)[0:]         // ERROR "slice: omit slice operation"
+	z = (**x)[2:8]        // ERROR "slice: omit check for 1st index" "slice: result len == 6"
+	z = (**x)[2:2]        // ERROR "slice: omit check for 1st index" "slice: result len == 0"
+	z = (**x)[0:i]        // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+	z = (**x)[2:i:8]      // ERROR "slice: result cap == 6"
+	z = (**x)[i:2:i]      // ERROR "slice: reuse 1st index" "slice: result cap == 0" "slice: skip base adjustment for cap == 0"
+
+	z = z[0:i]       // ERROR "slice: omit check for 1st index" "slice: result cap not computed" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
+	z = z[0:i : i+1] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len/cap-only update"
+	z = z[i : i+1]
+
+	println(z)
+
+	var zs string
+	zs = (**xs)[2:]          // ERROR "slice: omit check for 2nd index"
+	zs = (**xs)[2:len(**xs)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
+	zs = (**xs)[i:i]         // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
+	zs = (**xs)[0:]          // ERROR "slice: omit slice operation"
+	zs = (**xs)[2:8]         // ERROR "slice: omit check for 1st index" "slice: result len == 6"
+	zs = (**xs)[2:2]         // ERROR "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
+	zs = (**xs)[0:i]         // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+
+	zs = zs[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
+	zs = zs[i : i+1]
+	println(zs)
+}
diff --git a/test/writebarrier.go b/test/writebarrier.go
index 1f25d91ea4..9b741a60df 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -28,7 +28,7 @@ func f1a(x *[]byte, y *[]byte) {
 	*x = *y // ERROR "write barrier"
 
 	z := *y // no barrier
-	*x = z // ERROR "write barrier"
+	*x = z  // ERROR "write barrier"
 }
 
 func f2(x *interface{}, y interface{}) {
@@ -56,7 +56,7 @@ func f3a(x *string, y *string) {
 	*x = *y // ERROR "write barrier"
 
 	z := *y // no barrier
-	*x = z // ERROR "write barrier"
+	*x = z  // ERROR "write barrier"
 }
 
 func f4(x *[2]string, y [2]string) {
@@ -70,7 +70,7 @@ func f4a(x *[2]string, y *[2]string) {
 	*x = *y // ERROR "write barrier"
 
 	z := *y // no barrier
-	*x = z // ERROR "write barrier"
+	*x = z  // ERROR "write barrier"
 }
 
 type T struct {
@@ -108,3 +108,39 @@ func f10(x *byte, f func(interface{})) {
 func f11(x *unsafe.Pointer, y unsafe.Pointer) {
 	*x = unsafe.Pointer(uintptr(y) + 1) // ERROR "write barrier"
 }
+
+func f12(x []*int, y *int) []*int {
+	// write barrier for storing y in x's underlying array
+	x = append(x, y) // ERROR "write barrier"
+	return x
+}
+
+func f12a(x []int, y int) []int {
+	// y not a pointer, so no write barriers in this function
+	x = append(x, y)
+	return x
+}
+
+func f13(x []int, y *[]int) {
+	*y = append(x, 1) // ERROR "write barrier"
+}
+
+func f14(y *[]int) {
+	*y = append(*y, 1) // ERROR "write barrier"
+}
+
+type T1 struct {
+	X *int
+}
+
+func f15(x []T1, y T1) []T1 {
+	return append(x, y) // ERROR "write barrier"
+}
+
+type T8 struct {
+	X [8]*int
+}
+
+func f16(x []T8, y T8) []T8 {
+	return append(x, y) // ERROR "write barrier"
+}