[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch

Semi-regular merge of tip to dev.ssa.

Complicated a bit by the move of cmd/internal/* to cmd/compile/internal/*.

Change-Id: I1c66d3c29bb95cce4a53c5a3476373aa5245303d
diff --git a/api/next.txt b/api/next.txt
index cebbe87..b8e09df 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 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/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 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) 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, 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, 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, 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, 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 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) 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 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 d6be379..8a827d0 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -1382,7 +1382,7 @@
 <code>os</code>:
 </p>
 <pre>
-func (file *File) Read(buf []byte) (n int, err error)
+func (f *File) Read(buf []byte) (n int, err error)
 </pre>
 <p>
 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 b0602f9..f2ceb1d 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/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 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 @@
 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 d02697b..b5f18f3 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,24 +1,9 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of March 20, 2015",
+	"Subtitle": "Version of May 26, 2015",
 	"Path": "/ref/spec"
 }-->
 
-<!--
-TODO
-[ ] need language about function/method calls and parameter passing rules
-[ ] last paragraph of #Assignments (constant promotion) should be elsewhere
-    and mention assignment to empty interface.
-[ ] need to say something about "scope" of selectors?
-[ ] clarify what a field name is in struct declarations
-    (struct{T} vs struct {T T} vs struct {t T})
-[ ] need explicit language about the result type of operations
-[ ] should probably write something about evaluation order of statements even
-	though obvious
-[ ] in Selectors section, clarify what receiver value is passed in method invocations
--->
-
-
 <h2 id="Introduction">Introduction</h2>
 
 <p>
@@ -2605,7 +2590,7 @@
 <pre>
 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 @@
 </p>
 
 <pre class="ebnf">
-Expression = UnaryExpr | Expression binary_op UnaryExpr .
+Expression = UnaryExpr | Expression binary_op Expression .
 UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
 
 binary_op  = "||" | "&amp;&amp;" | rel_op | add_op | mul_op .
diff --git a/misc/android/cleaner.go b/misc/android/cleaner.go
new file mode 100644
index 0000000..dafb162
--- /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 6e1d106..3cc2af5 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -6,7 +6,8 @@
 
 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 0000000..518c533
--- /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 <signal.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+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 0000000..7d343e92
--- /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 9862a37..492d25e 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -15,6 +15,14 @@
 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 @@
 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 @@
 	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 @@
 
 # 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 0000000..f7a99af
--- /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, &note{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 fb112cd..d3bed3f 100644
--- a/misc/cgo/testshared/src/dep/dep.go
+++ b/misc/cgo/testshared/src/dep/dep.go
@@ -2,6 +2,12 @@
 
 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 0000000..bac1086
--- /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 0000000..acdb4dd
--- /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 21004ad..0000000
--- 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 1c013c1..8e53726 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -35,7 +35,7 @@
 				gofmt_test.go
 				testdata
 					+
-			link
+			newlink
 				testdata
 					+
 		archive
diff --git a/misc/trace/README.md b/misc/trace/README.md
index b9364de..775fdb8 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 aad1f7e..39e73c3 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -24,10 +24,11 @@
 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}/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 abd8f14..cd23fb5 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -463,6 +463,10 @@
 	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 9601ffe..ab1e844 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -741,3 +741,19 @@
 	}
 
 }
+
+// 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 0000000..5deea3d
--- /dev/null
+++ b/src/archive/tar/testdata/neg-size.tar
Binary files differ
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 8136b84..f68ab09 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -8,6 +8,7 @@
 	"bufio"
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"hash"
 	"hash/crc32"
 	"io"
@@ -77,6 +78,9 @@
 	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 @@
 	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 @@
 	}
 	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 29d0652..4806b89 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -531,3 +531,54 @@
 		}
 	}
 }
+
+// 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 a07529e..ba23d31 100755
--- a/src/buildall.bash
+++ b/src/buildall.bash
@@ -36,7 +36,7 @@
 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 06ab7d0..0000000
--- 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 725c635..d5d2772 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -493,7 +493,10 @@
 			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 c74f269..bf5cb1e 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -51,7 +51,7 @@
 	os.Exit(2)
 }
 
-func Parse(theChar int) {
+func Parse() {
 	flag.Usage = Usage
 	flag.Parse()
 	if flag.NArg() != 1 {
@@ -64,6 +64,6 @@
 		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 730042b..7e495b8 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -13,7 +13,6 @@
 	"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 @@
 	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 28a4b85..6a4d954 100644
--- a/src/cmd/asm/internal/lex/tokenizer.go
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -10,8 +10,6 @@
 	"strings"
 	"text/scanner"
 	"unicode"
-
-	"cmd/internal/obj"
 )
 
 // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
@@ -40,7 +38,7 @@
 	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 @@
 	if t.file != nil {
 		t.file.Close()
 		// It's an open file, so pop the line history.
-		obj.Linklinehist(linkCtxt, histLine, "<pop>", 0)
+		linkCtxt.LineHist.Pop(histLine)
 	}
 }
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 32bdee6..db0e28e 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -29,7 +29,7 @@
 		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 30f828c..87f21ed 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -846,6 +846,8 @@
 			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 @@
 		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 @@
 #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 23e2d1b..71f8f88 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 96%
rename from src/cmd/6g/galign.go
rename to src/cmd/compile/internal/amd64/galign.go
index 0ca8753..79bf94a 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 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 @@
 	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 6e5e6bc..6425633 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 @@
 	// 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 @@
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
 			check = 0
-		} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
 			check = 0
 		}
 	}
@@ -306,7 +306,7 @@
  * known to be dead.
  */
 func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
-	r := int(reg[dr])
+	r := reg[dr]
 
 	// save current ax and dx if they are live
 	// and not the destination
@@ -318,7 +318,7 @@
 		x.Type = gc.Types[gc.TINT64]
 		gmove(x, oldx)
 		x.Type = t
-		oldx.Ostk = int32(r) // squirrel away old r value
+		oldx.Etype = r // squirrel away old r value
 		reg[dr] = 1
 	}
 }
@@ -326,7 +326,7 @@
 func restx(x *gc.Node, oldx *gc.Node) {
 	if oldx.Op != 0 {
 		x.Type = gc.Types[gc.TINT64]
-		reg[x.Reg] = uint8(oldx.Ostk)
+		reg[x.Reg] = oldx.Etype
 		gmove(oldx, x)
 		gc.Regfree(oldx)
 	}
@@ -381,7 +381,7 @@
 		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 >= 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 94%
rename from src/cmd/6g/gsubr.go
rename to src/cmd/compile/internal/amd64/gsubr.go
index 53d0f03..a8e4170 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 @@
 	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 @@
 	// 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 @@
 			// 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 @@
 		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 cd07199..19db68e 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 5f60474..00918c8 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 cab07b5..7d4f406 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 2e92239..8ea6c5f 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 @@
 	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 98%
rename from src/cmd/5g/cgen64.go
rename to src/cmd/compile/internal/arm/cgen64.go
index 699e555..6c88b76 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 @@
 	//	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 @@
 		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 @@
 		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 3c8ba519..60a39d3 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 @@
 	gc.Widthreg = 4
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -65,6 +65,7 @@
 	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 0cf0d92..6633351 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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 57d511e..5263f15 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 @@
 	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 @@
 		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 @@
 
 	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 @@
 		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 @@
 		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 @@
 		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 b76719d..66eba41 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 c472cdf..cdf9d29 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 2afdf12..b72ccc9 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 6f268b4..30326d7 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 95%
rename from src/cmd/7g/galign.go
rename to src/cmd/compile/internal/arm64/galign.go
index 34b4ab6..38def8f 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 @@
 	gc.Widthreg = 8
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -65,6 +65,7 @@
 	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 b824a3a..851ca4e 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 @@
 	// 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 @@
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
 			check = 0
-		} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
 			check = 0
 		}
 	}
@@ -312,7 +312,7 @@
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gc.Cgen(nl, &n1)
-		sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
+		sc := uint64(nr.Int())
 		if sc >= 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 94%
rename from src/cmd/7g/gsubr.go
rename to src/cmd/compile/internal/arm64/gsubr.go
index a34a4306..0a14654 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 @@
 	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 @@
 		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 @@
 			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 @@
 }
 
 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 98%
rename from src/cmd/7g/peep.go
rename to src/cmd/compile/internal/arm64/peep.go
index 49bc69b..3dbccb7 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 @@
 		// 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 023f302..1106e78 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 0e5ac73..7bc756b 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 98%
rename from src/cmd/internal/gc/big/arith.go
rename to src/cmd/compile/internal/big/arith.go
index 328c85c..1ff6349 100644
--- a/src/cmd/internal/gc/big/arith.go
+++ b/src/cmd/compile/internal/big/arith.go
@@ -196,7 +196,6 @@
 	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 cd92dd7..f46a494 100644
--- a/src/cmd/internal/gc/big/arith_test.go
+++ b/src/cmd/compile/internal/big/arith_test.go
@@ -155,6 +155,7 @@
 	{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 078be47..cb91bc2 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 ed55e8e..dcb72c5 100644
--- a/src/cmd/internal/gc/big/float.go
+++ b/src/cmd/compile/internal/big/float.go
@@ -65,12 +65,16 @@
 	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 @@
 	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 @@
 			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<<mbits - 1) // cut off msb (implicit 1 bit)
-
 		// Rounding may have caused a denormal number to
 		// become normal. Check again.
-		c := float32(1.0)
-		if r.exp < emin+1 {
+		if e < emin {
 			// denormal number
-			r.exp += mbits
-			c = 1.0 / (1 << mbits) // 2**-mbits
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = high32(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
 		}
-		// emin+1 <= r.exp <= emax+1
-		e := uint32(r.exp-emin) << mbits
 
-		return c * math.Float32frombits(s|e|m), r.acc
+		return math.Float32frombits(sign | bexp | mant), r.acc
 
 	case zero:
 		if x.neg {
@@ -976,64 +983,70 @@
 			emax  = bias              //  1023  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 float64
-				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 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<<mbits - 1) // cut off msb (implicit 1 bit)
-
 		// Rounding may have caused a denormal number to
 		// become normal. Check again.
-		c := 1.0
-		if r.exp < emin+1 {
+		if e < emin {
 			// denormal number
-			r.exp += mbits
-			c = 1.0 / (1 << mbits) // 2**-mbits
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = high64(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
 		}
-		// emin+1 <= r.exp <= emax+1
-		e := uint64(r.exp-emin) << mbits
 
-		return c * math.Float64frombits(s|e|m), r.acc
+		return math.Float64frombits(sign | bexp | mant), r.acc
 
 	case zero:
 		if x.neg {
diff --git a/src/cmd/internal/gc/big/float_test.go b/src/cmd/compile/internal/big/float_test.go
similarity index 90%
rename from src/cmd/internal/gc/big/float_test.go
rename to src/cmd/compile/internal/big/float_test.go
index 2a48ec4..8bd3a9c 100644
--- a/src/cmd/internal/gc/big/float_test.go
+++ b/src/cmd/compile/internal/big/float_test.go
@@ -12,6 +12,9 @@
 	"testing"
 )
 
+// Verify that ErrNaN implements the error interface.
+var _ error = ErrNaN{}
+
 func (x *Float) uint64() uint64 {
 	u, acc := x.Uint64()
 	if acc != Exact {
@@ -200,6 +203,18 @@
 	return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
 }
 
+func alike32(x, y float32) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
+
+}
+
+func alike64(x, y float64) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(x) == math.Signbit(y)
+
+}
+
 func TestFloatMantExp(t *testing.T) {
 	for _, test := range []struct {
 		x    string
@@ -825,52 +840,69 @@
 		out float32
 		acc Accuracy
 	}{
-		{"-Inf", float32(math.Inf(-1)), Exact},
-		{"-0x1.ffffff0p2147483646", float32(-math.Inf(+1)), Below}, // overflow in rounding
-		{"-1e10000", float32(math.Inf(-1)), Below},                 // overflow
-		{"-0x1p128", float32(math.Inf(-1)), Below},                 // overflow
-		{"-0x1.ffffff0p127", float32(-math.Inf(+1)), Below},        // overflow
-		{"-0x1.fffffe8p127", -math.MaxFloat32, Above},
-		{"-0x1.fffffe0p127", -math.MaxFloat32, Exact},
-		{"-12345.000000000000000000001", -12345, Above},
-		{"-12345.0", -12345, Exact},
-		{"-1.000000000000000000001", -1, Above},
-		{"-1", -1, Exact},
-		{"-0x0.000002p-126", -math.SmallestNonzeroFloat32, Exact},
-		{"-0x0.000002p-127", -0, Above}, // underflow
-		{"-1e-1000", -0, Above},         // underflow
 		{"0", 0, Exact},
-		{"1e-1000", 0, Below},         // underflow
-		{"0x0.000002p-127", 0, Below}, // underflow
-		{"0x0.000002p-126", math.SmallestNonzeroFloat32, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.000002p-127", 0, Below},
+		{"0x.0000010p-126", 0, Below},
+
+		// denormals
+		{"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
+		{"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
+		{"1p-149", math.SmallestNonzeroFloat32, Exact},
+		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
+		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
+		{"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
+		{"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
 		{"1", 1, Exact},
 		{"1.000000000000000000001", 1, Below},
 		{"12345.0", 12345, Exact},
 		{"12345.000000000000000000001", 12345, Below},
 		{"0x1.fffffe0p127", math.MaxFloat32, Exact},
 		{"0x1.fffffe8p127", math.MaxFloat32, Below},
-		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},        // overflow
-		{"0x1p128", float32(math.Inf(+1)), Above},                // overflow
-		{"1e10000", float32(math.Inf(+1)), Above},                // overflow
+
+		// overflow
+		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
+		{"0x1p128", float32(math.Inf(+1)), Above},
+		{"1e10000", float32(math.Inf(+1)), Above},
 		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
-		{"+Inf", float32(math.Inf(+1)), Exact},
+
+		// inf
+		{"Inf", float32(math.Inf(+1)), Exact},
 	} {
-		// conversion should match strconv where syntax is agreeable
-		if f, err := strconv.ParseFloat(test.x, 32); err == nil && float32(f) != test.out {
-			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
-		}
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
 
-		x := makeFloat(test.x)
-		out, acc := x.Float32()
-		if out != test.out || acc != test.acc {
-			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), test.acc)
-		}
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
 
-		// test that x.SetFloat64(float64(f)).Float32() == f
-		var x2 Float
-		out2, acc2 := x2.SetFloat64(float64(out)).Float32()
-		if out2 != out || acc2 != Exact {
-			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			x := makeFloat(tx)
+			out, acc := x.Float32()
+			if !alike32(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(float64(f)).Float32() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(float64(out)).Float32()
+			if !alike32(out2, out) || acc2 != Exact {
+				t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			}
 		}
 	}
 }
@@ -882,35 +914,36 @@
 		out float64
 		acc Accuracy
 	}{
-		{"-Inf", math.Inf(-1), Exact},
-		{"-0x1.fffffffffffff8p2147483646", -math.Inf(+1), Below}, // overflow in rounding
-		{"-1e10000", math.Inf(-1), Below},                        // overflow
-		{"-0x1p1024", math.Inf(-1), Below},                       // overflow
-		{"-0x1.fffffffffffff8p1023", -math.Inf(+1), Below},       // overflow
-		{"-0x1.fffffffffffff4p1023", -math.MaxFloat64, Above},
-		{"-0x1.fffffffffffff0p1023", -math.MaxFloat64, Exact},
-		{"-12345.000000000000000000001", -12345, Above},
-		{"-12345.0", -12345, Exact},
-		{"-1.000000000000000000001", -1, Above},
-		{"-1", -1, Exact},
-		{"-0x0.0000000000001p-1022", -math.SmallestNonzeroFloat64, Exact},
-		{"-0x0.0000000000001p-1023", -0, Above}, // underflow
-		{"-1e-1000", -0, Above},                 // underflow
 		{"0", 0, Exact},
-		{"1e-1000", 0, Below},                 // underflow
-		{"0x0.0000000000001p-1023", 0, Below}, // underflow
-		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.0000000000001p-1023", 0, Below},
+		{"0x0.00000000000008p-1022", 0, Below},
+
+		// denormals
+		{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},  // smallest denormal
+		{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
+		{"1p-1074", math.SmallestNonzeroFloat64, Exact},
+		{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
+		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
 		{"1", 1, Exact},
 		{"1.000000000000000000001", 1, Below},
 		{"12345.0", 12345, Exact},
 		{"12345.000000000000000000001", 12345, Below},
 		{"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact},
 		{"0x1.fffffffffffff4p1023", math.MaxFloat64, Below},
-		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},       // overflow
-		{"0x1p1024", math.Inf(+1), Above},                      // overflow
-		{"1e10000", math.Inf(+1), Above},                       // overflow
+
+		// overflow
+		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
+		{"0x1p1024", math.Inf(+1), Above},
+		{"1e10000", math.Inf(+1), Above},
 		{"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
-		{"+Inf", math.Inf(+1), Exact},
+		{"Inf", math.Inf(+1), Exact},
 
 		// selected denormalized values that were handled incorrectly in the past
 		{"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
@@ -921,22 +954,32 @@
 		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
 		{"2.2250738585072012e-308", 2.2250738585072014e-308, Above},
 	} {
-		// conversion should match strconv where syntax is agreeable
-		if f, err := strconv.ParseFloat(test.x, 64); err == nil && f != test.out {
-			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
-		}
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
 
-		x := makeFloat(test.x)
-		out, acc := x.Float64()
-		if out != test.out || acc != test.acc {
-			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), test.acc)
-		}
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
 
-		// test that x.SetFloat64(f).Float64() == f
-		var x2 Float
-		out2, acc2 := x2.SetFloat64(out).Float64()
-		if out2 != out || acc2 != Exact {
-			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			x := makeFloat(tx)
+			out, acc := x.Float64()
+			if !alike64(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(f).Float64() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(out).Float64()
+			if !alike64(out2, out) || acc2 != Exact {
+				t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			}
 		}
 	}
 }
@@ -1656,7 +1699,7 @@
 					want = +1
 				}
 				if got != want {
-					t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
+					t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want)
 				}
 			}
 		}
diff --git a/src/cmd/internal/gc/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go
similarity index 100%
rename from src/cmd/internal/gc/big/floatconv.go
rename to src/cmd/compile/internal/big/floatconv.go
diff --git a/src/cmd/internal/gc/big/floatconv_test.go b/src/cmd/compile/internal/big/floatconv_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/floatconv_test.go
rename to src/cmd/compile/internal/big/floatconv_test.go
diff --git a/src/cmd/internal/gc/big/floatexample_test.go b/src/cmd/compile/internal/big/floatexample_test.go
similarity index 98%
rename from src/cmd/internal/gc/big/floatexample_test.go
rename to src/cmd/compile/internal/big/floatexample_test.go
index 7db1023..0ac9617 100644
--- a/src/cmd/internal/gc/big/floatexample_test.go
+++ b/src/cmd/compile/internal/big/floatexample_test.go
@@ -5,9 +5,9 @@
 package big_test
 
 import (
+	"cmd/compile/internal/big"
 	"fmt"
 	"math"
-	"math/big"
 )
 
 func ExampleFloat_Add() {
diff --git a/src/cmd/internal/gc/big/ftoa.go b/src/cmd/compile/internal/big/ftoa.go
similarity index 100%
rename from src/cmd/internal/gc/big/ftoa.go
rename to src/cmd/compile/internal/big/ftoa.go
diff --git a/src/cmd/internal/gc/big/gcd_test.go b/src/cmd/compile/internal/big/gcd_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/gcd_test.go
rename to src/cmd/compile/internal/big/gcd_test.go
diff --git a/src/cmd/internal/gc/big/hilbert_test.go b/src/cmd/compile/internal/big/hilbert_test.go
similarity index 100%
rename from src/cmd/internal/gc/big/hilbert_test.go
rename to src/cmd/compile/internal/big/hilbert_test.go
diff --git a/src/cmd/internal/gc/big/int.go b/src/cmd/compile/internal/big/int.go
similarity index 88%
rename from src/cmd/internal/gc/big/int.go
rename to src/cmd/compile/internal/big/int.go
index 7b419bf..5e31253 100644
--- a/src/cmd/internal/gc/big/int.go
+++ b/src/cmd/compile/internal/big/int.go
@@ -583,6 +583,124 @@
 	return z
 }
 
+// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
+// The y argument must be an odd integer.
+func Jacobi(x, y *Int) int {
+	if len(y.abs) == 0 || y.abs[0]&1 == 0 {
+		panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
+	}
+
+	// We use the formulation described in chapter 2, section 2.4,
+	// "The Yacas Book of Algorithms":
+	// http://yacas.sourceforge.net/Algo.book.pdf
+
+	var a, b, c Int
+	a.Set(x)
+	b.Set(y)
+	j := 1
+
+	if b.neg {
+		if a.neg {
+			j = -1
+		}
+		b.neg = false
+	}
+
+	for {
+		if b.Cmp(intOne) == 0 {
+			return j
+		}
+		if len(a.abs) == 0 {
+			return 0
+		}
+		a.Mod(&a, &b)
+		if len(a.abs) == 0 {
+			return 0
+		}
+		// a > 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 89%
rename from src/cmd/internal/gc/big/int_test.go
rename to src/cmd/compile/internal/big/int_test.go
index a972a72..c19e88a 100644
--- a/src/cmd/internal/gc/big/int_test.go
+++ b/src/cmd/compile/internal/big/int_test.go
@@ -525,6 +525,7 @@
 	{"1234", "-1", "1", "0"},
 
 	// misc
+	{"5", "1", "3", "2"},
 	{"5", "-7", "", "1"},
 	{"-5", "-7", "", "1"},
 	{"5", "0", "", "1"},
@@ -703,6 +704,13 @@
 	"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 @@
 	}
 }
 
+// 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 2a279d1..c3eef76 100644
--- a/src/cmd/internal/gc/big/nat.go
+++ b/src/cmd/compile/internal/big/nat.go
@@ -216,6 +216,34 @@
 	}
 }
 
+// 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 @@
 	}
 	// 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 @@
 	// 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 @@
 	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<<n; i++ {
+		powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
+	}
+
+	// initialize z = 1 (Montgomery 1)
+	z = z.make(numWords)
+	copy(z, powers[0])
+
+	zz = zz.make(numWords)
+
+	// same windowed exponent, but with Montgomery multiplications
+	for i := len(y) - 1; i >= 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 b25a89f..a15a2bc 100644
--- a/src/cmd/internal/gc/big/nat_test.go
+++ b/src/cmd/compile/internal/big/nat_test.go
@@ -332,6 +332,67 @@
 	}
 }
 
+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 84aa750..1b191cc 100755
--- a/src/cmd/internal/gc/big/vendor.bash
+++ b/src/cmd/compile/internal/big/vendor.bash
@@ -15,9 +15,15 @@
 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 789e59b..892595a 100644
--- a/src/cmd/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -71,8 +71,8 @@
 			// 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 501cdcb..ca58b1c 100644
--- a/src/cmd/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -43,14 +43,7 @@
 
 	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 @@
 	case ODOTTYPE:
 		cgen_dottype(n, res, nil, wb)
 		return
+
+	case OAPPEND:
+		cgen_append(n, res)
+		return
 	}
 
 	if n.Ullman >= UINF {
@@ -545,7 +542,7 @@
 			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 @@
 
 			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 @@
 
 			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 @@
 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 @@
 	}
 
 	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_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 @@
 				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 @@
 						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 @@
 			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 @@
 				} 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 @@
 				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 @@
 
 				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 @@
 					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 @@
 			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 @@
 			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 @@
 				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 @@
 		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 @@
 			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 @@
 				// 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 @@
 			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 @@
 	}
 }
 
-/*
- * 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 @@
 			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 @@
 			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 @@
 
 	// 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 @@
 
 		if proc == 2 {
 			Nodreg(&reg, Types[TINT32], Thearch.REGRETURN)
-			Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), &reg, Nodintconst(0))
-			p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1)
+			p := Thearch.Ginscmp(OEQ, Types[TINT32], &reg, Nodintconst(0), +1)
 			cgen_ret(nil)
 			Patch(p, Pc)
 		}
@@ -2576,7 +2536,7 @@
 	}
 
 	// call direct
-	n.Left.Method = true
+	n.Left.Name.Method = true
 
 	Ginscall(n.Left, proc)
 }
@@ -2701,7 +2661,7 @@
 	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 @@
 	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 @@
 		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 8d5fd5a..64cd972 100644
--- a/src/cmd/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -17,7 +17,7 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 	}
 	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 @@
 	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 @@
 		// 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 @@
 				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 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 @@
 			}
 			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 @@
 				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 @@
 			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 @@
 				// 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 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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 ad29158..b3605ab 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 @@
 
 	var v Val
 	v.Ctype = CTFLT
-	v.U.Fval = oldv
+	v.U = oldv
 	overflow(v, t)
 
 	fv := newMpflt()
@@ -190,8 +227,8 @@
 		// 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 @@
 		}
 
 	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 @@
 
 				// 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 @@
 		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 @@
 	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 @@
 	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 @@
 
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 	case CTNIL:
 		v = Val{}
 		v.Ctype = CTSTR
-		v.U.Sval = ""
+		v.U = ""
 	}
 
 	return v
@@ -519,7 +562,7 @@
 				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 @@
 				*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 @@
 
 		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 @@
 				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 @@
 
 	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 @@
 		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 @@
 
 	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 @@
 		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 @@
 
 	// 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 @@
 	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 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 @@
 			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 @@
 			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 @@
 	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 @@
 			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 @@
 	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 cf48c92..56a4892 100644
--- a/src/cmd/internal/gc/cplx.go
+++ b/src/cmd/compile/internal/gc/cplx.go
@@ -89,8 +89,8 @@
 	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 @@
 	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 08d2469..4a9cb29 100644
--- a/src/cmd/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -183,7 +183,7 @@
 	}
 
 	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 @@
 			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 @@
 		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 @@
  * 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 @@
 		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 @@
 		// 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 @@
 			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 @@
 	dclcontext = PPARAM
 	markdcl()
 	Funcdepth++
-	n.Outer = Curfn
+	n.Param.Outer = Curfn
 	Curfn = n
 	funcargs(n.Right)
 
@@ -583,13 +584,13 @@
 	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 @@
 		}
 		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 @@
 		}
 		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 @@
 			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 @@
 	}
 	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 @@
  * 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 @@
 	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 92%
rename from src/cmd/internal/gc/esc.go
rename to src/cmd/compile/internal/gc/esc.go
index c816fea..2c13493 100644
--- a/src/cmd/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -154,7 +154,7 @@
 	}
 
 	if n.Op == OCLOSURE {
-		m := v.visit(n.Closure)
+		m := v.visit(n.Param.Closure)
 		if m < min {
 			min = m
 		}
@@ -379,7 +379,7 @@
 	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 @@
 	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 @@
 	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 @@
 		}
 	}
 
+	// 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 @@
 	}
 
 	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 @@
 
 		// 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 @@
 			// 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 @@
 			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 @@
 
 	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 @@
 			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 @@
 	}
 
 	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 @@
 
 	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 @@
 	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 @@
 // 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 @@
 	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 @@
 
 	case OCALLINTER:
 		fntype = n.Left.Type
+		indirect = true
 	}
 
 	ll := n.List
@@ -1307,8 +1340,30 @@
 		}
 	}
 
+	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 @@
 		}
 
 		// 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 @@
 	}
 
 	// 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 @@
 		}
 	}
 
-	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 @@
 
 		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 @@
 	}
 
 	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 @@
 	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 @@
 			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 @@
 		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 98%
rename from src/cmd/internal/gc/export.go
rename to src/cmd/compile/internal/gc/export.go
index 1efc815..5117490 100644
--- a/src/cmd/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -64,7 +64,7 @@
 	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 1a991a0..4b93363 100644
--- a/src/cmd/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -302,12 +302,12 @@
 	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 @@
 		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 @@
 		// 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 @@
 		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 @@
 		} 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 @@
 
 	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 e6af897..c0dd996 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -57,14 +57,14 @@
 
 		// 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 @@
 			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 @@
 	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 @@
 
 	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 @@
 		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 @@
 	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 @@
 	}
 	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 @@
 	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 @@
 	}
 	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)
@@ -556,122 +553,6 @@
 }
 
 /*
- * 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
  * <0 is pointer to next field (+1)
@@ -1085,7 +966,7 @@
 	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 @@
 		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 @@
 		// 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 71bce0b..dc33f62 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -6,7 +6,7 @@
 
 import (
 	"bytes"
-	"cmd/internal/gc/big"
+	"cmd/compile/internal/big"
 	"cmd/internal/obj"
 )
 
@@ -83,13 +83,13 @@
 
 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 nsyntaxerrors int
 
-var decldepth int
+var decldepth int32
 
 var safemode int
 
@@ -778,13 +778,27 @@
 	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 f1904b0..ae2e761 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 @@
 %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 @@
 	{
 		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 @@
 	{
 		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 @@
 		$$ = 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 @@
 		$$.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 @@
 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 @@
 		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 @@
 		$$ = 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 @@
 	{
 		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 53b3f6c..5ec4587 100644
--- a/src/cmd/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -90,6 +90,10 @@
 		p.From.Offset = int64(obj.Bool2int(likely > 0))
 	}
 
+	if Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
 	return p
 }
 
@@ -210,7 +214,7 @@
 	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 @@
 		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 @@
 
 		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 @@
 	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 b5d1e50..92bfeec 100644
--- a/src/cmd/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -116,7 +116,7 @@
 	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 97%
rename from src/cmd/internal/gc/inl.go
rename to src/cmd/compile/internal/gc/inl.go
index dd2087d..22a5d3d 100644
--- a/src/cmd/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -511,10 +511,10 @@
 
 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 @@
 			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 @@
 		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 @@
 		// 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 @@
 		// 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 @@
 
 	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 4bbda95..cf41c40 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 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 @@
 	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 @@
 	lexlineno = 1
 
 	for _, infile = range flag.Args() {
-		linehist(infile, 0, 0)
+		linehistpush(infile)
 
 		curio.infile = infile
 		var err error
@@ -339,7 +345,7 @@
 			errorexit()
 		}
 
-		linehist("<pop>", 0, 0)
+		linehistpop()
 		if curio.bin != nil {
 			obj.Bterm(curio.bin)
 		}
@@ -394,7 +400,7 @@
 	// 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 @@
 	// 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 @@
 		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 @@
 		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 @@
 		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 fakeimport() {
 	importpkg = mkpkg("fake")
-	cannedimports("fake.6", "$$\n")
+	cannedimports("fake.o", "$$\n")
 }
 
 func importfile(f *Val, line int) {
@@ -641,13 +645,13 @@
 		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 @@
 	// 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 @@
 
 	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 @@
 	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 @@
 
 	// 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 @@
 		return
 	}
 
-	Yyerror("no import in %q", f.U.Sval)
+	Yyerror("no import in %q", f.U.(string))
 	unimportfile()
 }
 
@@ -1060,8 +1064,8 @@
 			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 @@
 	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 @@
 	}
 
 caseep:
+	if importpkg == nil && (c == 'p' || c == 'P') {
+		// <mantissa>p<base-2-exponent> 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 @@
 	}
 
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	}
 
 	name = text[:linep-1]
-	linehist(name, int32(n), 0)
+	linehistupdate(name, n)
 	return c
 
 out:
@@ -2590,6 +2599,6 @@
 		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 82%
rename from src/cmd/internal/gc/mkbuiltin.go
rename to src/cmd/compile/internal/gc/mkbuiltin.go
index b2362a6..f4569b4 100644
--- a/src/cmd/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -13,21 +13,14 @@
 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 @@
 	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 @@
 }
 
 // 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 @@
 	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 de96e97..2c7e517 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 @@
 /// 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 2700b64..0e0b626 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 @@
 	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 @@
 	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 05c5b1a..9bb334c 100644
--- a/src/cmd/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -102,8 +102,7 @@
 			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 @@
 	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 f08f5f2..ee0ec52 100644
--- a/src/cmd/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -104,9 +104,23 @@
 // 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 @@
 	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 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 @@
 // 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 @@
 	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 @@
 		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 @@
 
 		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 @@
 		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 @@
 		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 @@
 
 	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 @@
 	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 @@
 	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 @@
 					// 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 @@
 
 					// 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 @@
 	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 @@
 	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 @@
 // 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 @@
 
 // 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 @@
 
 	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 @@
 		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 @@
 		}
 
 	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 @@
 
 		// 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 @@
 		// 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 @@
 
 	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 @@
 		n.Right.Ninit = concat(l, n.Right.Ninit)
 		orderexprinplace(&n.Right, order)
 
-	case OAPPEND,
-		OCALLFUNC,
+	case OCALLFUNC,
 		OCALLINTER,
 		OCALLMETH,
 		OCAP,
@@ -1064,7 +1084,37 @@
 		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 @@
 		}
 
 	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 @@
 		}
 
 	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 @@
 		}
 
 	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 2c225c8..c170060 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 @@
 		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 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 040a778..b4d0699 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -944,7 +944,7 @@
 		*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 @@
 						}
 						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 e7f3500..05a902e 100644
--- a/src/cmd/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -186,31 +186,6 @@
 	// 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 @@
 		}
 		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 @@
 			*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 9979fe8..6c0962f 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 @@
 
 // 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 @@
 		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 @@
 				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 @@
 	// 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 @@
 	//		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 @@
 	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 @@
 	if isdirectiface(t) {
 		i |= obj.KindDirectIface
 	}
-	if gcprog {
+	if useGCProg {
 		i |= obj.KindGCProg
 	}
 	ot = duint8(s, ot, uint8(i)) // kind
@@ -832,48 +834,7 @@
 	} 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 @@
 	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 a9af945..b5427a3 100644
--- a/src/cmd/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -221,7 +221,7 @@
 	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 @@
 
 	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 @@
 			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 @@
 	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 @@
 	// 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 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 @@
 			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 @@
 			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 @@
 		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 bb4d278..7f78fce 100644
--- a/src/cmd/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -7,9 +7,9 @@
 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 @@
 	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 96%
rename from src/cmd/internal/gc/subr.go
rename to src/cmd/compile/internal/gc/subr.go
index 06ceff5..ed5001a 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -125,13 +125,6 @@
 	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 @@
 		}
 		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 @@
 	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 @@
 	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 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 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 @@
 	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 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 @@
 			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 @@
 	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 @@
 		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 @@
 
 			*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 @@
 	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 @@
 	lineno = lexlineno
 	if genwrapper_linehistdone == 0 {
 		// All the wrappers can share the same linehist entry.
-		linehist("<autogenerated>", 0, 0)
+		linehistpush("<autogenerated>")
 
 		genwrapper_linehistdone = 1
 	}
@@ -2368,7 +2375,7 @@
 	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 @@
 	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 @@
 
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 7cb632c..221b1f4 100644
--- a/src/cmd/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -169,10 +169,10 @@
 			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 @@
 	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 @@
 	// 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 7c9fb8d..be43076 100644
--- a/src/cmd/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -23,14 +23,67 @@
 	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 @@
 	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 6f7830d..cf1589e 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 6daf842..2900da8 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -311,8 +311,8 @@
 		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 @@
 				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 @@
 		}
 
 		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 @@
 		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 @@
 			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 @@
 			}
 
 			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 @@
 		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 @@
 			}
 
 			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 @@
 		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 @@
 			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 @@
 		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 @@
 		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 @@
 		}
 
 		// 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 @@
 			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)
+				}
 			}
-			args.N = assignconv(args.N, t.Type, "append")
+		} else {
+			for args = args.Next; args != nil; args = args.Next {
+				if args.N.Type == nil {
+					continue
+				}
+				args.N = assignconv(args.N, t.Type, "append")
+			}
 		}
 
 		break OpSwitch
@@ -1852,7 +1862,7 @@
 				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 @@
 	}
 
 	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 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 @@
 		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 @@
 
 	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 @@
 			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 @@
 		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 @@
 		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 @@
 	// 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 @@
 		}
 	}
 
-	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 @@
 	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 @@
 		// 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 @@
 			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 @@
 				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 @@
 			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 @@
 
 	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 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 @@
 	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 @@
 		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 @@
 		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 @@
 		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 97%
rename from src/cmd/internal/gc/unsafe.go
rename to src/cmd/compile/internal/gc/unsafe.go
index aa90a19..824ecd0 100644
--- a/src/cmd/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -140,8 +140,8 @@
 	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 5dc6561..c59af06 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 @@
 )
 
 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 88%
rename from src/cmd/internal/gc/walk.go
rename to src/cmd/compile/internal/gc/walk.go
index c32a813..d5eb44c 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -352,6 +352,20 @@
 	*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 @@
 			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 @@
 			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 @@
 				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 @@
 					// 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 @@
 	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 @@
 		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 @@
 	// 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 @@
 		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 @@
 			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 @@
 	*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 @@
 	}
 
 	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 @@
 		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 @@
 
 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 Debug_wb > 1 {
+			Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
 		}
-		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)
-		}
+		n.Op = OASWB
+		return n
 	}
 	return n
 }
@@ -2728,10 +2685,10 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 //     ...
 //   }
 //   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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 @@
 				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 @@
 	// 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 @@
 		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 @@
 			// 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 @@
 	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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 
 		// 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 @@
 	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 91%
rename from src/cmd/internal/gc/y.go
rename to src/cmd/compile/internal/gc/y.go
index f2c8b96..56b9d04 100644
--- a/src/cmd/internal/gc/y.go
+++ b/src/cmd/compile/internal/gc/y.go
@@ -5,10 +5,11 @@
 
 //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 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 @@
 	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 yyParserImpl struct {
 	lookahead func() int
-	state     func() int
 }
 
 func (p *yyParserImpl) Lookahead() int {
@@ -887,7 +915,6 @@
 func yyNewParser() yyParser {
 	p := &yyParserImpl{
 		lookahead: func() int { return -1 },
-		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -918,6 +945,13 @@
 	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 @@
 	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 @@
 
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	case 55:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:475
+		//line go.y:537
 		{
 			var n, nn *Node
 
@@ -1594,7 +1627,7 @@
 		}
 	case 56:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:498
+		//line go.y:560
 		{
 			var n *Node
 
@@ -1614,7 +1647,7 @@
 		}
 	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 @@
 		}
 	case 58:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line go.y:525
+		//line go.y:587
 		{
 			var n, nn *Node
 
@@ -1646,13 +1679,13 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	case 205:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line go.y:1338
+		//line go.y:1400
 		{
 			var t *Node
 
@@ -2527,14 +2560,14 @@
 			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 @@
 			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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	case 236:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line go.y:1623
+		//line go.y:1685
 		{
 			var n *Node
 
@@ -2819,7 +2852,7 @@
 		}
 	case 237:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line go.y:1633
+		//line go.y:1695
 		{
 			var pkg *Pkg
 
@@ -2834,33 +2867,33 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 			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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	case 331:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line go.y:2095
+		//line go.y:2157
 		{
 			var t *Type
 
@@ -3338,7 +3371,7 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 @@
 		}
 	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 e4a5e5c..2821702 100644
--- a/src/cmd/internal/gc/y.output
+++ b/src/cmd/compile/internal/gc/y.output
@@ -3,7 +3,7 @@
 	$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 @@
 	package: .    (2)
 
 	LPACKAGE  shift 5
-	.  reduce 2 (src line 131)
+	.  reduce 2 (src line 193)
 
 	package  goto 4
 
@@ -37,7 +37,7 @@
 	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 @@
 	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 @@
 	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 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 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 @@
 	import_safety: .    (19)
 
 	LNAME  shift 24
-	.  reduce 19 (src line 264)
+	.  reduce 19 (src line 326)
 
 	import_safety  goto 23
 
@@ -140,7 +140,7 @@
 	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 @@
 	'*'  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 20
 	package:  LPACKAGE sym ';'.    (3)
 
-	.  reduce 3 (src line 138)
+	.  reduce 3 (src line 200)
 
 
 state 21
@@ -271,7 +271,7 @@
 state 24
 	import_safety:  LNAME.    (20)
 
-	.  reduce 20 (src line 265)
+	.  reduce 20 (src line 327)
 
 
 state 25
@@ -284,25 +284,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 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 40
 	non_dcl_stmt:  LFALL.    (263)
 
-	.  reduce 263 (src line 1756)
+	.  reduce 263 (src line 1818)
 
 
 state 41
@@ -420,7 +420,7 @@
 	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 @@
 	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 @@
 	'['  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 47
 	lconst:  LCONST.    (38)
 
-	.  reduce 38 (src line 354)
+	.  reduce 38 (src line 416)
 
 
 state 48
@@ -593,7 +593,7 @@
 	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 @@
 	'/'  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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	'('  shift 160
 	'.'  shift 161
 	'['  shift 162
-	.  reduce 114 (src line 877)
+	.  reduce 114 (src line 939)
 
 
 state 58
@@ -1027,7 +1027,7 @@
 	pexpr:  pexpr_no_paren.    (146)
 
 	'{'  shift 171
-	.  reduce 146 (src line 1054)
+	.  reduce 146 (src line 1116)
 
 
 state 67
@@ -1078,19 +1078,19 @@
 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 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 @@
 	'['  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 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 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 @@
 	$$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 88
 	import_here:  LLITERAL.    (15)
 
-	.  reduce 15 (src line 224)
+	.  reduce 15 (src line 286)
 
 
 state 89
@@ -1336,7 +1336,7 @@
 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 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 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 109
 	common_dcl:  LTYPE typedcl.    (35)
 
-	.  reduce 35 (src line 341)
+	.  reduce 35 (src line 403)
 
 
 state 110
@@ -1577,7 +1577,7 @@
 state 112
 	typedclname:  sym.    (47)
 
-	.  reduce 47 (src line 395)
+	.  reduce 47 (src line 457)
 
 
 state 113
@@ -1585,7 +1585,7 @@
 	fnbody: .    (210)
 
 	'{'  shift 242
-	.  reduce 210 (src line 1457)
+	.  reduce 210 (src line 1519)
 
 	fnbody  goto 241
 
@@ -1607,7 +1607,7 @@
 	'['  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 @@
 	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 123
 	name:  sym.    (162)
 
-	.  reduce 162 (src line 1158)
+	.  reduce 162 (src line 1220)
 
 
 state 124
@@ -1710,23 +1710,23 @@
 	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 @@
 	oexpr_list:  expr_list.    (293)
 
 	','  shift 155
-	.  reduce 293 (src line 1909)
+	.  reduce 293 (src line 1971)
 
 
 state 129
@@ -1780,7 +1780,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 276 (src line 1840)
+	.  reduce 276 (src line 1902)
 
 
 state 130
@@ -1827,13 +1827,13 @@
 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 @@
 	'['  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 @@
 	'['  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 @@
 	'['  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 @@
 	'['  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 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 @@
 	'/'  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 @@
 	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 @@
 	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 @@
 	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 @@
 	'*'  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 185
 	fnliteral:  fnlitdcl error.    (217)
 
-	.  reduce 217 (src line 1496)
+	.  reduce 217 (src line 1558)
 
 
 state 186
@@ -3463,13 +3463,13 @@
 	'/'  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 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 @@
 	dotname:  name.'.' sym 
 
 	'.'  shift 314
-	.  reduce 189 (src line 1234)
+	.  reduce 189 (src line 1296)
 
 
 state 198
@@ -3665,27 +3665,27 @@
 	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 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 213
 	hidden_pkg_importsym:  hidden_importsym.    (310)
 
-	.  reduce 310 (src line 1985)
+	.  reduce 310 (src line 2047)
 
 
 state 214
@@ -3807,7 +3807,7 @@
 state 216
 	hidden_pkgtype:  hidden_pkg_importsym.    (311)
 
-	.  reduce 311 (src line 1992)
+	.  reduce 311 (src line 2054)
 
 
 state 217
@@ -3815,7 +3815,7 @@
 	fnbody: .    (210)
 
 	'{'  shift 242
-	.  reduce 210 (src line 1457)
+	.  reduce 210 (src line 1519)
 
 	fnbody  goto 353
 
@@ -3845,20 +3845,20 @@
 	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 @@
 	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 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 @@
 	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 @@
 	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 @@
 	'*'  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 @@
 	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 @@
 	'['  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 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 @@
 	'['  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 @@
 	'['  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 @@
 	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 @@
 	'*'  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 @@
 	'['  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 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 50 (src line 425)
+	.  reduce 50 (src line 487)
 
 
 state 255
@@ -4502,7 +4502,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 94 (src line 795)
+	.  reduce 94 (src line 857)
 
 
 state 256
@@ -4545,7 +4545,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 95 (src line 799)
+	.  reduce 95 (src line 861)
 
 
 state 257
@@ -4582,7 +4582,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 96 (src line 803)
+	.  reduce 96 (src line 865)
 
 
 state 258
@@ -4619,7 +4619,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 97 (src line 807)
+	.  reduce 97 (src line 869)
 
 
 state 259
@@ -4656,7 +4656,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 98 (src line 811)
+	.  reduce 98 (src line 873)
 
 
 state 260
@@ -4693,7 +4693,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 99 (src line 815)
+	.  reduce 99 (src line 877)
 
 
 state 261
@@ -4730,7 +4730,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 100 (src line 819)
+	.  reduce 100 (src line 881)
 
 
 state 262
@@ -4767,7 +4767,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 101 (src line 823)
+	.  reduce 101 (src line 885)
 
 
 state 263
@@ -4800,7 +4800,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 102 (src line 827)
+	.  reduce 102 (src line 889)
 
 
 state 264
@@ -4833,7 +4833,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 103 (src line 831)
+	.  reduce 103 (src line 893)
 
 
 state 265
@@ -4866,7 +4866,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 104 (src line 835)
+	.  reduce 104 (src line 897)
 
 
 state 266
@@ -4899,7 +4899,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 105 (src line 839)
+	.  reduce 105 (src line 901)
 
 
 state 267
@@ -4925,7 +4925,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 106 (src line 843)
+	.  reduce 106 (src line 905)
 
 
 state 268
@@ -4951,7 +4951,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 107 (src line 847)
+	.  reduce 107 (src line 909)
 
 
 state 269
@@ -4977,7 +4977,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 108 (src line 851)
+	.  reduce 108 (src line 913)
 
 
 state 270
@@ -5003,7 +5003,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 109 (src line 855)
+	.  reduce 109 (src line 917)
 
 
 state 271
@@ -5029,7 +5029,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 110 (src line 859)
+	.  reduce 110 (src line 921)
 
 
 state 272
@@ -5055,7 +5055,7 @@
 	expr:  expr.LRSH expr 
 	expr:  expr.LCOMM expr 
 
-	.  reduce 111 (src line 863)
+	.  reduce 111 (src line 925)
 
 
 state 273
@@ -5081,7 +5081,7 @@
 	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 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 113 (src line 872)
+	.  reduce 113 (src line 934)
 
 
 state 275
@@ -5134,7 +5134,7 @@
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 51 (src line 430)
+	.  reduce 51 (src line 492)
 
 
 state 276
@@ -5142,7 +5142,7 @@
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 52 (src line 442)
+	.  reduce 52 (src line 504)
 
 
 state 277
@@ -5188,13 +5188,13 @@
 	'/'  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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 @@
 	'%'  shift 147
 	'&'  shift 148
 	']'  shift 396
-	.  reduce 291 (src line 1903)
+	.  reduce 291 (src line 1965)
 
 
 state 295
@@ -5467,7 +5467,7 @@
 	'['  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 @@
 	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 @@
 	'%'  shift 147
 	'&'  shift 148
 	','  shift 413
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 412
 
@@ -5609,7 +5609,7 @@
 	'['  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 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 311
 	othertype:  LCHAN LCOMM ntype.    (194)
 
-	.  reduce 194 (src line 1263)
+	.  reduce 194 (src line 1325)
 
 
 state 312
@@ -5753,7 +5753,7 @@
 state 313
 	ptrtype:  '*' ntype.    (198)
 
-	.  reduce 198 (src line 1275)
+	.  reduce 198 (src line 1337)
 
 
 state 314
@@ -5780,20 +5780,20 @@
 	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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 427
 
@@ -5861,13 +5861,13 @@
 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 @@
 	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 @@
 	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 330
 	interfacedcl:  packname.    (240)
 
-	.  reduce 240 (src line 1658)
+	.  reduce 240 (src line 1720)
 
 
 state 331
@@ -5942,7 +5942,7 @@
 	'.'  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 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 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 @@
 	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 356
 	hidden_funarg_list:  hidden_funarg.    (346)
 
-	.  reduce 346 (src line 2212)
+	.  reduce 346 (src line 2274)
 
 
 state 357
@@ -6191,7 +6191,7 @@
 	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 @@
 	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 @@
 	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 @@
 	expr_list:  expr_list.',' expr 
 
 	','  shift 155
-	.  reduce 43 (src line 379)
+	.  reduce 43 (src line 441)
 
 
 state 369
@@ -6379,7 +6379,7 @@
 	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 @@
 	'['  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 @@
 	'['  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 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 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 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 @@
 	'['  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 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 69 (src line 624)
+	.  reduce 69 (src line 686)
 
 
 state 387
@@ -6728,7 +6728,7 @@
 	'['  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 @@
 	ocomma: .    (288)
 
 	','  shift 413
-	.  reduce 288 (src line 1896)
+	.  reduce 288 (src line 1958)
 
 	ocomma  goto 510
 
@@ -6809,7 +6809,7 @@
 	'['  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 396
 	pexpr_no_paren:  pexpr '[' expr ']'.    (131)
 
-	.  reduce 131 (src line 966)
+	.  reduce 131 (src line 1028)
 
 
 state 397
@@ -6875,7 +6875,7 @@
 	'['  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 @@
 	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 @@
 	'%'  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 @@
 	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 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 413
 	ocomma:  ','.    (289)
 
-	.  reduce 289 (src line 1897)
+	.  reduce 289 (src line 1959)
 
 
 state 414
@@ -7118,7 +7118,7 @@
 state 415
 	fnliteral:  fnlitdcl lbrace stmt_list '}'.    (216)
 
-	.  reduce 216 (src line 1490)
+	.  reduce 216 (src line 1552)
 
 
 state 416
@@ -7128,11 +7128,11 @@
 	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 @@
 	'*'  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 @@
 	'*'  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 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 @@
 	'('  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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 529
 
@@ -7373,13 +7373,13 @@
 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 @@
 	packname:  LNAME.'.' sym 
 
 	'.'  shift 434
-	.  reduce 236 (src line 1621)
+	.  reduce 236 (src line 1683)
 
 
 state 432
@@ -7411,7 +7411,7 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 533
 
@@ -7450,7 +7450,7 @@
 	'('  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 437
 	interfacedcl:  new_name indcl.    (239)
 
-	.  reduce 239 (src line 1652)
+	.  reduce 239 (src line 1714)
 
 
 state 438
@@ -7481,7 +7481,7 @@
 	'['  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 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 @@
 	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 @@
 	'['  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 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 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 @@
 	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 458
 	hidden_constant:  hidden_literal.    (342)
 
-	.  reduce 342 (src line 2195)
+	.  reduce 342 (src line 2257)
 
 
 state 459
@@ -7741,7 +7741,7 @@
 state 460
 	hidden_literal:  LLITERAL.    (339)
 
-	.  reduce 339 (src line 2164)
+	.  reduce 339 (src line 2226)
 
 
 state 461
@@ -7754,7 +7754,7 @@
 state 462
 	hidden_literal:  sym.    (341)
 
-	.  reduce 341 (src line 2187)
+	.  reduce 341 (src line 2249)
 
 
 state 463
@@ -7776,13 +7776,13 @@
 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 @@
 	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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 565
 
@@ -7856,13 +7856,13 @@
 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 @@
 	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 @@
 	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 @@
 	'?'  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 @@
 	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 @@
 	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 @@
 	'['  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 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 @@
 	'['  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 @@
 	'['  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 @@
 	'*'  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 @@
 	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 @@
 	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 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 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 @@
 	'['  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 517
 	braced_keyval_list:  keyval_list ocomma.    (285)
 
-	.  reduce 285 (src line 1885)
+	.  reduce 285 (src line 1947)
 
 
 state 518
@@ -8546,7 +8546,7 @@
 	'['  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 @@
 	'['  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 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 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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 594
 
@@ -8700,7 +8700,7 @@
 state 533
 	structdcl:  '*' embed oliteral.    (233)
 
-	.  reduce 233 (src line 1600)
+	.  reduce 233 (src line 1662)
 
 
 state 534
@@ -8713,19 +8713,19 @@
 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 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 @@
 	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 @@
 	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 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 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 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 560
 	hidden_literal:  '-' LLITERAL.    (340)
 
-	.  reduce 340 (src line 2169)
+	.  reduce 340 (src line 2231)
 
 
 state 561
@@ -8934,7 +8934,7 @@
 	'('  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 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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 615
 
@@ -8986,7 +8986,7 @@
 	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 @@
 	constdcl1:  dcl_name_list ntype.    (45)
 
 	'='  shift 367
-	.  reduce 45 (src line 386)
+	.  reduce 45 (src line 448)
 
 
 state 570
@@ -9020,7 +9020,7 @@
 	'['  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 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 @@
 	'['  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 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 67 (src line 610)
+	.  reduce 67 (src line 672)
 
 
 state 576
@@ -9195,7 +9195,7 @@
 	'/'  shift 146
 	'%'  shift 147
 	'&'  shift 148
-	.  reduce 68 (src line 617)
+	.  reduce 68 (src line 679)
 
 
 state 577
@@ -9217,11 +9217,11 @@
 	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 @@
 	'*'  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 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 @@
 	'['  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 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 @@
 	'/'  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 @@
 	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 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 633
 
@@ -9490,7 +9490,7 @@
 	oliteral: .    (302)
 
 	LLITERAL  shift 428
-	.  reduce 302 (src line 1935)
+	.  reduce 302 (src line 1997)
 
 	oliteral  goto 634
 
@@ -9510,7 +9510,7 @@
 	'['  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 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 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 @@
 	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 @@
 	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 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 @@
 	'('  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 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 @@
 	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 613
 	hidden_funres:  hidden_type.    (338)
 
-	.  reduce 338 (src line 2155)
+	.  reduce 338 (src line 2217)
 
 
 state 614
@@ -9715,7 +9715,7 @@
 	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 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 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 @@
 	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 @@
 	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 @@
 	'['  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 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 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 @@
 	'['  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 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 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 @@
 	'('  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 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 @@
 	'('  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 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 @@
 	'['  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 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 5d24a6f..37dd6ce 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 a2f4a0e..73aef6f 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 @@
 	gc.Widthreg = 8
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -72,6 +72,7 @@
 	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 28ebd9c..1b936b8 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 @@
 	// 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 @@
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
 			check = 0
-		} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
 			check = 0
 		}
 	}
@@ -308,7 +308,7 @@
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gc.Cgen(nl, &n1)
-		sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
+		sc := uint64(nr.Int())
 		if sc >= 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 8223fe7..2501972 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 @@
 	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 @@
 		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 @@
 			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 @@
 }
 
 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 4a134f1..1704f63 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 94c9b15..16eeb39 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 e28e389..c7e1827 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 fb0c2e3..fa1cb71 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 dfbdafe..1768674 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 @@
  */
 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 a682e2f..0b061ff 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 @@
 	//	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 @@
 
 	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 @@
 
 	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 @@
 
 		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 e96b628..2b602e1 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 @@
 	gc.Widthreg = 4
 }
 
-func main() {
+func Main() {
 	gc.Thearch.Thechar = thechar
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
@@ -81,6 +81,7 @@
 	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 5902552..dabc139 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 @@
 	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 @@
 	check := 0
 	if gc.Issigned[t.Etype] {
 		check = 1
-		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1<<uint64(t.Width*8-1) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -1<<uint64(t.Width*8-1) {
 			check = 0
-		} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
 			check = 0
 		}
 	}
@@ -391,7 +391,7 @@
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gmove(&n2, &n1)
-		sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
+		sc := uint64(nr.Int())
 		if sc >= 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 94%
rename from src/cmd/8g/gsubr.go
rename to src/cmd/compile/internal/x86/gsubr.go
index 34ddfe0..baf2517 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 @@
 	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 @@
 	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 @@
 		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 @@
 
 	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 @@
 	}
 }
 
-/*
- * 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 @@
 	// 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 @@
 	// 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 e309aea7..8b50eab 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 1346c20..f96a1aa 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 50b5b97..8c97171 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 0000000..7b69c34
--- /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 64b2399..0cdb7d6 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -20,7 +20,6 @@
 	goarch           string
 	gobin            string
 	gohostarch       string
-	gohostchar       string
 	gohostos         string
 	goos             string
 	goarm            string
@@ -30,10 +29,8 @@
 	goextlinkenabled string
 	workdir          string
 	tooldir          string
-	gochar           string
 	oldgoos          string
 	oldgoarch        string
-	oldgochar        string
 	slash            string
 	exe              string
 	defaultcc        string
@@ -48,17 +45,13 @@
 	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 @@
 		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 @@
 // 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 @@
 	}
 
 	// 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 @@
 		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 @@
 	} 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 @@
 		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 @@
 // 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 @@
 	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 @@
 	// 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 @@
 	// 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 f5037fa..7988129 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -23,31 +23,34 @@
 // 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 1ed0995..f5a0dc5 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -14,6 +14,7 @@
 	"os/exec"
 	"path/filepath"
 	"regexp"
+	"runtime"
 	"strconv"
 	"strings"
 	"time"
@@ -23,8 +24,11 @@
 	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 @@
 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 @@
 	}
 
 	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 @@
 	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 @@
 			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 @@
 	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 @@
 		},
 	})
 
-	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 @@
 			},
 		})
 	}
-	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 @@
 				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 @@
 			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 @@
 			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 @@
 		})
 	}
 
+	// 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 b3be2a9..18dafc2 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -132,11 +132,12 @@
 	// 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 3a0aa7f..5c8976b 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -115,7 +115,7 @@
 			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 @@
 	pkg.valueSummary(pkg.doc.Vars)
 	pkg.funcSummary(pkg.doc.Funcs)
 	pkg.typeSummary()
+	pkg.bugs()
 }
 
 // packageClause prints the package clause.
@@ -253,6 +254,18 @@
 	}
 }
 
+// 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 @@
 		}
 		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 @@
 	}
 }
 
-// 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 @@
 			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 e0d4a6c..2b1cbf9 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -503,6 +503,7 @@
         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 @@
 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 fda126b..17ff7e0 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -547,9 +547,6 @@
 	goarch    string
 	goos      string
 	exeSuffix string
-
-	archCharVal string
-	archCharErr error
 )
 
 func init() {
@@ -558,16 +555,6 @@
 	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 @@
 			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 @@
 		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 @@
 		}
 	}
 
-	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 @@
 
 	// 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 @@
 		}
 		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 @@
 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 @@
 		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 @@
 	}
 	// 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 @@
 	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 @@
 	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 @@
 	// 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 863eb4d..8d427b3 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -49,10 +49,6 @@
 		{"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 65dc3ca..1722b9d 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 @@
 }
 
 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 56e8493..2062f0c 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -47,7 +47,7 @@
 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 9466aad..601c303 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -394,25 +394,17 @@
 
 // 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 @@
 			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 @@
 	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 408104d..2179000 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -115,8 +115,12 @@
 	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 b5e5d1e..a1519c8 100644
--- a/src/cmd/internal/asm/lexbody.go
+++ b/src/cmd/internal/asm/lexbody.go
@@ -149,7 +149,7 @@
 	}
 
 	fi.P = nil
-	obj.Linklinehist(Ctxt, int(Lineno), s, 0)
+	Ctxt.LineHist.Push(int(Lineno), s)
 }
 
 var thetext *obj.LSym
@@ -630,7 +630,7 @@
 	n, _ = i.F.Read(i.B[:])
 	if n == 0 {
 		i.F.Close()
-		obj.Linklinehist(Ctxt, int(Lineno), "<pop>", 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 c488ea1..4565d3a 100644
--- a/src/cmd/internal/asm/macbody.go
+++ b/src/cmd/internal/asm/macbody.go
@@ -32,7 +32,6 @@
 
 import (
 	"bytes"
-	"cmd/internal/obj"
 	"fmt"
 	"os"
 	"strings"
@@ -683,7 +682,7 @@
 	}
 
 nn:
-	obj.Linklinehist(Ctxt, int(Lineno), symb, int(n))
+	Ctxt.LineHist.Update(int(Lineno), symb, int(n))
 	return
 
 bad:
@@ -796,7 +795,7 @@
 		/*
 		 * 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 8370a20..0000000
--- 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 9dc54d9..0000000
--- 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 cb45cb8..0000000
--- 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 0000000..5845f7d
--- /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 6e00cb5..9e64393 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -2677,8 +2677,8 @@
 	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 dde5d64..5486f0d 100644
--- a/src/cmd/internal/obj/line_test.go
+++ b/src/cmd/internal/obj/line_test.go
@@ -13,13 +13,13 @@
 	ctxt := new(Link)
 	ctxt.Hash = make(map[SymVer]*LSym)
 
-	Linklinehist(ctxt, 1, "a.c", 0)
-	Linklinehist(ctxt, 3, "a.h", 0)
-	Linklinehist(ctxt, 5, "<pop>", 0)
-	Linklinehist(ctxt, 7, "linedir", 2)
-	Linklinehist(ctxt, 9, "<pop>", 0)
-	Linklinehist(ctxt, 11, "b.c", 0)
-	Linklinehist(ctxt, 13, "<pop>", 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 9f5e87b..2fc12c1 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -206,7 +206,6 @@
 	From     Addr
 	From3    Addr
 	To       Addr
-	To2      Addr
 	Opt      interface{}
 	Forwd    *Prog
 	Pcond    *Prog
@@ -217,12 +216,12 @@
 	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 2407dea..a385d60 100644
--- a/src/cmd/internal/obj/mgc0.go
+++ b/src/cmd/internal/obj/mgc0.go
@@ -22,16 +22,6 @@
 // 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
 	InsArrayEnd
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index 39db239..af3290d 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -241,12 +241,6 @@
 	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 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 != "<pop>" and n == 0, the call pushes the start of a new file named f at lineno.
-// If f != "<pop>" and n > 0, the call amends the top of the stack to record that lineno
-// now corresponds to f at line n.
-// If f == "<pop>", 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 == "<pop>":
-		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 b0b2091..efecae6 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -213,10 +213,17 @@
 }
 
 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 (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 @@
 	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) 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 0c0cc04..2b9c267 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2974,15 +2974,12 @@
 	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 7a4fc12..4798c8f 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -350,9 +350,6 @@
 		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 a6cd02b..7371c0d 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -13,6 +13,8 @@
 	"sort"
 )
 
+const stabTypeMask = 0xe0
+
 type machoFile struct {
 	macho *macho.File
 }
@@ -34,12 +36,19 @@
 	// 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 a025ce6..74ec9dd3 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 @@
 
 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 @@
 			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 @@
 			// 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 @@
 		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 @@
 		return
 	}
 
-	adddynsym(ld.Ctxt, s)
+	ld.Adddynsym(ld.Ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
@@ -612,7 +594,7 @@
 		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 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 @@
 			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 95%
rename from src/cmd/6l/l.go
rename to src/cmd/link/internal/amd64/l.go
index 6b42088..2537419 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 @@
 	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 9e6dc60..1aa4422 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 @@
 	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 @@
 		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 @@
 		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 0000000..f70035b
--- /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 86%
rename from src/cmd/5l/asm.go
rename to src/cmd/link/internal/arm/asm.go
index 85ea684..39d4550 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 @@
 			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 @@
 		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 @@
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -495,7 +477,7 @@
 		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 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 @@
 			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 @@
 			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 97%
rename from src/cmd/5l/l.go
rename to src/cmd/link/internal/arm/l.go
index a521545..49737721 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 @@
 	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 fa74908..14fe7a6 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 @@
 	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 a17899d..3aebd8a 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 @@
 
 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 @@
 		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 @@
 	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 @@
 			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 @@
 			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 97%
rename from src/cmd/7l/l.go
rename to src/cmd/link/internal/arm64/l.go
index 6f90acb..8d0d57e 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 @@
 	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 f8ac7d3..56f5815 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 @@
 	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 3194bd5..fd1cdd6 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 @@
 				} 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 @@
 					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 @@
 	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 @@
 	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 @@
 
 	/* 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 @@
 		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 @@
 	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 754c89f..c1cf4d7 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 @@
 // 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 @@
 	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_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 6d90404..b8fb2e6b 100644
--- a/src/cmd/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -17,6 +17,7 @@
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"os"
 	"strings"
 )
 
@@ -240,6 +241,7 @@
 			{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 @@
 	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 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 @@
 	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 @@
 			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 @@
 const (
 	CIERESERVE          = 16
 	DATAALIGNMENTFACTOR = -4
-	FAKERETURNCOLUMN    = 16 // TODO gdb6 doesn't like > 15?
 )
 
 func putpccfadelta(deltapc int64, cfa int64) {
@@ -1778,21 +1798,30 @@
 	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 @@
 				}
 			}
 
-			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 @@
 	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 @@
 		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 @@
 	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 @@
 /*
  * 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 @@
 		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 @@
 		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 5c17b2d..68d21f4 100644
--- a/src/cmd/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -6,8 +6,12 @@
 
 import (
 	"cmd/internal/obj"
+	"crypto/sha1"
 	"encoding/binary"
 	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
 )
 
 /*
@@ -1199,32 +1203,15 @@
 	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 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 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 @@
 		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 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 @@
 	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 @@
 
 		// 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 @@
 		// 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 @@
 		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 @@
 			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 0223bfa..80a6c6e 100644
--- a/src/cmd/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -416,7 +416,11 @@
 				// 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 @@
 	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 @@
 	}
 
 	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 @@
 		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 7242301..1068bdd 100644
--- a/src/cmd/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -109,8 +109,8 @@
 		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 184175e..d87f180 100644
--- a/src/cmd/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -34,7 +34,9 @@
 	"bufio"
 	"bytes"
 	"cmd/internal/obj"
+	"crypto/sha1"
 	"debug/elf"
+	"encoding/binary"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -86,15 +88,14 @@
 	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 @@
 	Length  uint64
 	Next    *Section
 	Seg     *Segment
-	Elfsect interface{}
+	Elfsect *ElfShdr
 	Reloff  uint64
 	Rellen  uint64
 }
@@ -178,6 +179,7 @@
 	Thelinkarch        *LinkArch
 	outfile            string
 	dynexp             []*LSym
+	dynlib             []string
 	ldflag             []string
 	havedynamic        int
 	Funcalign          int
@@ -473,7 +475,7 @@
 		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 @@
 				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 @@
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 			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 @@
 	}
 
 	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 @@
 	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 @@
 
 	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 @@
 	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, &noteType)
+			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 @@
 		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 @@
 		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 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 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 03da52a..33b17c5 100644
--- a/src/cmd/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -34,6 +34,7 @@
 	"cmd/internal/obj"
 	"debug/elf"
 	"encoding/binary"
+	"fmt"
 )
 
 type LSym struct {
@@ -77,13 +78,19 @@
 	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 @@
 	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 @@
 	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 @@
 	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 ceeb7b0..3a8a881 100644
--- a/src/cmd/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -443,7 +443,8 @@
 		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 @@
 	}
 
 	// 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 @@
 				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 @@
 	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 0000000..9134373
--- /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 98%
rename from src/cmd/internal/ld/objfile.go
rename to src/cmd/link/internal/ld/objfile.go
index 3d59323..613fcb2 100644
--- a/src/cmd/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -347,7 +347,7 @@
 			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 8568744..5b2442805 100644
--- a/src/cmd/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -160,10 +160,9 @@
 	}
 
 	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 d6e79dc..7ceb64f 100644
--- a/src/cmd/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -32,6 +32,8 @@
 
 import (
 	"cmd/internal/obj"
+	"fmt"
+	"path/filepath"
 	"strings"
 )
 
@@ -128,12 +130,12 @@
 			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 @@
 
 	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 @@
 	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 @@
 		}
 	}
 
+	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 @@
 	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 257f23e..f070921 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 @@
 		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 @@
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -622,70 +604,6 @@
 	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 97%
rename from src/cmd/9l/l.go
rename to src/cmd/link/internal/ppc64/l.go
index e7dc102..1275a34 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 @@
 	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 46a9239..d663b6e 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 @@
 	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 7231379..d30bd48 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 @@
 			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 @@
 			// 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 @@
 		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 @@
 		return
 	}
 
-	adddynsym(ctxt, s)
+	ld.Adddynsym(ctxt, s)
 
 	if ld.Iself {
 		plt := ld.Linklookup(ctxt, ".plt", 0)
@@ -480,7 +462,7 @@
 		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 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 @@
 			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 6005085..8a811ff 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 @@
 	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 7b490ae..ee408f7 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 @@
 	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 b23f3f8..0e6c34e 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 0000000..b23f3f8
--- /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
Binary files differ
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
Binary files differ
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
Binary files differ
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
Binary files differ
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
Binary files differ
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
Binary files differ
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 9c33f4f..cd32020 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -13,7 +13,6 @@
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"testing"
 	"time"
@@ -223,16 +222,14 @@
 		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 @@
 		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 @@
 	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 bfc8110..e4c92cd 100644
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ b/src/cmd/pprof/internal/profile/legacy_profile.go
@@ -554,9 +554,10 @@
 			}
 		}
 
-		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 5c7b0b7..53c0fab 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -128,6 +128,7 @@
 	TYPEDEF
 	TYPENAME
 	UNION
+	ERROR
 )
 
 const ENDFILE = 0
@@ -325,8 +326,24 @@
 	{"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 @@
 			}
 			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 @@
 	}
 	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 @@
 	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 @@
 	}
 	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 @@
 	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 $$ParserImpl struct {
 	lookahead func() int
-	state     func() int
 }
 
 func (p *$$ParserImpl) Lookahead() int {
@@ -3222,7 +3339,6 @@
 func $$NewParser() $$Parser {
 	p := &$$ParserImpl{
 		lookahead: func() int { return -1 },
-		state:     func() int { return -1 },
 	}
 	return p
 }
@@ -3253,6 +3369,13 @@
 	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 @@
 	$$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 6855a65..c6943a6 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -49,7 +49,7 @@
 	// 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 d0acaba..31223b6 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 @@
 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 @@
 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 @@
 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 @@
 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 a340e47..62d0f42 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 @@
 	// 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 c0bd379..8a72a31 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -976,3 +976,21 @@
 		}
 	}
 }
+
+// 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 f26a7d4..613641a 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -739,7 +739,7 @@
 		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 7ecc8f4..f208ee8 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -1207,7 +1207,28 @@
 	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 4db9f35..7789bb5 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -275,8 +275,6 @@
 	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 7880342..66383ef 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -209,6 +209,7 @@
 
 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 4e42790..0606602 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 ba99cb0..93121bb 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -557,10 +557,13 @@
 	{"%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 _ 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 099f8a5..ba984cf 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -163,7 +163,7 @@
 	}
 
 	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 @@
 				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 0000000..1267cc3
--- /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 0000000..ae3147a
--- /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 124da40..db6bdcf 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -296,11 +296,7 @@
 	// 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 @@
 	// 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 @@
 		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 84c1e2a..8e985aa 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -184,42 +184,43 @@
 	},
 
 	// 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 @@
 	// 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 @@
 
 	// 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 @@
 	// 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 78e17b2..233f8b9 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 f445b82..a4a838a 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 c698fa6..2ab6da0 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 ad4533c..79a80af 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 6a74e2d..08cdd5e 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 ee83a72..7278c0c 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -18,14 +18,14 @@
 	"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 5d4de39..fe4a758 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -50,9 +50,8 @@
 		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 4910305..f3bc4b9 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -91,7 +91,10 @@
 	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 0095d7f..18278ba 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -412,14 +412,17 @@
 	}
 }
 
-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 @@
 		// 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 @@
 			// 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 @@
 			ellipsis = p.pos
 			p.next()
 		}
-		if !p.atComma("argument list") {
+		if !p.atComma("argument list", token.RPAREN) {
 			break
 		}
 		p.next()
@@ -1323,7 +1326,7 @@
 
 	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 @@
 				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 4b960d9..c7bb36d 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -492,3 +492,42 @@
 		})
 	}
 }
+
+// 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 970ef2d..ef2ffad 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -99,8 +99,9 @@
 	`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 cec82ea..e9476c4 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -706,13 +706,14 @@
 					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 fc450d8..0d21905 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -734,6 +734,41 @@
 	}
 }
 
+// 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 1a384d4..0000000
--- 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 a2a55e3..ad9baa9 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -28,7 +28,7 @@
 	"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 203a9c1..c224699 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -8,7 +8,7 @@
 
 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 b4c356a..7ae81eb 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -8,7 +8,7 @@
 
 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 0cf9953..da65f42 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 c2c18ec..4af5b57 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -6,7 +6,7 @@
 
 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 bc27a8b..36e1cb9 100644
--- a/src/go/types/eval_test.go
+++ b/src/go/types/eval_test.go
@@ -14,7 +14,6 @@
 	"strings"
 	"testing"
 
-	_ "go/internal/gcimporter"
 	. "go/types"
 )
 
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index f91d89e..425ae91 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -9,7 +9,7 @@
 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 2404753..829e7a9 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -8,7 +8,7 @@
 	"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 88c3870..8d16706 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -9,7 +9,7 @@
 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 be46b59..64dcebe 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -7,7 +7,7 @@
 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 85dc6ae..4ff4e4d 100644
--- a/src/go/types/self_test.go
+++ b/src/go/types/self_test.go
@@ -15,7 +15,6 @@
 	"testing"
 	"time"
 
-	_ "go/internal/gcimporter"
 	. "go/types"
 )
 
@@ -31,7 +30,7 @@
 	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 d04dd71..28a66ce 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -146,6 +146,7 @@
 		"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 8b59df3..586f6cc 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -9,7 +9,7 @@
 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 d08e0fd..595a634 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -71,3 +71,27 @@
 	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 afd1dab..3fc1574 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -8,7 +8,7 @@
 
 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 @@
 	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 c02543e..5e445e2 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 dd5dfa7..f50a4b9 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 @@
 	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 = "&amp;"
-		case '\'':
-			// "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
-			esc = "&#39;"
-		case '<':
-			esc = "&lt;"
-		case '>':
-			esc = "&gt;"
-		case '"':
-			// "&#34;" is shorter than "&quot;".
-			esc = "&#34;"
-		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(
+	`&`, "&amp;",
+	`'`, "&#39;", // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
+	`<`, "&lt;",
+	`>`, "&gt;",
+	`"`, "&#34;", // "&#34;" is shorter than "&quot;".
+)
 
 // EscapeString escapes special characters like "<" to become "&lt;". 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 "&lt;" to become "<". It unescapes a
@@ -241,10 +208,8 @@
 // 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 2d7ad8a..3702626 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 @@
 		}
 	}
 }
+
+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 634f183..3184648 100644
--- a/src/html/template/css.go
+++ b/src/html/template/css.go
@@ -157,56 +157,20 @@
 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 @@
 	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 ee01fb1..a952944 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -297,9 +297,9 @@
 // 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 9c9502a..6729ebf 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -1547,6 +1547,16 @@
 			"($).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 9c069ef..de4aa4a 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -138,21 +138,24 @@
 // 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 b9b9703..f04ee04 100644
--- a/src/html/template/html_test.go
+++ b/src/html/template/html_test.go
@@ -19,7 +19,8 @@
 		`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 := ("&#xfffd;\x01\x02\x03\x04\x05\x06\x07" +
 		"\x08&#9;&#10;&#11;&#12;&#13;\x0E\x0F" +
@@ -31,14 +32,16 @@
 		`PQRSTUVWXYZ[\]^_` +
 		`&#96;abcdefghijklmno` +
 		`pqrstuvwxyz{|}~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E")
+		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E" +
+		"erroneous&#xfffd;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 999a61e..f6d166b 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -246,8 +246,10 @@
 // `\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 @@
 		}
 		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 9bc3e5e..0000000
--- 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 0000000..d7a9b9c
--- /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 0000000..47105e0
--- /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 0000000..48e2094
--- /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 0000000..1c89ed1
--- /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 0000000..a769bb3
--- /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 0000000..8badf6f
--- /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 5f75feb..07eccb2 100644
--- a/src/internal/syscall/windows/registry/registry_test.go
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -611,3 +611,68 @@
 		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 1c1771d..bb45a23 100644
--- a/src/internal/syscall/windows/registry/value.go
+++ b/src/internal/syscall/windows/registry/value.go
@@ -130,7 +130,7 @@
 			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 @@
 	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 @@
 	}
 	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 1ff6349..d7ea838 100644
--- a/src/math/big/arith.go
+++ b/src/math/big/arith.go
@@ -107,11 +107,26 @@
 	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 @@
 		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 d2d5187..b69a2c6 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -351,6 +351,34 @@
 	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 3ce2422..14ecab5 100644
--- a/src/math/big/bits_test.go
+++ b/src/math/big/bits_test.go
@@ -203,18 +203,18 @@
 	}{
 		// 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 3d024dc..2595e5f 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 @@
 	// special case 0
 	if len(m) == 0 {
 		x.mant = x.mant[:0]
+		x.exp = 0
 		return
 	}
 
@@ -255,4 +258,7 @@
 		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 d46c046..1563528 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -525,25 +525,6 @@
 	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 @@
 	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 @@
 		// 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 @@
 		// 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 @@
 	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 @@
 			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<<mbits - 1) // cut off msb (implicit 1 bit)
-
 		// Rounding may have caused a denormal number to
 		// become normal. Check again.
-		c := float32(1.0)
-		if r.exp < emin+1 {
+		if e < emin {
 			// denormal number
-			r.exp += mbits
-			c = 1.0 / (1 << mbits) // 2**-mbits
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb32(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = msb32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
 		}
-		// emin+1 <= r.exp <= emax+1
-		e := uint32(r.exp-emin) << mbits
 
-		return c * math.Float32frombits(s|e|m), r.acc
+		return math.Float32frombits(sign | bexp | mant), r.acc
 
 	case zero:
 		if x.neg {
@@ -980,64 +984,71 @@
 			emax  = bias              //  1023  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 float64
-				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 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<<mbits - 1) // cut off msb (implicit 1 bit)
-
 		// Rounding may have caused a denormal number to
 		// become normal. Check again.
-		c := 1.0
-		if r.exp < emin+1 {
+		if e < emin {
 			// denormal number
-			r.exp += mbits
-			c = 1.0 / (1 << mbits) // 2**-mbits
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb64(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = msb64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
 		}
-		// emin+1 <= r.exp <= emax+1
-		e := uint64(r.exp-emin) << mbits
 
-		return c * math.Float64frombits(s|e|m), r.acc
+		return math.Float64frombits(sign | bexp | mant), r.acc
 
 	case zero:
 		if x.neg {
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index 5b5a024..7df9fc7 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -203,6 +203,18 @@
 	return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
 }
 
+func alike32(x, y float32) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
+
+}
+
+func alike64(x, y float64) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(x) == math.Signbit(y)
+
+}
+
 func TestFloatMantExp(t *testing.T) {
 	for _, test := range []struct {
 		x    string
@@ -828,52 +840,69 @@
 		out float32
 		acc Accuracy
 	}{
-		{"-Inf", float32(math.Inf(-1)), Exact},
-		{"-0x1.ffffff0p2147483646", float32(-math.Inf(+1)), Below}, // overflow in rounding
-		{"-1e10000", float32(math.Inf(-1)), Below},                 // overflow
-		{"-0x1p128", float32(math.Inf(-1)), Below},                 // overflow
-		{"-0x1.ffffff0p127", float32(-math.Inf(+1)), Below},        // overflow
-		{"-0x1.fffffe8p127", -math.MaxFloat32, Above},
-		{"-0x1.fffffe0p127", -math.MaxFloat32, Exact},
-		{"-12345.000000000000000000001", -12345, Above},
-		{"-12345.0", -12345, Exact},
-		{"-1.000000000000000000001", -1, Above},
-		{"-1", -1, Exact},
-		{"-0x0.000002p-126", -math.SmallestNonzeroFloat32, Exact},
-		{"-0x0.000002p-127", -0, Above}, // underflow
-		{"-1e-1000", -0, Above},         // underflow
 		{"0", 0, Exact},
-		{"1e-1000", 0, Below},         // underflow
-		{"0x0.000002p-127", 0, Below}, // underflow
-		{"0x0.000002p-126", math.SmallestNonzeroFloat32, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.000002p-127", 0, Below},
+		{"0x.0000010p-126", 0, Below},
+
+		// denormals
+		{"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
+		{"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
+		{"1p-149", math.SmallestNonzeroFloat32, Exact},
+		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
+		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
+		{"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
+		{"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
 		{"1", 1, Exact},
 		{"1.000000000000000000001", 1, Below},
 		{"12345.0", 12345, Exact},
 		{"12345.000000000000000000001", 12345, Below},
 		{"0x1.fffffe0p127", math.MaxFloat32, Exact},
 		{"0x1.fffffe8p127", math.MaxFloat32, Below},
-		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},        // overflow
-		{"0x1p128", float32(math.Inf(+1)), Above},                // overflow
-		{"1e10000", float32(math.Inf(+1)), Above},                // overflow
+
+		// overflow
+		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
+		{"0x1p128", float32(math.Inf(+1)), Above},
+		{"1e10000", float32(math.Inf(+1)), Above},
 		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
-		{"+Inf", float32(math.Inf(+1)), Exact},
+
+		// inf
+		{"Inf", float32(math.Inf(+1)), Exact},
 	} {
-		// conversion should match strconv where syntax is agreeable
-		if f, err := strconv.ParseFloat(test.x, 32); err == nil && float32(f) != test.out {
-			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
-		}
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
 
-		x := makeFloat(test.x)
-		out, acc := x.Float32()
-		if out != test.out || acc != test.acc {
-			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), test.acc)
-		}
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
 
-		// test that x.SetFloat64(float64(f)).Float32() == f
-		var x2 Float
-		out2, acc2 := x2.SetFloat64(float64(out)).Float32()
-		if out2 != out || acc2 != Exact {
-			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			x := makeFloat(tx)
+			out, acc := x.Float32()
+			if !alike32(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(float64(f)).Float32() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(float64(out)).Float32()
+			if !alike32(out2, out) || acc2 != Exact {
+				t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			}
 		}
 	}
 }
@@ -885,35 +914,36 @@
 		out float64
 		acc Accuracy
 	}{
-		{"-Inf", math.Inf(-1), Exact},
-		{"-0x1.fffffffffffff8p2147483646", -math.Inf(+1), Below}, // overflow in rounding
-		{"-1e10000", math.Inf(-1), Below},                        // overflow
-		{"-0x1p1024", math.Inf(-1), Below},                       // overflow
-		{"-0x1.fffffffffffff8p1023", -math.Inf(+1), Below},       // overflow
-		{"-0x1.fffffffffffff4p1023", -math.MaxFloat64, Above},
-		{"-0x1.fffffffffffff0p1023", -math.MaxFloat64, Exact},
-		{"-12345.000000000000000000001", -12345, Above},
-		{"-12345.0", -12345, Exact},
-		{"-1.000000000000000000001", -1, Above},
-		{"-1", -1, Exact},
-		{"-0x0.0000000000001p-1022", -math.SmallestNonzeroFloat64, Exact},
-		{"-0x0.0000000000001p-1023", -0, Above}, // underflow
-		{"-1e-1000", -0, Above},                 // underflow
 		{"0", 0, Exact},
-		{"1e-1000", 0, Below},                 // underflow
-		{"0x0.0000000000001p-1023", 0, Below}, // underflow
-		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.0000000000001p-1023", 0, Below},
+		{"0x0.00000000000008p-1022", 0, Below},
+
+		// denormals
+		{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},  // smallest denormal
+		{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
+		{"1p-1074", math.SmallestNonzeroFloat64, Exact},
+		{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
+		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
 		{"1", 1, Exact},
 		{"1.000000000000000000001", 1, Below},
 		{"12345.0", 12345, Exact},
 		{"12345.000000000000000000001", 12345, Below},
 		{"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact},
 		{"0x1.fffffffffffff4p1023", math.MaxFloat64, Below},
-		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},       // overflow
-		{"0x1p1024", math.Inf(+1), Above},                      // overflow
-		{"1e10000", math.Inf(+1), Above},                       // overflow
+
+		// overflow
+		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
+		{"0x1p1024", math.Inf(+1), Above},
+		{"1e10000", math.Inf(+1), Above},
 		{"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
-		{"+Inf", math.Inf(+1), Exact},
+		{"Inf", math.Inf(+1), Exact},
 
 		// selected denormalized values that were handled incorrectly in the past
 		{"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
@@ -924,22 +954,32 @@
 		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
 		{"2.2250738585072012e-308", 2.2250738585072014e-308, Above},
 	} {
-		// conversion should match strconv where syntax is agreeable
-		if f, err := strconv.ParseFloat(test.x, 64); err == nil && f != test.out {
-			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
-		}
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
 
-		x := makeFloat(test.x)
-		out, acc := x.Float64()
-		if out != test.out || acc != test.acc {
-			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), test.acc)
-		}
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
 
-		// test that x.SetFloat64(f).Float64() == f
-		var x2 Float
-		out2, acc2 := x2.SetFloat64(out).Float64()
-		if out2 != out || acc2 != Exact {
-			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			x := makeFloat(tx)
+			out, acc := x.Float64()
+			if !alike64(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(f).Float64() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(out).Float64()
+			if !alike64(out2, out) || acc2 != Exact {
+				t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+			}
 		}
 	}
 }
@@ -1523,32 +1563,32 @@
 		x, y, want string
 		acc        Accuracy
 	}{
-		{4, ToNearestEven, '+', "0", "0", "0", Exact},                // smoke test
-		{4, ToNearestEven, '+', "0x.8p0", "0x.8p0", "0x.8p1", Exact}, // smoke test
+		{4, ToNearestEven, '+', "0", "0", "0", Exact},                   // smoke test
+		{4, ToNearestEven, '+', "0x.8p+0", "0x.8p+0", "0x.8p+1", Exact}, // smoke test
 
-		{4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p2147483647", Exact},
-		{4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p2147483647", Below}, // rounded to zero
-		{4, ToNearestEven, '+', "0x.8p2147483647", "0x.8p2147483647", "+Inf", Above},            // exponent overflow in +
-		{4, ToNearestEven, '+', "-0x.8p2147483647", "-0x.8p2147483647", "-Inf", Below},          // exponent overflow in +
-		{4, ToNearestEven, '-', "-0x.8p2147483647", "0x.8p2147483647", "-Inf", Below},           // exponent overflow in -
+		{4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p+2147483647", Exact},
+		{4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p+2147483647", Below}, // rounded to zero
+		{4, ToNearestEven, '+', "0x.8p2147483647", "0x.8p2147483647", "+Inf", Above},             // exponent overflow in +
+		{4, ToNearestEven, '+', "-0x.8p2147483647", "-0x.8p2147483647", "-Inf", Below},           // exponent overflow in +
+		{4, ToNearestEven, '-', "-0x.8p2147483647", "0x.8p2147483647", "-Inf", Below},            // exponent overflow in -
 
-		{4, ToZero, '+', "0x.fp2147483647", "0x.8p2147483643", "0x.fp2147483647", Below}, // rounded to zero
-		{4, ToNearestEven, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},     // exponent overflow in rounding
-		{4, AwayFromZero, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},      // exponent overflow in rounding
+		{4, ToZero, '+', "0x.fp2147483647", "0x.8p2147483643", "0x.fp+2147483647", Below}, // rounded to zero
+		{4, ToNearestEven, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},      // exponent overflow in rounding
+		{4, AwayFromZero, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},       // exponent overflow in rounding
 
-		{4, AwayFromZero, '-', "-0x.fp2147483647", "0x.8p2147483644", "-Inf", Below},       // exponent overflow in rounding
-		{4, ToNearestEven, '-', "-0x.fp2147483647", "0x.8p2147483643", "-Inf", Below},      // exponent overflow in rounding
-		{4, ToZero, '-', "-0x.fp2147483647", "0x.8p2147483643", "-0x.fp2147483647", Above}, // rounded to zero
+		{4, AwayFromZero, '-', "-0x.fp2147483647", "0x.8p2147483644", "-Inf", Below},        // exponent overflow in rounding
+		{4, ToNearestEven, '-', "-0x.fp2147483647", "0x.8p2147483643", "-Inf", Below},       // exponent overflow in rounding
+		{4, ToZero, '-', "-0x.fp2147483647", "0x.8p2147483643", "-0x.fp+2147483647", Above}, // rounded to zero
 
 		{4, ToNearestEven, '+', "0", "0x.8p-2147483648", "0x.8p-2147483648", Exact},
 		{4, ToNearestEven, '+', "0x.8p-2147483648", "0x.8p-2147483648", "0x.8p-2147483647", Exact},
 
-		{4, ToNearestEven, '*', "1", "0x.8p2147483647", "0x.8p2147483647", Exact},
+		{4, ToNearestEven, '*', "1", "0x.8p2147483647", "0x.8p+2147483647", Exact},
 		{4, ToNearestEven, '*', "2", "0x.8p2147483647", "+Inf", Above},  // exponent overflow in *
 		{4, ToNearestEven, '*', "-2", "0x.8p2147483647", "-Inf", Below}, // exponent overflow in *
 
 		{4, ToNearestEven, '/', "0.5", "0x.8p2147483647", "0x.8p-2147483646", Exact},
-		{4, ToNearestEven, '/', "0x.8p0", "0x.8p2147483647", "0x.8p-2147483646", Exact},
+		{4, ToNearestEven, '/', "0x.8p+0", "0x.8p2147483647", "0x.8p-2147483646", Exact},
 		{4, ToNearestEven, '/', "0x.8p-1", "0x.8p2147483647", "0x.8p-2147483647", Exact},
 		{4, ToNearestEven, '/', "0x.8p-2", "0x.8p2147483647", "0x.8p-2147483648", Exact},
 		{4, ToNearestEven, '/', "0x.8p-3", "0x.8p2147483647", "0", Below}, // exponent underflow in /
@@ -1659,7 +1699,7 @@
 					want = +1
 				}
 				if got != want {
-					t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
+					t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want)
 				}
 			}
 		}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index b929d12..dc62b45 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements float-to-string conversion functions.
+// This file implements string-to-Float conversion functions.
 
 package big
 
 import (
 	"fmt"
 	"io"
-	"strconv"
 	"strings"
 )
 
@@ -67,6 +66,7 @@
 // defined if an error is reported.
 //
 // BUG(gri) The Float.Scan signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+//          (https://github.com/golang/go/issues/10938)
 func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
 	prec := z.prec
 	if prec == 0 {
@@ -243,131 +243,3 @@
 func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
 	return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
 }
-
-// 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.
-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))
-}
-
-// Append appends the string form of the floating-point number x,
-// as generated by x.Format, to buf and returns the extended buffer.
-func (x *Float) Append(buf []byte, format byte, prec int) []byte {
-	// TODO(gri) factor out handling of sign?
-
-	// Inf
-	if x.IsInf() {
-		var ch byte = '+'
-		if x.neg {
-			ch = '-'
-		}
-		buf = append(buf, ch)
-		return append(buf, "Inf"...)
-	}
-
-	// easy formats
-	switch format {
-	case 'b':
-		return x.bstring(buf)
-	case 'p':
-		return x.pstring(buf)
-	}
-
-	return x.bigFtoa(buf, format, prec)
-}
-
-// BUG(gri): Float.String uses x.Format('g', 10) rather than x.Format('g', -1).
-func (x *Float) String() string {
-	return x.Format('g', 10)
-}
-
-// bstring 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.
-func (x *Float) bstring(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
-
-	// 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)
-}
-
-// 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 96c01ee..9fc2b89 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -125,12 +125,16 @@
 		{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 @@
 
 		{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 @@
 		{"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 @@
 		{"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 7db1023..d9d39ed 100644
--- a/src/math/big/floatexample_test.go
+++ b/src/math/big/floatexample_test.go
@@ -21,9 +21,9 @@
 	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 0a9edfd..4c3e743 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 @@
 	// 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 @@
 			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 @@
 	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 @@
 	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 7157a54..6545bc1 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -216,6 +216,34 @@
 	}
 }
 
+// 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 @@
 	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 @@
 	// 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 @@
 	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<<n; i++ {
+		powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
+	}
+
+	// initialize z = 1 (Montgomery 1)
+	z = z.make(numWords)
+	copy(z, powers[0])
+
+	zz = zz.make(numWords)
+
+	// same windowed exponent, but with Montgomery multiplications
+	for i := len(y) - 1; i >= 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 b25a89f..7ac3cb8 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -205,11 +205,11 @@
 	}
 }
 
-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 @@
 	}
 }
 
+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 ab0dc49..c61494f 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -8,6 +8,8 @@
 	"errors"
 	"fmt"
 	"math"
+	"os"
+	"runtime"
 	"testing"
 )
 
@@ -322,10 +324,17 @@
 	}
 }
 
-// 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 0000000..9796f50
--- /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 0000000..02236ea
--- /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?= <eric@example.org>, =?utf-8?q?Ana=C3=AFs?= <anais@example.org>")
+	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 <eric@example.org>, Anaïs <anais@example.org>
+	// ¡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é" <jose@example.org>`, 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é" <jose@example.org>`},
+		{"=?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 55ea86a..4d5ab23 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 5a4411f..fab515f 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -214,95 +214,106 @@
 	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 @@
 
 	// 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 1b88e77..06c9ad3 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -94,10 +94,8 @@
 
 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 @@
 		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 @@
 		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) 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 @@
 	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 @@
 	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 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 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 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 cc660c9..be07dc6 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -68,7 +68,7 @@
 }
 
 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 c65d3f9..772e0c7 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -521,7 +521,7 @@
 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 20611ff..d5ff2be 100644
--- a/src/net/external_test.go
+++ b/src/net/external_test.go
@@ -15,33 +15,23 @@
 	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 @@
 	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 @@
 	}
 	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 64e94fe..827045b 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 @@
 		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 @@
 	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 @@
 	}
 	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 @@
 	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 1aad477..1d0686c 100644
--- a/src/net/file.go
+++ b/src/net/file.go
@@ -46,3 +46,47 @@
 	}
 	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 0000000..ffe3c61
--- /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 "<nil>" }
+
+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 0000000..e04fea3
--- /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 892775a..efe416f 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -135,3 +135,11 @@
 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 0f7460c..41ca78b 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -11,6 +11,8 @@
 	"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 147ca1e..df884d1 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 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 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 @@
 	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 241fa17..1ed72d5 100644
--- a/src/net/file_windows.go
+++ b/src/net/file_windows.go
@@ -23,3 +23,13 @@
 	// 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 dc499a9..b1d8799 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -927,7 +927,14 @@
 		<-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 9294deb..6d7c698 100644
--- a/src/net/http/internal/chunked.go
+++ b/src/net/http/internal/chunked.go
@@ -173,8 +173,12 @@
 		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 @@
 	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 5640344..289d53d 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -43,6 +43,7 @@
 	Close            bool
 	TransferEncoding []string
 	Trailer          Header
+	IsResponse       bool
 }
 
 func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -89,6 +90,7 @@
 			}
 		}
 	case *Response:
+		t.IsResponse = true
 		if rr.Request != nil {
 			t.Method = rr.Request.Method
 		}
@@ -206,6 +208,9 @@
 	// 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 ace5889..ca1a3ab 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -23,6 +23,7 @@
 	"net/http/httptest"
 	"net/url"
 	"os"
+	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -2447,6 +2448,104 @@
 	}
 }
 
+// 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 0e5c2e3..567d18d 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -229,7 +229,7 @@
 }
 
 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 BenchmarkInterfaceByIndex(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -253,7 +253,7 @@
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -267,7 +267,7 @@
 }
 
 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 BenchmarkInterfacesAndAddrs(b *testing.B) {
-	testHookUninstaller.Do(func() { uninstallTestHooks() })
+	testHookUninstaller.Do(uninstallTestHooks)
 
 	ifi := loopbackInterface()
 	if ifi == nil {
@@ -291,7 +291,7 @@
 }
 
 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 3ae1c6b..60e581f 100644
--- a/src/net/internal/socktest/main_test.go
+++ b/src/net/internal/socktest/main_test.go
@@ -9,6 +9,7 @@
 import (
 	"net/internal/socktest"
 	"os"
+	"sync"
 	"syscall"
 	"testing"
 )
@@ -27,6 +28,21 @@
 	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 5e558a2..4e38c7a 100644
--- a/src/net/internal/socktest/switch.go
+++ b/src/net/internal/socktest/switch.go
@@ -10,12 +10,6 @@
 	"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 @@
 	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 @@
 
 // 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 2b89276..14c0c22 100644
--- a/src/net/internal/socktest/switch_unix.go
+++ b/src/net/internal/socktest/switch_unix.go
@@ -22,7 +22,7 @@
 // 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 3cee49b..4f1d597 100644
--- a/src/net/internal/socktest/switch_windows.go
+++ b/src/net/internal/socktest/switch_windows.go
@@ -22,7 +22,7 @@
 // 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 4089f8c..f983e26 100644
--- a/src/net/internal/socktest/sys_unix.go
+++ b/src/net/internal/socktest/sys_unix.go
@@ -10,6 +10,8 @@
 
 // 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 907e01b..07af0e7 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -8,6 +8,8 @@
 
 // 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 24f67ca..b1939cd 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -53,7 +53,7 @@
 }
 
 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 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 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 56b9872..83eaf85 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 @@
 	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 @@
 		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 8f43c84..89d4d7e 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -218,8 +218,6 @@
 // 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 @@
 			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 @@
 			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 1f36184..064bc0b 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -23,17 +23,34 @@
 	}
 }
 
+// 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 @@
 	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 @@
 		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 @@
 			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)
+	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)
+		}
 	}
-	if !strings.HasSuffix(cname, ".icann.org.") {
-		t.Errorf("got %q; want a record containing .icann.org.", 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 f3f698c..04cbfd3 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -20,9 +20,9 @@
 	"bytes"
 	"errors"
 	"fmt"
-	"internal/mime"
 	"io"
 	"log"
+	"mime"
 	"net/textproto"
 	"strings"
 	"time"
@@ -138,12 +138,30 @@
 
 // Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
 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 <gf@example.com>" 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 <gf@example.com>" 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 @@
 		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 @@
 
 // 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 @@
 		}, 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 @@
 
 // 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 @@
 
 // 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 @@
 			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 @@
 		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 @@
 			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 @@
 		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 @@
 	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) 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 6ba48be..43574c6 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -6,7 +6,9 @@
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
+	"mime"
 	"reflect"
 	"strings"
 	"testing"
@@ -278,6 +280,175 @@
 	}
 }
 
+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 <jdoe@machine.example>`,
+			[]*Address{{
+				Name:    "John Doe",
+				Address: "jdoe@machine.example",
+			}},
+		},
+		// RFC 5322, Appendix A.1.2
+		{
+			`"Joe Q. Public" <john.q.public@example.com>`,
+			[]*Address{{
+				Name:    "Joe Q. Public",
+				Address: "john.q.public@example.com",
+			}},
+		},
+		{
+			`Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>`,
+			[]*Address{
+				{
+					Name:    "Mary Smith",
+					Address: "mary@x.test",
+				},
+				{
+					Address: "jdoe@example.org",
+				},
+				{
+					Name:    "Who?",
+					Address: "one@y.test",
+				},
+			},
+		},
+		{
+			`<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>`,
+			[]*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?= <joerg@example.com>`,
+			[]*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?= <joerg@example.com>`,
+			[]*Address{
+				{
+					Name:    `Jorg Doe`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded ISO-8859-15 address.
+		{
+			`=?ISO-8859-15?Q?J=F6rg_Doe?= <joerg@example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg Doe`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// RFC 2047 "B"-encoded windows-1252 address.
+		{
+			`=?windows-1252?q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
+			[]*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==?= <joerg@example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// Custom example of RFC 2047 "B"-encoded UTF-8 address.
+		{
+			`=?UTF-8?B?SsO2cmc=?= <joerg@example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg@example.com",
+				},
+			},
+		},
+		// Custom example with "." in name. For issue 4938
+		{
+			`Asem H. <noreply@example.com>`,
+			[]*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 a56b9cd..f3f8b1a 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -30,10 +30,16 @@
 
 	// 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 @@
 
 	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 @@
 		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 @@
 			{"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 @@
 	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 62bcfa4..dd6f4df 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -186,7 +186,7 @@
 	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 21b4796..da03e10 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -15,16 +15,31 @@
 	"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 @@
 
 		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 @@
 	}()
 
 	// 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 @@
 	}
 
 	// 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 b700091..d624852 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -14,7 +14,8 @@
 // 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 @@
 			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 00e4dbf..1b4a586 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -25,7 +25,7 @@
 			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 6229df2..2191c91 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -58,7 +58,7 @@
 }
 
 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 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 @@
 		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 @@
 			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 1f43521..51a8e97 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -13,11 +13,6 @@
 	"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 cafa375..9688c21 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -696,14 +696,18 @@
 	}
 	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 2213468..b25f96a 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -238,55 +238,32 @@
 		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 @@
 			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 949f666..7bbcf6e 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -200,9 +200,16 @@
 }
 
 // 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 2e43068..36ada17 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -220,32 +220,39 @@
 }
 
 // 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 877b2ef..9a99f74 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -4388,18 +4388,16 @@
 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 @@
 			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 @@
 			roundup(3*4, PtrSize) + PtrSize + 2,
 			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			r,
-			s,
+			r,
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4442,8 +4438,8 @@
 			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 @@
 			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 @@
 			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 @@
 			PtrSize,
 			roundup(PtrSize, argAlign),
 			[]byte{},
-			append([]byte{BitsScalar}, naclExtra...),
+			[]byte{},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4491,7 +4487,7 @@
 			0,
 			0,
 			[]byte{},
-			[]byte{BitsScalar},
+			[]byte{},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4501,8 +4497,8 @@
 			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 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 c89e9c1..a4e2e7e 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 @@
 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 @@
 		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 @@
 	}
 	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 5315bd3..e55a0d1 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -247,17 +247,17 @@
 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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	}
 }
 
-// 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 // 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 @@
 	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 @@
 		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 @@
 	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 fb9e85a..91c38c9 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -10,7 +10,7 @@
 	"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 6fc864d..f35ec78 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -35,4 +35,4 @@
 	[ "$(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 b024d7a..d41696a 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 932b2b7..15f4cc6 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 79421e8..3c5456f 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 c3fe4f0..0ec2093 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 549a635..1a3165c 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 ee453c0..de6dd91 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 aa028a1..9a55c71 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 36353d1..0f9aeb8 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -1693,8 +1693,10 @@
 	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 50a3024..f84afe0 100644
--- a/src/runtime/atomic_pointer.go
+++ b/src/runtime/atomic_pointer.go
@@ -20,18 +20,12 @@
 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 @@
 		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 @@
 	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_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 @@
 		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 3ecaac1..9aec3b0 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -22,17 +22,12 @@
 		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 e0c8b17..3fddcc8 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -76,24 +76,17 @@
 }
 
 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 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 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 540d7b5..476c3c5 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -58,18 +58,6 @@
 
 	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 6abec4c..e3e0c3a 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"os"
+	"reflect"
 	"runtime"
 	"runtime/debug"
 	"testing"
@@ -197,45 +198,166 @@
 	}
 }
 
-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 66b0353..f330bf2 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -10,8 +10,14 @@
 	"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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 
 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 @@
 
 var (
 	// BSS
+	bssPtr       Ptr
 	bssScalarPtr ScalarPtr
 	bssPtrScalar PtrScalar
 	bssBigStruct BigStruct
@@ -175,6 +186,7 @@
 	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 9ca3399..b199330 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -233,6 +233,9 @@
 		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)<<B); B++ {
@@ -990,3 +993,60 @@
 func reflect_ismapkey(t *_type) bool {
 	return ismapkey(t)
 }
+
+var zerobuf struct {
+	lock mutex
+	p    *byte
+	size uintptr
+}
+
+var zerotiny [1024]byte
+
+// mapzero ensures that t.zero points at a zero value for type t.
+// Types known to the compiler are in read-only memory and all point
+// to a single zero in the bss of a large enough size.
+// Types allocated by package reflect are in writable memory and
+// start out with zero set to nil; we initialize those on demand.
+func mapzero(t *_type) {
+	// On ARM, atomicloadp is implemented as xadd(p, 0),
+	// so we cannot use atomicloadp on read-only memory.
+	// Check whether the pointer is in the heap; if not, it's not writable
+	// so the zero value must already be set.
+	if GOARCH == "arm" && !inheap(uintptr(unsafe.Pointer(t))) {
+		if t.zero == nil {
+			print("runtime: map element ", *t._string, " missing zero value\n")
+			throw("mapzero")
+		}
+		return
+	}
+
+	// Already done?
+	// Check without lock, so must use atomicload to sync with atomicstore in allocation case below.
+	if atomicloadp(unsafe.Pointer(&t.zero)) != nil {
+		return
+	}
+
+	// Small enough for static buffer?
+	if t.size <= uintptr(len(zerotiny)) {
+		atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(&zerotiny[0]))
+		return
+	}
+
+	// Use allocated buffer.
+	lock(&zerobuf.lock)
+	if zerobuf.size < t.size {
+		if zerobuf.size == 0 {
+			zerobuf.size = 4 * 1024
+		}
+		for zerobuf.size < t.size {
+			zerobuf.size *= 2
+			if zerobuf.size == 0 {
+				// need >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 e18aa79..c0fff3f 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -15,20 +15,13 @@
 
 //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 @@
 	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 68f221d..4da4d88 100644
--- a/src/runtime/lfstack_test.go
+++ b/src/runtime/lfstack_test.go
@@ -24,8 +24,12 @@
 	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 1619ccb..2d7e556 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -424,9 +424,6 @@
 		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 @@
 	if mp.mallocing != 0 {
 		throw("malloc deadlock")
 	}
+	if mp.gsignal == getg() {
+		throw("malloc during signal")
+	}
 	mp.mallocing = 1
 
 	shouldhelpgc := false
@@ -669,10 +669,6 @@
 		})
 	}
 
-	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 eb58817..53a0a00 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 @@
 	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 @@
 // 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 @@
 	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 @@
 // 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 @@
 // 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 @@
 // 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 @@
 		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 @@
 
 //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 f0c7520..b20908f 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<<typeBitsWidth - 1
+	heapBitsShift   = 1                 // shift offset between successive bitPointer or bitMarked entries
+	heapBitmapScale = ptrSize * (8 / 2) // number of data bytes described by one heap bitmap byte
 
-	heapBitsWidth   = 4
-	heapBitmapScale = ptrSize * (8 / heapBitsWidth) // number of data bytes per heap bitmap byte
-	bitMarked       = 2
-	typeShift       = 2
+	// all mark/pointer bits in a byte
+	bitMarkedAll  = bitMarked | bitMarked<<heapBitsShift | bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+	bitPointerAll = bitPointer | bitPointer<<heapBitsShift | bitPointer<<(2*heapBitsShift) | bitPointer<<(3*heapBitsShift)
 )
 
-// Information from the compiler about the layout of stack frames.
-type bitvector struct {
-	n        int32 // # of bits
-	bytedata *uint8
-}
-
 // addb returns the byte pointer p+n.
 //go:nowritebarrier
 func addb(p *byte, n uintptr) *byte {
-	return (*byte)(add(unsafe.Pointer(p), n))
+	// Note: wrote out full expression instead of calling add(p, n)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n))
 }
 
 // subtractb returns the byte pointer p-n.
 //go:nowritebarrier
 func subtractb(p *byte, n uintptr) *byte {
-	return (*byte)(add(unsafe.Pointer(p), -n))
+	// Note: wrote out full expression instead of calling add(p, -n)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n))
+}
+
+// add1 returns the byte pointer p+1.
+//go:nowritebarrier
+func add1(p *byte) *byte {
+	// Note: wrote out full expression instead of calling addb(p, 1)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1))
+}
+
+// subtract1 returns the byte pointer p-1.
+//go:nowritebarrier
+func subtract1(p *byte) *byte {
+	// Note: wrote out full expression instead of calling subtractb(p, 1)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1))
 }
 
 // mHeap_MapBits is called each time arena_used is extended.
@@ -140,9 +148,13 @@
 
 // heapBitsForAddr returns the heapBits for the address addr.
 // The caller must have already checked that addr is in the range [mheap_.arena_start, mheap_.arena_used).
+//
+// nosplit because it is used during write barriers and must not be preempted.
+//go:nosplit
 func heapBitsForAddr(addr uintptr) heapBits {
+	// 2 bits per work, 4 pairs per byte, and a mask is hard coded.
 	off := (addr - mheap_.arena_start) / ptrSize
-	return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/2 - 1)), uint32(4 * (off & 1))}
+	return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/4 - 1)), uint32(off & 3)}
 }
 
 // heapBitsForSpan returns the heapBits for the span base address base.
@@ -229,20 +241,39 @@
 // That is, if h describes address p, h.next() describes p+ptrSize.
 // Note that next does not modify h. The caller must record the result.
 func (h heapBits) next() heapBits {
-	if h.shift == 0 {
-		return heapBits{h.bitp, 4}
+	if h.shift < 3*heapBitsShift {
+		return heapBits{h.bitp, h.shift + heapBitsShift}
 	}
-	return heapBits{subtractb(h.bitp, 1), 0}
+	return heapBits{subtract1(h.bitp), 0}
+}
+
+// forward returns the heapBits describing n pointer-sized words ahead of h in memory.
+// That is, if h describes address p, h.forward(n) describes p+n*ptrSize.
+// h.forward(1) is equivalent to h.next(), just slower.
+// Note that forward does not modify h. The caller must record the result.
+// bits returns the heap bits for the current word.
+func (h heapBits) forward(n uintptr) heapBits {
+	n += uintptr(h.shift) / heapBitsShift
+	return heapBits{subtractb(h.bitp, n/4), uint32(n%4) * heapBitsShift}
+}
+
+// The caller can test isMarked and isPointer by &-ing with bitMarked and bitPointer.
+// The result includes in its higher bits the bits for subsequent words
+// described by the same bitmap byte.
+func (h heapBits) bits() uint32 {
+	return uint32(*h.bitp) >> 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) != 0
 }
 
 // setMarked sets the marked bit in the heap bits, atomically.
+// h must describe the initial word of the object.
 func (h heapBits) setMarked() {
-	// Each byte of GC bitmap holds info for two words.
+	// Each byte of GC bitmap holds info for four words.
 	// Might be racing with other updates, so use atomic update always.
 	// We used to be clever here and use a non-atomic update in certain
 	// cases, but it's not worth the risk.
@@ -250,30 +281,103 @@
 }
 
 // setMarkedNonAtomic sets the marked bit in the heap bits, non-atomically.
+// h must describe the initial word of the object.
 func (h heapBits) setMarkedNonAtomic() {
 	*h.bitp |= bitMarked << h.shift
 }
 
-// typeBits returns the heap bits' type bits.
-func (h heapBits) typeBits() uint8 {
-	return (*h.bitp >> (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<<heapBitsShift) != 0 {
+		return true
+	}
+	if size == 2*ptrSize {
+		return false
+	}
+	// At least a 4-word object. Check scan bit (aka marked bit) in third word.
+	if h.shift == 0 {
+		return b&(bitMarked<<(2*heapBitsShift)) != 0
+	}
+	return uint32(*subtract1(h.bitp))&bitMarked != 0
 }
 
 // isCheckmarked reports whether the heap bits have the checkmarked bit set.
-func (h heapBits) isCheckmarked() bool {
-	typ := h.typeBits()
-	return typ == typeScalarCheckmarked || typ == typePointerCheckmarked
+// It must be told how large the object at h is, because the encoding of the
+// checkmark bit varies by size.
+// h must describe the initial word of the object.
+func (h heapBits) isCheckmarked(size uintptr) bool {
+	if size == ptrSize {
+		return (*h.bitp>>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)<<h.shift)
+// It must be told how large the object at h is, because the encoding of the
+// checkmark bit varies by size.
+// h must describe the initial word of the object.
+func (h heapBits) setCheckmarked(size uintptr) {
+	if size == ptrSize {
+		atomicor8(h.bitp, bitPointer<<h.shift)
+		return
+	}
+	atomicor8(h.bitp, bitMarked<<(heapBitsShift+h.shift))
+}
+
+// heapBitsBulkBarrier executes writebarrierptr_nostore
+// for every pointer slot in the memory range [p, p+size),
+// using the heap bitmap to locate those pointer slots.
+// This executes the write barriers necessary after a memmove.
+// Both p and size must be pointer-aligned.
+// The range [p, p+size) must lie within a single allocation.
+//
+// Callers should call heapBitsBulkBarrier immediately after
+// calling memmove(p, src, size). This function is marked nosplit
+// to avoid being preempted; the GC must not stop the goroutine
+// betwen the memmove and the execution of the barriers.
+//
+// The heap bitmap is not maintained for allocations containing
+// no pointers at all; any caller of heapBitsBulkBarrier must first
+// make sure the underlying allocation contains pointers, usually
+// by checking typ.kind&kindNoPointers.
+//
+//go:nosplit
+func heapBitsBulkBarrier(p, size uintptr) {
+	if (p|size)&(ptrSize-1) != 0 {
+		throw("heapBitsBulkBarrier: unaligned arguments")
+	}
+	if !writeBarrierEnabled || !inheap(p) {
+		return
+	}
+
+	h := heapBitsForAddr(p)
+	for i := uintptr(0); i < size; i += ptrSize {
+		if h.isPointer() {
+			x := (*uintptr)(unsafe.Pointer(p + i))
+			writebarrierptr_nostore(x, *x)
+		}
+		h = h.next()
 	}
 }
 
@@ -291,99 +395,59 @@
 		throw("initSpan: unaligned length")
 	}
 	nbyte := total / heapBitmapScale
+	if ptrSize == 8 && size == ptrSize {
+		end := h.bitp
+		bitp := subtractb(end, nbyte-1)
+		for {
+			*bitp = bitPointerAll
+			if bitp == end {
+				break
+			}
+			bitp = add1(bitp)
+		}
+		return
+	}
 	memclr(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
 }
 
 // initCheckmarkSpan initializes a span for being checkmarked.
-// This would be a no-op except that we need to rewrite any
-// typeDead bits in the first word of the object into typeScalar
-// followed by a typeDead in the second word of the object.
+// It clears the checkmark bits, which are set to 1 in normal operation.
 func (h heapBits) initCheckmarkSpan(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.
-		// There is no second word in these objects, so all we have
-		// to do is rewrite typeDead to typeScalar by adding the 1<<typeShift bit.
+		// 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)
-
-			if (x>>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 @@
 // 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<<heapBitsShift) != 0 {
+				x &^= bitMarked << heapBitsShift
 			} else {
-				x &^= typeMask << (4 + typeShift)
 				f(base + (i+1)*ptrSize)
 			}
+			if x&(bitMarked<<(2*heapBitsShift)) != 0 {
+				x &^= bitMarked << (2 * heapBitsShift)
+			} else {
+				f(base + (i+2)*ptrSize)
+			}
+			if x&(bitMarked<<(3*heapBitsShift)) != 0 {
+				x &^= bitMarked << (3 * heapBitsShift)
+			} else {
+				f(base + (i+3)*ptrSize)
+			}
 			*bitp = uint8(x)
-			bitp = subtractb(bitp, 1)
+			bitp = subtract1(bitp)
 		}
-		return
-	}
 
-	bitp := h.bitp
-	step := size / heapBitmapScale
-	for i := uintptr(0); i < n; i++ {
-		x := int(*bitp)
-		if x&bitMarked != 0 {
-			x &^= bitMarked
-		} else {
-			x = 0
-			f(base + i*size)
+	case size%(4*ptrSize) == 0:
+		// Mark bit is in first word of each object.
+		// Each object starts at bit 0 of a heap bitmap byte.
+		bitp := h.bitp
+		step := size / heapBitmapScale
+		for i := uintptr(0); i < n; i++ {
+			x := uint32(*bitp)
+			if x&bitMarked != 0 {
+				x &^= bitMarked
+			} else {
+				x = 0
+				f(base + i*size)
+			}
+			*bitp = uint8(x)
+			bitp = subtractb(bitp, step)
 		}
-		*bitp = uint8(x)
-		bitp = subtractb(bitp, step)
+
+	case size%(4*ptrSize) == 2*ptrSize:
+		// Mark bit is in first word of each object,
+		// but every other object starts halfway through a heap bitmap byte.
+		// Unroll loop 2x to handle alternating shift count and step size.
+		bitp := h.bitp
+		step := size / heapBitmapScale
+		var i uintptr
+		for i = uintptr(0); i < n; i += 2 {
+			x := uint32(*bitp)
+			if x&bitMarked != 0 {
+				x &^= bitMarked
+			} else {
+				x &^= bitMarked | bitPointer | (bitMarked|bitPointer)<<heapBitsShift
+				f(base + i*size)
+				if size > 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)
+		}
 	}
 }
 
-// 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<<h.shift)
+				}
+			} else {
+				// 2-element slice of pointer.
+				if gcphase == _GCoff {
+					*h.bitp |= (bitPointer | bitPointer<<heapBitsShift) << h.shift
+				} else {
+					atomicor8(h.bitp, (bitPointer|bitPointer<<heapBitsShift)<<h.shift)
 				}
 			}
-			prog = addb(prog, round(uintptr(siz)*typeBitsWidth, 8)/8)
+			return
+		}
+		// Otherwise typ.size must be 2*ptrSize, and typ.kind&kindGCProg == 0.
+		if doubleCheck {
+			if typ.size != 2*ptrSize || typ.kind&kindGCProg != 0 {
+				print("runtime: heapBitsSetType size=", size, " but typ.size=", typ.size, " gcprog=", typ.kind&kindGCProg != 0, "\n")
+				throw("heapBitsSetType")
+			}
+		}
+		b := uint32(*ptrmask)
+		hb := b & 3
+		if gcphase == _GCoff {
+			*h.bitp |= uint8(hb << h.shift)
+		} else {
+			atomicor8(h.bitp, uint8(hb<<h.shift))
+		}
+		return
+	}
 
-		case insArray:
-			prog = (*byte)(add(unsafe.Pointer(prog), 1))
-			siz := uintptr(0)
-			for i := uintptr(0); i < ptrSize; i++ {
-				siz = (siz << 8) + uintptr(*(*byte)(add(unsafe.Pointer(prog), ptrSize-i-1)))
-			}
-			prog = (*byte)(add(unsafe.Pointer(prog), ptrSize))
-			var prog1 *byte
-			for i := uintptr(0); i < siz; i++ {
-				prog1 = unrollgcprog1(&mask[0], prog, &pos, inplace, sparse)
-			}
-			if *prog1 != insArrayEnd {
-				throw("unrollgcprog: array does not end with insArrayEnd")
-			}
-			prog = (*byte)(add(unsafe.Pointer(prog1), 1))
+	// Copy from 1-bit ptrmask into 2-bit bitmap.
+	// The basic approach is to use a single uintptr as a bit buffer,
+	// alternating between reloading the buffer and writing bitmap bytes.
+	// In general, one load can supply two bitmap byte writes.
+	// This is a lot of lines of code, but it compiles into relatively few
+	// machine instructions.
 
-		case insArrayEnd, insEnd:
-			*ppos = pos
-			return prog
+	var (
+		// Ptrmask input.
+		p     *byte   // last ptrmask byte read
+		b     uintptr // ptrmask bits already loaded
+		nb    uintptr // number of bits in b at next read
+		endp  *byte   // final ptrmask byte to read (then repeat)
+		endnb uintptr // number of valid bits in *endp
+		pbits uintptr // alternate source of bits
+
+		// Heap bitmap output.
+		w     uintptr // words processed
+		nw    uintptr // number of words to process
+		hbitp *byte   // next heap bitmap byte to write
+		hb    uintptr // bits being prepared for *hbitp
+	)
+
+	hbitp = h.bitp
+
+	// Handle GC program. Delayed until this part of the code
+	// so that we can use the same double-checking mechanism
+	// as the 1-bit case. Nothing above could have encountered
+	// GC programs: the cases were all too small.
+	if typ.kind&kindGCProg != 0 {
+		heapBitsSetTypeGCProg(h, typ.ptrdata, typ.size, dataSize, size, addb(typ.gcdata, 4))
+		if doubleCheck {
+			// Double-check the heap bits written by GC program
+			// by running the GC program to create a 1-bit pointer mask
+			// and then jumping to the double-check code below.
+			// This doesn't catch bugs shared between the 1-bit and 4-bit
+			// GC program execution, but it does catch mistakes specific
+			// to just one of those and bugs in heapBitsSetTypeGCProg's
+			// implementation of arrays.
+			lock(&debugPtrmask.lock)
+			if debugPtrmask.data == nil {
+				debugPtrmask.data = (*byte)(persistentalloc(1<<20, 1, &memstats.other_sys))
+			}
+			ptrmask = debugPtrmask.data
+			runGCProg(addb(typ.gcdata, 4), nil, ptrmask, 1)
+			goto Phase4
+		}
+		return
+	}
+
+	// Note about sizes:
+	//
+	// typ.size is the number of words in the object,
+	// and typ.ptrdata is the number of words in the prefix
+	// of the object that contains pointers. That is, the final
+	// typ.size - typ.ptrdata words contain no pointers.
+	// This allows optimization of a common pattern where
+	// an object has a small header followed by a large scalar
+	// buffer. If we know the pointers are over, we don't have
+	// to scan the buffer's heap bitmap at all.
+	// The 1-bit ptrmasks are sized to contain only bits for
+	// the typ.ptrdata prefix, zero padded out to a full byte
+	// of bitmap. This code sets nw (below) so that heap bitmap
+	// bits are only written for the typ.ptrdata prefix; if there is
+	// more room in the allocated object, the next heap bitmap
+	// entry is a 00, indicating that there are no more pointers
+	// to scan. So only the ptrmask for the ptrdata bytes is needed.
+	//
+	// Replicated copies are not as nice: if there is an array of
+	// objects with scalar tails, all but the last tail does have to
+	// be initialized, because there is no way to say "skip forward".
+	// However, because of the possibility of a repeated type with
+	// size not a multiple of 4 pointers (one heap bitmap byte),
+	// the code already must handle the last ptrmask byte specially
+	// by treating it as containing only the bits for endnb pointers,
+	// where endnb <= 4. We represent large scalar tails that must
+	// be expanded in the replication by setting endnb larger than 4.
+	// This will have the effect of reading many bits out of b,
+	// but once the real bits are shifted out, b will supply as many
+	// zero bits as we try to read, which is exactly what we need.
+
+	p = ptrmask
+	if typ.size < dataSize {
+		// Filling in bits for an array of typ.
+		// Set up for repetition of ptrmask during main loop.
+		// Note that ptrmask describes only a prefix of
+		const maxBits = ptrSize*8 - 7
+		if typ.ptrdata/ptrSize <= maxBits {
+			// Entire ptrmask fits in uintptr with room for a byte fragment.
+			// Load into pbits and never read from ptrmask again.
+			// This is especially important when the ptrmask has
+			// fewer than 8 bits in it; otherwise the reload in the middle
+			// of the Phase 2 loop would itself need to loop to gather
+			// at least 8 bits.
+
+			// Accumulate ptrmask into b.
+			// ptrmask is sized to describe only typ.ptrdata, but we record
+			// it as describing typ.size bytes, since all the high bits are zero.
+			nb = typ.ptrdata / ptrSize
+			for i := uintptr(0); i < nb; i += 8 {
+				b |= uintptr(*p) << i
+				p = add1(p)
+			}
+			nb = typ.size / ptrSize
+
+			// Replicate ptrmask to fill entire pbits uintptr.
+			// Doubling and truncating is fewer steps than
+			// iterating by nb each time. (nb could be 1.)
+			// Since we loaded typ.ptrdata/ptrSize bits
+			// but are pretending to have typ.size/ptrSize,
+			// there might be no replication necessary/possible.
+			pbits = b
+			endnb = nb
+			if nb+nb <= maxBits {
+				for endnb <= ptrSize*8 {
+					pbits |= pbits << endnb
+					endnb += endnb
+				}
+				// Truncate to a multiple of original ptrmask.
+				endnb = maxBits / nb * nb
+				pbits &= 1<<endnb - 1
+				b = pbits
+				nb = endnb
+			}
+
+			// Clear p and endp as sentinel for using pbits.
+			// Checked during Phase 2 loop.
+			p = nil
+			endp = nil
+		} else {
+			// Ptrmask is larger. Read it multiple times.
+			n := (typ.ptrdata/ptrSize+7)/8 - 1
+			endp = addb(ptrmask, n)
+			endnb = typ.size/ptrSize - n*8
+		}
+	}
+	if p != nil {
+		b = uintptr(*p)
+		p = add1(p)
+		nb = 8
+	}
+
+	if typ.size == dataSize {
+		// Single entry: can stop once we reach the non-pointer data.
+		nw = typ.ptrdata / ptrSize
+	} else {
+		// Repeated instances of typ in an array.
+		// Have to process first N-1 entries in full, but can stop
+		// once we reach the non-pointer data in the final entry.
+		nw = ((dataSize/typ.size-1)*typ.size + typ.ptrdata) / ptrSize
+	}
+	if nw == 0 {
+		// No pointers! Caller was supposed to check.
+		println("runtime: invalid type ", *typ._string)
+		throw("heapBitsSetType: called with non-pointer type")
+		return
+	}
+	if nw < 2 {
+		// Must write at least 2 words, because the "no scan"
+		// encoding doesn't take effect until the third word.
+		nw = 2
+	}
+
+	// Phase 1: Special case for leading byte (shift==0) or half-byte (shift==4).
+	// The leading byte is special because it contains the bits for words 0 and 1,
+	// which do not have the marked bits set.
+	// The leading half-byte is special because it's a half a byte and must be
+	// manipulated atomically.
+	switch {
+	default:
+		throw("heapBitsSetType: unexpected shift")
+
+	case h.shift == 0:
+		// Ptrmask and heap bitmap are aligned.
+		// Handle first byte of bitmap specially.
+		// The first byte we write out contains the first two words of the object.
+		// In those words, the mark bits are mark and checkmark, respectively,
+		// and must not be set. In all following words, we want to set the mark bit
+		// as a signal that the object continues to the next 2-bit entry in the bitmap.
+		hb = b & bitPointerAll
+		hb |= bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+		if w += 4; w >= 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)<<heapBitsShift) | uint8(hb)
+		} else {
+			atomicand8(hbitp, ^uint8(bitPointer|bitMarked|(bitPointer|bitMarked)<<heapBitsShift))
+			atomicor8(hbitp, uint8(hb))
+		}
+	}
+
+Phase4:
+	// Phase 4: all done, but perhaps double check.
+	if doubleCheck {
+		end := heapBitsForAddr(x + size)
+		if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) {
+			println("ended at wrong bitmap byte for", *typ._string, "x", dataSize/typ.size)
+			print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\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("ended at hbitp=", hbitp, " but next starts at bitp=", end.bitp, " shift=", end.shift, "\n")
+			throw("bad heapBitsSetType")
+		}
+
+		// Double-check that bits to be written were written correctly.
+		// Does not check that other bits were not written, unfortunately.
+		h := heapBitsForAddr(x)
+		nptr := typ.ptrdata / ptrSize
+		ndata := typ.size / ptrSize
+		count := dataSize / typ.size
+		totalptr := ((count-1)*typ.size + typ.ptrdata) / ptrSize
+		for i := uintptr(0); i < size/ptrSize; i++ {
+			j := i % ndata
+			var have, want uint8
+			have = (*h.bitp >> 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")
 	}
-	unlock(&unroll)
+	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<<maxBits - 1
+					npattern = maxBits
+				} else {
+					npattern = c
+				}
+			} else {
+				b := pattern
+				nb := npattern
+				if nb+nb <= maxBits {
+					// Double pattern until the whole uintptr is filled.
+					for nb <= ptrSize*8 {
+						b |= b << nb
+						nb += nb
+					}
+					// Trim away incomplete copy of original pattern in high bits.
+					// TODO(rsc): Replace with table lookup or loop on systems without divide?
+					nb = maxBits / npattern * npattern
+					b &= 1<<nb - 1
+					pattern = b
+					npattern = nb
+				}
+			}
+
+			// Add pattern to bit buffer and flush bit buffer, c/npattern times.
+			// Since pattern contains >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<<c - 1
+				bits |= pattern << nbits
+				nbits += c
+			}
+			continue Run
+		}
+
+		// Repeat; n too large to fit in a register.
+		// Since nbits <= 7, we know the first few bytes of repeated data
+		// are already written to memory.
+		off := n - nbits // n > 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<<c - 1)) << nbits
+				nbits += c
+			}
+		} else {
+			// Leading src fragment.
+			src = addb(src, (off+3)/4)
+			if frag := off & 3; frag != 0 {
+				bits |= (uintptr(*src) & 0xf) >> (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<<c - 1)) << nbits
+				nbits += c
+			}
+		}
+	}
+
+	// Write any final bits out, using full-byte writes, even for the final byte.
+	var totalBits uintptr
+	if size == 1 {
+		totalBits = (uintptr(unsafe.Pointer(dst))-uintptr(unsafe.Pointer(dstStart)))*8 + nbits
+		nbits += -nbits & 7
+		for ; nbits > 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<<heapBitsShift
+	}
+	return totalBits
+}
+
+func dumpGCProg(p *byte) {
+	nptr := 0
+	for {
+		x := *p
+		p = add1(p)
+		if x == 0 {
+			print("\t", nptr, " end\n")
+			break
+		}
+		if x&0x80 == 0 {
+			print("\t", nptr, " lit ", x, ":")
+			n := int(x+7) / 8
+			for i := 0; i < n; i++ {
+				print(" ", hex(*p))
+				p = add1(p)
+			}
+			print("\n")
+			nptr += int(x)
+		} else {
+			nbit := int(x &^ 0x80)
+			if nbit == 0 {
+				for nb := uint(0); ; nb += 7 {
+					x := *p
+					p = add1(p)
+					nbit |= int(x&0x7f) << nb
+					if x&0x80 == 0 {
+						break
+					}
+				}
+			}
+			count := 0
+			for nb := uint(0); ; nb += 7 {
+				x := *p
+				p = add1(p)
+				count |= int(x&0x7f) << nb
+				if x&0x80 == 0 {
+					break
+				}
+			}
+			print("\t", nptr, " repeat ", nbit, " × ", count, "\n")
+			nptr += nbit * count
+		}
+	}
 }
 
 // Testing.
@@ -748,36 +1510,46 @@
 	return true
 }
 
-// Returns GC type info for object p for testing.
-func getgcmask(p unsafe.Pointer, t *_type, mask **byte, len *uintptr) {
-	*mask = nil
-	*len = 0
+// gcbits returns the GC type info for x, for testing.
+// The result is the bitmap entries (0 or 1), one entry per byte.
+//go:linkname reflect_gcbits reflect.gcbits
+func reflect_gcbits(x interface{}) []byte {
+	ret := getgcmask(x)
+	typ := (*ptrtype)(unsafe.Pointer((*eface)(unsafe.Pointer(&x))._type)).elem
+	nptr := typ.ptrdata / ptrSize
+	for uintptr(len(ret)) > 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 @@
 	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 _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
+			}
 		}
-		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
-		}
+		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 9bd36d1..db5b2dc 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -127,13 +127,22 @@
 	_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 @@
 	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 @@
 		in = -1
 	}
 	gcpercent = in
-	heapminimum = heapminimum * uint64(gcpercent) / 100
+	heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100
 	unlock(&mheap_.lock)
 	return out
 }
@@ -197,7 +206,6 @@
 
 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 @@
 //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 @@
 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 @@
 		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 @@
 			setGCPhase(_GCscan)
 
 			// Concurrent scan.
-			starttheworld()
+			startTheWorldWithSema()
 			if debug.gctrace > 0 {
 				tScan = nanotime()
 			}
@@ -858,7 +866,7 @@
 		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 @@
 	// 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 @@
 	}
 }
 
+// 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 9d78dde..62fa338 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -261,7 +261,7 @@
 	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 @@
 				// 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 @@
 			// 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 @@
 
 			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 @@
 		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 9c32ae8..b7feb84 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -7,7 +7,7 @@
 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 @@
 	}
 }
 
+// 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 10878ee..04fa050 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -28,6 +28,15 @@
 	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 @@
 	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 @@
 	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 @@
 
 // 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 4544344..a618bd5 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -521,9 +521,7 @@
 	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 @@
 			}
 		}
 
-		gp.m.preemptoff = ""
-		semrelease(&worldsema)
-		systemstack(starttheworld)
+		startTheWorld()
 	}
 
 	return n, ok
@@ -565,10 +561,7 @@
 // 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 @@
 	}
 
 	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 c8e5249..3eff7f6 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -153,24 +153,13 @@
 
 // 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 10cf460..1b74e3e 100644
--- a/src/runtime/os1_darwin.go
+++ b/src/runtime/os1_darwin.go
@@ -8,7 +8,6 @@
 
 //extern SigTabTT runtime·sigtab[];
 
-var sigset_none = uint32(0)
 var sigset_all = ^uint32(0)
 
 func unimplemented(name string) {
@@ -126,17 +125,36 @@
 	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 @@
 	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 a590aea..eb42b54 100644
--- a/src/runtime/os1_dragonfly.go
+++ b/src/runtime/os1_dragonfly.go
@@ -12,7 +12,6 @@
 	_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 @@
 	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 @@
 
 	// 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 @@
 	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 8719a49..f7f34bd 100644
--- a/src/runtime/os1_freebsd.go
+++ b/src/runtime/os1_freebsd.go
@@ -12,7 +12,6 @@
 	_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 @@
 	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 @@
 
 	// 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 @@
 	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 e4b18c7..02f98d7 100644
--- a/src/runtime/os1_linux.go
+++ b/src/runtime/os1_linux.go
@@ -6,7 +6,6 @@
 
 import "unsafe"
 
-var sigset_none sigset
 var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
 
 // Linux futex.
@@ -190,17 +189,36 @@
 	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 @@
 	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 dbb5dec..66e60f8 100644
--- a/src/runtime/os1_nacl.go
+++ b/src/runtime/os1_nacl.go
@@ -15,6 +15,9 @@
 
 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 8df74b5..3fb0598 100644
--- a/src/runtime/os1_netbsd.go
+++ b/src/runtime/os1_netbsd.go
@@ -17,7 +17,6 @@
 	_CLOCK_MONOTONIC = 3
 )
 
-var sigset_none = sigset{}
 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
 
 // From NetBSD's <sys/sysctl.h>
@@ -139,6 +138,14 @@
 	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 @@
 
 	// 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 @@
 	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 95729a5..5ccf642 100644
--- a/src/runtime/os1_openbsd.go
+++ b/src/runtime/os1_openbsd.go
@@ -148,6 +148,14 @@
 	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 @@
 
 	// 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 @@
 	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 c026218..bda7057 100644
--- a/src/runtime/os1_plan9.go
+++ b/src/runtime/os1_plan9.go
@@ -18,6 +18,9 @@
 	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 @@
 	} 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 5719b32..bc472d0 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -292,6 +292,9 @@
 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 69ac5b4..e4fe92d 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -114,7 +114,6 @@
 	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 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 @@
 	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 @@
 	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 0e4086c..47563f4 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -188,16 +188,6 @@
 		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 @@
 	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 b3d0ae9..4290edb 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -442,35 +442,33 @@
 
 	// 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 f725fc8..805b96e 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -203,7 +203,7 @@
 	// 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 00535da..c070f7d 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -59,7 +59,6 @@
 	goargs()
 	goenvs()
 	parsedebugvars()
-	wbshadowinit()
 	gcinit()
 
 	sched.lastpoll = uint64(nanotime())
@@ -212,7 +211,7 @@
 // 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 @@
 	}
 }
 
-// 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 @@
 		}
 	}
 	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 @@
 	_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 @@
 			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 @@
 	_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 @@
 	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 @@
 		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 @@
 	}
 	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 @@
 	_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 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 @@
 	}
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 	// 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 @@
 	// 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 @@
 	// 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 @@
 	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 @@
 	}
 }
 
-// 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 @@
 			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 @@
 // 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 @@
 	}
 }
 
-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 4c5712d..4471ee5 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -7,6 +7,7 @@
 import (
 	"math"
 	"runtime"
+	"runtime/debug"
 	"sync"
 	"sync/atomic"
 	"syscall"
@@ -104,8 +105,8 @@
 	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 fe7d38a..f4014b2 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -59,7 +59,7 @@
 
 	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 @@
 	// 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 ac539b9..3ee5d5d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -266,6 +266,7 @@
 	// 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 @@
 
 	// 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 @@
 }
 
 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 @@
 }
 
 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 d4cccbf..f65562a 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -6,13 +6,8 @@
 
 import (
 	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
 	. "runtime"
 	"runtime/debug"
-	"strconv"
-	"strings"
 	"testing"
 	"unsafe"
 )
@@ -88,53 +83,6 @@
 	}
 }
 
-// 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 7577d43..d3e9dac 100644
--- a/src/runtime/signal1_unix.go
+++ b/src/runtime/signal1_unix.go
@@ -19,6 +19,19 @@
 // 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 @@
 	}
 
 	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 @@
 	}
 
 	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 @@
 		}
 	}
 
-	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 32ecce0..6cd1865 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -16,14 +16,14 @@
 	/* 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 @@
 	/* 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 f8250b9..2f25b59 100644
--- a/src/runtime/signal_linux.go
+++ b/src/runtime/signal_linux.go
@@ -16,20 +16,20 @@
 	/* 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 @@
 	/* 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 78afc59..d93a450 100644
--- a/src/runtime/signal_netbsd.go
+++ b/src/runtime/signal_netbsd.go
@@ -14,14 +14,14 @@
 	/*  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 @@
 	/* 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 2986c5a..d8ac676 100644
--- a/src/runtime/signal_solaris.go
+++ b/src/runtime/signal_solaris.go
@@ -14,21 +14,21 @@
 	/* 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 @@
 	/* 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 da8a1c5..b2fce53 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -131,7 +131,9 @@
 
 	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 38f0a57..f000fab 100644
--- a/src/runtime/sigqueue_plan9.go
+++ b/src/runtime/sigqueue_plan9.go
@@ -17,21 +17,29 @@
 	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 @@
 	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 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 5ccc659..79b6118 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -84,10 +84,13 @@
 		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 f74694b..27427af 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -352,6 +352,12 @@
 	}
 }
 
+// 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 @@
 			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 25f5bf4..687f067 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -32,6 +32,8 @@
 // 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 @@
 
 	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 @@
 		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 3b7501b..6da7bad 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -132,10 +132,7 @@
 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 @@
 
 	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 @@
 
 	unlock(&trace.bufLock)
 
-	_g_.m.preemptoff = ""
-	semrelease(&worldsema)
-	systemstack(starttheworld)
+	startTheWorld()
 	return nil
 }
 
@@ -186,19 +179,14 @@
 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 @@
 
 	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 @@
 
 	// 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 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 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 9f34e37..5ed601e 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -46,6 +46,9 @@
 	timerprocPC          uintptr
 	gcBgMarkWorkerPC     uintptr
 	systemstack_switchPC uintptr
+	systemstackPC        uintptr
+
+	gogoPC uintptr
 
 	externalthreadhandlerp uintptr // initialized elsewhere
 )
@@ -69,6 +72,10 @@
 	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 @@
 		// 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 @@
 				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 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 48df2a4..45bdac8 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -20,17 +20,10 @@
 	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 d59c78e..468c37f 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -223,9 +223,8 @@
 	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 ced2ca86..3aa30c7 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -132,26 +132,6 @@
 		}
 	}
 
-	// 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 @@
 		}
 	}
 
+	// 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 1b7cd64..85fab4f 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -179,7 +179,7 @@
 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 @@
 		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 d25527b..438de6e 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -87,7 +87,9 @@
 includes_Linux='
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
+#ifndef __LP64__
 #define _FILE_OFFSET_BITS 64
+#endif
 #define _GNU_SOURCE
 
 #include <bits/sockaddr.h>
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index 7a8add8..b6fbcb5 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -28,7 +28,8 @@
 }
 
 my $prev;
-while(<>){
+open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
+while(<GCC>){
 	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 05d4044..4f88d51 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -852,7 +852,6 @@
 //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 98636a5..9ee1c1c 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -66,6 +66,7 @@
 //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 fad9c32..6fbef21 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -16,6 +16,7 @@
 //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 f0cc25e..218d6b8 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -87,6 +87,7 @@
 //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 3c4eabc..7ca4164 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -124,11 +124,14 @@
 	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 5318c61..10489d9 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -19,6 +19,7 @@
 //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 0000000..40fce6d
--- /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 01fc670..af92013 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -60,20 +60,58 @@
 
 // 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 @@
 	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 bb3a161..debadaa 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 05ab48e..d4262ba 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 7e800d4..a64f373 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 a3841a2..98f431c 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 59bff75..15d300f 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 cd3aa80..bbad05f 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 9edce6e..b36125b 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 f29dd05..0c844f1 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 7aa8ff0..d433a4f 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 94d051d..dd86a3b 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 dcaaef7..2a9c0f9 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 f3d708b..35d9ace 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 15e0770..1c769cd 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 @@
 	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 fdecdf2..73727a4 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 @@
 	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 1e3dff7..6f32def 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 1469d00..a6d1701 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 1a88c0d..7f99279 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 0829834..540d310 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 e9fa37c..ae5b8c9 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 5376fe6..c49ebcf 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 3f4cbfd..62ec81b 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 0ce383f..23e7b5e 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 2370630..6e63d9a 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 c9426ee..f996a50 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 828b167..c260cc7 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 5eef138..88e09d3 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 7cb21c9..30f29e5 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 3cb87c1..93059d1 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 3404183..84096b0 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 e7cf745..620fba2 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 @@
 
 // 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 @@
 
 // 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 b23573b..16cafbf 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 @@
 
 // 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 @@
 
 // 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 054cf40..9bc3a54 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 @@
 
 // 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 @@
 
 // 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 26a14b7..2ee58cf 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 @@
 
 // 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 3262180..4f61114 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 @@
 
 // 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 @@
 
 // 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 3262180..4073a0f 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 @@
 
 // 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 @@
 
 // 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 d0ff66c..bf3f9e3 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 592c8d8..3f08da6 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 10657ad..77d46c3 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 5131c25..e24c3b7 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 0e26f68..7aa75ab 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 4aae104..21f482b 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 f6a1983..df7df1e 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 93f5fc0..1d64070 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 f59739c..f40fb31 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 06f1f04..a424e78 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 06f1f04..d58556b 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 be9bc28..cabab7e 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 abdef77..c6f8342 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 abdef77..7189abe 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 1a53f13..1d76861 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 723b1aa..ddf8e83 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 4b086b9..277478d 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 dfca558..5e47217 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 dfca558..df8928c 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 dfca558..f670a59 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 c40b5f1..c277ed9 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 7cf70a4..978a4d3 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 7068e4e..5061cba 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 4bcf057..d53712c 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 0567fd0..82d253a 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 52c63e3..3af4e83 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 c570965..c8af210 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 c570965..e342a3c 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 c570965..1f5b569 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 3b9ac4c..c19f6de 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 3b9ac4c..86e04cd 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 8457c14..38b43ca 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 43b3d8b..be198f8 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 13724c3..7298d02 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 65b02ae..ec95d51 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 ec87f54..91c4470 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 65b02ae..1d65cfd 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 954ffd7..00120d0 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 b809eea..d972fb6 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 a05908a..0a5a10b 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 9303816..5d7acd5 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 a887f31..dd198cb 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 adf95ca..a39489e 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 1ae9718..f446e41 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 1cb1d43..dcb1178 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 fe43836..33d1b7f 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 @@
 	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 c6b6f16..27ca004 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 @@
 	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 6add325..1752c6c 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 4451fc1..b8d4b0b 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 4e853ea..c21d875 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 2e4d9dd..0376d3a 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 f07bc71..bf23626 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 5f8fb12..e1d8938 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 77275a5..2471519 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 61339a6..30baf27 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -43,7 +43,7 @@
 
 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 280d76a..2a1c45f 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 @@
 			}
 			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 d3eadfd..eacc0a2 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -314,7 +314,9 @@
 	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 @@
 		}
 	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 aca17b1..798bed7 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -619,13 +619,12 @@
 
 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 @@
 
 	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 e6e1287..ebafb4b 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -660,7 +660,7 @@
 	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 abce27f..0f1ad62 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -531,6 +531,8 @@
 	{"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 @@
 	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 @@
 		"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 cdd187b..ccd0dfc 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -92,6 +92,8 @@
 // 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 8611faa..a7c5c8c 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -7,18 +7,20 @@
 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 @@
 		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 @@
 // 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 @@
 // 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 7e689b8..6fd4509 100644
--- a/src/time/export_windows_test.go
+++ b/src/time/export_windows_test.go
@@ -8,3 +8,7 @@
 	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 0300e84..fbf3f8d3 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -966,6 +966,8 @@
 // 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 9f987ab..d04ebec 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -49,7 +49,7 @@
 // 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 9db81b7..5f1141d 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 @@
 	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 a06c326..d8b1486 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 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	fi
 	run 'gccgo -O2 regex-dna.go' a.$EXE <x
 	run 'gccgo -O2 regex-dna-parallel.go' a.$EXE <x
-	run 'gc regex-dna' $O.$EXE <x
-	run 'gc regex-dna-parallel' $O.$EXE <x
-	run 'gc_B regex-dna' $O.$EXE <x
+	run 'gc regex-dna' a.$EXE <x
+	run 'gc regex-dna-parallel' a.$EXE <x
+	run 'gc_B regex-dna' a.$EXE <x
 	rm x
 }
 
@@ -176,8 +175,8 @@
 	runonly echo 'spectral-norm 5500'
 	run "gcc $gccm -O2 spectral-norm.c -lm" a.$EXE 5500
 	run 'gccgo -O2 spectral-norm.go' a.$EXE -n 5500
-	run 'gc spectral-norm' $O.$EXE -n 5500
-	run 'gc_B spectral-norm' $O.$EXE -n 5500
+	run 'gc spectral-norm' a.$EXE -n 5500
+	run 'gc_B spectral-norm' a.$EXE -n 5500
 }
 
 knucleotide() {
@@ -189,9 +188,9 @@
 	fi
 	run 'gccgo -O2 k-nucleotide.go' a.$EXE <x
 	run 'gccgo -O2 k-nucleotide-parallel.go' a.$EXE <x
-	run 'gc k-nucleotide' $O.$EXE <x
-	run 'gc k-nucleotide-parallel' $O.$EXE <x
-	run 'gc_B k-nucleotide' $O.$EXE <x
+	run 'gc k-nucleotide' a.$EXE <x
+	run 'gc k-nucleotide-parallel' a.$EXE <x
+	run 'gc_B k-nucleotide' a.$EXE <x
 	rm x
 }
 
@@ -199,16 +198,16 @@
 	runonly echo 'mandelbrot 16000'
 	run "gcc $gccm -O2 mandelbrot.c" a.$EXE 16000
 	run 'gccgo -O2 mandelbrot.go' a.$EXE -n 16000
-	run 'gc mandelbrot' $O.$EXE -n 16000
-	run 'gc_B mandelbrot' $O.$EXE -n 16000
+	run 'gc mandelbrot' a.$EXE -n 16000
+	run 'gc_B mandelbrot' a.$EXE -n 16000
 }
 
 meteor() {
 	runonly echo 'meteor 2098'
 	run "gcc $gccm -O2 meteor-contest.c" a.$EXE 2098
 	run 'gccgo -O2 meteor-contest.go' a.$EXE -n 2098
-	run 'gc meteor-contest' $O.$EXE -n 2098
-	run 'gc_B  meteor-contest' $O.$EXE -n 2098
+	run 'gc meteor-contest' a.$EXE -n 2098
+	run 'gc_B  meteor-contest' a.$EXE -n 2098
 }
 
 pidigits() {
@@ -217,22 +216,22 @@
 		run "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
 	fi
 	run 'gccgo -O2 pidigits.go' a.$EXE -n 10000
-	run 'gc pidigits' $O.$EXE -n 10000
-	run 'gc_B  pidigits' $O.$EXE -n 10000
+	run 'gc pidigits' a.$EXE -n 10000
+	run 'gc_B  pidigits' a.$EXE -n 10000
 }
 
 threadring() {
 	runonly echo 'threadring 50000000'
 	run "gcc $gccm -O2 threadring.c -lpthread" a.$EXE 50000000
 	run 'gccgo -O2 threadring.go' a.$EXE -n 50000000
-	run 'gc threadring' $O.$EXE -n 50000000
+	run 'gc threadring' a.$EXE -n 50000000
 }
 
 chameneos() {
 	runonly echo 'chameneos 6000000'
 	run "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
 	run 'gccgo -O2 chameneosredux.go' a.$EXE 6000000
-	run 'gc chameneosredux' $O.$EXE 6000000
+	run 'gc chameneosredux' a.$EXE 6000000
 }
 
 case $# in
diff --git a/test/convlit.go b/test/convlit.go
index 8a6145d..904e1e6 100644
--- a/test/convlit.go
+++ b/test/convlit.go
@@ -9,6 +9,8 @@
 
 package main
 
+import "unsafe"
+
 // explicit conversion of constants
 var x1 = string(1)
 var x2 string = string(1)
@@ -18,6 +20,11 @@
 var x6 = int(1e100)      // ERROR "overflow"
 var x7 = float32(1e1000) // ERROR "overflow"
 
+// unsafe.Pointer can only convert to/from uintptr
+var _ = string(unsafe.Pointer(uintptr(65)))  // ERROR "convert"
+var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert"
+var _ = int(unsafe.Pointer(uintptr(65)))     // ERROR "convert"
+
 // implicit conversions merit scrutiny
 var s string
 var bad1 string = 1  // ERROR "conver|incompatible|invalid|cannot"
diff --git a/test/escape2.go b/test/escape2.go
index cc71471..dfc37ed 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -802,8 +802,8 @@
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
@@ -823,7 +823,7 @@
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -863,8 +863,8 @@
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "foo105 x does not escape$"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
@@ -894,7 +894,7 @@
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x$"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
 	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
diff --git a/test/escape2n.go b/test/escape2n.go
index bf8c534..56f05eb 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -802,8 +802,8 @@
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
@@ -823,7 +823,7 @@
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -863,8 +863,8 @@
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "foo105 x does not escape$"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
@@ -894,7 +894,7 @@
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x$"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
 	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
diff --git a/test/escape5.go b/test/escape5.go
index 1d411b3..6a138ea 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -117,7 +117,6 @@
 	return p, q
 }
 
-
 var global interface{}
 
 type T1 struct {
@@ -141,12 +140,12 @@
 
 func f9() {
 	var j T1 // ERROR "moved to heap: j"
-	f8(&j) // ERROR "&j escapes to heap"
+	f8(&j)   // ERROR "&j escapes to heap"
 }
 
 func f10() {
 	// These don't escape but are too big for the stack
-	var x [1<<30]byte // ERROR "moved to heap: x"
-	var y = make([]byte, 1<<30) // ERROR "does not escape"
+	var x [1 << 30]byte         // ERROR "moved to heap: x"
+	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
 	_ = x[0] + y[0]
 }
diff --git a/test/escape_array.go b/test/escape_array.go
index ac51fe7..5da7771 100644
--- a/test/escape_array.go
+++ b/test/escape_array.go
@@ -4,10 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test escape analysis for function parameters.
-
-// In this test almost everything is BAD except the simplest cases
-// where input directly flows to output.
+// Test escape analysis for arrays and some large things
 
 package foo
 
@@ -59,14 +56,67 @@
 	return x[1]
 }
 
-// BAD: would be nice to record that *y (content) is what leaks, not y itself
 func fum(x *U, y **string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$"
 	x[0] = *y
 	return x[1]
 }
 
-// BAD: would be nice to record that y[0] (content) is what leaks, not y itself
 func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$"
 	x[0] = y[0]
 	return x[1]
 }
+
+// These two tests verify that:
+// small array literals are stack allocated;
+// pointers stored in small array literals do not escape;
+// large array literals are heap allocated;
+// pointers stored in large array literals escape.
+func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "hugeLeaks1 y does not escape" "mark escaped content: x"
+	a := [10]*string{*y}
+	_ = a
+	// 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger.
+	b := [4000000]*string{*x} // ERROR "moved to heap: b"
+	_ = b
+}
+
+func hugeLeaks2(x *string, y *string) { // ERROR "leaking param: x" "hugeLeaks2 y does not escape"
+	a := [10]*string{y}
+	_ = a
+	// 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger.
+	b := [4000000]*string{x} // ERROR "moved to heap: b"
+	_ = b
+}
+
+// BAD: x need not leak.
+func doesNew1(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := new([10]*string) // ERROR "new\(\[10\]\*string\) does not escape"
+	a[0] = x
+	b := new([65537]*string) // ERROR "new\(\[65537\]\*string\) escapes to heap"
+	b[0] = y
+}
+
+type a10 struct {
+	s *string
+	i [10]int32
+}
+
+type a65537 struct {
+	s *string
+	i [65537]int32
+}
+
+// BAD: x need not leak.
+func doesNew2(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := new(a10) // ERROR "new\(a10\) does not escape"
+	a.s = x
+	b := new(a65537) // ERROR "new\(a65537\) escapes to heap"
+	b.s = y
+}
+
+// BAD: x need not leak.
+func doesMakeSlice(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := make([]*string, 10) // ERROR "make\(\[\]\*string, 10\) does not escape"
+	a[0] = x
+	b := make([]*string, 65537) // ERROR "make\(\[\]\*string, 65537\) escapes to heap"
+	b[0] = y
+}
diff --git a/test/escape_calls.go b/test/escape_calls.go
index f289670..8c9a6da 100644
--- a/test/escape_calls.go
+++ b/test/escape_calls.go
@@ -42,3 +42,13 @@
 	*np = n
 	return w + wl + wr
 }
+
+// Test for bug where func var f used prototype's escape analysis results.
+func prototype(xyz []string) {} // ERROR "prototype xyz does not escape"
+func bar() {
+	var got [][]string
+	f := prototype
+	f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape"
+	s := "string"
+	f([]string{s}) // ERROR "\[\]string literal escapes to heap"
+}
diff --git a/test/escape_slice.go b/test/escape_slice.go
index 9315e27..0b65997 100644
--- a/test/escape_slice.go
+++ b/test/escape_slice.go
@@ -8,6 +8,11 @@
 
 package escape
 
+import (
+	"os"
+	"strings"
+)
+
 var sink interface{}
 
 func slice0() {
@@ -71,9 +76,8 @@
 }
 
 func slice8() {
-	// BAD: i should not escape here
-	i := 0          // ERROR "moved to heap: i"
-	s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape"
+	i := 0
+	s := []*int{&i} // ERROR "&i does not escape" "literal does not escape"
 	_ = s
 }
 
@@ -88,3 +92,74 @@
 	s := []*int{&i} // ERROR "&i escapes to heap" "literal escapes to heap"
 	return s
 }
+
+func envForDir(dir string) []string { // ERROR "dir does not escape"
+	env := os.Environ()
+	return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape"
+}
+
+func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0"
+NextVar:
+	for _, inkv := range in {
+		k := strings.SplitAfterN(inkv, "=", 2)[0]
+		for i, outkv := range out {
+			if strings.HasPrefix(outkv, k) {
+				out[i] = inkv
+				continue NextVar
+			}
+		}
+		out = append(out, inkv)
+	}
+	return out
+}
+
+const (
+	IPv4len = 4
+	IPv6len = 16
+)
+
+var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
+
+func IPv4(a, b, c, d byte) IP {
+	p := make(IP, IPv6len) // ERROR "make\(IP, IPv6len\) escapes to heap"
+	copy(p, v4InV6Prefix)
+	p[12] = a
+	p[13] = b
+	p[14] = c
+	p[15] = d
+	return p
+}
+
+type IP []byte
+
+type IPAddr struct {
+	IP   IP
+	Zone string // IPv6 scoped addressing zone
+}
+
+type resolveIPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *IPAddr
+	err           error
+}
+
+var resolveIPAddrTests = []resolveIPAddrTest{
+	{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+}
+
+func setupTestData() {
+	resolveIPAddrTests = append(resolveIPAddrTests,
+		[]resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest literal does not escape"
+			{"ip",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+			{"ip4",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+		}...)
+}
diff --git a/test/fixedbugs/bug248.go b/test/fixedbugs/bug248.go
index 3d9a408..173b46f 100644
--- a/test/fixedbugs/bug248.go
+++ b/test/fixedbugs/bug248.go
@@ -9,16 +9,12 @@
 
 import (
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 	"path/filepath"
 )
 
 func main() {
-	a, err := build.ArchChar(build.Default.GOARCH)
-	check(err)
-
 	// TODO: If we get rid of errchk, re-enable this test on Windows.
 	errchk, err := filepath.Abs("errchk")
 	check(err)
@@ -26,17 +22,17 @@
 	err = os.Chdir(filepath.Join("fixedbugs", "bug248.dir"))
 	check(err)
 
-	run("go", "tool", a+"g", "bug0.go")
-	run("go", "tool", a+"g", "bug1.go")
-	run("go", "tool", a+"g", "bug2.go")
-	run(errchk, "go", "tool", a+"g", "-e", "bug3.go")
-	run("go", "tool", a+"l", "bug2."+a)
-	run(fmt.Sprintf(".%c%s.out", filepath.Separator, a))
+	run("go", "tool", "compile", "bug0.go")
+	run("go", "tool", "compile", "bug1.go")
+	run("go", "tool", "compile", "bug2.go")
+	run(errchk, "go", "tool", "compile", "-e", "bug3.go")
+	run("go", "tool", "link", "bug2.o")
+	run(fmt.Sprintf(".%ca.out", filepath.Separator))
 
-	os.Remove("bug0." + a)
-	os.Remove("bug1." + a)
-	os.Remove("bug2." + a)
-	os.Remove(a + ".out")
+	os.Remove("bug0.o")
+	os.Remove("bug1.o")
+	os.Remove("bug2.o")
+	os.Remove("a.out")
 }
 
 func run(name string, args ...string) {
diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go
index 327d522..42345a9 100644
--- a/test/fixedbugs/bug302.go
+++ b/test/fixedbugs/bug302.go
@@ -9,26 +9,18 @@
 
 import (
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 	"path/filepath"
-	"runtime"
 )
 
 func main() {
-	a, err := build.ArchChar(runtime.GOARCH)
-	if err != nil {
-		fmt.Println("BUG:", err)
-		os.Exit(1)
-	}
-
-	run("go", "tool", a+"g", filepath.Join("fixedbugs", "bug302.dir", "p.go"))
-	run("go", "tool", "pack", "grc", "pp.a", "p."+a)
-	run("go", "tool", a+"g", "-I", ".", filepath.Join("fixedbugs", "bug302.dir", "main.go"))
-	os.Remove("p."+a)
+	run("go", "tool", "compile", filepath.Join("fixedbugs", "bug302.dir", "p.go"))
+	run("go", "tool", "pack", "grc", "pp.a", "p.o")
+	run("go", "tool", "compile", "-I", ".", filepath.Join("fixedbugs", "bug302.dir", "main.go"))
+	os.Remove("p.o")
 	os.Remove("pp.a")
-	os.Remove("main."+a)
+	os.Remove("main.o")
 }
 
 func run(cmd string, args ...string) {
diff --git a/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
index 745144f..e291a55 100644
--- a/test/fixedbugs/bug345.go
+++ b/test/fixedbugs/bug345.go
@@ -9,16 +9,12 @@
 
 import (
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 	"path/filepath"
 )
 
 func main() {
-	a, err := build.ArchChar(build.Default.GOARCH)
-	check(err)
-
 	// TODO: If we get rid of errchk, re-enable this test on Plan 9 and Windows.
 	errchk, err := filepath.Abs("errchk")
 	check(err)
@@ -26,9 +22,9 @@
 	err = os.Chdir(filepath.Join(".", "fixedbugs", "bug345.dir"))
 	check(err)
 
-	run("go", "tool", a+"g", "io.go")
-	run(errchk, "go", "tool", a+"g", "-e", "main.go")
-	os.Remove("io." + a)
+	run("go", "tool", "compile", "io.go")
+	run(errchk, "go", "tool", "compile", "-e", "main.go")
+	os.Remove("io.o")
 }
 
 func run(name string, args ...string) {
diff --git a/test/fixedbugs/bug369.go b/test/fixedbugs/bug369.go
index 519703f..dd48da8 100644
--- a/test/fixedbugs/bug369.go
+++ b/test/fixedbugs/bug369.go
@@ -11,28 +11,24 @@
 
 import (
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 	"path/filepath"
 )
 
 func main() {
-	a, err := build.ArchChar(build.Default.GOARCH)
+	err := os.Chdir(filepath.Join(".", "fixedbugs", "bug369.dir"))
 	check(err)
 
-	err = os.Chdir(filepath.Join(".", "fixedbugs", "bug369.dir"))
-	check(err)
-
-	run("go", "tool", a+"g", "-N", "-o", "slow."+a, "pkg.go")
-	run("go", "tool", a+"g", "-o", "fast."+a, "pkg.go")
-	run("go", "tool", a+"g", "-o", "main."+a, "main.go")
-	run("go", "tool", a+"l", "-o", "a.exe", "main."+a)
+	run("go", "tool", "compile", "-N", "-o", "slow.o", "pkg.go")
+	run("go", "tool", "compile", "-o", "fast.o", "pkg.go")
+	run("go", "tool", "compile", "-o", "main.o", "main.go")
+	run("go", "tool", "link", "-o", "a.exe", "main.o")
 	run("." + string(filepath.Separator) + "a.exe")
 
-	os.Remove("slow." + a)
-	os.Remove("fast." + a)
-	os.Remove("main." + a)
+	os.Remove("slow.o")
+	os.Remove("fast.o")
+	os.Remove("main.o")
 	os.Remove("a.exe")
 }
 
diff --git a/test/fixedbugs/issue10925.go b/test/fixedbugs/issue10925.go
new file mode 100644
index 0000000..30add82
--- /dev/null
+++ b/test/fixedbugs/issue10925.go
@@ -0,0 +1,23 @@
+// run
+
+// 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 "fmt"
+
+func prototype(xyz []string) {}
+func main() {
+	var got [][]string
+	f := prototype
+	f = func(ss []string) { got = append(got, ss) }
+	for _, s := range []string{"one", "two", "three"} {
+		f([]string{s})
+	}
+	if got[0][0] != "one" || got[1][0] != "two" || got[2][0] != "three" {
+		// Bug's wrong output was [[three] [three] [three]]
+		fmt.Println("Expected [[one] [two] [three]], got", got)
+	}
+}
diff --git a/test/fixedbugs/issue7746.go b/test/fixedbugs/issue7746.go
new file mode 100644
index 0000000..0dc119d
--- /dev/null
+++ b/test/fixedbugs/issue7746.go
@@ -0,0 +1,133 @@
+// errorcheck
+
+// 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
+
+const (
+	c0   = 1 << 100
+	c1   = c0 * c0
+	c2   = c1 * c1
+	c3   = c2 * c2 // ERROR "overflow"
+	c4   = c3 * c3
+	c5   = c4 * c4
+	c6   = c5 * c5
+	c7   = c6 * c6
+	c8   = c7 * c7
+	c9   = c8 * c8
+	c10  = c9 * c9
+	c11  = c10 * c10
+	c12  = c11 * c11
+	c13  = c12 * c12
+	c14  = c13 * c13
+	c15  = c14 * c14
+	c16  = c15 * c15
+	c17  = c16 * c16
+	c18  = c17 * c17
+	c19  = c18 * c18
+	c20  = c19 * c19
+	c21  = c20 * c20
+	c22  = c21 * c21
+	c23  = c22 * c22
+	c24  = c23 * c23
+	c25  = c24 * c24
+	c26  = c25 * c25
+	c27  = c26 * c26
+	c28  = c27 * c27
+	c29  = c28 * c28
+	c30  = c29 * c29
+	c31  = c30 * c30
+	c32  = c31 * c31
+	c33  = c32 * c32
+	c34  = c33 * c33
+	c35  = c34 * c34
+	c36  = c35 * c35
+	c37  = c36 * c36
+	c38  = c37 * c37
+	c39  = c38 * c38
+	c40  = c39 * c39
+	c41  = c40 * c40
+	c42  = c41 * c41
+	c43  = c42 * c42
+	c44  = c43 * c43
+	c45  = c44 * c44
+	c46  = c45 * c45
+	c47  = c46 * c46
+	c48  = c47 * c47
+	c49  = c48 * c48
+	c50  = c49 * c49
+	c51  = c50 * c50
+	c52  = c51 * c51
+	c53  = c52 * c52
+	c54  = c53 * c53
+	c55  = c54 * c54
+	c56  = c55 * c55
+	c57  = c56 * c56
+	c58  = c57 * c57
+	c59  = c58 * c58
+	c60  = c59 * c59
+	c61  = c60 * c60
+	c62  = c61 * c61
+	c63  = c62 * c62
+	c64  = c63 * c63
+	c65  = c64 * c64
+	c66  = c65 * c65
+	c67  = c66 * c66
+	c68  = c67 * c67
+	c69  = c68 * c68
+	c70  = c69 * c69
+	c71  = c70 * c70
+	c72  = c71 * c71
+	c73  = c72 * c72
+	c74  = c73 * c73
+	c75  = c74 * c74
+	c76  = c75 * c75
+	c77  = c76 * c76
+	c78  = c77 * c77
+	c79  = c78 * c78
+	c80  = c79 * c79
+	c81  = c80 * c80
+	c82  = c81 * c81
+	c83  = c82 * c82
+	c84  = c83 * c83
+	c85  = c84 * c84
+	c86  = c85 * c85
+	c87  = c86 * c86
+	c88  = c87 * c87
+	c89  = c88 * c88
+	c90  = c89 * c89
+	c91  = c90 * c90
+	c92  = c91 * c91
+	c93  = c92 * c92
+	c94  = c93 * c93
+	c95  = c94 * c94
+	c96  = c95 * c95
+	c97  = c96 * c96
+	c98  = c97 * c97
+	c99  = c98 * c98
+	c100 = c99 * c99
+)
+
+func main() {
+	println(c1 / c1)
+	println(c2 / c2)
+	println(c3 / c3)
+	println(c4 / c4)
+	println(c5 / c5)
+	println(c6 / c6)
+	println(c7 / c7)
+	println(c8 / c8)
+	println(c9 / c9)
+	println(c10 / c10)
+	println(c20 / c20)
+	println(c30 / c30)
+	println(c40 / c40)
+	println(c50 / c50)
+	println(c60 / c60)
+	println(c70 / c70)
+	println(c80 / c80)
+	println(c90 / c90)
+	println(c100 / c100)
+}
diff --git a/test/fixedbugs/issue8183.go b/test/fixedbugs/issue8183.go
new file mode 100644
index 0000000..7104f1e
--- /dev/null
+++ b/test/fixedbugs/issue8183.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// 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.
+
+// Tests correct reporting of line numbers for errors involving iota,
+// Issue #8183.
+package foo
+
+const (
+	ok = byte(iota + 253)
+	bad
+	barn
+	bard // ERROR "constant 256 overflows byte"
+)
+
+const (
+	c = len([1 - iota]int{})
+	d
+	e // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
+	f // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
+)
diff --git a/test/fixedbugs/issue8745.go b/test/fixedbugs/issue8745.go
new file mode 100644
index 0000000..f3a70af
--- /dev/null
+++ b/test/fixedbugs/issue8745.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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 that the error says s[2] is a byte, not a uint8.
+
+package p
+
+func f(s string) {
+	var _ float64 = s[2] // ERROR "cannot use.*type byte.*as type float64"
+}
diff --git a/test/fixedbugs/issue9036.go b/test/fixedbugs/issue9036.go
new file mode 100644
index 0000000..283159e
--- /dev/null
+++ b/test/fixedbugs/issue9036.go
@@ -0,0 +1,29 @@
+// errorcheck
+
+// 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.
+
+// Expects to see error messages on "p" exponents.
+
+package main
+
+import "fmt"
+
+const (
+	x1 = 1.1    // float
+	x2 = 1e10   // float
+	x3 = 0x1e10 // integer (e is a hex digit)
+	x4 = 0x1p10 // ERROR "malformed floating point constant"
+	x5 = 1p10   // ERROR "malformed floating point constant"
+	x6 = 0p0    // ERROR "malformed floating point constant"
+)
+
+func main() {
+	fmt.Printf("%g %T\n", x1, x1)
+	fmt.Printf("%g %T\n", x2, x2)
+	fmt.Printf("%g %T\n", x3, x3)
+	fmt.Printf("%g %T\n", x4, x4)
+	fmt.Printf("%g %T\n", x5, x5)
+	fmt.Printf("%g %T\n", x6, x6)
+}
diff --git a/test/fixedbugs/issue9355.go b/test/fixedbugs/issue9355.go
index bdc0dd0..40c9ba9 100644
--- a/test/fixedbugs/issue9355.go
+++ b/test/fixedbugs/issue9355.go
@@ -8,7 +8,6 @@
 
 import (
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -20,14 +19,12 @@
 	if runtime.Compiler != "gc" || runtime.GOOS == "nacl" {
 		return
 	}
-	a, err := build.ArchChar(runtime.GOARCH)
+
+	err := os.Chdir(filepath.Join("fixedbugs", "issue9355.dir"))
 	check(err)
 
-	err = os.Chdir(filepath.Join("fixedbugs", "issue9355.dir"))
-	check(err)
-
-	out := run("go", "tool", a+"g", "-S", "a.go")
-	os.Remove("a." + a)
+	out := run("go", "tool", "compile", "-S", "a.go")
+	os.Remove("a.o")
 
 	// 6g/8g print the offset as dec, but 5g/9g print the offset as hex.
 	patterns := []string{
diff --git a/test/fixedbugs/issue9521.go b/test/fixedbugs/issue9521.go
new file mode 100644
index 0000000..ef0a5a6
--- /dev/null
+++ b/test/fixedbugs/issue9521.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// 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 an incorrect use of the blank identifer is caught.
+// Does not compile.
+
+package main
+
+func f() (_, _ []int)         { return }
+func g() (x []int, y float64) { return }
+
+func main() {
+	_ = append(f()) // ERROR "cannot append \[\]int value to \[\]int"
+	_ = append(g()) // ERROR "cannot append float64 value to \[\]int"
+}
diff --git a/test/nosplit.go b/test/nosplit.go
index bd7a8dd..8864137 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -184,19 +184,10 @@
 		goarch = runtime.GOARCH
 	}
 
-	thechar := ""
-	if gochar, err := exec.Command("go", "env", "GOCHAR").Output(); err != nil {
-		bug()
-		fmt.Printf("running go env GOCHAR: %v\n", err)
-		return
-	} else {
-		thechar = strings.TrimSpace(string(gochar))
-	}
-
-	version, err := exec.Command("go", "tool", thechar+"g", "-V").Output()
+	version, err := exec.Command("go", "tool", "compile", "-V").Output()
 	if err != nil {
 		bug()
-		fmt.Printf("running go tool %sg -V: %v\n", thechar, err)
+		fmt.Printf("running go tool compile -V: %v\n", err)
 		return
 	}
 	if strings.Contains(string(version), "framepointer") {
diff --git a/test/rotate0.go b/test/rotate0.go
index 9c4f560..400b225 100644
--- a/test/rotate0.go
+++ b/test/rotate0.go
@@ -1,5 +1,3 @@
-// skip
-
 // runoutput ./rotate.go
 
 // Copyright 2013 The Go Authors.  All rights reserved.
diff --git a/test/rotate1.go b/test/rotate1.go
index 2d9b797..98b0b1c 100644
--- a/test/rotate1.go
+++ b/test/rotate1.go
@@ -1,5 +1,3 @@
-// skip
-
 // runoutput ./rotate.go
 
 // Copyright 2013 The Go Authors.  All rights reserved.
diff --git a/test/rotate2.go b/test/rotate2.go
index 9044625..c50f8ce 100644
--- a/test/rotate2.go
+++ b/test/rotate2.go
@@ -1,5 +1,3 @@
-// skip
-
 // runoutput ./rotate.go
 
 // Copyright 2013 The Go Authors.  All rights reserved.
diff --git a/test/rotate3.go b/test/rotate3.go
index b6b71c8..73d47d8 100644
--- a/test/rotate3.go
+++ b/test/rotate3.go
@@ -1,5 +1,3 @@
-// skip
-
 // runoutput ./rotate.go
 
 // Copyright 2013 The Go Authors.  All rights reserved.
diff --git a/test/run.go b/test/run.go
index 10ba7a8..47a6298 100644
--- a/test/run.go
+++ b/test/run.go
@@ -15,7 +15,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"go/build"
 	"io/ioutil"
 	"log"
 	"os"
@@ -41,12 +40,6 @@
 )
 
 var (
-	// gc and ld are [568][gl].
-	gc, ld string
-
-	// letter is the build.ArchChar
-	letter string
-
 	goos, goarch string
 
 	// dirs are the directories to look for *.go files in.
@@ -84,11 +77,6 @@
 
 	ratec = make(chan bool, *numParallel)
 	rungatec = make(chan bool, *runoutputLimit)
-	var err error
-	letter, err = build.ArchChar(build.Default.GOARCH)
-	check(err)
-	gc = letter + "g"
-	ld = letter + "l"
 
 	var tests []*test
 	if flag.NArg() > 0 {
@@ -192,11 +180,11 @@
 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 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 @@
 		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 @@
 			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 b0a91ce..c9afd3b7 100644
--- a/test/sinit_run.go
+++ b/test/sinit_run.go
@@ -12,26 +12,19 @@
 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 0000000..c9d089f
--- /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 1f25d91..9b741a6 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -28,7 +28,7 @@
 	*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 @@
 	*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 @@
 	*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 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"
+}